Last active
July 12, 2018 01:28
-
-
Save kevincennis/f1ac7166a4b16d90c0501cb69760c4a7 to your computer and use it in GitHub Desktop.
haveibeenpwned password check
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// convert an unsigned int to hex string | |
const toHex = b => ( '00' + b.toString( 16 ) ).slice( -2 ); | |
// return the SHA-1 hash of a given string | |
// note: crypto.subtle is unavailable on non-HTTPS pages | |
const sha1 = async str => { | |
const msg = new TextEncoder('utf-8').encode( str ); | |
const buf = await crypto.subtle.digest( 'SHA-1', msg ); | |
return [ ...new Uint8Array( buf ) ].map( toHex ).join(''); | |
}; | |
// get a Map of hibp hash suffixes (suffix => count) | |
const getMatches = async prefix => { | |
const url = `https://api.pwnedpasswords.com/range/${ prefix }`; | |
const res = await fetch( url ); | |
const txt = await res.text(); | |
return txt.split('\n').reduce( ( map, line ) => { | |
const [ suffix, count ] = line.split(':'); | |
return map.set( suffix.toLowerCase(), Number( count ) ); | |
}, new Map ); | |
}; | |
// check how many matches hibp has for a password | |
// (0 is good, everything else is obviously not) | |
const checkPassword = async password => { | |
const hash = await sha1( password ); | |
const prefix = hash.substr( 0, 5 ); | |
const suffix = hash.substr( 5 ); | |
const matches = await getMatches( prefix ); | |
return matches.get( suffix ) || 0; | |
}; | |
// usage | |
checkPassword('badpassword').then( console.log.bind( console ) ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment