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'
6 import { HttpStatusCode, UserRegister, UserRegistrationRequest, UserRegistrationState, UserRight } from '@shared/models'
7 import { auditLoggerFactory, UserAuditView } from '../../../helpers/audit-logger'
8 import { logger } from '../../../helpers/logger'
9 import { CONFIG } from '../../../initializers/config'
10 import { Notifier } from '../../../lib/notifier'
11 import { buildUser, createUserAccountAndChannelAndPlaylist, sendVerifyRegistrationEmail, sendVerifyUserEmail } from '../../../lib/user'
13 acceptOrRejectRegistrationValidator,
15 asyncRetryTransactionMiddleware,
19 ensureUserRegistrationAllowedFactory,
20 ensureUserRegistrationAllowedForIP,
21 getRegistrationValidator,
22 listRegistrationsValidator,
26 userRegistrationsSortValidator,
27 usersDirectRegistrationValidator,
28 usersRequestRegistrationValidator
29 } from '../../../middlewares'
31 const auditLogger = auditLoggerFactory('users')
33 const registrationRateLimiter = buildRateLimiter({
34 windowMs: CONFIG.RATES_LIMIT.SIGNUP.WINDOW_MS,
35 max: CONFIG.RATES_LIMIT.SIGNUP.MAX,
36 skipFailedRequests: true
39 const registrationsRouter = express.Router()
41 registrationsRouter.post('/registrations/request',
42 registrationRateLimiter,
43 asyncMiddleware(ensureUserRegistrationAllowedFactory('request-registration')),
44 ensureUserRegistrationAllowedForIP,
45 asyncMiddleware(usersRequestRegistrationValidator),
46 asyncRetryTransactionMiddleware(requestRegistration)
49 registrationsRouter.post('/registrations/:registrationId/accept',
51 ensureUserHasRight(UserRight.MANAGE_REGISTRATIONS),
52 asyncMiddleware(acceptOrRejectRegistrationValidator),
53 asyncRetryTransactionMiddleware(acceptRegistration)
55 registrationsRouter.post('/registrations/:registrationId/reject',
57 ensureUserHasRight(UserRight.MANAGE_REGISTRATIONS),
58 asyncMiddleware(acceptOrRejectRegistrationValidator),
59 asyncRetryTransactionMiddleware(rejectRegistration)
62 registrationsRouter.delete('/registrations/:registrationId',
64 ensureUserHasRight(UserRight.MANAGE_REGISTRATIONS),
65 asyncMiddleware(getRegistrationValidator),
66 asyncRetryTransactionMiddleware(deleteRegistration)
69 registrationsRouter.get('/registrations',
71 ensureUserHasRight(UserRight.MANAGE_REGISTRATIONS),
73 userRegistrationsSortValidator,
76 listRegistrationsValidator,
77 asyncMiddleware(listRegistrations)
80 registrationsRouter.post('/register',
81 registrationRateLimiter,
82 asyncMiddleware(ensureUserRegistrationAllowedFactory('direct-registration')),
83 ensureUserRegistrationAllowedForIP,
84 asyncMiddleware(usersDirectRegistrationValidator),
85 asyncRetryTransactionMiddleware(registerUser)
88 // ---------------------------------------------------------------------------
94 // ---------------------------------------------------------------------------
96 async function requestRegistration (req: express.Request, res: express.Response) {
97 const body: UserRegistrationRequest = req.body
99 const registration = new UserRegistrationModel({
100 ...pick(body, [ 'username', 'password', 'email', 'registrationReason' ]),
102 accountDisplayName: body.displayName,
103 channelDisplayName: body.channel?.displayName,
104 channelHandle: body.channel?.name,
106 state: UserRegistrationState.PENDING,
108 emailVerified: CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION ? false : null
111 await registration.save()
113 if (CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION) {
114 await sendVerifyRegistrationEmail(registration)
117 Notifier.Instance.notifyOnNewRegistrationRequest(registration)
119 Hooks.runAction('action:api.user.requested-registration', { body, registration, req, res })
121 return res.json(registration.toFormattedJSON())
124 // ---------------------------------------------------------------------------
126 async function acceptRegistration (req: express.Request, res: express.Response) {
127 const registration = res.locals.userRegistration
129 const userToCreate = buildUser({
130 username: registration.username,
131 password: registration.password,
132 email: registration.email,
133 emailVerified: registration.emailVerified
135 // We already encrypted password in registration model
136 userToCreate.skipPasswordEncryption = true
138 // TODO: handle conflicts if someone else created a channel handle/user handle/user email between registration and approval
140 const { user } = await createUserAccountAndChannelAndPlaylist({
142 userDisplayName: registration.accountDisplayName,
143 channelNames: registration.channelHandle && registration.channelDisplayName
145 name: registration.channelHandle,
146 displayName: registration.channelDisplayName
151 registration.userId = user.id
152 registration.state = UserRegistrationState.ACCEPTED
153 registration.moderationResponse = req.body.moderationResponse
155 await registration.save()
157 logger.info('Registration of %s accepted', registration.username)
159 Emailer.Instance.addUserRegistrationRequestProcessedJob(registration)
161 return res.sendStatus(HttpStatusCode.NO_CONTENT_204)
164 async function rejectRegistration (req: express.Request, res: express.Response) {
165 const registration = res.locals.userRegistration
167 registration.state = UserRegistrationState.REJECTED
168 registration.moderationResponse = req.body.moderationResponse
170 await registration.save()
172 Emailer.Instance.addUserRegistrationRequestProcessedJob(registration)
174 logger.info('Registration of %s rejected', registration.username)
176 return res.sendStatus(HttpStatusCode.NO_CONTENT_204)
179 // ---------------------------------------------------------------------------
181 async function deleteRegistration (req: express.Request, res: express.Response) {
182 const registration = res.locals.userRegistration
184 await registration.destroy()
186 logger.info('Registration of %s deleted', registration.username)
188 return res.sendStatus(HttpStatusCode.NO_CONTENT_204)
191 // ---------------------------------------------------------------------------
193 async 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
202 total: resultList.total,
203 data: resultList.data.map(d => d.toFormattedJSON())
207 // ---------------------------------------------------------------------------
209 async function registerUser (req: express.Request, res: express.Response) {
210 const body: UserRegister = req.body
212 const userToCreate = buildUser({
213 ...pick(body, [ 'username', 'password', 'email' ]),
215 emailVerified: CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION ? false : null
218 const { user, account, videoChannel } = await createUserAccountAndChannelAndPlaylist({
220 userDisplayName: body.displayName || undefined,
221 channelNames: body.channel
224 auditLogger.create(body.username, new UserAuditView(user.toFormattedJSON()))
225 logger.info('User %s with its channel and account registered.', body.username)
227 if (CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION) {
228 await sendVerifyUserEmail(user)
231 Notifier.Instance.notifyOnNewDirectRegistration(user)
233 Hooks.runAction('action:api.user.registered', { body, user, account, videoChannel, req, res })
235 return res.sendStatus(HttpStatusCode.NO_CONTENT_204)