1 import express from 'express'
2 import { Emailer } from '@server/lib/emailer'
3 import { Hooks } from '@server/lib/plugins/hooks'
4 import { UserRegistrationModel } from '@server/models/user/user-registration'
5 import { pick } from '@shared/core-utils'
9 UserRegistrationRequest,
10 UserRegistrationState,
11 UserRegistrationUpdateState,
13 } from '@shared/models'
14 import { auditLoggerFactory, UserAuditView } from '../../../helpers/audit-logger'
15 import { logger } from '../../../helpers/logger'
16 import { CONFIG } from '../../../initializers/config'
17 import { Notifier } from '../../../lib/notifier'
18 import { buildUser, createUserAccountAndChannelAndPlaylist, sendVerifyRegistrationEmail, sendVerifyUserEmail } from '../../../lib/user'
20 acceptOrRejectRegistrationValidator,
22 asyncRetryTransactionMiddleware,
26 ensureUserRegistrationAllowedFactory,
27 ensureUserRegistrationAllowedForIP,
28 getRegistrationValidator,
29 listRegistrationsValidator,
33 userRegistrationsSortValidator,
34 usersDirectRegistrationValidator,
35 usersRequestRegistrationValidator
36 } from '../../../middlewares'
38 const auditLogger = auditLoggerFactory('users')
40 const registrationRateLimiter = buildRateLimiter({
41 windowMs: CONFIG.RATES_LIMIT.SIGNUP.WINDOW_MS,
42 max: CONFIG.RATES_LIMIT.SIGNUP.MAX,
43 skipFailedRequests: true
46 const registrationsRouter = express.Router()
48 registrationsRouter.post('/registrations/request',
49 registrationRateLimiter,
50 asyncMiddleware(ensureUserRegistrationAllowedFactory('request-registration')),
51 ensureUserRegistrationAllowedForIP,
52 asyncMiddleware(usersRequestRegistrationValidator),
53 asyncRetryTransactionMiddleware(requestRegistration)
56 registrationsRouter.post('/registrations/:registrationId/accept',
58 ensureUserHasRight(UserRight.MANAGE_REGISTRATIONS),
59 asyncMiddleware(acceptOrRejectRegistrationValidator),
60 asyncRetryTransactionMiddleware(acceptRegistration)
62 registrationsRouter.post('/registrations/:registrationId/reject',
64 ensureUserHasRight(UserRight.MANAGE_REGISTRATIONS),
65 asyncMiddleware(acceptOrRejectRegistrationValidator),
66 asyncRetryTransactionMiddleware(rejectRegistration)
69 registrationsRouter.delete('/registrations/:registrationId',
71 ensureUserHasRight(UserRight.MANAGE_REGISTRATIONS),
72 asyncMiddleware(getRegistrationValidator),
73 asyncRetryTransactionMiddleware(deleteRegistration)
76 registrationsRouter.get('/registrations',
78 ensureUserHasRight(UserRight.MANAGE_REGISTRATIONS),
80 userRegistrationsSortValidator,
83 listRegistrationsValidator,
84 asyncMiddleware(listRegistrations)
87 registrationsRouter.post('/register',
88 registrationRateLimiter,
89 asyncMiddleware(ensureUserRegistrationAllowedFactory('direct-registration')),
90 ensureUserRegistrationAllowedForIP,
91 asyncMiddleware(usersDirectRegistrationValidator),
92 asyncRetryTransactionMiddleware(registerUser)
95 // ---------------------------------------------------------------------------
101 // ---------------------------------------------------------------------------
103 async function requestRegistration (req: express.Request, res: express.Response) {
104 const body: UserRegistrationRequest = req.body
106 const registration = new UserRegistrationModel({
107 ...pick(body, [ 'username', 'password', 'email', 'registrationReason' ]),
109 accountDisplayName: body.displayName,
110 channelDisplayName: body.channel?.displayName,
111 channelHandle: body.channel?.name,
113 state: UserRegistrationState.PENDING,
115 emailVerified: CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION ? false : null
118 await registration.save()
120 if (CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION) {
121 await sendVerifyRegistrationEmail(registration)
124 Notifier.Instance.notifyOnNewRegistrationRequest(registration)
126 Hooks.runAction('action:api.user.requested-registration', { body, registration, req, res })
128 return res.json(registration.toFormattedJSON())
131 // ---------------------------------------------------------------------------
133 async function acceptRegistration (req: express.Request, res: express.Response) {
134 const registration = res.locals.userRegistration
135 const body: UserRegistrationUpdateState = req.body
137 const userToCreate = buildUser({
138 username: registration.username,
139 password: registration.password,
140 email: registration.email,
141 emailVerified: registration.emailVerified
143 // We already encrypted password in registration model
144 userToCreate.skipPasswordEncryption = true
146 // TODO: handle conflicts if someone else created a channel handle/user handle/user email between registration and approval
148 const { user } = await createUserAccountAndChannelAndPlaylist({
150 userDisplayName: registration.accountDisplayName,
151 channelNames: registration.channelHandle && registration.channelDisplayName
153 name: registration.channelHandle,
154 displayName: registration.channelDisplayName
159 registration.userId = user.id
160 registration.state = UserRegistrationState.ACCEPTED
161 registration.moderationResponse = body.moderationResponse
163 await registration.save()
165 logger.info('Registration of %s accepted', registration.username)
167 if (body.preventEmailDelivery !== true) {
168 Emailer.Instance.addUserRegistrationRequestProcessedJob(registration)
171 return res.sendStatus(HttpStatusCode.NO_CONTENT_204)
174 async function rejectRegistration (req: express.Request, res: express.Response) {
175 const registration = res.locals.userRegistration
176 const body: UserRegistrationUpdateState = req.body
178 registration.state = UserRegistrationState.REJECTED
179 registration.moderationResponse = body.moderationResponse
181 await registration.save()
183 if (body.preventEmailDelivery !== true) {
184 Emailer.Instance.addUserRegistrationRequestProcessedJob(registration)
187 logger.info('Registration of %s rejected', registration.username)
189 return res.sendStatus(HttpStatusCode.NO_CONTENT_204)
192 // ---------------------------------------------------------------------------
194 async function deleteRegistration (req: express.Request, res: express.Response) {
195 const registration = res.locals.userRegistration
197 await registration.destroy()
199 logger.info('Registration of %s deleted', registration.username)
201 return res.sendStatus(HttpStatusCode.NO_CONTENT_204)
204 // ---------------------------------------------------------------------------
206 async function listRegistrations (req: express.Request, res: express.Response) {
207 const resultList = await UserRegistrationModel.listForApi({
208 start: req.query.start,
209 count: req.query.count,
210 sort: req.query.sort,
211 search: req.query.search
215 total: resultList.total,
216 data: resultList.data.map(d => d.toFormattedJSON())
220 // ---------------------------------------------------------------------------
222 async function registerUser (req: express.Request, res: express.Response) {
223 const body: UserRegister = req.body
225 const userToCreate = buildUser({
226 ...pick(body, [ 'username', 'password', 'email' ]),
228 emailVerified: CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION ? false : null
231 const { user, account, videoChannel } = await createUserAccountAndChannelAndPlaylist({
233 userDisplayName: body.displayName || undefined,
234 channelNames: body.channel
237 auditLogger.create(body.username, new UserAuditView(user.toFormattedJSON()))
238 logger.info('User %s with its channel and account registered.', body.username)
240 if (CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION) {
241 await sendVerifyUserEmail(user)
244 Notifier.Instance.notifyOnNewDirectRegistration(user)
246 Hooks.runAction('action:api.user.registered', { body, user, account, videoChannel, req, res })
248 return res.sendStatus(HttpStatusCode.NO_CONTENT_204)