/*	Password Validator 0.1	(c) 2007 Steven Levithan <stevenlevithan.com>	MIT License		Validation types supported	    *  Minimum and maximum length.    * Minimum n lowercase characters (a\u2013z).    * Minimum n uppercase characters (A\u2013Z).    * Minimum n combined a\u2013z and A\u2013Z characters.    * Minimum n numeric characters (0\u20139).    * Minimum n special characters (characters other than a\u2013z, A\u2013Z, and 0\u20139).    * 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).*/function validatePassword (pw, options) {	// default options (allows any password)	var o = {		lower:    1,		upper:    1,		alpha:    1, /* lower + upper */		numeric:  1,		special:  1,		length:   [10, 10],		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,			custom: /[!@\u00A3$%^&*()_+]/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;}
