UNPKG

password-validator

Version:

Validates password according to flexible and intuitive specifications

274 lines (249 loc) 8.82 kB
/* eslint-disable no-unused-vars */ var lib = require('./lib'); var error = require('./constants').error; var getValidationMessage = require('./validationMessages'); /** * Validates that a number is a valid length (positive number) * * @private * @param {number} num - Number to validate */ function _validateLength(num) { const len = Number(num); if (isNaN(len) || !Number.isInteger(len) || len < 1) { throw new Error(error.length); } } /** * Tests a validation and return the result * * @private * @param {string} property - Property to validate * @returns {boolean} Boolean value indicting the validity * of the password against the property */ function _isPasswordValidFor(property) { return lib[property.method].apply(this, property.arguments); } /** * Registers the properties of a password-validation schema object * * @private * @param {string} method - Property name * @param {array} arguments - arguments for the func property * @returns {PasswordValidator} */ function _register(method, args, description) { // Add property to the schema this.properties.push({ method, arguments: args, description }); return this; } class PasswordValidator { /** * Creates a password-validator schema * * @constructor */ constructor() { this.properties = []; } /** * Method to validate the password against schema * * @param {string} pwd - password to validate * @param {object} [options] - optional options to configure validation * @param {boolean} [options.list] - asks for a list of validation * failures instead of just true/false * @param {boolean} [options.details] - asks for more details about * failed validations including arguments, and error messages * @returns {boolean|array} Boolean value indicting the validity * of the password as per schema, if 'options.list' or * 'options.details' is not set. Otherwise, it returns an * array of property names which failed validations */ validate(pwd, options) { this.list = Boolean(options && options.list); this.details = Boolean(options && options.details); this.password = String(pwd); this.positive = true; if (this.list || this.details) { return this.properties.reduce((errorList, property) => { // Applies all validations defined in lib one by one if (!_isPasswordValidFor.call(this, property)) { // If the validation for a property fails, // add it to the error list var detail = property.method; // If the details option was provided, // return a rich object including validation message if (this.details) { detail = { validation: property.method }; if (property.arguments && property.arguments[0]) { detail.arguments = property.arguments[0]; } if (!this.positive && property.method !== 'not') { detail.inverted = true; } var description = property.arguments && property.arguments[1]; var validationMessage = description || getValidationMessage(property.method, detail.arguments, detail.inverted); detail.message = validationMessage; } return errorList.concat(detail); } return errorList; }, []); } return this.properties.every(_isPasswordValidFor.bind(this)); } /** * Rule to mandate the presence of letters in the password * * @param {number} [count] - minimum number of letters required * @param {string} [description] - description of the validation * @returns {PasswordValidator} instance of PasswordValidator schema */ letters(count, description) { count && _validateLength(count); return _register.call(this, 'letters', arguments); } /** * Rule to mandate the presence of digits in the password * * @param {number} [count] - minimum number of digits required * @param {string} [description] - description of the validation * @returns {PasswordValidator} instance of PasswordValidator schema */ digits(count, description) { count && _validateLength(count); return _register.call(this, 'digits', arguments); } /** * Rule to mandate the presence of symbols in the password * * @param {number} [count] - minimum number of symbols required * @param {string} [description] - description of the validation * @returns {PasswordValidator} instance of PasswordValidator schema */ symbols(count, description) { count && _validateLength(count); return _register.call(this, 'symbols', arguments); } /** * Rule to specify a minimum length of the password * * @param {number} num - minimum length * @param {string} [description] - description of the validation * @returns {PasswordValidator} instance of PasswordValidator schema */ min(num, description) { _validateLength(num); return _register.call(this, 'min', arguments); } /** * Rule to specify a maximum length of the password * * @param {number} num - maximum length * @param {string} [description] - description of the validation * @returns {PasswordValidator} instance of PasswordValidator schema */ max(num, description) { _validateLength(num); return _register.call(this, 'max', arguments); } /** * Rule to mandate the presence of lowercase letters in the password * * @param {number} [count] - minimum number of lowercase letters required * @param {string} [description] - description of the validation * @returns {PasswordValidator} instance of PasswordValidator schema */ lowercase(count, description) { count && _validateLength(count); return _register.call(this, 'lowercase', arguments); } /** * Rule to mandate the presence of uppercase letters in the password * * @param {number} [count] - minimum number of uppercase letters required * @param {string} [description] - description of the validation * @returns {PasswordValidator} instance of PasswordValidator schema */ uppercase(count, description) { count && _validateLength(count); return _register.call(this, 'uppercase', arguments); } /** * Rule to mandate the presence of space in the password * It can be used along with 'not' to not allow spaces * in the password * * @param {number} [count] - minimum number of spaces required * @param {string} [description] - description of the validation * @returns {PasswordValidator} instance of PasswordValidator schema */ spaces(count, description) { count && _validateLength(count); return _register.call(this, 'spaces', arguments); } /** * Rule to invert the effects of 'not' * Apart from that, 'has' is also used * to make the api readable and chainable * * @param {string|RegExp} [pattern] - pattern to match * @param {string} [description] - description of the validation * @returns {PasswordValidator} instance of PasswordValidator schema */ has(pattern, description) { return _register.call(this, 'has', arguments); } /** * Rule to invert the next applied rules. * All the rules applied after 'not' will have opposite effect, * until 'has' rule is applied * * @param {string|RegExp} [pattern] - pattern to not match * @param {string} [description] - description of the validation * @returns {PasswordValidator} instance of PasswordValidator schema */ not(pattern, description) { return _register.call(this, 'not', arguments); } /** * Rule to invert the effects of 'not' * Apart from that, 'is' is also used * to make the api readable and chainable * * @returns {PasswordValidator} instance of PasswordValidator schema */ is() { return _register.call(this, 'is', arguments); } /** * Rule to whitelist words to be used as password * * @param {array} list - list of values allowed * @param {string} [description] - description of the validation * @returns {PasswordValidator} instance of PasswordValidator schema */ oneOf(list, description) { return _register.call(this, 'oneOf', arguments); } /** * Insert a plugin function into the validation chain * * @param {Plugin} fn - A plugin function * @param {string} [description] - description of the validation * @returns {PasswordValidator} instance of PasswordValidator schema */ usingPlugin(fn, description) { if (typeof fn !== 'function') { throw new Error(error.invalidPlugin); } return _register.call(this, 'usingPlugin', arguments); } } module.exports = PasswordValidator; /** * @callback Plugin * @param password Password injected by the library */