Skip to content

Instantly share code, notes, and snippets.

@distracteddev
Created September 13, 2012 08:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save distracteddev/3712776 to your computer and use it in GitHub Desktop.
Save distracteddev/3712776 to your computer and use it in GitHub Desktop.
Password Validating Function
/*
REGULAR USAGE
verifier.exec('myInvalidPassword') -> returns an [] of error messages
EXTENDED USAGE
verify = function(passwd, options) {
// Some logic
return errors || null;
};
// Extend the original exec() function with extend
verify = verifier.extend(verify);
// Use our new function to verify passwords
verify('myPassword');
EXTENDED ASYNC USAGE
verify = function(passwd, options, cb) {
// Some logic
cb(errors || null)
}
verify = verifier.extend(verify);
verify('myPassword', function(errors) {
// Async validation complete
});
*/
var verifier = {
/**
* Verifies the passwd meets certain strength requirements
* @param {string} passwd
* @param {object} [options]
* @param {string} [options.firstName]
* @param {string} [options.lastName]
* @param {string} [options.confirm]
* @return {Array} || null
*/
exec: function(passwd, options) {
if (arguments.length < 1) {
throw new Error("You must pass a password string to the verifier.exec() function");
}
options = options || {};
// Lets define some test objects that consist of a regEx and an error message:
// matches any non-new-line character 8 or more times
var properLength = { re: /.{8,}/, errorMsg: 'The password must be at least 8 characters in length.<br/>'};
// matches at least one capital character
var hasCapital = { re: /[A-Z]/, errorMsg: 'The password must contain at least 1 capital letter.<br/>'};
// matches at least one lower-case character
var hasLowercase = {re: /[a-z]/, errorMsg: 'The password must contain at least 1 lower case letter.<br/>'};
// matches at least one special character
var hasSpecial = { re: /\W/, errorMsg: 'The password must contain at least 1 special chracter.<br/>'};
// matches at least one numeral character
var hasNumeral = { re: /\d/, errorMsg: 'The password must contain at least 1 number.<br/>'};
// if the user's name is part of the password, reject it
// Create an array holding all of the tests we want run
var tests = [properLength, hasCapital, hasSpecial, hasNumeral, hasLowercase];
// Push optional tests onto the array if the required data is provided
// if any names are provided, make sure they aren't used within the password
if (options.firstName || options.lastName) {
var names;
var restricted = [];
if (options.firstName) {
restricted.push(options.firstName);
}
if (options.lastName) {
restricted.push(options.lastName);
}
// Join all restricted words by the regEx OR operator
names = new RegExp(restricted.join('|'));
// Build the test and push it onto our tests array
var containsName = {re: names, errorMsg: 'Your password cannot contain either your First or Last name', expected: false};
tests.push(containsName);
}
// If a confirm password has been provided, ensure it matches the original
if (options.confirm) {
var confirmRegEx = new RegExp('$' + options.confirm + '^');
var confirmPassword = {re: regEx, errorMsg: 'The passwords you provided do not match'};
tests.push(confirmPassword);
}
// Array of error messages
var errors = null;
// Run each of our pre-defined tests
tests.forEach(function(test) {
var expected = test.expected;
// If no expected result, assume the re should test to true
if (expected === undefined) {
expected = true;
}
// Run the regEx and compare to expected result
if (test.re.test(passwd) !== expected) {
// Oops, an error occured. If this is the first error, init errors.
if (!errors) {
errors = [];
}
errors.push(test.errorMsg);
}
});
// Either null or an array of error messages.
// NOTE: If errors exist, should we Return errors.join('<br/>') instead?
return errors;
},
/**
* Takes the verify function and returns a new function that calls
* both verifier.exec() and verify on the passed arguments
* @param verify
* @return {function}
*/
extend: function(verify) {
var exec = this.exec;
// If a callback is provided to the returned function, it will assume
// that 'verify' is asynchronous.
return function(passwd, options, cb) {
// Deal with variable number of args
if (typeof options === 'function') {
cb = options;
options = {};
}
// Run both verify functions
var errors = exec(passwd, options);
var moreErrors;
// If a callback is provided, assume verify is asynchronous
if (typeof cb === 'function') {
// Pass along the options object incase it is needed.
verify(passwd, options, function(errs) {
moreErrors = errs;
// Concat the error messages if neccessary.
if (errors && moreErrors) {
errors = errors.concat(moreErrors);
}
// If both are null, null will be returned
// If one is an array, that array will be returned.
var result = errors || moreErrors;
cb(result);
});
} else {
// If no callback is provided, assume verify is synchronous
moreErrors = verify(passwd, options);
// concat
if (errors && moreErrors) {
errors = errors.concat(moreErrors);
}
// return
return errors || moreErrors;
}
};
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment