express-validator
Advanced tools
Comparing version 2.11.0 to 2.12.0
@@ -1,262 +0,245 @@ | ||
/* | ||
* This binds the node-validator library to the req object so that | ||
* the validation / sanitization methods can be called on parameter | ||
* names rather than the actual strings. | ||
var validator = require('validator'); | ||
var _ = require('lodash'); | ||
// validators and sanitizers not prefixed with is/to | ||
var additionalValidators = ['contains', 'equals', 'matches']; | ||
var additionalSanitizers = ['trim', 'ltrim', 'rtrim', 'escape', 'stripLow', 'whitelist', 'blacklist', 'normalizeEmail']; | ||
/** | ||
* Initalizes a chain of validators | ||
* | ||
* | ||
* 1. To validate parameters, use `req.check(param_name, [err_message])` | ||
* e.g. req.check('param1').len(1, 6).isInt(); | ||
* e.g. req.checkHeader('referer').contains('mydomain.com'); | ||
* | ||
* Each call to `check()` will throw an exception by default. To | ||
* specify a custom err handler, use `req.onValidationError(errback)` | ||
* where errback receives a parameter containing the error message | ||
* | ||
* 2. To sanitize parameters, use `req.sanitize(param_name)` | ||
* e.g. req.sanitize('param1').toBoolean(); | ||
* e.g. req.sanitize('param2').toInt(); | ||
* | ||
* 3. Done! Access your validated and sanitized paramaters through the | ||
* `req.params` object | ||
* @class | ||
* @param {(string|string[])} param path to property to validate | ||
* @param {string} failMsg validation failure message | ||
* @param {Request} req request to attach validation errors | ||
* @param {string} location request property to find value (body, params, query, etc.) | ||
* @param {object} options options containing error formatter | ||
*/ | ||
var validator = require('validator'); | ||
function ValidatorChain(param, failMsg, req, location, options) { | ||
this.errorFormatter = options.errorFormatter; | ||
this.param = param; | ||
this.value = location ? _.get(req[location], param) : undefined; | ||
this.validationErrors = []; | ||
this.failMsg = failMsg; | ||
this.req = req; | ||
var expressValidator = function(options) { | ||
options = options || {}; | ||
return this; | ||
} | ||
var _options = {}; | ||
_options.customValidators = options.customValidators || {}; | ||
_options.customSanitizers = options.customSanitizers || {}; | ||
/** | ||
* Initializes a sanitizers | ||
* | ||
* @class | ||
* @param {(string|string[])} param path to property to sanitize | ||
* @param {[type]} req request to sanitize | ||
* @param {[type]} location request property to find value | ||
*/ | ||
_options.errorFormatter = options.errorFormatter || function(param, msg, value) { | ||
return { | ||
param : param, | ||
msg : msg, | ||
value : value | ||
}; | ||
}; | ||
function Sanitizer(param, req, locations) { | ||
this.values = locations.map(function(location) { | ||
return _.get(req[location], param); | ||
}); | ||
var sanitizers = ['trim', 'ltrim', 'rtrim', 'escape', 'stripLow', 'whitelist', | ||
'blacklist', 'normalizeEmail']; | ||
this.req = req; | ||
this.param = param; | ||
this.locations = locations; | ||
return this; | ||
} | ||
var sanitize = function(request, param, value) { | ||
var methods = {}; | ||
/** | ||
* Adds validation methods to request object via express middleware | ||
* | ||
* @method expressValidator | ||
* @param {object} options | ||
* @return {function} middleware | ||
*/ | ||
Object.keys(validator).forEach(function(methodName) { | ||
if (methodName.match(/^to/) || sanitizers.indexOf(methodName) !== -1) { | ||
methods[methodName] = function() { | ||
var args = [value].concat(Array.prototype.slice.call(arguments)); | ||
var result = validator[methodName].apply(validator, args); | ||
request.updateParam(param, result); | ||
return result; | ||
}; | ||
} | ||
}); | ||
Object.keys(_options.customSanitizers).forEach(function(customName) { | ||
methods[customName] = function() { | ||
var args = [value].concat(Array.prototype.slice.call(arguments)); | ||
var result = _options.customSanitizers[customName].apply(null, args); | ||
request.updateParam(param, result); | ||
return result; | ||
var expressValidator = function(options) { | ||
var defaults = { | ||
customValidators: {}, | ||
customSanitizers: {}, | ||
errorFormatter: function(param, msg, value) { | ||
return { | ||
param: param, | ||
msg: msg, | ||
value: value | ||
}; | ||
}); | ||
return methods; | ||
}, | ||
}; | ||
function checkParam(req, getter) { | ||
return function(param, failMsg) { | ||
_.defaults(options, defaults); | ||
var value; | ||
// _.set validators and sainitizers as prototype methods on corresponding chains | ||
_.forEach(validator, function(method, methodName) { | ||
if (methodName.match(/^is/) || _.contains(additionalValidators, methodName)) { | ||
ValidatorChain.prototype[methodName] = makeValidator(methodName, validator); | ||
} | ||
// If param is not an array, then split by dot notation | ||
// returning an array. It will return an array even if | ||
// param doesn't have the dot notation. | ||
// 'blogpost' = ['blogpost'] | ||
// 'login.username' = ['login', 'username'] | ||
// For regex matches you can access the parameters using numbers. | ||
if (!Array.isArray(param)) { | ||
param = typeof param === 'number' ? | ||
[param] : | ||
param.split('.').filter(function(e){ | ||
return e !== ''; | ||
}); | ||
} | ||
if (methodName.match(/^to/) || _.contains(additionalSanitizers, methodName)) { | ||
Sanitizer.prototype[methodName] = makeSanitizer(methodName, validator); | ||
} | ||
}); | ||
// Extract value from params | ||
param.map(function(item) { | ||
if (value === undefined) { | ||
value = getter(item); | ||
} else { | ||
value = value[item]; | ||
} | ||
}); | ||
param = param.join('.'); | ||
ValidatorChain.prototype.notEmpty = function() { | ||
return this.isLength(1); | ||
}; | ||
var errorHandler = function(msg) { | ||
var error = _options.errorFormatter(param, msg, value); | ||
ValidatorChain.prototype.len = function() { | ||
return this.isLength.apply(this, arguments); | ||
}; | ||
if (req._validationErrors === undefined) { | ||
req._validationErrors = []; | ||
} | ||
req._validationErrors.push(error); | ||
ValidatorChain.prototype.optional = function() { | ||
if (this.value === undefined) { | ||
this.skipValidating = true; | ||
} | ||
if (req.onErrorCallback) { | ||
req.onErrorCallback(msg); | ||
} | ||
return this; | ||
}; | ||
return this; | ||
}; | ||
var methods = []; | ||
_.forEach(options.customValidators, function(method, customValidatorName) { | ||
ValidatorChain.prototype[customValidatorName] = makeValidator(customValidatorName, options.customValidators); | ||
}); | ||
Object.keys(validator).forEach(function(methodName) { | ||
if (!methodName.match(/^to/) && sanitizers.indexOf(methodName) === -1) { | ||
methods[methodName] = function() { | ||
var args = [value].concat(Array.prototype.slice.call(arguments)); | ||
var isCorrect = validator[methodName].apply(validator, args); | ||
_.forEach(options.customSanitizers, function(method, customSanitizerName) { | ||
Sanitizer.prototype[customSanitizerName] = makeSanitizer(customSanitizerName, options.customSanitizers); | ||
}); | ||
if (!isCorrect) { | ||
errorHandler(failMsg || 'Invalid value'); | ||
} | ||
return function(req, res, next) { | ||
var locations = ['body', 'params', 'query']; | ||
return methods; | ||
}; | ||
} | ||
}); | ||
req._validationErrors = []; | ||
req.validationErrors = function(mapped) { | ||
if (mapped && req._validationErrors.length > 0) { | ||
var errors = {}; | ||
req._validationErrors.forEach(function(err) { | ||
errors[err.param] = err; | ||
}); | ||
Object.keys(_options.customValidators).forEach(function(customName) { | ||
methods[customName] = function() { | ||
var args = [value].concat(Array.prototype.slice.call(arguments)); | ||
var isCorrect = _options.customValidators[customName].apply(null, args); | ||
return errors; | ||
} | ||
if (!isCorrect) { | ||
errorHandler(failMsg || 'Invalid value'); | ||
} | ||
return req._validationErrors.length > 0 ? req._validationErrors : false; | ||
}; | ||
return methods; | ||
}; | ||
}); | ||
methods['notEmpty'] = function() { | ||
return methods.isLength(1); | ||
locations.forEach(function(location) { | ||
req['sanitize' + _.capitalize(location)] = function(param) { | ||
return new Sanitizer(param, req, [location]); | ||
}; | ||
}); | ||
methods['len'] = function() { | ||
return methods.isLength.apply(methods.isLength, Array.prototype.slice.call(arguments)); | ||
}; | ||
req.sanitize = function(param) { | ||
return new Sanitizer(param, req, locations); | ||
}; | ||
methods['optional'] = function() { | ||
if (value !== undefined) { | ||
return methods; | ||
} | ||
var dummyMethods = []; | ||
for (var methodName in methods) { | ||
dummyMethods[methodName] = function() { return dummyMethods; }; | ||
} | ||
return dummyMethods; | ||
locations.forEach(function(location) { | ||
req['check' + _.capitalize(location)] = function(param, failMsg) { | ||
return new ValidatorChain(param, failMsg, req, location, options); | ||
}; | ||
}); | ||
return methods; | ||
req.checkFiles = function(param, failMsg) { | ||
return new ValidatorChain(param, failMsg, req, 'files', options); | ||
}; | ||
} | ||
return function(req, res, next) { | ||
req.updateParam = function(name, value) { | ||
// route params like /user/:id | ||
if (this.params && this.params.hasOwnProperty(name) && | ||
undefined !== this.params[name]) { | ||
return this.params[name] = value; | ||
req.checkHeaders = function(param, failMsg) { | ||
if (param === 'referrer') { | ||
param = 'referer'; | ||
} | ||
// query string params | ||
if (undefined !== this.query[name]) { | ||
return this.query[name] = value; | ||
} | ||
// request body params via connect.bodyParser | ||
if (this.body && undefined !== this.body[name]) { | ||
return this.body[name] = value; | ||
} | ||
return false; | ||
return new ValidatorChain(param, failMsg, req, 'headers', options); | ||
}; | ||
req.check = checkParam(req, function(item) { | ||
return param(req, item); | ||
}); | ||
req.check = function(param, failMsg) { | ||
return new ValidatorChain(param, failMsg, req, locate(req, param), options); | ||
}; | ||
req.checkFiles = checkParam(req, function(item) { | ||
return req.files && req.files[item]; | ||
}); | ||
req.filter = req.sanitize; | ||
req.assert = req.check; | ||
req.validate = req.check; | ||
req.checkBody = checkParam(req, function(item) { | ||
return req.body && req.body[item]; | ||
}); | ||
next(); | ||
}; | ||
}; | ||
req.checkParams = checkParam(req, function(item) { | ||
return req.params && req.params[item]; | ||
}); | ||
/** | ||
* Validates and handles errors, return instance of itself to allow for chaining | ||
* | ||
* @method makeValidator | ||
* @param {string} methodName | ||
* @param {object} container | ||
* @return {function} | ||
*/ | ||
req.checkQuery = checkParam(req, function(item) { | ||
return req.query && req.query[item]; | ||
}); | ||
function makeValidator(methodName, container) { | ||
return function() { | ||
var args = []; | ||
args.push(this.value); | ||
args = args.concat(Array.prototype.slice.call(arguments)); | ||
req.checkHeader = checkParam(req, function(header) { | ||
var toCheck; | ||
var result = container[methodName].apply(container, args); | ||
if (header === 'referrer' || header === 'referer') { | ||
toCheck = req.headers.referer; | ||
} else { | ||
toCheck = req.headers[header]; | ||
} | ||
return req.headers && toCheck; | ||
}); | ||
var isValid = this.skipValidating || result; | ||
req.onValidationError = function(errback) { | ||
req.onErrorCallback = errback; | ||
}; | ||
if (!isValid) { | ||
var error = this.errorFormatter(this.param, this.failMsg || 'Invalid value', this.value); | ||
this.validationErrors.push(error); | ||
this.req._validationErrors.push(error); | ||
} | ||
req.validationErrors = function(mapped) { | ||
if (req._validationErrors === undefined) { | ||
return null; | ||
} | ||
if (mapped) { | ||
var errors = {}; | ||
req._validationErrors.forEach(function(err) { | ||
errors[err.param] = err; | ||
}); | ||
return errors; | ||
} | ||
return req._validationErrors; | ||
}; | ||
return this; | ||
}; | ||
} | ||
req.filter = function(item) { | ||
return sanitize(this, item, param(req, item)); | ||
}; | ||
/** | ||
* Sanitizes and sets sanitized value on the request, then return instance of itself to allow for chaining | ||
* | ||
* @method makeSanitizer | ||
* @param {string} methodName | ||
* @param {object} container | ||
* @return {function} | ||
*/ | ||
// Create some aliases - might help with code readability | ||
req.sanitize = req.filter; | ||
req.assert = req.check; | ||
req.validate = req.check; | ||
function makeSanitizer(methodName, container) { | ||
return function() { | ||
var _arguments = arguments; | ||
var result; | ||
this.values.forEach(function(value, i) { | ||
if (value) { | ||
var args = [value]; | ||
args = args.concat(Array.prototype.slice.call(_arguments)); | ||
result = container[methodName].apply(container, args); | ||
// Taken from express 3.x for express 4.x compatibility | ||
function param(req, name, defaultValue){ | ||
// route params like /user/:id | ||
if (req.params && req.params.hasOwnProperty(name) && undefined !== req.params[name]) { | ||
return req.params[name]; | ||
_.set(this.req[this.locations[i]], this.param, result); | ||
this.values[i] = result; | ||
} | ||
// query string params | ||
if (undefined !== req.query[name]) { | ||
return req.query[name]; | ||
} | ||
// request body params via connect.bodyParser | ||
if (req.body && undefined !== req.body[name]) { | ||
return req.body[name]; | ||
} | ||
return defaultValue; | ||
} | ||
}.bind(this)); | ||
return next(); | ||
return result; | ||
}; | ||
}; | ||
} | ||
/** | ||
* find location of param | ||
* | ||
* @method param | ||
* @param {Request} req express request object | ||
* @param {(string|string[])} name [description] | ||
* @return {string} | ||
*/ | ||
function locate(req, name) { | ||
if (_.get(req.params, name)) { | ||
return 'params'; | ||
} else if (_.has(req.query, name)) { | ||
return 'query'; | ||
} else if (_.has(req.body, name)) { | ||
return 'body'; | ||
} | ||
return undefined; | ||
} | ||
module.exports = expressValidator; | ||
module.exports.validator = validator; |
@@ -12,3 +12,3 @@ { | ||
], | ||
"version": "2.11.0", | ||
"version": "2.12.0", | ||
"homepage": "https://github.com/ctavan/express-validator", | ||
@@ -29,3 +29,4 @@ "license": "MIT", | ||
"dependencies": { | ||
"validator": "3.39.0" | ||
"lodash": "3.9.3", | ||
"validator": "3.40.1" | ||
}, | ||
@@ -32,0 +33,0 @@ "devDependencies": { |
@@ -27,2 +27,3 @@ # express-validator | ||
// VALIDATION | ||
// checkBody only checks req.body; none of the other req parameters | ||
@@ -40,2 +41,10 @@ // Similarly checkParams only checks in req.params (URL params) and | ||
// SANITIZATION | ||
// as with validation these will only validate the corresponding | ||
// request object | ||
req.sanitizeBody('postparam').toBoolean(); | ||
req.sanitizeParams('urlparam').toBoolean(); | ||
req.sanitizeQuery('getparam').toBoolean(); | ||
// OR find the relevent param in all areas | ||
req.sanitize('postparam').toBoolean(); | ||
@@ -49,5 +58,5 @@ | ||
res.json({ | ||
urlparam: req.param('urlparam'), | ||
getparam: req.param('getparam'), | ||
postparam: req.param('postparam') | ||
urlparam: req.params.urlparam, | ||
getparam: req.params.getparam, | ||
postparam: req.params.postparam | ||
}); | ||
@@ -152,4 +161,32 @@ }); | ||
### Validation errors | ||
## Validation | ||
#### req.check(); | ||
```javascript | ||
req.check('testparam', 'Error Message').notEmpty().isInt(); | ||
req.check('testparam.child', 'Error Message').isInt(); // find nested params | ||
req.check(['testparam', 'child'], 'Error Message').isInt(); // find nested params | ||
``` | ||
Starts the validation of the specifed parameter, will look for the parameter in `req` in the order `params`, `query`, `body`, then validate, you can use 'dot-notation' or an array to access nested values. | ||
Validators are appended and can be chained. See [chriso/validator.js](https://github.com/chriso/validator.js) for available validators, or [add your own](#customvalidators). | ||
#### req.assert(); | ||
Alias for [req.check()](#reqcheck). | ||
#### req.validate(); | ||
Alias for [req.check()](#reqcheck). | ||
#### req.checkBody(); | ||
Same as [req.check()](#reqcheck), but only looks in `req.body`. | ||
#### req.checkQuery(); | ||
Same as [req.check()](#reqcheck), but only looks in `req.query`. | ||
#### req.checkParams(); | ||
Same as [req.check()](#reqcheck), but only looks in `req.params`. | ||
## Validation errors | ||
You have two choices on how to get the validation errors: | ||
@@ -202,36 +239,34 @@ | ||
### Nested input data | ||
## Sanitizer | ||
Example: | ||
#### req.sanitize(); | ||
```javascript | ||
```html | ||
<input name="user[fields][email]" /> | ||
``` | ||
req.body.comment = 'a <span>comment</span>'; | ||
req.body.comment.username = ' user '; | ||
Provide an array instead of a string: | ||
req.sanitize('comment').escape(); // returns 'a <span>comment</span>' | ||
req.sanitize('comment.user').trim(); // returns 'a user' | ||
```javascript | ||
req.assert(['user', 'fields', 'email'], 'valid email required').isEmail(); | ||
var errors = req.validationErrors(); | ||
console.log(errors); | ||
console.log(req.body.comment); // 'a <span>comment</span>' | ||
console.log(req.body.comment.user); // 'a user' | ||
``` | ||
Output: | ||
Sanitizes the specified parameter (using 'dot-notation' or array), the parameter will be updated to the sanitized result. Cannot be chained, and will return the result. See [chriso/validator.js](https://github.com/chriso/validator.js) for available sanitizers, or [add your own](#customsanitizers). | ||
```javascript | ||
[ | ||
{ | ||
param: "user_fields_email", | ||
msg: "valid email required", | ||
value: "<received input>" | ||
} | ||
] | ||
``` | ||
If the parameter is present in multiple places with the same name e.g. `req.params.comment` & `req.query.comment`, they will all be sanitized. | ||
Alternatively you can use dot-notation to specify nested fields to be checked: | ||
#### req.filter(); | ||
Alias for [req.sanitize()](#reqsanitize). | ||
```javascript | ||
req.assert(['user.fields.email'], 'valid email required').isEmail(); | ||
``` | ||
#### req.sanitizeBody(); | ||
Same as [req.sanitize()](#reqsanitize), but only looks in `req.body`. | ||
#### req.sanitizeQuery(); | ||
Same as [req.sanitize()](#reqsanitize), but only looks in `req.query`. | ||
#### req.sanitizeParams(); | ||
Same as [req.sanitize()](#reqsanitize), but only looks in `req.params`. | ||
### Regex routes | ||
@@ -251,6 +286,2 @@ | ||
### Extending | ||
You can add your own validators using the `customValidators` option. See [Middleware Options](#middleware-options) for usage details. | ||
## Changelog | ||
@@ -269,2 +300,1 @@ | ||
Copyright (c) 2010 Chris O'Hara <cohara87@gmail.com>, MIT License | ||
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
80177
27
1196
294
2
+ Addedlodash@3.9.3
+ Addedlodash@3.9.3(transitive)
+ Addedvalidator@3.40.1(transitive)
- Removedvalidator@3.39.0(transitive)
Updatedvalidator@3.40.1