aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/controllers/api/users/registrations.ts
diff options
context:
space:
mode:
Diffstat (limited to 'server/controllers/api/users/registrations.ts')
-rw-r--r--server/controllers/api/users/registrations.ts236
1 files changed, 236 insertions, 0 deletions
diff --git a/server/controllers/api/users/registrations.ts b/server/controllers/api/users/registrations.ts
new file mode 100644
index 000000000..3d4e0aa18
--- /dev/null
+++ b/server/controllers/api/users/registrations.ts
@@ -0,0 +1,236 @@
1import express from 'express'
2import { Emailer } from '@server/lib/emailer'
3import { Hooks } from '@server/lib/plugins/hooks'
4import { UserRegistrationModel } from '@server/models/user/user-registration'
5import { pick } from '@shared/core-utils'
6import { HttpStatusCode, UserRegister, UserRegistrationRequest, UserRegistrationState, UserRight } from '@shared/models'
7import { auditLoggerFactory, UserAuditView } from '../../../helpers/audit-logger'
8import { logger } from '../../../helpers/logger'
9import { CONFIG } from '../../../initializers/config'
10import { Notifier } from '../../../lib/notifier'
11import { buildUser, createUserAccountAndChannelAndPlaylist, sendVerifyRegistrationEmail, sendVerifyUserEmail } from '../../../lib/user'
12import {
13 acceptOrRejectRegistrationValidator,
14 asyncMiddleware,
15 asyncRetryTransactionMiddleware,
16 authenticate,
17 buildRateLimiter,
18 ensureUserHasRight,
19 ensureUserRegistrationAllowedFactory,
20 ensureUserRegistrationAllowedForIP,
21 getRegistrationValidator,
22 listRegistrationsValidator,
23 paginationValidator,
24 setDefaultPagination,
25 setDefaultSort,
26 userRegistrationsSortValidator,
27 usersDirectRegistrationValidator,
28 usersRequestRegistrationValidator
29} from '../../../middlewares'
30
31const auditLogger = auditLoggerFactory('users')
32
33const registrationRateLimiter = buildRateLimiter({
34 windowMs: CONFIG.RATES_LIMIT.SIGNUP.WINDOW_MS,
35 max: CONFIG.RATES_LIMIT.SIGNUP.MAX,
36 skipFailedRequests: true
37})
38
39const registrationsRouter = express.Router()
40
41registrationsRouter.post('/registrations/request',
42 registrationRateLimiter,
43 asyncMiddleware(ensureUserRegistrationAllowedFactory('request-registration')),
44 ensureUserRegistrationAllowedForIP,
45 asyncMiddleware(usersRequestRegistrationValidator),
46 asyncRetryTransactionMiddleware(requestRegistration)
47)
48
49registrationsRouter.post('/registrations/:registrationId/accept',
50 authenticate,
51 ensureUserHasRight(UserRight.MANAGE_REGISTRATIONS),
52 asyncMiddleware(acceptOrRejectRegistrationValidator),
53 asyncRetryTransactionMiddleware(acceptRegistration)
54)
55registrationsRouter.post('/registrations/:registrationId/reject',
56 authenticate,
57 ensureUserHasRight(UserRight.MANAGE_REGISTRATIONS),
58 asyncMiddleware(acceptOrRejectRegistrationValidator),
59 asyncRetryTransactionMiddleware(rejectRegistration)
60)
61
62registrationsRouter.delete('/registrations/:registrationId',
63 authenticate,
64 ensureUserHasRight(UserRight.MANAGE_REGISTRATIONS),
65 asyncMiddleware(getRegistrationValidator),
66 asyncRetryTransactionMiddleware(deleteRegistration)
67)
68
69registrationsRouter.get('/registrations',
70 authenticate,
71 ensureUserHasRight(UserRight.MANAGE_REGISTRATIONS),
72 paginationValidator,
73 userRegistrationsSortValidator,
74 setDefaultSort,
75 setDefaultPagination,
76 listRegistrationsValidator,
77 asyncMiddleware(listRegistrations)
78)
79
80registrationsRouter.post('/register',
81 registrationRateLimiter,
82 asyncMiddleware(ensureUserRegistrationAllowedFactory('direct-registration')),
83 ensureUserRegistrationAllowedForIP,
84 asyncMiddleware(usersDirectRegistrationValidator),
85 asyncRetryTransactionMiddleware(registerUser)
86)
87
88// ---------------------------------------------------------------------------
89
90export {
91 registrationsRouter
92}
93
94// ---------------------------------------------------------------------------
95
96async function requestRegistration (req: express.Request, res: express.Response) {
97 const body: UserRegistrationRequest = req.body
98
99 const registration = new UserRegistrationModel({
100 ...pick(body, [ 'username', 'password', 'email', 'registrationReason' ]),
101
102 accountDisplayName: body.displayName,
103 channelDisplayName: body.channel?.displayName,
104 channelHandle: body.channel?.name,
105
106 state: UserRegistrationState.PENDING,
107
108 emailVerified: CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION ? false : null
109 })
110
111 await registration.save()
112
113 if (CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION) {
114 await sendVerifyRegistrationEmail(registration)
115 }
116
117 Notifier.Instance.notifyOnNewRegistrationRequest(registration)
118
119 Hooks.runAction('action:api.user.requested-registration', { body, registration, req, res })
120
121 return res.json(registration.toFormattedJSON())
122}
123
124// ---------------------------------------------------------------------------
125
126async function acceptRegistration (req: express.Request, res: express.Response) {
127 const registration = res.locals.userRegistration
128
129 const userToCreate = buildUser({
130 username: registration.username,
131 password: registration.password,
132 email: registration.email,
133 emailVerified: registration.emailVerified
134 })
135 // We already encrypted password in registration model
136 userToCreate.skipPasswordEncryption = true
137
138 // TODO: handle conflicts if someone else created a channel handle/user handle/user email between registration and approval
139
140 const { user } = await createUserAccountAndChannelAndPlaylist({
141 userToCreate,
142 userDisplayName: registration.accountDisplayName,
143 channelNames: registration.channelHandle && registration.channelDisplayName
144 ? {
145 name: registration.channelHandle,
146 displayName: registration.channelDisplayName
147 }
148 : undefined
149 })
150
151 registration.userId = user.id
152 registration.state = UserRegistrationState.ACCEPTED
153 registration.moderationResponse = req.body.moderationResponse
154
155 await registration.save()
156
157 logger.info('Registration of %s accepted', registration.username)
158
159 Emailer.Instance.addUserRegistrationRequestProcessedJob(registration)
160
161 return res.sendStatus(HttpStatusCode.NO_CONTENT_204)
162}
163
164async function rejectRegistration (req: express.Request, res: express.Response) {
165 const registration = res.locals.userRegistration
166
167 registration.state = UserRegistrationState.REJECTED
168 registration.moderationResponse = req.body.moderationResponse
169
170 await registration.save()
171
172 Emailer.Instance.addUserRegistrationRequestProcessedJob(registration)
173
174 logger.info('Registration of %s rejected', registration.username)
175
176 return res.sendStatus(HttpStatusCode.NO_CONTENT_204)
177}
178
179// ---------------------------------------------------------------------------
180
181async function deleteRegistration (req: express.Request, res: express.Response) {
182 const registration = res.locals.userRegistration
183
184 await registration.destroy()
185
186 logger.info('Registration of %s deleted', registration.username)
187
188 return res.sendStatus(HttpStatusCode.NO_CONTENT_204)
189}
190
191// ---------------------------------------------------------------------------
192
193async function listRegistrations (req: express.Request, res: express.Response) {
194 const resultList = await UserRegistrationModel.listForApi({
195 start: req.query.start,
196 count: req.query.count,
197 sort: req.query.sort,
198 search: req.query.search
199 })
200
201 return res.json({
202 total: resultList.total,
203 data: resultList.data.map(d => d.toFormattedJSON())
204 })
205}
206
207// ---------------------------------------------------------------------------
208
209async function registerUser (req: express.Request, res: express.Response) {
210 const body: UserRegister = req.body
211
212 const userToCreate = buildUser({
213 ...pick(body, [ 'username', 'password', 'email' ]),
214
215 emailVerified: CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION ? false : null
216 })
217
218 const { user, account, videoChannel } = await createUserAccountAndChannelAndPlaylist({
219 userToCreate,
220 userDisplayName: body.displayName || undefined,
221 channelNames: body.channel
222 })
223
224 auditLogger.create(body.username, new UserAuditView(user.toFormattedJSON()))
225 logger.info('User %s with its channel and account registered.', body.username)
226
227 if (CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION) {
228 await sendVerifyUserEmail(user)
229 }
230
231 Notifier.Instance.notifyOnNewDirectRegistration(user)
232
233 Hooks.runAction('action:api.user.registered', { body, user, account, videoChannel, req, res })
234
235 return res.sendStatus(HttpStatusCode.NO_CONTENT_204)
236}