Skip to content

Instantly share code, notes, and snippets.

@justenwalker
Last active August 29, 2015 14:05
Show Gist options
  • Save justenwalker/f2c1d8f10a7538b4d671 to your computer and use it in GitHub Desktop.
Save justenwalker/f2c1d8f10a7538b4d671 to your computer and use it in GitHub Desktop.
Password Checker
###*
* @namespace PasswordChecker
*
* Utility class to check a password's complexity
*
*
* {@link PasswordChecker.strength} returns an object containing:
*
* - *summary* The results of {@link PasswordChecker.summary}
* - *total* The total raw score for the password
* - *strength* The strength of the password scaled to the min/max values of score.
* It is a value between 0 and 100, so it can be used as the 'strength' on a meter
*
* {@link PasswordChecker.summary} returns an object containing:
*
* - *length* The length of the password
* - *characters* The number of unique characters in the password
* - *transitions* The number of transitions between character types
* - *types* The number of different character types
###
class PasswordChecker
###*
* Gets the character's type
* @param {string} char Single character to test
* @return {Number} Type of character. 1 = Upper Case, 2 = Lower Case, 3 = Numbers, 4 = ASCII Symbols, 5 = Other
###
@charType: (char) ->
code = char.charCodeAt(0)
switch
## Upper Case
when code >= 65 && code <= 90 then 1
## Lower Case
when code >= 97 && code <= 122 then 2
## Numbers
when code >= 48 && code <= 57 then 3
## ASCII Symbols
when code < 128 then 4
## Everything Else
else 5
###*
* Get a summary of the password's characteristics
* @param {String} password Password to check
* @return {Object} contains length, characters, transitions, and types
* @static
###
@summary: (password) ->
count = password.length
transitions = 0
uniques = 0
types = 0
# State
lastType = 0
uniqueChars = ""
uniqueTypes = []
for i in [0..count-1]
c = password.charAt(i)
thisType = @charType(c)
if thisType not in uniqueTypes
types++
uniqueTypes.push thisType
if thisType != lastType
transitions++
lastType = thisType
if uniqueChars.indexOf(c) < 0
uniques++
uniqueChars += c
# First transition doesn't count
{length: count, characters: uniques, transitions: transitions - 1, types: types}
###*
* Measure the strength of the password
* @param {String} password Password to check
* @param {Number} min Minimum score (This score and below has strength of 0)
* @param {Number} max Maximum score (This score and above has strength of 100)
* @returns {Object} contains summary, strength, and raw total score
* @static
###
@strength: (password, min, max) ->
summary = @summary(password)
{length, characters, transitions, types} = summary
total = length + characters + (2 * transitions) + ( 2 * types )
summary['length_pct'] = 1.0 * length / total
summary['characters_pct'] = 1.0 * characters / total
summary['transitions_pct'] = 2.0 * transitions / total
summary['types_pct'] = 2.0 * types / total
strength = Math.round(Math.min( Math.max(total - min,0) / (max - min) , 1.0 ) * 100.0)
{ summary: summary , strength: strength, total: total }
@justenwalker
Copy link
Author

A good MIN appears to be 20 points. Anything below this is probably useless as a password.
70 or 80 appears to be a decent MAX value.

Here are a few test vectors for some passwords of varying strength: https://jsfiddle.net/uh9duyhn/1/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment