-
-
Save flourigh/1b1629354e1e77266dc3b68efe3d55c7 to your computer and use it in GitHub Desktop.
Generates an authenticator token based on a secret key. (Usually given in the QR code that apps have you scan)
This file contains hidden or 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
async function getToken(key, options) { | |
let { default: JsSHA } = await import( | |
"https://cdn.skypack.dev/pin/[email protected]/mode=imports,min/optimized/jssha.js" | |
); | |
options = { | |
period: 30, | |
algorithm: "SHA-1", | |
digits: 6, | |
timestamp: Date.now(), | |
...options, | |
}; | |
key = base32tohex(key); | |
let epoch = Math.round(options.timestamp / 1000.0); | |
let time = leftpad(dec2hex(Math.floor(epoch / options.period)), 16, "0"); | |
let shaObj = new JsSHA(options.algorithm, "HEX"); | |
shaObj.setHMACKey(key, "HEX"); | |
shaObj.update(time); | |
let hmac = shaObj.getHMAC("HEX"); | |
let offset = hex2dec(hmac.substring(hmac.length - 1)); | |
let otp = (hex2dec(hmac.substr(offset * 2, 8)) & hex2dec("7fffffff")) + ""; | |
otp = otp.substr(Math.max(otp.length - options.digits, 0), options.digits); | |
return otp; | |
function hex2dec(s) { | |
return parseInt(s, 16); | |
} | |
function dec2hex(s) { | |
return (s < 15.5 ? "0" : "") + Math.round(s).toString(16); | |
} | |
function base32tohex(base32) { | |
let base32chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567", | |
bits = "", | |
hex = ""; | |
base32 = base32.replace(/=+$/, ""); | |
for (let i = 0; i < base32.length; i++) { | |
let val = base32chars.indexOf(base32.charAt(i).toUpperCase()); | |
if (val === -1) throw new Error("Invalid base32 character in key"); | |
bits += leftpad(val.toString(2), 5, "0"); | |
} | |
for (let i = 0; i + 8 <= bits.length; i += 8) { | |
let chunk = bits.substr(i, 8); | |
hex = hex + leftpad(parseInt(chunk, 2).toString(16), 2, "0"); | |
} | |
return hex; | |
} | |
function leftpad(str, len, pad) { | |
if (len + 1 >= str.length) { | |
str = Array(len + 1 - str.length).join(pad) + str; | |
} | |
return str; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment