├── .gitignore ├── Makefile ├── README.md ├── complexify ├── lib └── complexify.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | 10 | pids 11 | logs 12 | results 13 | 14 | npm-debug.log 15 | /node_modules 16 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | git submodule init 3 | git submodule update 4 | npm install 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | node-complexify 2 | =============== 3 | 4 | node.js port of [jquery.complexify.js](https://github.com/danpalmer/jquery.complexify.js/) 5 | 6 | ## Installing 7 | ``` 8 | npm install node-complexify 9 | ``` 10 | 11 | ## Usage 12 | As a module: 13 | ```javascript 14 | var complexify = require('node-complexify'); 15 | 16 | complexify.evalPasswordComplexity("MadHatter", function(err, valid, complexity) { 17 | console.log(complexity); 18 | console.log(valid); 19 | }); 20 | ``` 21 | 22 | As an executable: 23 | ``` 24 | complexify "MadHatter" || echo "Password not complex enough" 25 | ``` 26 | -------------------------------------------------------------------------------- /complexify: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var complexify = require('./lib/complexify'); 4 | 5 | if (process.argv[2] == undefined) { 6 | console.error("Evaluate password complexity using jquery.complexify.js."); 7 | console.error("Exit with an error if complexity is below the threshold."); 8 | console.error("Usage: " + __filename + " password"); 9 | process.exit(1); 10 | } 11 | 12 | complexify.evalPasswordComplexity(process.argv[2], function(err, valid, complexity) { 13 | console.log(JSON.stringify({ err: err, valid: valid, complexity: complexity })); 14 | if (!valid) { 15 | process.exit(2); 16 | } 17 | }); 18 | -------------------------------------------------------------------------------- /lib/complexify.js: -------------------------------------------------------------------------------- 1 | // @module complexify 2 | 'use strict' 3 | var _ = require('underscore'); 4 | 5 | // @callback evalPasswordComplexityCallback 6 | // @param {string} err - error code if an error occurs, null otherwise 7 | // @param {boolean} valid - straight boolean to determine whether the password is valid or not given the supplied complexity params 8 | // @param {number} complexity - complexity score for the password scaled according to strengthScaleFactor (0-100% is default) 9 | 10 | var DEFAULT_BAN_LIST = '123456|password|12345678|1234|pussy|12345|dragon|qwerty|696969|mustang|letmein|baseball|master|michael|football|shadow|monkey|abc123|pass|fuckme|6969|jordan|harley|ranger|iwantu|jennifer|hunter|fuck|2000|test|batman|trustno1|thomas|tigger|robert|access|love|buster|1234567|soccer|hockey|killer|george|sexy|andrew|charlie|superman|asshole|fuckyou|dallas|jessica|panties|pepper|1111|austin|william|daniel|golfer|summer|heather|hammer|yankees|joshua|maggie|biteme|enter|ashley|thunder|cowboy|silver|richard|fucker|orange|merlin|michelle|corvette|bigdog|cheese|matthew|121212|patrick|martin|freedom|ginger|blowjob|nicole|sparky|yellow|camaro|secret|dick|falcon|taylor|111111|131313|123123|bitch|hello|scooter|please|porsche|guitar|chelsea|black|diamond|nascar|jackson|cameron|654321|computer|amanda|wizard|xxxxxxxx|money|phoenix|mickey|bailey|knight|iceman|tigers|purple|andrea|horny|dakota|aaaaaa|player|sunshine|morgan|starwars|boomer|cowboys|edward|charles|girls|booboo|coffee|xxxxxx|bulldog|ncc1701|rabbit|peanut|john|johnny|gandalf|spanky|winter|brandy|compaq|carlos|tennis|james|mike|brandon|fender|anthony|blowme|ferrari|cookie|chicken|maverick|chicago|joseph|diablo|sexsex|hardcore|666666|willie|welcome|chris|panther|yamaha|justin|banana|driver|marine|angels|fishing|david|maddog|hooters|wilson|butthead|dennis|fucking|captain|bigdick|chester|smokey|xavier|steven|viking|snoopy|blue|eagles|winner|samantha|house|miller|flower|jack|firebird|butter|united|turtle|steelers|tiffany|zxcvbn|tomcat|golf|bond007|bear|tiger|doctor|gateway|gators|angel|junior|thx1138|porno|badboy|debbie|spider|melissa|booger|1212|flyers|fish|porn|matrix|teens|scooby|jason|walter|cumshot|boston|braves|yankee|lover|barney|victor|tucker|princess|mercedes|5150|doggie|zzzzzz|gunner|horney|bubba|2112|fred|johnson|xxxxx|tits|member|boobs|donald|bigdaddy|bronco|penis|voyager|rangers|birdie|trouble|white|topgun|bigtits|bitches|green|super|qazwsx|magic|lakers|rachel|slayer|scott|2222|asdf|video|london|7777|marlboro|srinivas|internet|action|carter|jasper|monster|teresa|jeremy|11111111|bill|crystal|peter|pussies|cock|beer|rocket|theman|oliver|prince|beach|amateur|7777777|muffin|redsox|star|testing|shannon|murphy|frank|hannah|dave|eagle1|11111|mother|nathan|raiders|steve|forever|angela|viper|ou812|jake|lovers|suckit|gregory|buddy|whatever|young|nicholas|lucky|helpme|jackie|monica|midnight|college|baby|cunt|brian|mark|startrek|sierra|leather|232323|4444|beavis|bigcock|happy|sophie|ladies|naughty|giants|booty|blonde|fucked|golden|0|fire|sandra|pookie|packers|einstein|dolphins|chevy|winston|warrior|sammy|slut|8675309|zxcvbnm|nipples|power|victoria|asdfgh|vagina|toyota|travis|hotdog|paris|rock|xxxx|extreme|redskins|erotic|dirty|ford|freddy|arsenal|access14|wolf|nipple|iloveyou|alex|florida|eric|legend|movie|success|rosebud|jaguar|great|cool|cooper|1313|scorpio|mountain|madison|987654|brazil|lauren|japan|naked|squirt|stars|apple|alexis|aaaa|bonnie|peaches|jasmine|kevin|matt|qwertyui|danielle|beaver|4321|4128|runner|swimming|dolphin|gordon|casper|stupid|shit|saturn|gemini|apples|august|3333|canada|blazer|cumming|hunting|kitty|rainbow|112233|arthur|cream|calvin|shaved|surfer|samson|kelly|paul|mine|king|racing|5555|eagle|hentai|newyork|little|redwings|smith|sticky|cocacola|animal|broncos|private|skippy|marvin|blondes|enjoy|girl|apollo|parker|qwert|time|sydney|women|voodoo|magnum|juice|abgrtyu|777777|dreams|maxwell|music|rush2112|russia|scorpion|rebecca|tester|mistress|phantom|billy|6666|albert|111111|11111111|112233|121212|123123|123456|1234567|12345678|131313|232323|654321|666666|696969|777777|7777777|8675309|987654|abcdef|password1|password12|password123|twitter'.split('|'); 11 | var MIN_COMPLEXITY = 49; // 12 chars with Upper, Lower and Number 12 | var MAX_COMPLEXITY = 120; // 25 chars, all charsets 13 | var CHARSETS = [ 14 | // Commonly Used 15 | //////////////////// 16 | [0x0030, 0x0039], // Numbers 17 | [0x0041, 0x005A], // Uppercase 18 | [0x0061, 0x007A], // Lowercase 19 | [0x0021, 0x002F], // Punctuation 20 | [0x003A, 0x0040], // Punctuation 21 | [0x005B, 0x0060], // Punctuation 22 | [0x007B, 0x007E], // Punctuation 23 | // Everything Else 24 | //////////////////// 25 | [0x0080, 0x00FF], // Latin-1 Supplement 26 | [0x0100, 0x017F], // Latin Extended-A 27 | [0x0180, 0x024F], // Latin Extended-B 28 | [0x0250, 0x02AF], // IPA Extensions 29 | [0x02B0, 0x02FF], // Spacing Modifier Letters 30 | [0x0300, 0x036F], // Combining Diacritical Marks 31 | [0x0370, 0x03FF], // Greek 32 | [0x0400, 0x04FF], // Cyrillic 33 | [0x0530, 0x058F], // Armenian 34 | [0x0590, 0x05FF], // Hebrew 35 | [0x0600, 0x06FF], // Arabic 36 | [0x0700, 0x074F], // Syriac 37 | [0x0780, 0x07BF], // Thaana 38 | [0x0900, 0x097F], // Devanagari 39 | [0x0980, 0x09FF], // Bengali 40 | [0x0A00, 0x0A7F], // Gurmukhi 41 | [0x0A80, 0x0AFF], // Gujarati 42 | [0x0B00, 0x0B7F], // Oriya 43 | [0x0B80, 0x0BFF], // Tamil 44 | [0x0C00, 0x0C7F], // Telugu 45 | [0x0C80, 0x0CFF], // Kannada 46 | [0x0D00, 0x0D7F], // Malayalam 47 | [0x0D80, 0x0DFF], // Sinhala 48 | [0x0E00, 0x0E7F], // Thai 49 | [0x0E80, 0x0EFF], // Lao 50 | [0x0F00, 0x0FFF], // Tibetan 51 | [0x1000, 0x109F], // Myanmar 52 | [0x10A0, 0x10FF], // Georgian 53 | [0x1100, 0x11FF], // Hangul Jamo 54 | [0x1200, 0x137F], // Ethiopic 55 | [0x13A0, 0x13FF], // Cherokee 56 | [0x1400, 0x167F], // Unified Canadian Aboriginal Syllabics 57 | [0x1680, 0x169F], // Ogham 58 | [0x16A0, 0x16FF], // Runic 59 | [0x1780, 0x17FF], // Khmer 60 | [0x1800, 0x18AF], // Mongolian 61 | [0x1E00, 0x1EFF], // Latin Extended Additional 62 | [0x1F00, 0x1FFF], // Greek Extended 63 | [0x2000, 0x206F], // General Punctuation 64 | [0x2070, 0x209F], // Superscripts and Subscripts 65 | [0x20A0, 0x20CF], // Currency Symbols 66 | [0x20D0, 0x20FF], // Combining Marks for Symbols 67 | [0x2100, 0x214F], // Letterlike Symbols 68 | [0x2150, 0x218F], // Number Forms 69 | [0x2190, 0x21FF], // Arrows 70 | [0x2200, 0x22FF], // Mathematical Operators 71 | [0x2300, 0x23FF], // Miscellaneous Technical 72 | [0x2400, 0x243F], // Control Pictures 73 | [0x2440, 0x245F], // Optical Character Recognition 74 | [0x2460, 0x24FF], // Enclosed Alphanumerics 75 | [0x2500, 0x257F], // Box Drawing 76 | [0x2580, 0x259F], // Block Elements 77 | [0x25A0, 0x25FF], // Geometric Shapes 78 | [0x2600, 0x26FF], // Miscellaneous Symbols 79 | [0x2700, 0x27BF], // Dingbats 80 | [0x2800, 0x28FF], // Braille Patterns 81 | [0x2E80, 0x2EFF], // CJK Radicals Supplement 82 | [0x2F00, 0x2FDF], // Kangxi Radicals 83 | [0x2FF0, 0x2FFF], // Ideographic Description Characters 84 | [0x3000, 0x303F], // CJK Symbols and Punctuation 85 | [0x3040, 0x309F], // Hiragana 86 | [0x30A0, 0x30FF], // Katakana 87 | [0x3100, 0x312F], // Bopomofo 88 | [0x3130, 0x318F], // Hangul Compatibility Jamo 89 | [0x3190, 0x319F], // Kanbun 90 | [0x31A0, 0x31BF], // Bopomofo Extended 91 | [0x3200, 0x32FF], // Enclosed CJK Letters and Months 92 | [0x3300, 0x33FF], // CJK Compatibility 93 | [0x3400, 0x4DB5], // CJK Unified Ideographs Extension A 94 | [0x4E00, 0x9FFF], // CJK Unified Ideographs 95 | [0xA000, 0xA48F], // Yi Syllables 96 | [0xA490, 0xA4CF], // Yi Radicals 97 | [0xAC00, 0xD7A3], // Hangul Syllables 98 | [0xD800, 0xDB7F], // High Surrogates 99 | [0xDB80, 0xDBFF], // High Private Use Surrogates 100 | [0xDC00, 0xDFFF], // Low Surrogates 101 | [0xE000, 0xF8FF], // Private Use 102 | [0xF900, 0xFAFF], // CJK Compatibility Ideographs 103 | [0xFB00, 0xFB4F], // Alphabetic Presentation Forms 104 | [0xFB50, 0xFDFF], // Arabic Presentation Forms-A 105 | [0xFE20, 0xFE2F], // Combining Half Marks 106 | [0xFE30, 0xFE4F], // CJK Compatibility Forms 107 | [0xFE50, 0xFE6F], // Small Form Variants 108 | [0xFE70, 0xFEFE], // Arabic Presentation Forms-B 109 | [0xFEFF, 0xFEFF], // Specials 110 | [0xFF00, 0xFFEF], // Halfwidth and Fullwidth Forms 111 | [0xFFF0, 0xFFFD] // Specials 112 | ]; 113 | 114 | 115 | // Array of banned passwords generated from 500 worst passwords and 370 Banned Twitter lists 116 | // @property defaultBanList 117 | // @source http://www.skullsecurity.org/wiki/index.php/Passwords 118 | // 119 | exports.defaultBanList = DEFAULT_BAN_LIST; 120 | 121 | // Evaluates the supplied password and returns it's complexity score. 122 | // @method evalPasswordComplexity 123 | // @param {string} password - The password to be evaluated 124 | // @param {object} [options] - Options that modify the password complexity checking 125 | // @param {integer} [options.minimumChars=8] - Minimum number of characters in the password. 126 | // @param {number} [options.minimumComplexity=49] - Minimum complexity in order to be considered to be valid. Complexify's default settings will enforce a minimum level of complexity that would mean brute-forcing should take ~600 years on a commodity desktop machine. 127 | // @param {integer} [options.strengthScaleFactor=1] - Scale value for the complexity score (1 is equivalent to a percentage between 0-100%) 128 | // @param {string[]} [options.bannedPasswords={defaultBanList}] - Array of banned passwords 129 | // @param {string} [options.banMode='loose'] - 'strict' will match on the substrings within the banned passwords, 'loose' will only match on the whole word, 'none' will not used the banned list 130 | // @param {evalPasswordComplexityCallback} callback - Callback to be called when the complexity check is complete. 131 | // @returns {any} Returns the result of the supplied callback back to the calling function. 132 | // 133 | exports.evalPasswordComplexity = function(password, options, callback) { 134 | // Process defaults 135 | var defaults = { 136 | minimumChars: 8, // minimum number of characters in the password 137 | minimumComplexity: MIN_COMPLEXITY, 138 | strengthScaleFactor: 1, // how to scale the resulting complexity score 139 | bannedPasswords: DEFAULT_BAN_LIST, // array of banned words 140 | banMode: 'loose' // (strict|loose|none) 141 | }; 142 | 143 | if (typeof options == 'function' && !callback) { 144 | callback = options; 145 | options = {}; 146 | } 147 | 148 | // Set the defaults 149 | options = _.pick(options, _.keys(defaults)); 150 | options = _.defaults(options, defaults); 151 | 152 | // @function additionaComplexityForCharset 153 | // @param {string} str - password to check 154 | // @param {integer[]} charset - pair of integers reprenting a range of unicode characters 155 | // @returns {integer } complexity score based on size of charset 156 | // @private 157 | function additionalComplexityForCharset(str, charset) { 158 | for (var i = str.length - 1; i >= 0; i--) { 159 | if (charset[0] <= str.charCodeAt(i) && str.charCodeAt(i) <= charset[1]) { 160 | return charset[1] - charset[0] + 1; 161 | } 162 | } 163 | return 0; 164 | } 165 | 166 | // @function inBanlist 167 | // @param {string} str - determines whether the supplied string is in the banlist 168 | // @param {string[]} bannedPasswords - Array of banned passwords 169 | // @param {string} banMode - 'strict' will match on the substrings within the banned passwords, 'loose' will only match on the whole word, 'none' will not used the banned list 170 | // @returns {boolean} true if password is in the ban list, false otherwise 171 | // @private 172 | function inBanlist(str, bannedPasswords, banMode) { 173 | if (bannedPasswords.length == 0 || banMode == 'none') 174 | return false; 175 | 176 | for (var i = 0; i < bannedPasswords.length; i++) { 177 | if (banMode === 'strict') { 178 | if (bannedPasswords[i].indexOf(str) !== -1) { 179 | console.log("Strict ban: " + bannedPasswords[i]); 180 | return true; 181 | } 182 | } else { 183 | if (bannedPasswords[i] === str) { 184 | console.log("Loose ban: " + bannedPasswords[i]); 185 | return true; 186 | } 187 | } 188 | } 189 | return false; 190 | } 191 | 192 | var complexity = 0, valid = false; 193 | var error = []; 194 | 195 | if (!inBanlist(password, options.bannedPasswords, options.banMode)) { 196 | for (var i = CHARSETS.length - 1; i >= 0; i--) { 197 | complexity += additionalComplexityForCharset(password, CHARSETS[i]); 198 | } 199 | } else { 200 | error.push("banned"); 201 | } 202 | 203 | // Use natural log to produce linear scale 204 | complexity = Math.log(Math.pow(complexity, password.length)) * (1 / options.strengthScaleFactor); 205 | console.log("Unscaled complexity: " + complexity); 206 | 207 | // Check if complexity meets minimum and password is long enough 208 | if (complexity < options.minimumComplexity) 209 | error.push("toosimple"); 210 | if (password.length < options.minimumChars) 211 | error.push("tooshort"); 212 | 213 | // Scale to percentage, so it can be used for a progress bar 214 | complexity = (complexity / MAX_COMPLEXITY) * 100; 215 | complexity = (complexity > 100) ? 100 : complexity; 216 | 217 | return callback(error.length == 0 ? null : error, error.length == 0, complexity); 218 | } 219 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-complexify", 3 | "version": "0.1.0", 4 | "description": "node.js wrapper for jquery.complexify.js", 5 | "main": "./lib/complexify", 6 | "dependencies": { 7 | "underscore" : "*" 8 | }, 9 | "bin": { 10 | "complexify": "./complexify" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/kislyuk/node-complexify.git" 15 | }, 16 | "license": "BSD", 17 | "engines": { 18 | "node": ">=0.6" 19 | } 20 | } 21 | --------------------------------------------------------------------------------