user-email-verification.ts 3.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. import express from 'express'
  2. import { body, param } from 'express-validator'
  3. import { toBooleanOrNull } from '@server/helpers/custom-validators/misc'
  4. import { HttpStatusCode } from '@shared/models'
  5. import { logger } from '../../helpers/logger'
  6. import { Redis } from '../../lib/redis'
  7. import { areValidationErrors, checkUserEmailExist, checkUserIdExist } from './shared'
  8. import { checkRegistrationEmailExist, checkRegistrationIdExist } from './shared/user-registrations'
  9. const usersAskSendVerifyEmailValidator = [
  10. body('email').isEmail().not().isEmpty().withMessage('Should have a valid email'),
  11. async (req: express.Request, res: express.Response, next: express.NextFunction) => {
  12. if (areValidationErrors(req, res)) return
  13. const [ userExists, registrationExists ] = await Promise.all([
  14. checkUserEmailExist(req.body.email, res, false),
  15. checkRegistrationEmailExist(req.body.email, res, false)
  16. ])
  17. if (!userExists && !registrationExists) {
  18. logger.debug('User or registration with email %s does not exist (asking verify email).', req.body.email)
  19. // Do not leak our emails
  20. return res.status(HttpStatusCode.NO_CONTENT_204).end()
  21. }
  22. if (res.locals.user?.pluginAuth) {
  23. return res.fail({
  24. status: HttpStatusCode.CONFLICT_409,
  25. message: 'Cannot ask verification email of a user that uses a plugin authentication.'
  26. })
  27. }
  28. return next()
  29. }
  30. ]
  31. const usersVerifyEmailValidator = [
  32. param('id')
  33. .isInt().not().isEmpty().withMessage('Should have a valid id'),
  34. body('verificationString')
  35. .not().isEmpty().withMessage('Should have a valid verification string'),
  36. body('isPendingEmail')
  37. .optional()
  38. .customSanitizer(toBooleanOrNull),
  39. async (req: express.Request, res: express.Response, next: express.NextFunction) => {
  40. if (areValidationErrors(req, res)) return
  41. if (!await checkUserIdExist(req.params.id, res)) return
  42. const user = res.locals.user
  43. const redisVerificationString = await Redis.Instance.getUserVerifyEmailLink(user.id)
  44. if (redisVerificationString !== req.body.verificationString) {
  45. return res.fail({ status: HttpStatusCode.FORBIDDEN_403, message: 'Invalid verification string.' })
  46. }
  47. return next()
  48. }
  49. ]
  50. // ---------------------------------------------------------------------------
  51. const registrationVerifyEmailValidator = [
  52. param('registrationId')
  53. .isInt().not().isEmpty().withMessage('Should have a valid registrationId'),
  54. body('verificationString')
  55. .not().isEmpty().withMessage('Should have a valid verification string'),
  56. async (req: express.Request, res: express.Response, next: express.NextFunction) => {
  57. if (areValidationErrors(req, res)) return
  58. if (!await checkRegistrationIdExist(req.params.registrationId, res)) return
  59. const registration = res.locals.userRegistration
  60. const redisVerificationString = await Redis.Instance.getRegistrationVerifyEmailLink(registration.id)
  61. if (redisVerificationString !== req.body.verificationString) {
  62. return res.fail({ status: HttpStatusCode.FORBIDDEN_403, message: 'Invalid verification string.' })
  63. }
  64. return next()
  65. }
  66. ]
  67. // ---------------------------------------------------------------------------
  68. export {
  69. usersAskSendVerifyEmailValidator,
  70. usersVerifyEmailValidator,
  71. registrationVerifyEmailValidator
  72. }