UNPKG

xotp

Version:

One-Time Password (HOTP/TOTP) library for Node.js, Deno and Bun, with support for Google Authenticator.

58 lines (57 loc) 2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.base32Decode = exports.base32Encode = void 0; const formats = { RFC4648: { alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567", padding: "=", }, RFC3548: { alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567", padding: "=" }, RFC4648_HEX: { alphabet: "0123456789ABCDEFGHIJKLMNOPQRSTUV", padding: "=" }, CROCKFORD: { alphabet: "0123456789ABCDEFGHJKMNPQRSTVWXYZ", padding: "" }, }; const base32Encode = (arr, format = "RFC4648") => { const { padding, alphabet } = formats[format]; let bytes = 0b0; let left = 0; let base32 = ""; for (let i = 0; i < arr.byteLength; i++) { bytes = (bytes << 8) | arr[i]; left += 8; for (let j = 1; j <= left / 5; j++) { const charAt = (bytes >>> (left - j * 5)) & 0x1f; base32 += alphabet[charAt]; } left = left % 5; } if (left) base32 += alphabet[(bytes << (5 - left)) & 0x1f]; if (base32.length % 8 != 0) base32 += padding.repeat(8 - (base32.length % 8)); return base32; }; exports.base32Encode = base32Encode; const base32Decode = (base32Encoded, format = "RFC4648") => { const { padding, alphabet } = formats[format]; const removedPad = base32Encoded .replace(new RegExp(`${padding}+$`), "") .toUpperCase(); const bytesLen = ((removedPad.length * 5) / 8) | 0; const bytes = new Uint8Array(bytesLen); let binary = 0; let left = 0; let index = 0; for (let i = 0; i < removedPad.length; i++) { const charNum = alphabet.search(removedPad[i]); if (charNum === -1) throw new TypeError(`Invalid base32 character: ${removedPad[i]}`); binary = (binary << 5) | charNum; left += 5; if (left >= 8) { bytes[index++] = (binary >>> (left - 8)) & 0xff; left -= 8; } } return bytes; }; exports.base32Decode = base32Decode;