====== JavaScript - Password validation ======
Validation types supported out of the box. All are optional, which means that all passwords are allowed by default.
* Minimum and maximum length.
* Minimum n lowercase characters (a–z).
* Minimum n uppercase characters (A–Z).
* Minimum n combined a–z and A–Z characters.
* Minimum n numeric characters (0–9).
* Minimum n special characters (characters other than a–z, A–Z, and 0–9).
* Ban particular words (tested case-insensitively).
* Ban n-length character sequences (e.g. "abc", "XYZ", or "789", with a sequence length of 3; does not apply to special characters).
* Ban n-length qwerty character sequences (e.g. "qwerty" or "asdf", with a sequence length of 4; does not apply to special characters).
* Ban sequential, identical characters (e.g. "aa" or "!!").
* Use custom regular expressions (tested using RegExp.prototype.test) and functions (the password is provided as the first argument, and a Boolean value is expected in return).
Here's an example of how it can be used:
var password = "password";
var passed = validatePassword(password, {
length: [8, Infinity],
lower: 1,
upper: 1,
numeric: 1,
special: 1,
badWords: ["password", "steven", "levithan"],
badSequenceLength: 4
});
// passed: false
The above requires that password is at least eight characters long; has at least one lowercase, uppercase, numeric, and special character; doesn't include the words "password", "steven", or "levithan"; and doesn't include an alphanumeric sequence four or more characters in length (e.g. "1234").
Here's the code (there are no external library dependencies):
http://blog.stevenlevithan.com/archives/javascript-password-validator
/*
Password Validator 0.1
(c) 2007 Steven Levithan
MIT License
*/
function validatePassword (pw, options) {
// default options (allows any password)
var o = {
lower: 0,
upper: 0,
alpha: 0, /* lower + upper */
numeric: 0,
special: 0,
length: [0, Infinity],
custom: [ /* regexes and/or functions */ ],
badWords: [],
badSequenceLength: 0,
noQwertySequences: false,
noSequential: false
};
for (var property in options)
o[property] = options[property];
var re = {
lower: /[a-z]/g,
upper: /[A-Z]/g,
alpha: /[A-Z]/gi,
numeric: /[0-9]/g,
special: /[\W_]/g
},
rule, i;
// enforce min/max length
if (pw.length < o.length[0] || pw.length > o.length[1])
return false;
// enforce lower/upper/alpha/numeric/special rules
for (rule in re) {
if ((pw.match(re[rule]) || []).length < o[rule])
return false;
}
// enforce word ban (case insensitive)
for (i = 0; i < o.badWords.length; i++) {
if (pw.toLowerCase().indexOf(o.badWords[i].toLowerCase()) > -1)
return false;
}
// enforce the no sequential, identical characters rule
if (o.noSequential && /([\S\s])\1/.test(pw))
return false;
// enforce alphanumeric/qwerty sequence ban rules
if (o.badSequenceLength) {
var lower = "abcdefghijklmnopqrstuvwxyz",
upper = lower.toUpperCase(),
numbers = "0123456789",
qwerty = "qwertyuiopasdfghjklzxcvbnm",
start = o.badSequenceLength - 1,
seq = "_" + pw.slice(0, start);
for (i = start; i < pw.length; i++) {
seq = seq.slice(1) + pw.charAt(i);
if (
lower.indexOf(seq) > -1 ||
upper.indexOf(seq) > -1 ||
numbers.indexOf(seq) > -1 ||
(o.noQwertySequences && qwerty.indexOf(seq) > -1)
) {
return false;
}
}
}
// enforce custom regex/function rules
for (i = 0; i < o.custom.length; i++) {
rule = o.custom[i];
if (rule instanceof RegExp) {
if (!rule.test(pw))
return false;
} else if (rule instanceof Function) {
if (!rule(pw))
return false;
}
}
// great success!
return true;
}
Whitespaces will be invalidated if you add the /[\s]/g within the custom regexes declaration. The correct regexp is /^\S+$/g