diff --git a/api-server/package-lock.json b/api-server/package-lock.json index cf833f4074..11f81d7e47 100644 --- a/api-server/package-lock.json +++ b/api-server/package-lock.json @@ -8669,18 +8669,18 @@ } }, "express-validator": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/express-validator/-/express-validator-5.3.1.tgz", - "integrity": "sha512-g8xkipBF6VxHbO1+ksC7nxUU7+pWif0+OZXjZTybKJ/V0aTVhuCoHbyhIPgSYVldwQLocGExPtB2pE0DqK4jsw==", + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/express-validator/-/express-validator-6.7.0.tgz", + "integrity": "sha512-sLnTFlyKEvesC2Fyn1TY4Q05cWCZHQQ1ijQOVbBG7hFeTKt4CNzttoF4t6CqrYroKa+2DOzj0E09odPIYDTbRg==", "requires": { - "lodash": "^4.17.10", - "validator": "^10.4.0" + "lodash": "^4.17.20", + "validator": "^13.1.1" }, "dependencies": { "validator": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/validator/-/validator-10.10.0.tgz", - "integrity": "sha512-DyZyLJlMXM3CGdVaVHE/EDzCagMRoPI3mmGdxxNQbqkGqh56+M3d1i0ZAWd69En8U21DHbPTn12aOdhO+hfm5w==" + "version": "13.5.1", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.5.1.tgz", + "integrity": "sha512-s+7LW1Xi0OzPNfGN7Hb2vk0YB/epp9KFHHGC5JtqZOE1dUkN4ULPFZAQ1inCu7ceAsWmOJu6sn9cnwm3R+ghWQ==" } } }, diff --git a/api-server/package.json b/api-server/package.json index c0f2bb3c22..59396df344 100644 --- a/api-server/package.json +++ b/api-server/package.json @@ -31,7 +31,7 @@ "dotenv": "^6.2.0", "express-flash": "~0.0.2", "express-session": "^1.17.1", - "express-validator": "^5.3.1", + "express-validator": "^6.7.0", "googleapis": "^42.0.0", "helmet": "^3.23.3", "helmet-csp": "^2.10.0", diff --git a/api-server/server/boot/authentication.js b/api-server/server/boot/authentication.js index 636667f2ea..4f0ae01c7b 100644 --- a/api-server/server/boot/authentication.js +++ b/api-server/server/boot/authentication.js @@ -1,6 +1,6 @@ import passport from 'passport'; import dedent from 'dedent'; -import { check } from 'express-validator/check'; +import { check } from 'express-validator'; import { isEmail } from 'validator'; import jwt from 'jsonwebtoken'; diff --git a/api-server/server/boot/settings.js b/api-server/server/boot/settings.js index 521b7e4189..be81789602 100644 --- a/api-server/server/boot/settings.js +++ b/api-server/server/boot/settings.js @@ -1,5 +1,5 @@ import debug from 'debug'; -import { check } from 'express-validator/check'; +import { check } from 'express-validator'; import { ifNoUser401, createValidatorErrorHandler } from '../utils/middleware'; import { themes } from '../../common/utils/themes.js'; diff --git a/api-server/server/boot/user.js b/api-server/server/boot/user.js index 4d9d40da11..238ae6f04d 100644 --- a/api-server/server/boot/user.js +++ b/api-server/server/boot/user.js @@ -2,6 +2,7 @@ import dedent from 'dedent'; import debugFactory from 'debug'; import { pick } from 'lodash'; import { Observable } from 'rx'; +import { body } from 'express-validator'; import { homeLocation } from '../../../config/env'; import { @@ -12,6 +13,7 @@ import { import { fixCompletedChallengeItem } from '../../common/utils'; import { ifNoUser401, ifNoUserRedirectTo } from '../utils/middleware'; import { removeCookies } from '../utils/getSetAccessToken'; +import { trimTags } from '../utils/validators'; const log = debugFactory('fcc:boot:user'); const sendNonUserToHome = ifNoUserRedirectTo(homeLocation); @@ -29,7 +31,12 @@ function bootUser(app) { api.post('/account/delete', ifNoUser401, postDeleteAccount); api.post('/account/reset-progress', ifNoUser401, postResetProgress); - api.post('/user/report-user/', ifNoUser401, postReportUserProfile); + api.post( + '/user/report-user/', + ifNoUser401, + body('reportDescription').customSanitizer(trimTags), + postReportUserProfile + ); app.use(api); } @@ -201,8 +208,7 @@ function createPostReportUserProfile(app) { const { Email } = app.models; return function postReportUserProfile(req, res, next) { const { user } = req; - const { username } = req.body; - const report = req.sanitize('reportDescription').trimTags(); + const { username, reportDescription: report } = req.body; log(username); log(report); diff --git a/api-server/server/middleware.json b/api-server/server/middleware.json index 3588498b11..00554e217c 100644 --- a/api-server/server/middleware.json +++ b/api-server/server/middleware.json @@ -41,9 +41,6 @@ }, "method-override": {} }, - "parse:after": { - "./middlewares/validator": {} - }, "routes:before": { "helmet#xssFilter": {}, "helmet#noSniff": {}, diff --git a/api-server/server/middlewares/validator.js b/api-server/server/middlewares/validator.js deleted file mode 100644 index 8a703ec64c..0000000000 --- a/api-server/server/middlewares/validator.js +++ /dev/null @@ -1,63 +0,0 @@ -import validator from 'express-validator'; -import { isPoly } from '../../../utils/polyvinyl'; - -const isObject = val => !!val && typeof val === 'object'; - -export default function() { - return validator({ - customValidators: { - matchRegex(param, regex) { - return regex.test(param); - }, - isString(value) { - return typeof value === 'string'; - }, - isNumber(value) { - return typeof value === 'number'; - }, - isFiles(value) { - if (!isObject(value)) { - return false; - } - const keys = Object.keys(value); - return ( - !!keys.length && - // every key is a file - keys.every(key => isObject(value[key])) && - // every file has contents - keys.map(key => value[key]).every(file => isPoly(file)) - ); - } - }, - customSanitizers: { - // Refer : http://stackoverflow.com/a/430240/1932901 - trimTags(value) { - const tagBody = '(?:[^"\'>]|"[^"]*"|\'[^\']*\')*'; - const tagOrComment = new RegExp( - '<(?:' + - // Comment body. - '!--(?:(?:-*[^->])*--+|-?)' + - // Special "raw text" elements whose content should be elided. - '|script\\b' + - tagBody + - '>[\\s\\S]*?[\\s\\S]*?', - 'gi' - ); - let rawValue; - do { - rawValue = value; - value = value.replace(tagOrComment, ''); - } while (value !== rawValue); - - return value.replace(/]|"[^"]*"|\'[^\']*\')*'; + const tagOrComment = new RegExp( + '<(?:' + + // Comment body. + '!--(?:(?:-*[^->])*--+|-?)' + + // Special "raw text" elements whose content should be elided. + '|script\\b' + + tagBody + + '>[\\s\\S]*?[\\s\\S]*?', + 'gi' + ); + let rawValue; + do { + rawValue = value; + value = value.replace(tagOrComment, ''); + } while (value !== rawValue); + + return value.replace(/