From e364e31e25bd1d4b8d801c845a96d6be708f0a18 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 19 Jan 2023 09:27:16 +0100 Subject: Implement signup approval in server --- .../validators/user-email-verification.ts | 94 ++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 server/middlewares/validators/user-email-verification.ts (limited to 'server/middlewares/validators/user-email-verification.ts') diff --git a/server/middlewares/validators/user-email-verification.ts b/server/middlewares/validators/user-email-verification.ts new file mode 100644 index 000000000..74702a8f5 --- /dev/null +++ b/server/middlewares/validators/user-email-verification.ts @@ -0,0 +1,94 @@ +import express from 'express' +import { body, param } from 'express-validator' +import { toBooleanOrNull } from '@server/helpers/custom-validators/misc' +import { HttpStatusCode } from '@shared/models' +import { logger } from '../../helpers/logger' +import { Redis } from '../../lib/redis' +import { areValidationErrors, checkUserEmailExist, checkUserIdExist } from './shared' +import { checkRegistrationEmailExist, checkRegistrationIdExist } from './shared/user-registrations' + +const usersAskSendVerifyEmailValidator = [ + body('email').isEmail().not().isEmpty().withMessage('Should have a valid email'), + + async (req: express.Request, res: express.Response, next: express.NextFunction) => { + if (areValidationErrors(req, res)) return + + const [ userExists, registrationExists ] = await Promise.all([ + checkUserEmailExist(req.body.email, res, false), + checkRegistrationEmailExist(req.body.email, res, false) + ]) + + if (!userExists && !registrationExists) { + logger.debug('User or registration with email %s does not exist (asking verify email).', req.body.email) + // Do not leak our emails + return res.status(HttpStatusCode.NO_CONTENT_204).end() + } + + if (res.locals.user?.pluginAuth) { + return res.fail({ + status: HttpStatusCode.CONFLICT_409, + message: 'Cannot ask verification email of a user that uses a plugin authentication.' + }) + } + + return next() + } +] + +const usersVerifyEmailValidator = [ + param('id') + .isInt().not().isEmpty().withMessage('Should have a valid id'), + + body('verificationString') + .not().isEmpty().withMessage('Should have a valid verification string'), + body('isPendingEmail') + .optional() + .customSanitizer(toBooleanOrNull), + + async (req: express.Request, res: express.Response, next: express.NextFunction) => { + if (areValidationErrors(req, res)) return + if (!await checkUserIdExist(req.params.id, res)) return + + const user = res.locals.user + const redisVerificationString = await Redis.Instance.getUserVerifyEmailLink(user.id) + + if (redisVerificationString !== req.body.verificationString) { + return res.fail({ status: HttpStatusCode.FORBIDDEN_403, message: 'Invalid verification string.' }) + } + + return next() + } +] + +// --------------------------------------------------------------------------- + +const registrationVerifyEmailValidator = [ + param('registrationId') + .isInt().not().isEmpty().withMessage('Should have a valid registrationId'), + + body('verificationString') + .not().isEmpty().withMessage('Should have a valid verification string'), + + async (req: express.Request, res: express.Response, next: express.NextFunction) => { + if (areValidationErrors(req, res)) return + if (!await checkRegistrationIdExist(req.params.registrationId, res)) return + + const registration = res.locals.userRegistration + const redisVerificationString = await Redis.Instance.getRegistrationVerifyEmailLink(registration.id) + + if (redisVerificationString !== req.body.verificationString) { + return res.fail({ status: HttpStatusCode.FORBIDDEN_403, message: 'Invalid verification string.' }) + } + + return next() + } +] + +// --------------------------------------------------------------------------- + +export { + usersAskSendVerifyEmailValidator, + usersVerifyEmailValidator, + + registrationVerifyEmailValidator +} -- cgit v1.2.3