1/* globals define */ 2(function (root, factory) { 3 4 if (typeof define === 'function' && define.amd) { 5 define([], factory); 6 } else if (typeof exports === 'object') { 7 module.exports = factory(); 8 } else { 9 root.owaspPasswordStrengthTest = factory(); 10 } 11 12 }(this, function () { 13 14 var owasp = {}; 15 16 // These are configuration settings that will be used when testing password 17 // strength 18 owasp.configs = { 19 allowPassphrases : true, 20 maxLength : 128, 21 minLength : 4, 22 minPhraseLength : 20, 23 minOptionalTestsToPass : 2 24 }; 25 26 // This method makes it more convenient to set config parameters 27 owasp.config = function(params) { 28 for (var prop in params) { 29 if (params.hasOwnProperty(prop) && this.configs.hasOwnProperty(prop)) { 30 this.configs[prop] = params[prop]; 31 } 32 } 33 }; 34 35 // This is an object containing the tests to run against all passwords. 36 owasp.tests = { 37 38 // An array of required tests. A password *must* pass these tests in order 39 // to be considered strong. 40 required: [ 41 42 // enforce a minimum length 43 function(password) { 44 if (password.length < owasp.configs.minLength) { 45 return 'The password must be at least ' + owasp.configs.minLength + ' characters long.'; 46 } 47 }, 48 49 // enforce a maximum length 50 function(password) { 51 if (password.length > owasp.configs.maxLength) { 52 return 'The password must be fewer than ' + owasp.configs.maxLength + ' characters.'; 53 } 54 }, 55 56 // forbid repeating characters 57 function(password) { 58 if (/(.)\1{2,}/.test(password)) { 59 return 'The password may not contain sequences of three or more repeated characters.'; 60 } 61 } 62 63 ], 64 65 // An array of optional tests. These tests are "optional" in two senses: 66 // 67 // 1. Passphrases (passwords whose length exceeds 68 // this.configs.minPhraseLength) are not obligated to pass these tests 69 // provided that this.configs.allowPassphrases is set to Boolean true 70 // (which it is by default). 71 // 72 // 2. A password need only to pass this.configs.minOptionalTestsToPass 73 // number of these optional tests in order to be considered strong. 74 optional: [ 75 76 // require at least one lowercase letter 77 function(password) { 78 if (!/[a-z]/.test(password)) { 79 return 'The password must contain at least one lowercase letter.'; 80 } 81 }, 82 83 // require at least one uppercase letter 84 function(password) { 85 if (!/[A-Z]/.test(password)) { 86 return 'The password must contain at least one uppercase letter.'; 87 } 88 }, 89 90 // require at least one number 91 function(password) { 92 if (!/[0-9]/.test(password)) { 93 return 'The password must contain at least one number.'; 94 } 95 }, 96 97 // require at least one special character 98 function(password) { 99 if (!/[^A-Za-z0-9]/.test(password)) { 100 return 'The password must contain at least one special character.'; 101 } 102 } 103 104 ] 105 }; 106 107 // This method tests password strength 108 owasp.test = function(password) { 109 110 // create an object to store the test results 111 var result = { 112 errors : [], 113 failedTests : [], 114 passedTests : [], 115 requiredTestErrors : [], 116 optionalTestErrors : [], 117 isPassphrase : false, 118 strong : true, 119 optionalTestsPassed : 0 120 }; 121 122 // Always submit the password/passphrase to the required tests 123 var i = 0; 124 this.tests.required.forEach(function(test) { 125 var err = test(password); 126 if (typeof err === 'string') { 127 result.strong = false; 128 result.errors.push(err); 129 result.requiredTestErrors.push(err); 130 result.failedTests.push(i); 131 } else { 132 result.passedTests.push(i); 133 } 134 i++; 135 }); 136 137 // If configured to allow passphrases, and if the password is of a 138 // sufficient length to consider it a passphrase, exempt it from the 139 // optional tests. 140 if ( 141 this.configs.allowPassphrases === true && 142 password.length >= this.configs.minPhraseLength 143 ) { 144 result.isPassphrase = true; 145 } 146 147 if (!result.isPassphrase) { 148 var j = this.tests.required.length; 149 this.tests.optional.forEach(function(test) { 150 var err = test(password); 151 if (typeof err === 'string') { 152 result.errors.push(err); 153 result.optionalTestErrors.push(err); 154 result.failedTests.push(j); 155 } else { 156 result.optionalTestsPassed++; 157 result.passedTests.push(j); 158 } 159 j++; 160 }); 161 } 162 163 // If the password is not a passphrase, assert that it has passed a 164 // sufficient number of the optional tests, per the configuration 165 if ( 166 !result.isPassphrase && 167 result.optionalTestsPassed < this.configs.minOptionalTestsToPass 168 ) { 169 result.strong = false; 170 } 171 172 // return the result 173 return result; 174 }; 175 176 return owasp; 177 } 178));
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.