UNPKG

otp-io

Version:

🕖 Typed library to work 2fa via Google Authenticator/Time-based TOTP/Hmac-based HOTP

49 lines • 1.65 kB
import {HmacAlgorithm}from'./crypto/hmac.mjs';import {hotp}from'./hotp.mjs';import {SecretKey}from'./key.mjs';import {getDefaultTOTPOptions}from'./totp.options.mjs';const keyLengths = new Map([ [HmacAlgorithm.SHA1, 20], [HmacAlgorithm.SHA256, 32], [HmacAlgorithm.SHA512, 64] ]); /** * * * @param {Uint8Array} buffer * @param {number} length * @return {Uint8Array} */ function pad(buffer, length) { const factor = Math.ceil(length / buffer.length); const double = new Uint8Array(buffer.length * factor); for (let index = 0; index < factor; index++) { double.set(buffer, buffer.length * index); } return double.slice(0, length); } /** * Generates TOTP code from secret key and options * * @export * @param {Hmac} hmac * @param {TOTPOptions} options * @return {Promise<string>} * @throws {Error} if HMAC algorithm is invalid. Use {@link HmacAlgorithm} to avoid this */ async function totp(hmac, options) { const merged = Object.assign(Object.assign({}, getDefaultTOTPOptions()), options); const counter = Math.floor(merged.now.getTime() / 1000 / merged.stepSeconds); let bytes = new Uint8Array(options.secret.bytes); if (merged.pad) { const length = keyLengths.get(merged.algorithm); if (length === undefined) { throw new Error(`Invalid hmac algorithm: "${merged.algorithm}"`); } if (bytes.length < length) { bytes = pad(bytes, length); } } return await hotp(hmac, { secret: new SecretKey(bytes), algorithm: merged.algorithm, digits: merged.digits, counter }); }export{totp};