123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- import express from 'express'
- import { body, param, query, ValidationChain } from 'express-validator'
- import { exists, isIdValid } from '@server/helpers/custom-validators/misc'
- import { isRegistrationModerationResponseValid, isRegistrationReasonValid } from '@server/helpers/custom-validators/user-registration'
- import { CONFIG } from '@server/initializers/config'
- import { Hooks } from '@server/lib/plugins/hooks'
- import { HttpStatusCode, UserRegister, UserRegistrationRequest, UserRegistrationState } from '@shared/models'
- import { isUserDisplayNameValid, isUserPasswordValid, isUserUsernameValid } from '../../helpers/custom-validators/users'
- import { isVideoChannelDisplayNameValid, isVideoChannelUsernameValid } from '../../helpers/custom-validators/video-channels'
- import { isSignupAllowed, isSignupAllowedForCurrentIP, SignupMode } from '../../lib/signup'
- import { ActorModel } from '../../models/actor/actor'
- import { areValidationErrors, checkUserNameOrEmailDoNotAlreadyExist } from './shared'
- import { checkRegistrationHandlesDoNotAlreadyExist, checkRegistrationIdExist } from './shared/user-registrations'
- const usersDirectRegistrationValidator = usersCommonRegistrationValidatorFactory()
- const usersRequestRegistrationValidator = [
- ...usersCommonRegistrationValidatorFactory([
- body('registrationReason')
- .custom(isRegistrationReasonValid)
- ]),
- async (req: express.Request, res: express.Response, next: express.NextFunction) => {
- const body: UserRegistrationRequest = req.body
- if (CONFIG.SIGNUP.REQUIRES_APPROVAL !== true) {
- return res.fail({
- status: HttpStatusCode.BAD_REQUEST_400,
- message: 'Signup approval is not enabled on this instance'
- })
- }
- const options = { username: body.username, email: body.email, channelHandle: body.channel?.name, res }
- if (!await checkRegistrationHandlesDoNotAlreadyExist(options)) return
- return next()
- }
- ]
- // ---------------------------------------------------------------------------
- function ensureUserRegistrationAllowedFactory (signupMode: SignupMode) {
- return async (req: express.Request, res: express.Response, next: express.NextFunction) => {
- const allowedParams = {
- body: req.body,
- ip: req.ip,
- signupMode
- }
- const allowedResult = await Hooks.wrapPromiseFun(
- isSignupAllowed,
- allowedParams,
- signupMode === 'direct-registration'
- ? 'filter:api.user.signup.allowed.result'
- : 'filter:api.user.request-signup.allowed.result'
- )
- if (allowedResult.allowed === false) {
- return res.fail({
- status: HttpStatusCode.FORBIDDEN_403,
- message: allowedResult.errorMessage || 'User registration is not enabled, user limit is reached or registration requires approval.'
- })
- }
- return next()
- }
- }
- const ensureUserRegistrationAllowedForIP = [
- (req: express.Request, res: express.Response, next: express.NextFunction) => {
- const allowed = isSignupAllowedForCurrentIP(req.ip)
- if (allowed === false) {
- return res.fail({
- status: HttpStatusCode.FORBIDDEN_403,
- message: 'You are not on a network authorized for registration.'
- })
- }
- return next()
- }
- ]
- // ---------------------------------------------------------------------------
- const acceptOrRejectRegistrationValidator = [
- param('registrationId')
- .custom(isIdValid),
- body('moderationResponse')
- .custom(isRegistrationModerationResponseValid),
- async (req: express.Request, res: express.Response, next: express.NextFunction) => {
- if (areValidationErrors(req, res)) return
- if (!await checkRegistrationIdExist(req.params.registrationId, res)) return
- if (res.locals.userRegistration.state !== UserRegistrationState.PENDING) {
- return res.fail({
- status: HttpStatusCode.CONFLICT_409,
- message: 'This registration is already accepted or rejected.'
- })
- }
- return next()
- }
- ]
- // ---------------------------------------------------------------------------
- const getRegistrationValidator = [
- param('registrationId')
- .custom(isIdValid),
- async (req: express.Request, res: express.Response, next: express.NextFunction) => {
- if (areValidationErrors(req, res)) return
- if (!await checkRegistrationIdExist(req.params.registrationId, res)) return
- return next()
- }
- ]
- // ---------------------------------------------------------------------------
- const listRegistrationsValidator = [
- query('search')
- .optional()
- .custom(exists),
- (req: express.Request, res: express.Response, next: express.NextFunction) => {
- if (areValidationErrors(req, res)) return
- return next()
- }
- ]
- // ---------------------------------------------------------------------------
- export {
- usersDirectRegistrationValidator,
- usersRequestRegistrationValidator,
- ensureUserRegistrationAllowedFactory,
- ensureUserRegistrationAllowedForIP,
- getRegistrationValidator,
- listRegistrationsValidator,
- acceptOrRejectRegistrationValidator
- }
- // ---------------------------------------------------------------------------
- function usersCommonRegistrationValidatorFactory (additionalValidationChain: ValidationChain[] = []) {
- return [
- body('username')
- .custom(isUserUsernameValid),
- body('password')
- .custom(isUserPasswordValid),
- body('email')
- .isEmail(),
- body('displayName')
- .optional()
- .custom(isUserDisplayNameValid),
- body('channel.name')
- .optional()
- .custom(isVideoChannelUsernameValid),
- body('channel.displayName')
- .optional()
- .custom(isVideoChannelDisplayNameValid),
- ...additionalValidationChain,
- async (req: express.Request, res: express.Response, next: express.NextFunction) => {
- if (areValidationErrors(req, res, { omitBodyLog: true })) return
- const body: UserRegister | UserRegistrationRequest = req.body
- if (!await checkUserNameOrEmailDoNotAlreadyExist(body.username, body.email, res)) return
- if (body.channel) {
- if (!body.channel.name || !body.channel.displayName) {
- return res.fail({ message: 'Channel is optional but if you specify it, channel.name and channel.displayName are required.' })
- }
- if (body.channel.name === body.username) {
- return res.fail({ message: 'Channel name cannot be the same as user username.' })
- }
- const existing = await ActorModel.loadLocalByName(body.channel.name)
- if (existing) {
- return res.fail({
- status: HttpStatusCode.CONFLICT_409,
- message: `Channel with name ${body.channel.name} already exists.`
- })
- }
- }
- return next()
- }
- ]
- }
|