From a6228a9fd90316303124c273585b12859f6b1a68 Mon Sep 17 00:00:00 2001 From: rainbow napkin Date: Tue, 29 Apr 2025 00:13:19 -0400 Subject: [PATCH] Started improvement of validators and respective error messages --- .../api/admin/passwordResetController.js | 3 + src/schemas/channel/channelSchema.js | 3 +- src/schemas/user/userSchema.js | 10 +- src/validators/accountValidator.js | 165 ++++++++++++++++-- src/validators/channelValidator.js | 21 ++- 5 files changed, 180 insertions(+), 22 deletions(-) diff --git a/src/controllers/api/admin/passwordResetController.js b/src/controllers/api/admin/passwordResetController.js index deff3a3..4e87bfb 100644 --- a/src/controllers/api/admin/passwordResetController.js +++ b/src/controllers/api/admin/passwordResetController.js @@ -14,6 +14,9 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see .*/ +//config +const config = require('../../../../config.json'); + //npm imports const {validationResult, matchedData} = require('express-validator'); diff --git a/src/schemas/channel/channelSchema.js b/src/schemas/channel/channelSchema.js index b56cdd3..590d964 100644 --- a/src/schemas/channel/channelSchema.js +++ b/src/schemas/channel/channelSchema.js @@ -42,7 +42,8 @@ const channelSchema = new mongoose.Schema({ name: { type: mongoose.SchemaTypes.String, required: true, - maxLength: 50, + //Calculate max length by the validator max length and the size of an escaped character + maxLength: 50 * 6, default: 0 }, description: { diff --git a/src/schemas/user/userSchema.js b/src/schemas/user/userSchema.js index 4c1a983..85d9f7b 100644 --- a/src/schemas/user/userSchema.js +++ b/src/schemas/user/userSchema.js @@ -73,23 +73,25 @@ const userSchema = new mongoose.Schema({ required: true, default: "/img/johnny.png" }, - //These should be larger than validator values to make room for escaped characters bio: { type: mongoose.SchemaTypes.String, required: true, - maxLength: 2000, + //Calculate max length by the validator max length and the size of an escaped character + maxLength: 1000 * 6, default: "Bio not set!" }, pronouns:{ type: mongoose.SchemaTypes.String, optional: true, - maxLength: 50, + //Calculate max length by the validator max length and the size of an escaped character + maxLength: 15 * 6, default: "" }, signature: { type: mongoose.SchemaTypes.String, required: true, - maxLength: 300, + //Calculate max length by the validator max length and the size of an escaped character + maxLength: 25 * 6, default: "Signature not set!" }, highLevel: { diff --git a/src/validators/accountValidator.js b/src/validators/accountValidator.js index 9d1e9ed..4fc9d32 100644 --- a/src/validators/accountValidator.js +++ b/src/validators/accountValidator.js @@ -15,31 +15,166 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see .*/ //NPM Imports -const { check, body, checkSchema, checkExact} = require('express-validator'); +const {checkSchema} = require('express-validator'); //local imports const {isRank} = require('./permissionsValidator'); -module.exports = { - user: (field = 'user') => check(field).escape().trim().isAlphanumeric().isLength({min: 1, max: 22}), +module.exports.user = function(field = 'user'){ + return checkSchema({ + [field]: { + escape: true, + trim: true, + isAlphanumeric: { + errorMessage: "Usernames must be alphanumeric." + }, + isLength: { + options: { + min: 1, + max: 22 + }, + errorMessage: "Usernames must be between 1 and 22 characters." + }, + } + }); +} - //Password security requirements may change over time, therefore we should only validate against strongPassword() when creating new accounts - //that way we don't break old ones upon change - pass: (field = 'pass') => body(field).notEmpty().escape().trim(), - securePass: (field) => module.exports.pass(field).isStrongPassword({minLength: 8, minLowercase: 1, minUppercase: 1, minNumbers: 1, minSymbols: 1}), +function getPassSchema(field = 'pass'){ + //Heavily simplified from previous versions. + //Trimming passwords is iffy, and escaping them is a down-right bad idea + return { + [field]: { + notEmpty: true, + } + } +} - email: (field = 'email') => body(field).optional().isEmail().normalizeEmail(), +module.exports.pass = function(field = 'pass'){ + return checkSchema(getPassSchema(field)); +} - img: (field = 'img') => body(field).optional().isURL({require_tld: false, require_host: false}).trim(), +module.exports.securePass = function(field = 'pass'){ + const schema = getPassSchema(field); - //Length check before escaping to keep symbols from throwing the count - pronouns: (field = 'pronouns') => body(field).optional().trim().isLength({min: 0, max: 15}).escape(), + schema[field].isStrongPassword = { + options: { + minLength: 8, + minLowercase: 1, + minUppercase: 1, + minNumbers: 1, + minSymbols: 1 + }, + errorMessage: "Passwords must contain 8 characters, including at least one: Upper, Lower, Number, and Special char." + } - signature: (field = 'signature') => body(field).optional().trim().isLength({min: 1, max: 25}).escape(), + return checkSchema(schema); +} - bio: (field = 'bio') => body(field).optional().trim().isLength({min: 1, max: 1000}).escape(), +module.exports.email = function(field = 'email'){ + return checkSchema({ + [field]: { + optional: true, + isEmail: { + errorMessage: "Invalid E-Mail Address" + }, + normalizeEmail: true + } + }); +} - rank: (field = 'rank') => body(field).escape().trim().custom(isRank), +module.exports.img = function(field = 'img'){ + return checkSchema({ + [field]: { + optional: true, + isURL: { + options: { + require_tld: false, + require_host: false + }, + errorMessage: "Invalid URL." + }, + trim: true + } + }); +} - securityToken: (field = 'token') => check(field).escape().trim().isHexadecimal().isLength({min:32, max:32}) +module.exports.pronouns = function(field = 'pronouns'){ + return checkSchema({ + [field]: { + optional: true, + trim: true, + isLength: { + options: { + min: 0, + max: 15 + }, + errorMessage: "Pronouns must be under 15 characters." + }, + escape: true + } + }); +} + +module.exports.signature = function(field = 'signature'){ + return checkSchema({ + [field]: { + optional: true, + trim: true, + isLength: { + options: { + min: 1, + max: 25 + }, + errorMessage: "Signature must be between 1 and 25 characters." + }, + escape: true + } + }); +} + +module.exports.bio = function(field = 'bio'){ + return checkSchema({ + [field]: { + optional: true, + trim: true, + isLength: { + options: { + min: 1, + max: 1000 + }, + errorMessage: "Bio must be between 1 and 1000 characters." + }, + escape: true + } + }); +} + +module.exports.rank = function(field = 'rank'){ + return checkSchema({ + [field]: { + escape: true, + trim: true, + custom: { + options: isRank, + }, + errorMessage: "Invalid rank." + } + }); +} + +module.exports.securityToken = function(field = 'token'){ + return checkSchema({ + [field]: { + escape: true, + trim: true, + isHexadecimal: true, + isLength: { + options: { + min: 32, + max: 32 + } + }, + errorMessage: "Invalid security token." + } + }); } \ No newline at end of file diff --git a/src/validators/channelValidator.js b/src/validators/channelValidator.js index 29b6995..0032ad8 100644 --- a/src/validators/channelValidator.js +++ b/src/validators/channelValidator.js @@ -21,8 +21,6 @@ const { check, body, checkSchema, checkExact} = require('express-validator'); const accountValidator = require('./accountValidator'); module.exports = { - name: (field = 'name') => check(field).escape().trim().isAlphanumeric().isLength({min: 1, max: 50}), - description: (field = 'description') => body(field).escape().trim().isLength({min: 1, max: 1000}), thumbnail: (field = 'thumbnail') => accountValidator.img(field), @@ -35,4 +33,23 @@ module.exports = { isBoolean: true, } })) +} + +module.exports.name = function(field = 'name'){ + return checkSchema({ + [field]: { + esacpe: true, + isAlphanumeric: { + errorMessage: "Channel names must be alphanumeric." + }, + isLength: { + options: { + min: 1, + max: 50 + }, + errorMessage: "Channel numes must be between 1 and 50 characters." + }, + trim: true + } + }); } \ No newline at end of file