diff --git a/habitica-images b/habitica-images index e3215f16f9..aa72332019 160000 --- a/habitica-images +++ b/habitica-images @@ -1 +1 @@ -Subproject commit e3215f16f99f9e33bf218b46862d6b2ad9bd7fec +Subproject commit aa723320199d7f03ce749d431b46e8d7f95cc8de diff --git a/package.json b/package.json index 12972f46c4..4337c31920 100644 --- a/package.json +++ b/package.json @@ -29,9 +29,9 @@ "eslint": "^8.55.0", "eslint-config-habitrpg": "^6.2.3", "eslint-plugin-mocha": "^5.0.0", - "express": "^4.21.1", + "express": "5.1.0", "express-basic-auth": "^1.2.1", - "express-validator": "^5.2.0", + "express-validator": "7.2.1", "firebase-admin": "^12.1.1", "glob": "^8.1.0", "got": "^11.8.6", diff --git a/website/server/controllers/api-v3/auth.js b/website/server/controllers/api-v3/auth.js index 70c065a041..fb5f970120 100644 --- a/website/server/controllers/api-v3/auth.js +++ b/website/server/controllers/api-v3/auth.js @@ -3,6 +3,7 @@ import moment from 'moment'; import pick from 'lodash/pick'; import sortBy from 'lodash/sortBy'; import nconf from 'nconf'; +import { body , validationResult } from 'express-validator'; import { authWithHeaders, } from '../../middlewares/auth'; @@ -87,8 +88,8 @@ api.loginLocal = { errorMessage: res.t('missingPassword'), }, }); - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; req.sanitizeBody('username').trim(); req.sanitizeBody('password').trim(); @@ -216,8 +217,8 @@ api.updateUsername = { }, }); - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const newUsername = req.body.username; @@ -307,7 +308,7 @@ api.updatePassword = { }, }); - const validationErrors = req.validationErrors(); + const validationErrors = validationResult(req).array(); if (validationErrors) { throw validationErrors; @@ -353,8 +354,8 @@ api.resetPassword = { notEmpty: { errorMessage: res.t('missingEmail') }, }, }); - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const email = req.body.email.toLowerCase(); let user = await User.findOne( @@ -419,12 +420,12 @@ api.updateEmail = { if (!user.auth.local.email) throw new BadRequest(res.t('userHasNoLocalRegistration')); - req.checkBody('newEmail', res.t('newEmailRequired')).notEmpty().isEmail(); + await body('newEmail', res.t('newEmailRequired')).notEmpty().isEmail().run(req) if (user.auth.local.hashed_password) { - req.checkBody('password', res.t('missingPassword')).notEmpty(); + await body('password', res.t('missingPassword')).notEmpty().run(req) } - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const emailAlreadyInUse = await User.findOne({ 'auth.local.email': req.body.newEmail.toLowerCase(), @@ -485,8 +486,8 @@ api.resetPasswordSetNewOne = { }, }); - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const { newPassword, confirmPassword } = req.body; diff --git a/website/server/controllers/api-v3/challenges.js b/website/server/controllers/api-v3/challenges.js index ba9c411bf5..c190924150 100644 --- a/website/server/controllers/api-v3/challenges.js +++ b/website/server/controllers/api-v3/challenges.js @@ -4,6 +4,7 @@ import merge from 'lodash/merge'; import pick from 'lodash/pick'; import reduce from 'lodash/reduce'; import times from 'lodash/times'; +import { body, param, query , validationResult } from 'express-validator'; import { authWithHeaders, authWithSession } from '../../middlewares/auth'; import { model as Challenge } from '../../models/challenge'; import bannedWords from '../../libs/bannedWords'; @@ -232,11 +233,11 @@ api.createChallenge = { async handler (req, res) { const { user } = res.locals; - req.checkBody('group', apiError('groupIdRequired')).notEmpty(); - req.checkBody('summary', apiError('summaryLengthExceedsMax')).isLength({ max: MAX_SUMMARY_SIZE_FOR_CHALLENGES }); + await body('group', apiError('groupIdRequired')).notEmpty().run(req) + await body('summary', apiError('summaryLengthExceedsMax')).isLength({ max: MAX_SUMMARY_SIZE_FOR_CHALLENGES }).run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const group = await Group.getGroup({ user, groupId: req.body.group, fields: basicGroupFields, optionalMembership: true, @@ -328,10 +329,10 @@ api.joinChallenge = { async handler (req, res) { const { user } = res.locals; - req.checkParams('challengeId', res.t('challengeIdRequired')).notEmpty().isUUID(); + await param('challengeId', res.t('challengeIdRequired')).notEmpty().isUUID().run(req); - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const challenge = await Challenge.findOne({ _id: req.params.challengeId }).exec(); if (!challenge) throw new NotFound(res.t('challengeNotFound')); @@ -397,10 +398,10 @@ api.leaveChallenge = { const { user } = res.locals; const keep = req.body.keep === 'remove-all' ? 'remove-all' : 'keep-all'; - req.checkParams('challengeId', res.t('challengeIdRequired')).notEmpty().isUUID(); + await param('challengeId', res.t('challengeIdRequired')).notEmpty().isUUID().run(req); - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const challenge = await Challenge.findOne({ _id: req.params.challengeId }).exec(); if (!challenge) throw new NotFound(res.t('challengeNotFound')); @@ -463,10 +464,10 @@ api.getUserChallenges = { url: '/challenges/user', middlewares: [authWithHeaders()], async handler (req, res) { - req.checkQuery('page').notEmpty().isInt({ min: 0 }, apiError('queryPageInteger')); + await query('page').notEmpty().isInt({ min: 0 }, apiError('queryPageInteger')).run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const CHALLENGES_PER_PAGE = 10; const { @@ -599,10 +600,10 @@ api.getGroupChallenges = { const { user } = res.locals; let { groupId } = req.params; - req.checkParams('groupId', apiError('groupIdRequired')).notEmpty(); + await param('groupId', apiError('groupIdRequired')).notEmpty().run(req); - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; if (groupId === 'party') groupId = user.party._id; if (groupId === 'habitrpg') groupId = TAVERN_ID; @@ -661,10 +662,10 @@ api.getChallenge = { url: '/challenges/:challengeId', middlewares: [authWithHeaders()], async handler (req, res) { - req.checkParams('challengeId', res.t('challengeIdRequired')).notEmpty().isUUID(); + await param('challengeId', res.t('challengeIdRequired')).notEmpty().isUUID().run(req); - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const { user } = res.locals; const { challengeId } = req.params; @@ -719,10 +720,10 @@ api.exportChallengeCsv = { url: '/challenges/:challengeId/export/csv', middlewares: [authWithSession], async handler (req, res) { - req.checkParams('challengeId', res.t('challengeIdRequired')).notEmpty().isUUID(); + await param('challengeId', res.t('challengeIdRequired')).notEmpty().isUUID().run(req); - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const { user } = res.locals; const { challengeId } = req.params; @@ -836,11 +837,11 @@ api.updateChallenge = { url: '/challenges/:challengeId', middlewares: [authWithHeaders()], async handler (req, res) { - req.checkParams('challengeId', res.t('challengeIdRequired')).notEmpty().isUUID(); - req.checkBody('summary', apiError('summaryLengthExceedsMax')).isLength({ max: MAX_SUMMARY_SIZE_FOR_CHALLENGES }); + await param('challengeId', res.t('challengeIdRequired')).notEmpty().isUUID().run(req); + await body('summary', apiError('summaryLengthExceedsMax')).isLength({ max: MAX_SUMMARY_SIZE_FOR_CHALLENGES }).run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const { user } = res.locals; const { challengeId } = req.params; @@ -883,10 +884,10 @@ api.deleteChallenge = { async handler (req, res) { const { user } = res.locals; - req.checkParams('challengeId', res.t('challengeIdRequired')).notEmpty().isUUID(); + await param('challengeId', res.t('challengeIdRequired')).notEmpty().isUUID().run(req); - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const challenge = await Challenge.findOne({ _id: req.params.challengeId }).exec(); if (!challenge) throw new NotFound(res.t('challengeNotFound')); @@ -931,11 +932,11 @@ api.selectChallengeWinner = { async handler (req, res) { const { user } = res.locals; - req.checkParams('challengeId', res.t('challengeIdRequired')).notEmpty().isUUID(); - req.checkParams('winnerId', res.t('winnerIdRequired')).notEmpty().isUUID(); + await param('challengeId', res.t('challengeIdRequired')).notEmpty().isUUID().run(req); + await param('winnerId', res.t('winnerIdRequired')).notEmpty().isUUID().run(req); - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const challenge = await Challenge.findOne({ _id: req.params.challengeId }).exec(); if (!challenge) throw new NotFound(res.t('challengeNotFound')); @@ -992,10 +993,10 @@ api.cloneChallenge = { async handler (req, res) { const { user } = res.locals; - req.checkParams('challengeId', res.t('challengeIdRequired')).notEmpty().isUUID(); + await param('challengeId', res.t('challengeIdRequired')).notEmpty().isUUID().run(req); - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const challengeToClone = await Challenge.findOne({ _id: req.params.challengeId }).exec(); if (!challengeToClone) throw new NotFound(res.t('challengeNotFound')); @@ -1061,10 +1062,10 @@ api.flagChallenge = { async handler (req, res) { const { user } = res.locals; - req.checkParams('challengeId', res.t('challengeIdRequired')).notEmpty().isUUID(); + await param('challengeId', res.t('challengeIdRequired')).notEmpty().isUUID().run(req); - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const challenge = await Challenge.findOne({ _id: req.params.challengeId }).exec(); if (!challenge) throw new NotFound(res.t('challengeNotFound')); @@ -1094,10 +1095,10 @@ api.clearFlagsChallenge = { async handler (req, res) { const { user } = res.locals; - req.checkParams('challengeId', res.t('challengeIdRequired')).notEmpty().isUUID(); + await param('challengeId', res.t('challengeIdRequired')).notEmpty().isUUID().run(req); - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; if (!user.hasPermission('moderator')) { throw new NotAuthorized(res.t('messageGroupChatAdminClearFlagCount')); diff --git a/website/server/controllers/api-v3/coupon.js b/website/server/controllers/api-v3/coupon.js index 4b92178c57..ceaa991a15 100644 --- a/website/server/controllers/api-v3/coupon.js +++ b/website/server/controllers/api-v3/coupon.js @@ -1,5 +1,6 @@ import _ from 'lodash'; import couponCode from 'coupon-code'; +import { param, query , validationResult } from 'express-validator'; import csvStringify from '../../libs/csvStringify'; import { authWithHeaders, @@ -72,11 +73,11 @@ api.generateCoupons = { url: '/coupons/generate/:event', middlewares: [authWithHeaders(), ensurePermission('coupons')], async handler (req, res) { - req.checkParams('event', apiError('eventRequired')).notEmpty(); - req.checkQuery('count', apiError('countRequired')).notEmpty().isNumeric(); + await param('event', apiError('eventRequired')).notEmpty().run(req) + await query('count', apiError('countRequired')).notEmpty().isNumeric().run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const coupons = await Coupon.generate(req.params.event, req.query.count); res.respond(200, coupons); @@ -122,10 +123,10 @@ api.validateCoupon = { optional: true, })], async handler (req, res) { - req.checkParams('code', res.t('couponCodeRequired')).notEmpty(); + await param('code', res.t('couponCodeRequired')).notEmpty().run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; let valid = false; const code = couponCode.validate(req.params.code); diff --git a/website/server/controllers/api-v3/groups.js b/website/server/controllers/api-v3/groups.js index 7d0a4fb49a..498990d3cb 100644 --- a/website/server/controllers/api-v3/groups.js +++ b/website/server/controllers/api-v3/groups.js @@ -9,6 +9,7 @@ import pick from 'lodash/pick'; import uniqBy from 'lodash/uniqBy'; import nconf from 'nconf'; import moment from 'moment'; +import { body, param, query , validationResult } from 'express-validator'; import { authWithHeaders } from '../../middlewares/auth'; import { model as Group, @@ -132,10 +133,10 @@ api.createGroup = { const group = new Group(Group.sanitize(req.body)); group.leader = user._id; - req.checkBody('summary', apiError('summaryLengthExceedsMax')).isLength({ max: MAX_SUMMARY_SIZE_FOR_GUILDS }); + await body('summary', apiError('summaryLengthExceedsMax')).isLength({ max: MAX_SUMMARY_SIZE_FOR_GUILDS }).run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; if (group.type === 'guild') { if (!user.hasPermission('fullAccess')) { @@ -206,10 +207,10 @@ api.createGroupPlan = { const { user } = res.locals; const group = new Group(Group.sanitize(req.body.groupToCreate)); - req.checkBody('paymentType', res.t('paymentTypeRequired')).notEmpty(); - req.checkBody('summary', apiError('summaryLengthExceedsMax')).isLength({ max: MAX_SUMMARY_SIZE_FOR_GUILDS }); - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + await body('paymentType', res.t('paymentTypeRequired')).notEmpty().run(req) + await body('summary', apiError('summaryLengthExceedsMax')).isLength({ max: MAX_SUMMARY_SIZE_FOR_GUILDS }).run(req) + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; // @TODO: Change message if (group.privacy !== 'private') throw new NotAuthorized(res.t('partyMustbePrivate')); @@ -321,13 +322,13 @@ api.getGroups = { async handler (req, res) { const { user } = res.locals; - req.checkQuery('type', res.t('groupTypesRequired')).notEmpty(); + await query('type', res.t('groupTypesRequired')).notEmpty().run(req) // pagination options, can only be used with public guilds - req.checkQuery('paginate').optional().isIn(['true', 'false'], apiError('guildsPaginateBooleanString')); - req.checkQuery('page').optional().isInt({ min: 0 }, apiError('queryPageInteger')); + await query('paginate').optional().isIn(['true', 'false'], apiError('guildsPaginateBooleanString')).run(req) + await query('page').optional().isInt({ min: 0 }, apiError('queryPageInteger')).run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const types = req.query.type.split(','); @@ -419,10 +420,10 @@ api.getGroup = { async handler (req, res) { const { user } = res.locals; - req.checkParams('groupId', apiError('groupIdRequired')).notEmpty(); + await param('groupId', apiError('groupIdRequired')).notEmpty().run(req); - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const { groupId } = req.params; const group = await Group.getGroup({ user, groupId, populateLeader: false }); @@ -481,11 +482,11 @@ api.updateGroup = { async handler (req, res) { const { user } = res.locals; - req.checkParams('groupId', apiError('groupIdRequired')).notEmpty(); - req.checkBody('summary', apiError('summaryLengthExceedsMax')).isLength({ max: MAX_SUMMARY_SIZE_FOR_GUILDS }); + await param('groupId', apiError('groupIdRequired')).notEmpty().run(req); + await body('summary', apiError('summaryLengthExceedsMax')).isLength({ max: MAX_SUMMARY_SIZE_FOR_GUILDS }).run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const optionalMembership = Boolean(user.hasPermission('moderator')); const group = await Group.getGroup({ user, groupId: req.params.groupId, optionalMembership }); @@ -567,10 +568,10 @@ api.joinGroup = { const { user } = res.locals; let inviter; - req.checkParams('groupId', apiError('groupIdRequired')).notEmpty(); // .isUUID(); can't be used because it would block 'habitrpg' or 'party' + await param('groupId', apiError('groupIdRequired')).notEmpty().run(req); // .isUUID(); can't be used because it would block 'habitrpg' or 'party' - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; // Works even if the user is not yet a member of the group // Do not fetch chat and work even if the user is not yet a member of the group @@ -760,10 +761,10 @@ api.rejectGroupInvite = { async handler (req, res) { const { user } = res.locals; - req.checkParams('groupId', apiError('groupIdRequired')).notEmpty(); // .isUUID(); can't be used because it would block 'habitrpg' or 'party' + await param('groupId', apiError('groupIdRequired')).notEmpty().run(req); // .isUUID(); can't be used because it would block 'habitrpg' or 'party' - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const { groupId } = req.params; let isUserInvited = false; @@ -831,13 +832,13 @@ api.leaveGroup = { middlewares: [authWithHeaders()], async handler (req, res) { const { user } = res.locals; - req.checkParams('groupId', apiError('groupIdRequired')).notEmpty(); + await param('groupId', apiError('groupIdRequired')).notEmpty().run(req); // When removing the user from challenges, should we keep the tasks? - req.checkQuery('keep', apiError('keepOrRemoveAll')).optional().isIn(['keep-all', 'remove-all']); - req.checkBody('keepChallenges', apiError('groupRemainOrLeaveChallenges')).optional().isIn(['remain-in-challenges', 'leave-challenges']); + await query('keep', apiError('keepOrRemoveAll')).optional().isIn(['keep-all', 'remove-all']).run(req) + await body('keepChallenges', apiError('groupRemainOrLeaveChallenges')).optional().isIn(['remain-in-challenges', 'leave-challenges']).run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const { groupId } = req.params; await leaveGroup({ @@ -899,11 +900,11 @@ api.removeGroupMember = { async handler (req, res) { const { user } = res.locals; - req.checkParams('groupId', apiError('groupIdRequired')).notEmpty(); - req.checkParams('memberId', res.t('userIdRequired')).notEmpty().isUUID(); + await param('groupId', apiError('groupIdRequired')).notEmpty().run(req); + await param('memberId', res.t('userIdRequired')).notEmpty().isUUID().run(req); - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const optionalMembership = Boolean(user.hasPermission('moderator')); const group = await Group.getGroup({ user, groupId: req.params.groupId, optionalMembership, fields: '-chat', @@ -1105,12 +1106,12 @@ api.inviteToGroup = { if (user.flags.chatRevoked) throw new NotAuthorized(res.t('chatPrivilegesRevoked')); - req.checkParams('groupId', apiError('groupIdRequired')).notEmpty(); + await param('groupId', apiError('groupIdRequired')).notEmpty().run(req); if (user.invitesSent >= MAX_EMAIL_INVITES_BY_USER) throw new NotAuthorized(res.t('inviteLimitReached', { techAssistanceEmail: TECH_ASSISTANCE_EMAIL })); - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const group = await Group.getGroup({ user, groupId: req.params.groupId, fields: '-chat' }); if (!group) throw new NotFound(res.t('groupNotFound')); @@ -1182,11 +1183,11 @@ api.addGroupManager = { const { user } = res.locals; const { managerId } = req.body; - req.checkParams('groupId', apiError('groupIdRequired')).notEmpty(); // .isUUID(); can't be used because it would block 'habitrpg' or 'party' - req.checkBody('managerId', apiError('managerIdRequired')).notEmpty(); + await param('groupId', apiError('groupIdRequired')).notEmpty().run(req); // .isUUID(); can't be used because it would block 'habitrpg' or 'party' + await body('managerId', apiError('managerIdRequired')).notEmpty().run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const newManager = await User.findById(managerId, 'guilds party').exec(); const groupFields = basicGroupFields.concat(' managers'); @@ -1232,11 +1233,11 @@ api.removeGroupManager = { const { user } = res.locals; const { managerId } = req.body; - req.checkParams('groupId', apiError('groupIdRequired')).notEmpty(); // .isUUID(); can't be used because it would block 'habitrpg' or 'party' - req.checkBody('managerId', apiError('managerIdRequired')).notEmpty(); + await param('groupId', apiError('groupIdRequired')).notEmpty().run(req); // .isUUID(); can't be used because it would block 'habitrpg' or 'party' + await body('managerId', apiError('managerIdRequired')).notEmpty().run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const groupFields = basicGroupFields.concat(' managers'); const group = await Group.getGroup({ user, groupId: req.params.groupId, fields: groupFields }); @@ -1323,7 +1324,7 @@ api.getLookingForParty = { const USERS_PER_PAGE = 30; const { user } = res.locals; - req.checkQuery('page').optional().isInt({ min: 0 }, apiError('queryPageInteger')); + await query('page').optional().isInt({ min: 0 }, apiError('queryPageInteger')).run(req) const PAGE = req.query.page || 0; const PAGE_START = USERS_PER_PAGE * PAGE; diff --git a/website/server/controllers/api-v3/hall.js b/website/server/controllers/api-v3/hall.js index 78ad8669d8..3121537bb3 100644 --- a/website/server/controllers/api-v3/hall.js +++ b/website/server/controllers/api-v3/hall.js @@ -1,5 +1,6 @@ import _ from 'lodash'; import validator from 'validator'; +import { query, param , validationResult } from 'express-validator'; import { authWithHeaders } from '../../middlewares/auth'; import { ensurePermission } from '../../middlewares/ensureAccessRight'; import { model as User } from '../../models/user'; @@ -73,10 +74,10 @@ api.getPatrons = { url: '/hall/patrons', middlewares: [authWithHeaders()], async handler (req, res) { - req.checkQuery('page').optional().isInt({ min: 0 }, apiError('queryPageInteger')); + await query('page').optional().isInt({ min: 0 }, apiError('queryPageInteger')).run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const page = req.query.page ? Number(req.query.page) : 0; const perPage = 50; @@ -177,10 +178,10 @@ api.getHero = { url: '/hall/heroes/:heroId', middlewares: [authWithHeaders(), ensurePermission('userSupport')], async handler (req, res) { - req.checkParams('heroId', res.t('heroIdRequired')).notEmpty(); + await param('heroId', res.t('heroIdRequired')).notEmpty().run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const { heroId } = req.params; @@ -263,10 +264,10 @@ api.updateHero = { const { heroId } = req.params; const updateData = req.body; - req.checkParams('heroId', res.t('heroIdRequired')).notEmpty().isUUID(); + await param('heroId', res.t('heroIdRequired')).notEmpty().isUUID().run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const hero = await User.findById(heroId).exec(); if (!hero) throw new NotFound(res.t('userWithIDNotFound', { userId: heroId })); @@ -555,10 +556,10 @@ api.getHeroParty = { // @TODO XXX add tests url: '/hall/heroes/party/:groupId', middlewares: [authWithHeaders(), ensurePermission('userSupport')], async handler (req, res) { - req.checkParams('groupId', apiError('groupIdRequired')).notEmpty().isUUID(); + await param('groupId', apiError('groupIdRequired')).notEmpty().isUUID().run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const { groupId } = req.params; @@ -597,10 +598,10 @@ api.getHeroGroupPlans = { url: '/hall/heroes/:heroId/group-plans', middlewares: [authWithHeaders(), ensurePermission('userSupport')], async handler (req, res) { - req.checkParams('heroId', res.t('heroIdRequired')).notEmpty(); + await param('heroId', res.t('heroIdRequired')).notEmpty().run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const { heroId } = req.params; diff --git a/website/server/controllers/api-v3/members.js b/website/server/controllers/api-v3/members.js index 764a0ee211..76b8da081e 100644 --- a/website/server/controllers/api-v3/members.js +++ b/website/server/controllers/api-v3/members.js @@ -1,5 +1,6 @@ import escapeRegExp from 'lodash/escapeRegExp'; import pick from 'lodash/pick'; +import { body, param, query as checkQuery , validationResult } from 'express-validator'; import { authWithHeaders } from '../../middlewares/auth'; import { model as User, @@ -103,10 +104,10 @@ api.getMember = { url: '/members/:memberId', middlewares: [authWithHeaders()], async handler (req, res) { - req.checkParams('memberId', res.t('memberIdRequired')).notEmpty().isUUID(); + await param('memberId', res.t('memberIdRequired')).notEmpty().isUUID().run(req); - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const { memberId } = req.params; @@ -132,10 +133,10 @@ api.getMemberByUsername = { url: '/members/username/:username', middlewares: [authWithHeaders()], async handler (req, res) { - req.checkParams('username', res.t('invalidReqParams')).notEmpty(); + await param('username', res.t('invalidReqParams')).notEmpty().run(req); - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; let username = req.params.username.toLowerCase(); if (username[0] === '@') username = username.slice(1, username.length); @@ -261,10 +262,10 @@ api.getMemberAchievements = { url: '/members/:memberId/achievements', middlewares: [authWithHeaders()], async handler (req, res) { - req.checkParams('memberId', res.t('memberIdRequired')).notEmpty().isUUID(); + await param('memberId', res.t('memberIdRequired')).notEmpty().isUUID().run(req); - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const { memberId } = req.params; @@ -292,13 +293,13 @@ function _getMembersForItem (type) { } return async function handleGetMembersForItem (req, res) { - req.checkParams('groupId', res.t('groupIdRequired')).notEmpty(); - req.checkQuery('lastId').optional().notEmpty().isUUID(); + await param('groupId', res.t('groupIdRequired')).notEmpty().run(req); + await checkQuery('lastId').optional().notEmpty().isUUID().run(req) // Allow an arbitrary number of results (up to 60) - req.checkQuery('limit', res.t('groupIdRequired')).optional().notEmpty().isInt({ min: 1, max: 60 }); + await checkQuery('limit', res.t('groupIdRequired')).optional().notEmpty().isInt({ min: 1, max: 60 }).run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const { groupId } = req.params; const { lastId } = req.query; @@ -566,11 +567,11 @@ api.getChallengeMemberProgress = { url: '/challenges/:challengeId/members/:memberId', middlewares: [authWithHeaders()], async handler (req, res) { - req.checkParams('challengeId', res.t('challengeIdRequired')).notEmpty().isUUID(); - req.checkParams('memberId', res.t('memberIdRequired')).notEmpty().isUUID(); + await param('challengeId', res.t('challengeIdRequired')).notEmpty().isUUID().run(req); + await param('memberId', res.t('memberIdRequired')).notEmpty().isUUID().run(req); - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const { user } = res.locals; const { challengeId } = req.params; @@ -627,11 +628,11 @@ api.getObjectionsToInteraction = { url: '/members/:toUserId/objections/:interaction', middlewares: [authWithHeaders()], async handler (req, res) { - req.checkParams('toUserId', res.t('toUserIDRequired')).notEmpty().isUUID(); - req.checkParams('interaction', res.t('interactionRequired')).notEmpty().isIn(KNOWN_INTERACTIONS); + await param('toUserId', res.t('toUserIDRequired')).notEmpty().isUUID().run(req); + await param('interaction', res.t('interactionRequired')).notEmpty().isIn(KNOWN_INTERACTIONS).run(req); - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const sender = res.locals.user; const receiver = await User.findById(req.params.toUserId).exec(); @@ -662,11 +663,11 @@ api.transferGems = { url: '/members/transfer-gems', middlewares: [authWithHeaders()], async handler (req, res) { - req.checkBody('toUserId', res.t('toUserIDRequired')).notEmpty().isUUID(); - req.checkBody('gemAmount', res.t('gemAmountRequired')).notEmpty().isInt(); + await body('toUserId', res.t('toUserIDRequired')).notEmpty().isUUID().run(req) + await body('gemAmount', res.t('gemAmountRequired')).notEmpty().isInt().run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const sender = res.locals.user; const receiver = await User.findById(req.body.toUserId).exec(); @@ -815,9 +816,9 @@ api.clearUserFlags = { const { user } = res.locals; const { memberId } = req.params; - req.checkParams('memberId', res.t('memberIdRequired')).notEmpty().isUUID(); - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + await param('memberId', res.t('memberIdRequired')).notEmpty().isUUID().run(req); + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; if (!user.hasPermission('moderator')) { throw new BadRequest('Only a moderator may clear reports from a profile.'); diff --git a/website/server/controllers/api-v3/modelsPaths.js b/website/server/controllers/api-v3/modelsPaths.js index 5358d44f8c..338b8cabe5 100644 --- a/website/server/controllers/api-v3/modelsPaths.js +++ b/website/server/controllers/api-v3/modelsPaths.js @@ -1,4 +1,5 @@ import mongoose from 'mongoose'; +import { param , validationResult } from 'express-validator'; const api = {}; @@ -36,10 +37,10 @@ api.getModelPaths = { method: 'GET', url: '/models/:model/paths', async handler (req, res) { - req.checkParams('model', res.t('modelNotFound')).notEmpty().isIn(allModels); + await param('model', res.t('modelNotFound')).notEmpty().isIn(allModels).run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; let { model } = req.params; // tasks models are lowercase, the others have the first letter uppercase (User, Group) diff --git a/website/server/controllers/api-v3/pushNotifications.js b/website/server/controllers/api-v3/pushNotifications.js index 1b9c8a929a..5526d5adf4 100644 --- a/website/server/controllers/api-v3/pushNotifications.js +++ b/website/server/controllers/api-v3/pushNotifications.js @@ -1,3 +1,4 @@ +import { body, param , validationResult } from 'express-validator'; import { authWithHeaders } from '../../middlewares/auth'; import { NotFound, @@ -25,11 +26,11 @@ api.addPushDevice = { async handler (req, res) { const { user } = res.locals; - req.checkBody('regId', res.t('regIdRequired')).notEmpty(); - req.checkBody('type', res.t('typeRequired')).notEmpty().isIn(['ios', 'android']); + await body('regId', res.t('regIdRequired')).notEmpty().run(req) + await body('type', res.t('typeRequired')).notEmpty().isIn(['ios', 'android']).run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const { pushDevices } = user; @@ -75,10 +76,10 @@ api.removePushDevice = { async handler (req, res) { const { user } = res.locals; - req.checkParams('regId', res.t('regIdRequired')).notEmpty(); + await param('regId', res.t('regIdRequired')).notEmpty().run(req); - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const { regId } = req.params; diff --git a/website/server/controllers/api-v3/quests.js b/website/server/controllers/api-v3/quests.js index f45135e5b0..77d7627361 100644 --- a/website/server/controllers/api-v3/quests.js +++ b/website/server/controllers/api-v3/quests.js @@ -2,6 +2,7 @@ import each from 'lodash/each'; import every from 'lodash/every'; import isBoolean from 'lodash/isBoolean'; import pick from 'lodash/pick'; +import { param , validationResult } from 'express-validator'; import { authWithHeaders } from '../../middlewares/auth'; import { getAnalyticsServiceByEnvironment } from '../../libs/analyticsService'; import { @@ -68,10 +69,10 @@ api.inviteToQuest = { const { questKey } = req.params; const quest = questScrolls[questKey]; - req.checkParams('groupId', apiError('groupIdRequired')).notEmpty(); + await param('groupId', apiError('groupIdRequired')).notEmpty().run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const group = await Group.getGroup({ user, groupId: req.params.groupId, fields: basicGroupFields.concat(' quest chat') }); @@ -202,10 +203,10 @@ api.acceptQuest = { async handler (req, res) { const { user } = res.locals; - req.checkParams('groupId', apiError('groupIdRequired')).notEmpty(); + await param('groupId', apiError('groupIdRequired')).notEmpty().run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const group = await Group.getGroup({ user, groupId: req.params.groupId, fields: basicGroupFields.concat(' quest chat') }); @@ -267,10 +268,10 @@ api.rejectQuest = { async handler (req, res) { const { user } = res.locals; - req.checkParams('groupId', apiError('groupIdRequired')).notEmpty(); + await param('groupId', apiError('groupIdRequired')).notEmpty().run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const group = await Group.getGroup({ user, groupId: req.params.groupId, fields: basicGroupFields.concat(' quest chat') }); if (!group) throw new NotFound(res.t('groupNotFound')); @@ -335,10 +336,10 @@ api.forceStart = { async handler (req, res) { const { user } = res.locals; - req.checkParams('groupId', apiError('groupIdRequired')).notEmpty(); + await param('groupId', apiError('groupIdRequired')).notEmpty().run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const group = await Group.getGroup({ user, groupId: req.params.groupId, fields: basicGroupFields.concat(' quest chat') }); @@ -400,10 +401,10 @@ api.cancelQuest = { const { user } = res.locals; const { groupId } = req.params; - req.checkParams('groupId', apiError('groupIdRequired')).notEmpty(); + await param('groupId', apiError('groupIdRequired')).notEmpty().run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const group = await Group.getGroup({ user, groupId, fields: basicGroupFields.concat(' quest') }); @@ -475,10 +476,10 @@ api.abortQuest = { const { user } = res.locals; const { groupId } = req.params; - req.checkParams('groupId', apiError('groupIdRequired')).notEmpty(); + await param('groupId', apiError('groupIdRequired')).notEmpty().run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const group = await Group.getGroup({ user, groupId, fields: basicGroupFields.concat(' quest chat') }); @@ -549,10 +550,10 @@ api.leaveQuest = { const { user } = res.locals; const { groupId } = req.params; - req.checkParams('groupId', apiError('groupIdRequired')).notEmpty(); + await param('groupId', apiError('groupIdRequired')).notEmpty().run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const group = await Group.getGroup({ user, groupId, fields: basicGroupFields.concat(' quest') }); diff --git a/website/server/controllers/api-v3/tasks.js b/website/server/controllers/api-v3/tasks.js index 5d91b70557..606bad17fb 100644 --- a/website/server/controllers/api-v3/tasks.js +++ b/website/server/controllers/api-v3/tasks.js @@ -2,6 +2,7 @@ import assign from 'lodash/assign'; import find from 'lodash/find'; import merge from 'lodash/merge'; import pick from 'lodash/pick'; +import { param, query , validationResult } from 'express-validator' import moment from 'moment'; import { authWithHeaders } from '../../middlewares/auth'; import { @@ -310,9 +311,9 @@ api.createChallengeTasks = { url: '/tasks/challenge/:challengeId', middlewares: [authWithHeaders()], async handler (req, res) { - req.checkParams('challengeId', res.t('challengeIdRequired')).notEmpty().isUUID(); + await param('challengeId', res.t('challengeIdRequired')).notEmpty().isUUID().run(req) - const reqValidationErrors = req.validationErrors(); + const reqValidationErrors = validationResult(req).array(); if (reqValidationErrors) throw reqValidationErrors; const { user } = res.locals; @@ -394,10 +395,10 @@ api.getUserTasks = { async handler (req, res) { const types = Tasks.tasksTypes.map(type => `${type}s`); types.push('completedTodos', '_allCompletedTodos'); // _allCompletedTodos is currently in BETA and is likely to be removed in future - req.checkQuery('type', res.t('invalidTasksTypeExtra')).optional().isIn(types); + await query('type', res.t('invalidTasksTypeExtra')).optional().isIn(types).run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const { user } = res.locals; const { dueDate } = req.query; @@ -447,12 +448,12 @@ api.getChallengeTasks = { url: '/tasks/challenge/:challengeId', middlewares: [authWithHeaders()], async handler (req, res) { - req.checkParams('challengeId', res.t('challengeIdRequired')).notEmpty().isUUID(); + await param('challengeId', res.t('challengeIdRequired')).notEmpty().isUUID().run(req) const types = Tasks.tasksTypes.map(type => `${type}s`); - req.checkQuery('type', res.t('invalidTasksType')).optional().isIn(types); + await query('type', res.t('invalidTasksType')).optional().isIn(types).run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const { user } = res.locals; const { challengeId } = req.params; @@ -602,10 +603,10 @@ api.updateTask = { async handler (req, res) { const { user } = res.locals; - req.checkParams('taskId', apiError('taskIdRequired')).notEmpty(); + await param('taskId', apiError('taskIdRequired')).notEmpty().run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const { taskId } = req.params; const task = await Tasks.Task.findByIdOrAlias(taskId, user._id); @@ -805,11 +806,11 @@ api.moveTask = { url: '/tasks/:taskId/move/to/:position', middlewares: [authWithHeaders()], async handler (req, res) { - req.checkParams('taskId', apiError('taskIdRequired')).notEmpty(); - req.checkParams('position', res.t('positionRequired')).notEmpty().isNumeric(); + await param('taskId', apiError('taskIdRequired')).notEmpty().run(req) + await param('position', res.t('positionRequired')).notEmpty().isNumeric().run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const { user } = res.locals; const { taskId } = req.params; @@ -908,10 +909,10 @@ api.addChecklistItem = { async handler (req, res) { const { user } = res.locals; - req.checkParams('taskId', apiError('taskIdRequired')).notEmpty(); + await param('taskId', apiError('taskIdRequired')).notEmpty().run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const { taskId } = req.params; const task = await Tasks.Task.findByIdOrAlias(taskId, user._id); @@ -957,11 +958,11 @@ api.scoreCheckListItem = { async handler (req, res) { const { user } = res.locals; - req.checkParams('taskId', apiError('taskIdRequired')).notEmpty(); - req.checkParams('itemId', res.t('itemIdRequired')).notEmpty().isUUID(); + await param('taskId', apiError('taskIdRequired')).notEmpty().run(req) + await param('itemId', res.t('itemIdRequired')).notEmpty().isUUID().run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const { taskId } = req.params; const task = await Tasks.Task.findByIdOrAlias(taskId, user._id); @@ -1018,11 +1019,11 @@ api.updateChecklistItem = { async handler (req, res) { const { user } = res.locals; - req.checkParams('taskId', apiError('taskIdRequired')).notEmpty(); - req.checkParams('itemId', res.t('itemIdRequired')).notEmpty().isUUID(); + await param('taskId', apiError('taskIdRequired')).notEmpty().run(req) + await param('itemId', res.t('itemIdRequired')).notEmpty().isUUID().run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const { taskId } = req.params; const task = await Tasks.Task.findByIdOrAlias(taskId, user._id); @@ -1079,11 +1080,11 @@ api.removeChecklistItem = { async handler (req, res) { const { user } = res.locals; - req.checkParams('taskId', apiError('taskIdRequired')).notEmpty(); - req.checkParams('itemId', res.t('itemIdRequired')).notEmpty().isUUID(); + await param('taskId', apiError('taskIdRequired')).notEmpty().run(req) + await param('itemId', res.t('itemIdRequired')).notEmpty().isUUID().run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const { taskId } = req.params; const task = await Tasks.Task.findByIdOrAlias(taskId, user._id); @@ -1141,12 +1142,12 @@ api.addTagToTask = { async handler (req, res) { const { user } = res.locals; - req.checkParams('taskId', apiError('taskIdRequired')).notEmpty(); + await param('taskId', apiError('taskIdRequired')).notEmpty().run(req) const userTags = user.tags.map(tag => tag.id); - req.checkParams('tagId', res.t('tagIdRequired')).notEmpty().isUUID().isIn(userTags); + await param('tagId', res.t('tagIdRequired')).notEmpty().isUUID().isIn(userTags).run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const { taskId } = req.params; const task = await Tasks.Task.findByIdOrAlias(taskId, user._id, { userId: user._id }); @@ -1198,11 +1199,11 @@ api.removeTagFromTask = { async handler (req, res) { const { user } = res.locals; - req.checkParams('taskId', apiError('taskIdRequired')).notEmpty(); - req.checkParams('tagId', res.t('tagIdRequired')).notEmpty().isUUID(); + await param('taskId', apiError('taskIdRequired')).notEmpty().run(req) + await param('tagId', res.t('tagIdRequired')).notEmpty().isUUID().run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const { taskId } = req.params; const task = await Tasks.Task.findByIdOrAlias(taskId, user._id, { userId: user._id }); @@ -1243,11 +1244,11 @@ api.unlinkAllTasks = { url: '/tasks/unlink-all/:challengeId', middlewares: [authWithHeaders()], async handler (req, res) { - req.checkParams('challengeId', res.t('challengeIdRequired')).notEmpty().isUUID(); - req.checkQuery('keep', apiError('keepOrRemoveAll')).notEmpty().isIn(['keep-all', 'remove-all']); + await param('challengeId', res.t('challengeIdRequired')).notEmpty().isUUID().run(req) + await query('keep', apiError('keepOrRemoveAll')).notEmpty().isIn(['keep-all', 'remove-all']).run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const { user } = res.locals; const { keep } = req.query; @@ -1309,11 +1310,11 @@ api.unlinkOneTask = { url: '/tasks/unlink-one/:taskId', middlewares: [authWithHeaders()], async handler (req, res) { - req.checkParams('taskId', apiError('taskIdRequired')).notEmpty().isUUID(); - req.checkQuery('keep', apiError('keepOrRemove')).notEmpty().isIn(['keep', 'remove']); + await param('taskId', apiError('taskIdRequired')).notEmpty().isUUID().run(req) + await query('keep', apiError('keepOrRemove')).notEmpty().isIn(['keep', 'remove']).run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const { user } = res.locals; const { keep } = req.query; diff --git a/website/server/controllers/api-v3/tasks/groups.js b/website/server/controllers/api-v3/tasks/groups.js index 95ec995fbf..437577226e 100644 --- a/website/server/controllers/api-v3/tasks/groups.js +++ b/website/server/controllers/api-v3/tasks/groups.js @@ -1,5 +1,6 @@ import pick from 'lodash/pick'; import isUUID from 'validator/lib/isUUID'; +import { param , query , validationResult } from 'express-validator'; import { authWithHeaders } from '../../../middlewares/auth'; import * as Tasks from '../../../models/task'; import { model as Group } from '../../../models/group'; @@ -45,9 +46,9 @@ api.createGroupTasks = { url: '/tasks/group/:groupId', middlewares: [authWithHeaders()], async handler (req, res) { - req.checkParams('groupId', apiError('groupIdRequired')).notEmpty().isUUID(); + await param('groupId', apiError('groupIdRequired')).notEmpty().isUUID().run(req) - const reqValidationErrors = req.validationErrors(); + const reqValidationErrors = validationResult(req).array(); if (reqValidationErrors) throw reqValidationErrors; const { user } = res.locals; @@ -92,11 +93,11 @@ api.getGroupTasks = { url: '/tasks/group/:groupId', middlewares: [authWithHeaders()], async handler (req, res) { - req.checkParams('groupId', apiError('groupIdRequired')).notEmpty().isUUID(); - req.checkQuery('type', res.t('invalidTasksType')).optional().isIn(types); + await param('groupId', apiError('groupIdRequired')).notEmpty().isUUID().run(req) + await query('type', res.t('invalidTasksType')).optional().isIn(types).run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const { user } = res.locals; @@ -132,10 +133,10 @@ api.groupMoveTask = { url: '/group-tasks/:taskId/move/to/:position', middlewares: [authWithHeaders()], async handler (req, res) { - req.checkParams('taskId', apiError('taskIdRequired')).notEmpty(); - req.checkParams('position', res.t('positionRequired')).notEmpty().isNumeric(); + await param('taskId', apiError('taskIdRequired')).notEmpty().run(req) + await param('position', res.t('positionRequired')).notEmpty().isNumeric().run(req) - const reqValidationErrors = req.validationErrors(); + const reqValidationErrors = validationResult(req).array(); if (reqValidationErrors) throw reqValidationErrors; const { user } = res.locals; @@ -203,9 +204,9 @@ api.assignTask = { url: '/tasks/:taskId/assign', middlewares: [authWithHeaders()], async handler (req, res) { - req.checkParams('taskId', apiError('taskIdRequired')).notEmpty().isUUID(); + await param('taskId', apiError('taskIdRequired')).notEmpty().isUUID().run(req) - const reqValidationErrors = req.validationErrors(); + const reqValidationErrors = validationResult(req).array(); if (reqValidationErrors) throw reqValidationErrors; const { user } = res.locals; @@ -280,10 +281,10 @@ api.unassignTask = { url: '/tasks/:taskId/unassign/:assignedUserId', middlewares: [authWithHeaders()], async handler (req, res) { - req.checkParams('taskId', apiError('taskIdRequired')).notEmpty().isUUID(); - req.checkParams('assignedUserId', res.t('userIdRequired')).notEmpty().isUUID(); + await param('taskId', apiError('taskIdRequired')).notEmpty().isUUID().run(req) + await param('assignedUserId', res.t('userIdRequired')).notEmpty().isUUID().run(req) - const reqValidationErrors = req.validationErrors(); + const reqValidationErrors = validationResult(req).array(); if (reqValidationErrors) throw reqValidationErrors; const { user } = res.locals; @@ -337,10 +338,10 @@ api.taskNeedsWork = { url: '/tasks/:taskId/needs-work/:userId', middlewares: [authWithHeaders()], async handler (req, res) { - req.checkParams('taskId', apiError('taskIdRequired')).notEmpty().isUUID(); - req.checkParams('userId', res.t('userIdRequired')).notEmpty().isUUID(); + await param('taskId', apiError('taskIdRequired')).notEmpty().isUUID().run(req) + await param('userId', res.t('userIdRequired')).notEmpty().isUUID().run(req) - const reqValidationErrors = req.validationErrors(); + const reqValidationErrors = validationResult(req).array(); if (reqValidationErrors) throw reqValidationErrors; const { user } = res.locals; diff --git a/website/server/controllers/api-v3/user.js b/website/server/controllers/api-v3/user.js index ddc1f81ed0..7800dde789 100644 --- a/website/server/controllers/api-v3/user.js +++ b/website/server/controllers/api-v3/user.js @@ -4,6 +4,7 @@ import isFunction from 'lodash/isFunction'; import pick from 'lodash/pick'; import nconf from 'nconf'; import get from 'lodash/get'; +import { param , validationResult } from 'express-validator'; import { authWithHeaders } from '../../middlewares/auth'; import common from '../../../common'; import { @@ -1735,11 +1736,11 @@ api.movePinnedItem = { url: '/user/move-pinned-item/:path/move/to/:position', middlewares: [authWithHeaders()], async handler (req, res) { - req.checkParams('path', res.t('taskIdRequired')).notEmpty(); - req.checkParams('position', res.t('positionRequired')).notEmpty().isNumeric(); + await param('path', res.t('taskIdRequired')).notEmpty().run(req) + await param('position', res.t('positionRequired')).notEmpty().isNumeric().run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const { user } = res.locals; const { path } = req.params; diff --git a/website/server/controllers/api-v4/admin.js b/website/server/controllers/api-v4/admin.js index 747a0c777d..d8cef50ccb 100644 --- a/website/server/controllers/api-v4/admin.js +++ b/website/server/controllers/api-v4/admin.js @@ -1,5 +1,6 @@ import validator from 'validator'; import merge from 'lodash/merge'; +import { param , validationResult } from 'express-validator'; import uniqBy from 'lodash/uniqBy'; import { v4 as uuid } from 'uuid'; import { authWithHeaders } from '../../middlewares/auth'; @@ -41,10 +42,10 @@ api.searchHero = { url: '/admin/search/:userIdentifier', middlewares: [authWithHeaders(), ensurePermission('userSupport')], async handler (req, res) { - req.checkParams('userIdentifier', res.t('userIdentifierRequired')).notEmpty(); + await param('userIdentifier', res.t('userIdentifierRequired')).notEmpty().run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const { userIdentifier } = req.params; @@ -109,10 +110,10 @@ api.getUserHistory = { url: '/admin/user/:userId/history', middlewares: [authWithHeaders(), ensurePermission('userSupport')], async handler (req, res) { - req.checkParams('userId', res.t('heroIdRequired')).notEmpty().isUUID(); + await param('userId', res.t('heroIdRequired')).notEmpty().isUUID().run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const { userId } = req.params; @@ -161,10 +162,10 @@ api.updateBlocker = { url: '/admin/blockers/:blockerId', middlewares: [authWithHeaders(), ensurePermission('accessControl')], async handler (req, res) { - req.checkParams('blockerId', res.t('blockerIdRequired')).notEmpty().isUUID(); + await param('blockerId', res.t('blockerIdRequired')).notEmpty().isUUID().run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const blocker = await Blocker.findById(req.params.blockerId).exec(); if (!blocker) throw new NotFound(res.t('blockerNotFound')); @@ -181,10 +182,10 @@ api.deleteBlocker = { url: '/admin/blockers/:blockerId', middlewares: [authWithHeaders(), ensurePermission('accessControl')], async handler (req, res) { - req.checkParams('blockerId', res.t('blockerIdRequired')).notEmpty().isUUID(); + await param('blockerId', res.t('blockerIdRequired')).notEmpty().isUUID().run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const blocker = await Blocker.findById(req.params.blockerId).exec(); if (!blocker) throw new NotFound(res.t('blockerNotFound')); diff --git a/website/server/controllers/api-v4/auth.js b/website/server/controllers/api-v4/auth.js index 7745a78af4..e27ce75baa 100644 --- a/website/server/controllers/api-v4/auth.js +++ b/website/server/controllers/api-v4/auth.js @@ -21,8 +21,8 @@ api.verifyUsername = { }, }); - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const { user } = res.locals; const chosenUsername = req.body.username; @@ -105,8 +105,8 @@ api.checkEmail = { }, }); - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const lowercaseEmail = req.body.email.toLowerCase(); if (isRestrictedEmailDomain(lowercaseEmail)) { diff --git a/website/server/controllers/api-v4/faq.js b/website/server/controllers/api-v4/faq.js index 72b23f5561..5bde160ee0 100644 --- a/website/server/controllers/api-v4/faq.js +++ b/website/server/controllers/api-v4/faq.js @@ -1,4 +1,5 @@ import _ from 'lodash'; +import { query , validationResult } from 'express-validator'; import { langCodes } from '../../libs/i18n'; import { apiError } from '../../libs/apiError'; import common from '../../../common'; @@ -57,10 +58,10 @@ api.faq = { method: 'GET', url: '/faq', async handler (req, res) { - req.checkQuery('platform').optional().isIn(['web', 'android', 'ios'], apiError('invalidPlatform')); + await query('platform').optional().isIn(['web', 'android', 'ios'], apiError('invalidPlatform')).run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const proposedLang = req.query.language && req.query.language.toString(); const language = langCodes.includes(proposedLang) ? proposedLang : 'en'; diff --git a/website/server/controllers/api-v4/inbox.js b/website/server/controllers/api-v4/inbox.js index f1d8c6ffbe..f2a4875e4a 100644 --- a/website/server/controllers/api-v4/inbox.js +++ b/website/server/controllers/api-v4/inbox.js @@ -1,3 +1,4 @@ +import { param , validationResult } from 'express-validator'; import { authWithHeaders } from '../../middlewares/auth'; import { apiError } from '../../libs/apiError'; import { NotFound } from '../../libs/errors'; @@ -38,10 +39,10 @@ api.deleteMessage = { middlewares: [authWithHeaders()], url: '/inbox/messages/:messageId', async handler (req, res) { - req.checkParams('messageId', apiError('messageIdRequired')).notEmpty().isUUID(); + await param('messageId', apiError('messageIdRequired')).notEmpty().isUUID().run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const { messageId } = req.params; const { user } = res.locals; @@ -216,10 +217,10 @@ api.likePrivateMessage = { url: '/inbox/like-private-message/:uniqueMessageId', middlewares: [authWithHeaders()], async handler (req, res) { - req.checkParams('uniqueMessageId', apiError('messageIdRequired')).notEmpty(); + await param('uniqueMessageId', apiError('messageIdRequired')).notEmpty().run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const { user } = res.locals; const { uniqueMessageId } = req.params; diff --git a/website/server/controllers/api-v4/members.js b/website/server/controllers/api-v4/members.js index 9717907433..efef3c9f37 100644 --- a/website/server/controllers/api-v4/members.js +++ b/website/server/controllers/api-v4/members.js @@ -1,4 +1,5 @@ import { sendJob } from '../../libs/worker'; +import { param , validationResult } from 'express-validator'; import { authWithHeaders } from '../../middlewares/auth'; import { ensurePermission } from '../../middlewares/ensureAccessRight'; import { TransactionModel as Transaction } from '../../models/transaction'; @@ -16,9 +17,9 @@ api.purchaseHistory = { middlewares: [authWithHeaders(), ensurePermission('userSupport')], url: '/members/:memberId/purchase-history', async handler (req, res) { - req.checkParams('memberId', res.t('memberIdRequired')).notEmpty().isUUID(); - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + await param('memberId', res.t('memberIdRequired')).notEmpty().isUUID().run(req) + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; let transactions = await Transaction .find({ userId: req.params.memberId }) .sort({ createdAt: -1 }) diff --git a/website/server/controllers/api-v4/news.js b/website/server/controllers/api-v4/news.js index dd72ad8a20..8ffab68828 100644 --- a/website/server/controllers/api-v4/news.js +++ b/website/server/controllers/api-v4/news.js @@ -1,4 +1,5 @@ import _ from 'lodash'; +import { param , validationResult } from 'express-validator'; import { authWithHeaders } from '../../middlewares/auth'; import { apiError } from '../../libs/apiError'; import { model as NewsPost } from '../../models/newsPost'; @@ -110,7 +111,7 @@ api.getPost = { })], noLanguage: true, async handler (req, res) { - req.checkParams('postId', apiError('postIdRequired')).notEmpty().isUUID(); + await param('postId', apiError('postIdRequired')).notEmpty().isUUID().run(req) const { user } = res.locals; const newsPost = await NewsPost.findById(req.params.postId).exec(); @@ -148,9 +149,9 @@ api.updateNews = { url: '/news/:postId', middlewares: [authWithHeaders(), ensurePermission('news')], async handler (req, res) { - req.checkParams('postId', apiError('postIdRequired')).notEmpty().isUUID(); - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + await param('postId', apiError('postIdRequired')).notEmpty().isUUID().run(req) + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const newsPost = await NewsPost.findById(req.params.postId).exec(); if (!newsPost) throw new NotFound(res.t('newsPostNotFound')); @@ -183,9 +184,9 @@ api.deleteNews = { url: '/news/:postId', middlewares: [authWithHeaders(), ensurePermission('news')], async handler (req, res) { - req.checkParams('postId', apiError('postIdRequired')).notEmpty().isUUID(); - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + await param('postId', apiError('postIdRequired')).notEmpty().isUUID().run(req) + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const newsPost = await NewsPost.findById(req.params.postId).exec(); if (!newsPost) throw new NotFound(res.t('newsPostNotFound')); diff --git a/website/server/controllers/api-v4/user.js b/website/server/controllers/api-v4/user.js index e324ce13b6..885a6470d7 100644 --- a/website/server/controllers/api-v4/user.js +++ b/website/server/controllers/api-v4/user.js @@ -252,8 +252,8 @@ api.verifyDisplayName = { }, }); - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const chosenDisplayName = req.body.displayName; diff --git a/website/server/controllers/top-level/dataexport.js b/website/server/controllers/top-level/dataexport.js index 942ec67274..340af1f786 100644 --- a/website/server/controllers/top-level/dataexport.js +++ b/website/server/controllers/top-level/dataexport.js @@ -177,10 +177,10 @@ api.exportUserAvatarHtml = { async handler (/* req, res */) { throw new NotFound('This API route is currently not available. See https://github.com/HabitRPG/habitica/issues/9489.'); - /* req.checkParams('memberId', res.t('memberIdRequired')).notEmpty().isUUID(); + /* await param('memberId', res.t('memberIdRequired')).notEmpty().isUUID().run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const { memberId } = req.params; @@ -215,10 +215,10 @@ api.exportUserAvatarPng = { async handler (/* req, res */) { throw new NotFound('This API route is currently not available. See https://github.com/HabitRPG/habitica/issues/9489.'); - /* req.checkParams('memberId', res.t('memberIdRequired')).notEmpty().isUUID(); + /* await param('memberId', res.t('memberIdRequired')).notEmpty().isUUID().run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const { memberId } = req.params; diff --git a/website/server/controllers/top-level/email.js b/website/server/controllers/top-level/email.js index 72074907f1..b2123e7266 100644 --- a/website/server/controllers/top-level/email.js +++ b/website/server/controllers/top-level/email.js @@ -13,8 +13,8 @@ async function emailUnsubscribe (req, res) { notEmpty: { errorMessage: res.t('missingUnsubscriptionCode') }, }, }); - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const data = JSON.parse(decrypt(req.query.code)); diff --git a/website/server/libs/auth/index.js b/website/server/libs/auth/index.js index 15ac763d86..3bb42cc4c7 100644 --- a/website/server/libs/auth/index.js +++ b/website/server/libs/auth/index.js @@ -110,8 +110,8 @@ async function registerLocal (req, res, { isV3 = false }) { }, }); - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const issues = verifyUsername(req.body.username, res); if (issues.length > 0) throw new BadRequest(issues.join(' ')); diff --git a/website/server/libs/challenges/handleGetMembersForChallenge.js b/website/server/libs/challenges/handleGetMembersForChallenge.js index 26dbfb9b82..b0c197ddf6 100644 --- a/website/server/libs/challenges/handleGetMembersForChallenge.js +++ b/website/server/libs/challenges/handleGetMembersForChallenge.js @@ -1,4 +1,5 @@ import _ from 'lodash'; +import { param, query , validationResult } from 'express-validator'; import { model as User, publicFields as memberFields, @@ -22,13 +23,13 @@ async function getMembersTasksForChallenge (members, challenge) { } export async function handleGetMembersForChallenge (req, res) { - req.checkParams('challengeId', res.t('challengeIdRequired')).notEmpty().isUUID(); - req.checkQuery('lastId').optional().notEmpty().isUUID(); + await param('challengeId', res.t('challengeIdRequired')).notEmpty().isUUID().run(req); + await query('lastId').optional().notEmpty().isUUID().run(req); // Allow an arbitrary number of results (up to 60) - req.checkQuery('limit', res.t('groupIdRequired')).optional().notEmpty().isInt({ min: 1, max: 60 }); + await query('limit', res.t('groupIdRequired')).optional().notEmpty().isInt({ min: 1, max: 60 }).run(req); - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const { challengeId } = req.params; const { lastId } = req.query; diff --git a/website/server/libs/chatReporting/groupChatReporter.js b/website/server/libs/chatReporting/groupChatReporter.js index 2270674259..96de3645c0 100644 --- a/website/server/libs/chatReporting/groupChatReporter.js +++ b/website/server/libs/chatReporting/groupChatReporter.js @@ -1,5 +1,6 @@ import nconf from 'nconf'; import moment from 'moment'; +import { param , validationResult } from 'express-validator'; import { getAuthorEmailFromMessage } from '../chat'; import ChatReporter from './chatReporter'; import { @@ -23,11 +24,11 @@ export default class GroupChatReporter extends ChatReporter { } async validate () { - this.req.checkParams('groupId', apiError('groupIdRequired')).notEmpty(); - this.req.checkParams('chatId', apiError('chatIdRequired')).notEmpty(); + await param('groupId', apiError('groupIdRequired')).notEmpty().run(req) + await param('chatId', apiError('chatIdRequired')).notEmpty().run(req) - const validationErrors = this.req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = this.validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const group = await Group.getGroup({ user: this.user, diff --git a/website/server/libs/chatReporting/inboxChatReporter.js b/website/server/libs/chatReporting/inboxChatReporter.js index cee0309970..c430b6e72e 100644 --- a/website/server/libs/chatReporting/inboxChatReporter.js +++ b/website/server/libs/chatReporting/inboxChatReporter.js @@ -1,3 +1,4 @@ +import { param , validationResult } from 'express-validator'; import { model as User } from '../../models/user'; import ChatReporter from './chatReporter'; @@ -20,10 +21,10 @@ export default class InboxChatReporter extends ChatReporter { } async validate () { - this.req.checkParams('messageId', apiError('messageIdRequired')).notEmpty(); + await param('messageId', apiError('messageIdRequired')).notEmpty().run(req) - const validationErrors = this.req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = this.validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; if (this.user.hasPermission('moderator') && this.req.query.userId) { this.inboxUser = await User.findOne({ _id: this.req.query.userId }).exec(); diff --git a/website/server/libs/chatReporting/profileReporter.js b/website/server/libs/chatReporting/profileReporter.js index 008146dcf5..09e16ff3a9 100644 --- a/website/server/libs/chatReporting/profileReporter.js +++ b/website/server/libs/chatReporting/profileReporter.js @@ -1,5 +1,6 @@ import { model as User } from '../../models/user'; import * as slack from '../slack'; +import { param , validationResult } from 'express-validator'; import ChatReporter from './chatReporter'; import { @@ -15,10 +16,10 @@ export default class ProfileReporter extends ChatReporter { } async validate () { - this.req.checkParams('memberId', this.res.t('memberIdRequired')).notEmpty().isUUID(); + await param('memberId', this.res.t('memberIdRequired')).notEmpty().isUUID().run(req) - const validationErrors = this.req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = this.validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; const flaggedUser = await User.findOne( { _id: this.req.params.memberId }, diff --git a/website/server/libs/coupons/index.js b/website/server/libs/coupons/index.js index 0caf4b1f17..de63fd34d6 100644 --- a/website/server/libs/coupons/index.js +++ b/website/server/libs/coupons/index.js @@ -1,10 +1,11 @@ +import { param , validationResult } from 'express-validator'; import { model as Coupon } from '../../models/coupon'; export async function enterCode (req, res, user) { // eslint-disable-line import/prefer-default-export, max-len - req.checkParams('code', res.t('couponCodeRequired')).notEmpty(); + await param('code', res.t('couponCodeRequired')).notEmpty().run(req) - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + const validationErrors = validationResult(req).array(); + if (validationErrors && validationErrors.length > 0) throw validationErrors; await Coupon.apply(user, req, req.params.code); } diff --git a/website/server/libs/spells.js b/website/server/libs/spells.js index 8d7158c25c..b55c93bd40 100644 --- a/website/server/libs/spells.js +++ b/website/server/libs/spells.js @@ -1,3 +1,5 @@ + +import { query, validationResult } from 'express-validator'; import { model as User } from '../models/user'; import { chatModel as Chat } from '../models/message'; import * as Tasks from '../models/task'; @@ -157,9 +159,9 @@ async function castSpell (req, res, { isV3 = false }) { const quantity = req.body.quantity || 1; // optional because not required by all targetTypes, presence is checked later if necessary - req.checkQuery('targetId', res.t('targetIdUUID')).optional().isUUID(); + await query('targetId', res.t('targetIdUUID')).optional().isUUID().run(req) - const reqValidationErrors = req.validationErrors(); + const reqValidationErrors = validationResult(req).array(); if (reqValidationErrors) throw reqValidationErrors; const klass = common.content.spells.special[spellId] ? 'special' : user.stats.class; diff --git a/website/server/libs/tasks/index.js b/website/server/libs/tasks/index.js index 2b4c07464b..f5454b378c 100644 --- a/website/server/libs/tasks/index.js +++ b/website/server/libs/tasks/index.js @@ -97,7 +97,7 @@ async function createTasks (req, res, options = {}) { // and task in parallel it could save the user/challenge/group // with a tasksOrder that doens't match reality const validationErrors = newTask.validateSync(); - if (validationErrors) throw validationErrors; + if (validationErrors && validationErrors.length > 0) throw validationErrors; // Otherwise update the user/challenge/group if (!taskOrderToAdd[`${taskType}s`]) taskOrderToAdd[`${taskType}s`] = []; diff --git a/website/server/middlewares/appRoutes.js b/website/server/middlewares/appRoutes.js index 19931eab6b..8af5d35356 100644 --- a/website/server/middlewares/appRoutes.js +++ b/website/server/middlewares/appRoutes.js @@ -1,5 +1,4 @@ import express from 'express'; -import expressValidator from 'express-validator'; import path from 'path'; import analytics from './analytics'; import setupBody from './setupBody'; @@ -16,7 +15,6 @@ const app = express(); // re-set the view options because they are not inherited from the top level app setupExpress(app); -app.use(expressValidator()); app.use(analytics); app.use(setupBody); diff --git a/website/server/middlewares/errorHandler.js b/website/server/middlewares/errorHandler.js index 9480752517..ca1ab2dfaa 100644 --- a/website/server/middlewares/errorHandler.js +++ b/website/server/middlewares/errorHandler.js @@ -27,11 +27,11 @@ export default function errorHandler (err, req, res, next) { // eslint-disable-l } // Handle errors by express-validator - if (Array.isArray(err) && err[0].param && err[0].msg) { + if (Array.isArray(err) && err.length >= 1 && err[0].path && err[0].msg) { responseErr = new BadRequest(res.t('invalidReqParams')); responseErr.errors = err.map(paramErr => ({ message: paramErr.msg, - param: paramErr.param, + param: paramErr.path, value: paramErr.value, })); } @@ -66,7 +66,7 @@ export default function errorHandler (err, req, res, next) { // eslint-disable-l responseErr = new InternalServerError(); } - if (!err.skipLogging) { + if (!err.skipLogging && err instanceof Error) { // log the error logger.error(err, { method: req.method, diff --git a/website/server/middlewares/v1.js b/website/server/middlewares/v1.js index 2362b7cb97..0e6c34ab68 100644 --- a/website/server/middlewares/v1.js +++ b/website/server/middlewares/v1.js @@ -11,7 +11,7 @@ const router = express.Router(); // eslint-disable-line new-cap const BASE_URL = nconf.get('BASE_URL'); -router.all('*', (req, res, next) => { +router.all('*route', (req, res, next) => { const error = new NotFound(`API v1 is no longer supported, please use API v3 instead (${BASE_URL}/apidoc).`); return next(error); }); diff --git a/website/server/middlewares/v2.js b/website/server/middlewares/v2.js index 5e2b012f07..b9074f23d6 100644 --- a/website/server/middlewares/v2.js +++ b/website/server/middlewares/v2.js @@ -11,7 +11,7 @@ const router = express.Router(); // eslint-disable-line new-cap const BASE_URL = nconf.get('BASE_URL'); -router.all('*', (req, res, next) => { +router.all('*route', (req, res, next) => { const error = new NotFound(`API v2 is no longer supported, please use API v3 instead (${BASE_URL}/apidoc).`); return next(error); });