/* http://github.com/danpalmer/jquery.complexify.js This code is distributed under the WTFPL v2: */ (function ($) { $.fn.extend({ complexify: function(options, callback) { var MIN_COMPLEXITY = 49; // 12 chars with Upper, Lower and Number var MAX_COMPLEXITY = 120; // 25 chars, all charsets var CHARSETS = [ // Commonly Used //////////////////// [0x0020, 0x0020], // Space [0x0030, 0x0039], // Numbers [0x0041, 0x005A], // Uppercase [0x0061, 0x007A], // Lowercase [0x0021, 0x002F], // Punctuation [0x003A, 0x0040], // Punctuation [0x005B, 0x0060], // Punctuation [0x007B, 0x007E], // Punctuation // Everything Else //////////////////// [0x0080, 0x00FF], // Latin-1 Supplement [0x0100, 0x017F], // Latin Extended-A [0x0180, 0x024F], // Latin Extended-B [0x0250, 0x02AF], // IPA Extensions [0x02B0, 0x02FF], // Spacing Modifier Letters [0x0300, 0x036F], // Combining Diacritical Marks [0x0370, 0x03FF], // Greek [0x0400, 0x04FF], // Cyrillic [0x0530, 0x058F], // Armenian [0x0590, 0x05FF], // Hebrew [0x0600, 0x06FF], // Arabic [0x0700, 0x074F], // Syriac [0x0780, 0x07BF], // Thaana [0x0900, 0x097F], // Devanagari [0x0980, 0x09FF], // Bengali [0x0A00, 0x0A7F], // Gurmukhi [0x0A80, 0x0AFF], // Gujarati [0x0B00, 0x0B7F], // Oriya [0x0B80, 0x0BFF], // Tamil [0x0C00, 0x0C7F], // Telugu [0x0C80, 0x0CFF], // Kannada [0x0D00, 0x0D7F], // Malayalam [0x0D80, 0x0DFF], // Sinhala [0x0E00, 0x0E7F], // Thai [0x0E80, 0x0EFF], // Lao [0x0F00, 0x0FFF], // Tibetan [0x1000, 0x109F], // Myanmar [0x10A0, 0x10FF], // Georgian [0x1100, 0x11FF], // Hangul Jamo [0x1200, 0x137F], // Ethiopic [0x13A0, 0x13FF], // Cherokee [0x1400, 0x167F], // Unified Canadian Aboriginal Syllabics [0x1680, 0x169F], // Ogham [0x16A0, 0x16FF], // Runic [0x1780, 0x17FF], // Khmer [0x1800, 0x18AF], // Mongolian [0x1E00, 0x1EFF], // Latin Extended Additional [0x1F00, 0x1FFF], // Greek Extended [0x2000, 0x206F], // General Punctuation [0x2070, 0x209F], // Superscripts and Subscripts [0x20A0, 0x20CF], // Currency Symbols [0x20D0, 0x20FF], // Combining Marks for Symbols [0x2100, 0x214F], // Letterlike Symbols [0x2150, 0x218F], // Number Forms [0x2190, 0x21FF], // Arrows [0x2200, 0x22FF], // Mathematical Operators [0x2300, 0x23FF], // Miscellaneous Technical [0x2400, 0x243F], // Control Pictures [0x2440, 0x245F], // Optical Character Recognition [0x2460, 0x24FF], // Enclosed Alphanumerics [0x2500, 0x257F], // Box Drawing [0x2580, 0x259F], // Block Elements [0x25A0, 0x25FF], // Geometric Shapes [0x2600, 0x26FF], // Miscellaneous Symbols [0x2700, 0x27BF], // Dingbats [0x2800, 0x28FF], // Braille Patterns [0x2E80, 0x2EFF], // CJK Radicals Supplement [0x2F00, 0x2FDF], // Kangxi Radicals [0x2FF0, 0x2FFF], // Ideographic Description Characters [0x3000, 0x303F], // CJK Symbols and Punctuation [0x3040, 0x309F], // Hiragana [0x30A0, 0x30FF], // Katakana [0x3100, 0x312F], // Bopomofo [0x3130, 0x318F], // Hangul Compatibility Jamo [0x3190, 0x319F], // Kanbun [0x31A0, 0x31BF], // Bopomofo Extended [0x3200, 0x32FF], // Enclosed CJK Letters and Months [0x3300, 0x33FF], // CJK Compatibility [0x3400, 0x4DB5], // CJK Unified Ideographs Extension A [0x4E00, 0x9FFF], // CJK Unified Ideographs [0xA000, 0xA48F], // Yi Syllables [0xA490, 0xA4CF], // Yi Radicals [0xAC00, 0xD7A3], // Hangul Syllables [0xD800, 0xDB7F], // High Surrogates [0xDB80, 0xDBFF], // High Private Use Surrogates [0xDC00, 0xDFFF], // Low Surrogates [0xE000, 0xF8FF], // Private Use [0xF900, 0xFAFF], // CJK Compatibility Ideographs [0xFB00, 0xFB4F], // Alphabetic Presentation Forms [0xFB50, 0xFDFF], // Arabic Presentation Forms-A [0xFE20, 0xFE2F], // Combining Half Marks [0xFE30, 0xFE4F], // CJK Compatibility Forms [0xFE50, 0xFE6F], // Small Form Variants [0xFE70, 0xFEFE], // Arabic Presentation Forms-B [0xFEFF, 0xFEFF], // Specials [0xFF00, 0xFFEF], // Halfwidth and Fullwidth Forms [0xFFF0, 0xFFFD] // Specials ]; var defaults = { minimumChars: 8, strengthScaleFactor: 1, bannedPasswords: window.COMPLEXIFY_BANLIST || [], banMode: 'strict' // (strict|loose) }; if($.isFunction(options) && !callback) { callback = options; options = {}; } options = $.extend(defaults, options); function additionalComplexityForCharset(str, charset) { for (var i = str.length - 1; i >= 0; i--) { if (charset[0] <= str.charCodeAt(i) && str.charCodeAt(i) <= charset[1]) { return charset[1] - charset[0] + 1; } } return 0; } function inBanlist(str) { if (options.banMode === 'strict') { for (var i = 0; i < options.bannedPasswords.length; i++) { if (str.toLowerCase().indexOf(options.bannedPasswords[i].toLowerCase()) !== -1) { return true; } } return false; } else { return $.inArray(str, options.bannedPasswords) > -1 ? true : false; } } function evaluateSecurity() { var password = $(this).val(); var complexity = 0, valid = false; // Reset complexity to 0 when banned password is found if (!inBanlist(password)) { // Add character complexity for (var i = CHARSETS.length - 1; i >= 0; i--) { complexity += additionalComplexityForCharset(password, CHARSETS[i]); } } else { complexity = 1; } // Use natural log to produce linear scale complexity = Math.log(Math.pow(complexity, password.length)) * (1/options.strengthScaleFactor); valid = (complexity > MIN_COMPLEXITY && password.length >= options.minimumChars); // Scale to percentage, so it can be used for a progress bar complexity = (complexity / MAX_COMPLEXITY) * 100; complexity = (complexity > 100) ? 100 : complexity; callback.call(this, valid, complexity); } this.each(function () { if($(this).val()) { evaluateSecurity.apply(this); } }); return this.each(function () { $(this).bind('keyup focus input propertychange mouseup', evaluateSecurity); }); } }); })(jQuery);