aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/middlewares/validators/users.ts
diff options
context:
space:
mode:
Diffstat (limited to 'server/middlewares/validators/users.ts')
-rw-r--r--server/middlewares/validators/users.ts104
1 files changed, 47 insertions, 57 deletions
diff --git a/server/middlewares/validators/users.ts b/server/middlewares/validators/users.ts
index eb693318f..055af3b64 100644
--- a/server/middlewares/validators/users.ts
+++ b/server/middlewares/validators/users.ts
@@ -1,9 +1,8 @@
1import express from 'express' 1import express from 'express'
2import { body, param, query } from 'express-validator' 2import { body, param, query } from 'express-validator'
3import { Hooks } from '@server/lib/plugins/hooks' 3import { Hooks } from '@server/lib/plugins/hooks'
4import { MUserDefault } from '@server/types/models'
5import { HttpStatusCode, UserRegister, UserRight, UserRole } from '@shared/models' 4import { HttpStatusCode, UserRegister, UserRight, UserRole } from '@shared/models'
6import { isBooleanValid, isIdValid, toBooleanOrNull, toIntOrNull } from '../../helpers/custom-validators/misc' 5import { exists, isBooleanValid, isIdValid, toBooleanOrNull, toIntOrNull } from '../../helpers/custom-validators/misc'
7import { isThemeNameValid } from '../../helpers/custom-validators/plugins' 6import { isThemeNameValid } from '../../helpers/custom-validators/plugins'
8import { 7import {
9 isUserAdminFlagsValid, 8 isUserAdminFlagsValid,
@@ -30,8 +29,15 @@ import { isThemeRegistered } from '../../lib/plugins/theme-utils'
30import { Redis } from '../../lib/redis' 29import { Redis } from '../../lib/redis'
31import { isSignupAllowed, isSignupAllowedForCurrentIP } from '../../lib/signup' 30import { isSignupAllowed, isSignupAllowedForCurrentIP } from '../../lib/signup'
32import { ActorModel } from '../../models/actor/actor' 31import { ActorModel } from '../../models/actor/actor'
33import { UserModel } from '../../models/user/user' 32import {
34import { areValidationErrors, doesVideoChannelIdExist, doesVideoExist, isValidVideoIdParam } from './shared' 33 areValidationErrors,
34 checkUserEmailExist,
35 checkUserIdExist,
36 checkUserNameOrEmailDoesNotAlreadyExist,
37 doesVideoChannelIdExist,
38 doesVideoExist,
39 isValidVideoIdParam
40} from './shared'
35 41
36const usersListValidator = [ 42const usersListValidator = [
37 query('blocked') 43 query('blocked')
@@ -435,7 +441,7 @@ const usersResetPasswordValidator = [
435 if (!await checkUserIdExist(req.params.id, res)) return 441 if (!await checkUserIdExist(req.params.id, res)) return
436 442
437 const user = res.locals.user 443 const user = res.locals.user
438 const redisVerificationString = await Redis.Instance.getResetPasswordLink(user.id) 444 const redisVerificationString = await Redis.Instance.getResetPasswordVerificationString(user.id)
439 445
440 if (redisVerificationString !== req.body.verificationString) { 446 if (redisVerificationString !== req.body.verificationString) {
441 return res.fail({ 447 return res.fail({
@@ -500,6 +506,41 @@ const usersVerifyEmailValidator = [
500 } 506 }
501] 507]
502 508
509const usersCheckCurrentPasswordFactory = (targetUserIdGetter: (req: express.Request) => number | string) => {
510 return [
511 body('currentPassword').optional().custom(exists),
512
513 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
514 if (areValidationErrors(req, res)) return
515
516 const user = res.locals.oauth.token.User
517 const isAdminOrModerator = user.role === UserRole.ADMINISTRATOR || user.role === UserRole.MODERATOR
518 const targetUserId = parseInt(targetUserIdGetter(req) + '')
519
520 // Admin/moderator action on another user, skip the password check
521 if (isAdminOrModerator && targetUserId !== user.id) {
522 return next()
523 }
524
525 if (!req.body.currentPassword) {
526 return res.fail({
527 status: HttpStatusCode.BAD_REQUEST_400,
528 message: 'currentPassword is missing'
529 })
530 }
531
532 if (await user.isPasswordMatch(req.body.currentPassword) !== true) {
533 return res.fail({
534 status: HttpStatusCode.FORBIDDEN_403,
535 message: 'currentPassword is invalid.'
536 })
537 }
538
539 return next()
540 }
541 ]
542}
543
503const userAutocompleteValidator = [ 544const userAutocompleteValidator = [
504 param('search') 545 param('search')
505 .isString() 546 .isString()
@@ -567,6 +608,7 @@ export {
567 usersUpdateValidator, 608 usersUpdateValidator,
568 usersUpdateMeValidator, 609 usersUpdateMeValidator,
569 usersVideoRatingValidator, 610 usersVideoRatingValidator,
611 usersCheckCurrentPasswordFactory,
570 ensureUserRegistrationAllowed, 612 ensureUserRegistrationAllowed,
571 ensureUserRegistrationAllowedForIP, 613 ensureUserRegistrationAllowedForIP,
572 usersGetValidator, 614 usersGetValidator,
@@ -580,55 +622,3 @@ export {
580 ensureCanModerateUser, 622 ensureCanModerateUser,
581 ensureCanManageChannelOrAccount 623 ensureCanManageChannelOrAccount
582} 624}
583
584// ---------------------------------------------------------------------------
585
586function checkUserIdExist (idArg: number | string, res: express.Response, withStats = false) {
587 const id = parseInt(idArg + '', 10)
588 return checkUserExist(() => UserModel.loadByIdWithChannels(id, withStats), res)
589}
590
591function checkUserEmailExist (email: string, res: express.Response, abortResponse = true) {
592 return checkUserExist(() => UserModel.loadByEmail(email), res, abortResponse)
593}
594
595async function checkUserNameOrEmailDoesNotAlreadyExist (username: string, email: string, res: express.Response) {
596 const user = await UserModel.loadByUsernameOrEmail(username, email)
597
598 if (user) {
599 res.fail({
600 status: HttpStatusCode.CONFLICT_409,
601 message: 'User with this username or email already exists.'
602 })
603 return false
604 }
605
606 const actor = await ActorModel.loadLocalByName(username)
607 if (actor) {
608 res.fail({
609 status: HttpStatusCode.CONFLICT_409,
610 message: 'Another actor (account/channel) with this name on this instance already exists or has already existed.'
611 })
612 return false
613 }
614
615 return true
616}
617
618async function checkUserExist (finder: () => Promise<MUserDefault>, res: express.Response, abortResponse = true) {
619 const user = await finder()
620
621 if (!user) {
622 if (abortResponse === true) {
623 res.fail({
624 status: HttpStatusCode.NOT_FOUND_404,
625 message: 'User not found'
626 })
627 }
628
629 return false
630 }
631
632 res.locals.user = user
633 return true
634}