Skip to content

Instantly share code, notes, and snippets.

@kevincennis
Last active July 12, 2018 01:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kevincennis/f1ac7166a4b16d90c0501cb69760c4a7 to your computer and use it in GitHub Desktop.
Save kevincennis/f1ac7166a4b16d90c0501cb69760c4a7 to your computer and use it in GitHub Desktop.
haveibeenpwned password check
// 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