1 import express from 'express'
2 import { body, param, query, ValidationChain } from 'express-validator'
3 import { exists, isIdValid } from '@server/helpers/custom-validators/misc'
4 import { isRegistrationModerationResponseValid, isRegistrationReasonValid } from '@server/helpers/custom-validators/user-registration'
5 import { CONFIG } from '@server/initializers/config'
6 import { Hooks } from '@server/lib/plugins/hooks'
7 import { HttpStatusCode, UserRegister, UserRegistrationRequest, UserRegistrationState } from '@shared/models'
8 import { isUserDisplayNameValid, isUserPasswordValid, isUserUsernameValid } from '../../helpers/custom-validators/users'
9 import { isVideoChannelDisplayNameValid, isVideoChannelUsernameValid } from '../../helpers/custom-validators/video-channels'
10 import { isSignupAllowed, isSignupAllowedForCurrentIP, SignupMode } from '../../lib/signup'
11 import { ActorModel } from '../../models/actor/actor'
12 import { areValidationErrors, checkUserNameOrEmailDoNotAlreadyExist } from './shared'
13 import { checkRegistrationHandlesDoNotAlreadyExist, checkRegistrationIdExist } from './shared/user-registrations'
15 const usersDirectRegistrationValidator = usersCommonRegistrationValidatorFactory()
17 const usersRequestRegistrationValidator = [
18 ...usersCommonRegistrationValidatorFactory([
19 body('registrationReason')
20 .custom(isRegistrationReasonValid)
23 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
24 const body: UserRegistrationRequest = req.body
26 if (CONFIG.SIGNUP.REQUIRES_APPROVAL !== true) {
28 status: HttpStatusCode.BAD_REQUEST_400,
29 message: 'Signup approval is not enabled on this instance'
33 const options = { username: body.username, email: body.email, channelHandle: body.channel?.name, res }
34 if (!await checkRegistrationHandlesDoNotAlreadyExist(options)) return
40 // ---------------------------------------------------------------------------
42 function ensureUserRegistrationAllowedFactory (signupMode: SignupMode) {
43 return async (req: express.Request, res: express.Response, next: express.NextFunction) => {
44 const allowedParams = {
50 const allowedResult = await Hooks.wrapPromiseFun(
54 signupMode === 'direct-registration'
55 ? 'filter:api.user.signup.allowed.result'
56 : 'filter:api.user.request-signup.allowed.result'
59 if (allowedResult.allowed === false) {
61 status: HttpStatusCode.FORBIDDEN_403,
62 message: allowedResult.errorMessage || 'User registration is not enabled, user limit is reached or registration requires approval.'
70 const ensureUserRegistrationAllowedForIP = [
71 (req: express.Request, res: express.Response, next: express.NextFunction) => {
72 const allowed = isSignupAllowedForCurrentIP(req.ip)
74 if (allowed === false) {
76 status: HttpStatusCode.FORBIDDEN_403,
77 message: 'You are not on a network authorized for registration.'
85 // ---------------------------------------------------------------------------
87 const acceptOrRejectRegistrationValidator = [
88 param('registrationId')
91 body('moderationResponse')
92 .custom(isRegistrationModerationResponseValid),
94 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
95 if (areValidationErrors(req, res)) return
96 if (!await checkRegistrationIdExist(req.params.registrationId, res)) return
98 if (res.locals.userRegistration.state !== UserRegistrationState.PENDING) {
100 status: HttpStatusCode.CONFLICT_409,
101 message: 'This registration is already accepted or rejected.'
109 // ---------------------------------------------------------------------------
111 const getRegistrationValidator = [
112 param('registrationId')
115 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
116 if (areValidationErrors(req, res)) return
117 if (!await checkRegistrationIdExist(req.params.registrationId, res)) return
123 // ---------------------------------------------------------------------------
125 const listRegistrationsValidator = [
130 (req: express.Request, res: express.Response, next: express.NextFunction) => {
131 if (areValidationErrors(req, res)) return
137 // ---------------------------------------------------------------------------
140 usersDirectRegistrationValidator,
141 usersRequestRegistrationValidator,
143 ensureUserRegistrationAllowedFactory,
144 ensureUserRegistrationAllowedForIP,
146 getRegistrationValidator,
147 listRegistrationsValidator,
149 acceptOrRejectRegistrationValidator
152 // ---------------------------------------------------------------------------
154 function usersCommonRegistrationValidatorFactory (additionalValidationChain: ValidationChain[] = []) {
157 .custom(isUserUsernameValid),
159 .custom(isUserPasswordValid),
164 .custom(isUserDisplayNameValid),
168 .custom(isVideoChannelUsernameValid),
169 body('channel.displayName')
171 .custom(isVideoChannelDisplayNameValid),
173 ...additionalValidationChain,
175 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
176 if (areValidationErrors(req, res, { omitBodyLog: true })) return
178 const body: UserRegister | UserRegistrationRequest = req.body
180 if (!await checkUserNameOrEmailDoNotAlreadyExist(body.username, body.email, res)) return
183 if (!body.channel.name || !body.channel.displayName) {
184 return res.fail({ message: 'Channel is optional but if you specify it, channel.name and channel.displayName are required.' })
187 if (body.channel.name === body.username) {
188 return res.fail({ message: 'Channel name cannot be the same as user username.' })
191 const existing = await ActorModel.loadLocalByName(body.channel.name)
194 status: HttpStatusCode.CONFLICT_409,
195 message: `Channel with name ${body.channel.name} already exists.`