wip:milestone 0 fixes
Some checks failed
CI/CD Pipeline / unit-tests (push) Failing after 1m16s
CI/CD Pipeline / integration-tests (push) Failing after 2m32s
CI/CD Pipeline / lint (push) Successful in 5m22s
CI/CD Pipeline / e2e-tests (push) Has been skipped
CI/CD Pipeline / build (push) Has been skipped

This commit is contained in:
2026-03-15 12:35:42 +02:00
parent 6708cf28a7
commit cffdf8af86
61266 changed files with 4511646 additions and 1938 deletions

View File

@@ -0,0 +1,884 @@
//! otpauth 9.5.0 | (c) Héctor Molinero Fernández | MIT | https://github.com/hectorm/otpauth
/// <reference types="./otpauth.d.ts" />
// @ts-nocheck
/**
* Converts an integer to an Uint8Array.
* @param {number} num Integer.
* @returns {Uint8Array} Uint8Array.
*/ const uintDecode = (num)=>{
const buf = new ArrayBuffer(8);
const arr = new Uint8Array(buf);
let acc = num;
for(let i = 7; i >= 0; i--){
if (acc === 0) break;
arr[i] = acc & 255;
acc -= arr[i];
acc /= 256;
}
return arr;
};
/**
* "globalThis" ponyfill.
* @see [A horrifying globalThis polyfill in universal JavaScript](https://mathiasbynens.be/notes/globalthis)
* @type {Object.<string, *>}
*/ const globalScope = (()=>{
if (typeof globalThis === "object") return globalThis;
else {
Object.defineProperty(Object.prototype, "__GLOBALTHIS__", {
get () {
return this;
},
configurable: true
});
try {
// @ts-expect-error
// eslint-disable-next-line no-undef
if (typeof __GLOBALTHIS__ !== "undefined") return __GLOBALTHIS__;
} finally{
// @ts-expect-error
delete Object.prototype.__GLOBALTHIS__;
}
}
// Still unable to determine "globalThis", fall back to a naive method.
if (typeof self !== "undefined") return self;
else if (typeof window !== "undefined") return window;
else if (typeof global !== "undefined") return global;
return undefined;
})();
/**
* Canonicalizes a hash algorithm name.
* @param {string} algorithm Hash algorithm name.
* @returns {"SHA1"|"SHA224"|"SHA256"|"SHA384"|"SHA512"|"SHA3-224"|"SHA3-256"|"SHA3-384"|"SHA3-512"} Canonicalized hash algorithm name.
*/ const canonicalizeAlgorithm = (algorithm)=>{
switch(true){
case /^(?:SHA-?1|SSL3-SHA1)$/i.test(algorithm):
return "SHA1";
case /^SHA(?:2?-)?224$/i.test(algorithm):
return "SHA224";
case /^SHA(?:2?-)?256$/i.test(algorithm):
return "SHA256";
case /^SHA(?:2?-)?384$/i.test(algorithm):
return "SHA384";
case /^SHA(?:2?-)?512$/i.test(algorithm):
return "SHA512";
case /^SHA3-224$/i.test(algorithm):
return "SHA3-224";
case /^SHA3-256$/i.test(algorithm):
return "SHA3-256";
case /^SHA3-384$/i.test(algorithm):
return "SHA3-384";
case /^SHA3-512$/i.test(algorithm):
return "SHA3-512";
default:
throw new TypeError(`Unknown hash algorithm: ${algorithm}`);
}
};
/**
* Calculates an HMAC digest.
* @param {string} algorithm Algorithm.
* @param {Uint8Array} key Key.
* @param {Uint8Array} message Message.
* @returns {Uint8Array} Digest.
*/ const hmacDigest = (algorithm, key, message)=>{
{
throw new Error("Missing HMAC function");
}
};
/**
* RFC 4648 base32 alphabet without pad.
* @type {string}
*/ const ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
/**
* Converts a base32 string to an Uint8Array (RFC 4648).
* @see [LinusU/base32-decode](https://github.com/LinusU/base32-decode)
* @param {string} str Base32 string.
* @returns {Uint8Array} Uint8Array.
*/ const base32Decode = (str)=>{
// Remove spaces (although they are not allowed by the spec, some issuers add them for readability).
str = str.replace(/ /g, "");
// Canonicalize to all upper case and remove padding if it exists.
let end = str.length;
while(str[end - 1] === "=")--end;
str = (end < str.length ? str.substring(0, end) : str).toUpperCase();
const buf = new ArrayBuffer(str.length * 5 / 8 | 0);
const arr = new Uint8Array(buf);
let bits = 0;
let value = 0;
let index = 0;
for(let i = 0; i < str.length; i++){
const idx = ALPHABET.indexOf(str[i]);
if (idx === -1) throw new TypeError(`Invalid character found: ${str[i]}`);
value = value << 5 | idx;
bits += 5;
if (bits >= 8) {
bits -= 8;
arr[index++] = value >>> bits;
}
}
return arr;
};
/**
* Converts an Uint8Array to a base32 string (RFC 4648).
* @see [LinusU/base32-encode](https://github.com/LinusU/base32-encode)
* @param {Uint8Array} arr Uint8Array.
* @returns {string} Base32 string.
*/ const base32Encode = (arr)=>{
let bits = 0;
let value = 0;
let str = "";
for(let i = 0; i < arr.length; i++){
value = value << 8 | arr[i];
bits += 8;
while(bits >= 5){
str += ALPHABET[value >>> bits - 5 & 31];
bits -= 5;
}
}
if (bits > 0) {
str += ALPHABET[value << 5 - bits & 31];
}
return str;
};
/**
* Converts a hexadecimal string to an Uint8Array.
* @param {string} str Hexadecimal string.
* @returns {Uint8Array} Uint8Array.
*/ const hexDecode = (str)=>{
// Remove spaces (although they are not allowed by the spec, some issuers add them for readability).
str = str.replace(/ /g, "");
const buf = new ArrayBuffer(str.length / 2);
const arr = new Uint8Array(buf);
for(let i = 0; i < str.length; i += 2){
arr[i / 2] = parseInt(str.substring(i, i + 2), 16);
}
return arr;
};
/**
* Converts an Uint8Array to a hexadecimal string.
* @param {Uint8Array} arr Uint8Array.
* @returns {string} Hexadecimal string.
*/ const hexEncode = (arr)=>{
let str = "";
for(let i = 0; i < arr.length; i++){
const hex = arr[i].toString(16);
if (hex.length === 1) str += "0";
str += hex;
}
return str.toUpperCase();
};
/**
* Converts a Latin-1 string to an Uint8Array.
* @param {string} str Latin-1 string.
* @returns {Uint8Array} Uint8Array.
*/ const latin1Decode = (str)=>{
const buf = new ArrayBuffer(str.length);
const arr = new Uint8Array(buf);
for(let i = 0; i < str.length; i++){
arr[i] = str.charCodeAt(i) & 0xff;
}
return arr;
};
/**
* Converts an Uint8Array to a Latin-1 string.
* @param {Uint8Array} arr Uint8Array.
* @returns {string} Latin-1 string.
*/ const latin1Encode = (arr)=>{
let str = "";
for(let i = 0; i < arr.length; i++){
str += String.fromCharCode(arr[i]);
}
return str;
};
/**
* TextEncoder instance.
* @type {TextEncoder|null}
*/ const ENCODER = globalScope.TextEncoder ? new globalScope.TextEncoder() : null;
/**
* TextDecoder instance.
* @type {TextDecoder|null}
*/ const DECODER = globalScope.TextDecoder ? new globalScope.TextDecoder() : null;
/**
* Converts an UTF-8 string to an Uint8Array.
* @param {string} str String.
* @returns {Uint8Array} Uint8Array.
*/ const utf8Decode = (str)=>{
if (!ENCODER) {
throw new Error("Encoding API not available");
}
return ENCODER.encode(str);
};
/**
* Converts an Uint8Array to an UTF-8 string.
* @param {Uint8Array} arr Uint8Array.
* @returns {string} String.
*/ const utf8Encode = (arr)=>{
if (!DECODER) {
throw new Error("Encoding API not available");
}
return DECODER.decode(arr);
};
/**
* Returns random bytes.
* @param {number} size Size.
* @returns {Uint8Array} Random bytes.
*/ const randomBytes = (size)=>{
if (globalScope.crypto?.getRandomValues) {
return globalScope.crypto.getRandomValues(new Uint8Array(size));
} else {
throw new Error("Cryptography API not available");
}
};
/**
* OTP secret key.
*/ class Secret {
/**
* Converts a Latin-1 string to a Secret object.
* @param {string} str Latin-1 string.
* @returns {Secret} Secret object.
*/ static fromLatin1(str) {
return new Secret({
buffer: latin1Decode(str).buffer
});
}
/**
* Converts an UTF-8 string to a Secret object.
* @param {string} str UTF-8 string.
* @returns {Secret} Secret object.
*/ static fromUTF8(str) {
return new Secret({
buffer: utf8Decode(str).buffer
});
}
/**
* Converts a base32 string to a Secret object.
* @param {string} str Base32 string.
* @returns {Secret} Secret object.
*/ static fromBase32(str) {
return new Secret({
buffer: base32Decode(str).buffer
});
}
/**
* Converts a hexadecimal string to a Secret object.
* @param {string} str Hexadecimal string.
* @returns {Secret} Secret object.
*/ static fromHex(str) {
return new Secret({
buffer: hexDecode(str).buffer
});
}
/**
* Secret key buffer.
* @deprecated For backward compatibility, the "bytes" property should be used instead.
* @type {ArrayBufferLike}
*/ get buffer() {
return this.bytes.buffer;
}
/**
* Latin-1 string representation of secret key.
* @type {string}
*/ get latin1() {
Object.defineProperty(this, "latin1", {
enumerable: true,
writable: false,
configurable: false,
value: latin1Encode(this.bytes)
});
return this.latin1;
}
/**
* UTF-8 string representation of secret key.
* @type {string}
*/ get utf8() {
Object.defineProperty(this, "utf8", {
enumerable: true,
writable: false,
configurable: false,
value: utf8Encode(this.bytes)
});
return this.utf8;
}
/**
* Base32 string representation of secret key.
* @type {string}
*/ get base32() {
Object.defineProperty(this, "base32", {
enumerable: true,
writable: false,
configurable: false,
value: base32Encode(this.bytes)
});
return this.base32;
}
/**
* Hexadecimal string representation of secret key.
* @type {string}
*/ get hex() {
Object.defineProperty(this, "hex", {
enumerable: true,
writable: false,
configurable: false,
value: hexEncode(this.bytes)
});
return this.hex;
}
/**
* Creates a secret key object.
* @param {Object} [config] Configuration options.
* @param {ArrayBufferLike} [config.buffer] Secret key buffer.
* @param {number} [config.size=20] Number of random bytes to generate, ignored if 'buffer' is provided.
*/ constructor({ buffer, size = 20 } = {}){
/**
* Secret key.
* @type {Uint8Array}
* @readonly
*/ this.bytes = typeof buffer === "undefined" ? randomBytes(size) : new Uint8Array(buffer);
// Prevent the "bytes" property from being modified.
Object.defineProperty(this, "bytes", {
enumerable: true,
writable: false,
configurable: false,
value: this.bytes
});
}
}
/**
* Returns true if a is equal to b, without leaking timing information that would allow an attacker to guess one of the values.
* @param {string} a String a.
* @param {string} b String b.
* @returns {boolean} Equality result.
*/ const timingSafeEqual = (a, b)=>{
{
if (a.length !== b.length) {
throw new TypeError("Input strings must have the same length");
}
let i = -1;
let out = 0;
while(++i < a.length){
out |= a.charCodeAt(i) ^ b.charCodeAt(i);
}
return out === 0;
}
};
/**
* HOTP: An HMAC-based One-time Password Algorithm.
* @see [RFC 4226](https://datatracker.ietf.org/doc/html/rfc4226)
*/ class HOTP {
/**
* Default configuration.
* @type {{
* issuer: string,
* label: string,
* issuerInLabel: boolean,
* algorithm: string,
* digits: number,
* counter: number
* window: number
* }}
*/ static get defaults() {
return {
issuer: "",
label: "OTPAuth",
issuerInLabel: true,
algorithm: "SHA1",
digits: 6,
counter: 0,
window: 1
};
}
/**
* Generates an HOTP token.
* @param {Object} config Configuration options.
* @param {Secret} config.secret Secret key.
* @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
* @param {number} [config.digits=6] Token length.
* @param {number} [config.counter=0] Counter value.
* @param {(algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array} [config.hmac] Custom HMAC function.
* @returns {string} Token.
*/ static generate({ secret, algorithm = HOTP.defaults.algorithm, digits = HOTP.defaults.digits, counter = HOTP.defaults.counter, hmac = hmacDigest }) {
const message = uintDecode(counter);
const digest = hmac(algorithm, secret.bytes, message);
if (!digest?.byteLength || digest.byteLength < 19) {
throw new TypeError("Return value must be at least 19 bytes");
}
const offset = digest[digest.byteLength - 1] & 15;
const otp = ((digest[offset] & 127) << 24 | (digest[offset + 1] & 255) << 16 | (digest[offset + 2] & 255) << 8 | digest[offset + 3] & 255) % 10 ** digits;
return otp.toString().padStart(digits, "0");
}
/**
* Generates an HOTP token.
* @param {Object} [config] Configuration options.
* @param {number} [config.counter=this.counter++] Counter value.
* @returns {string} Token.
*/ generate({ counter = this.counter++ } = {}) {
return HOTP.generate({
secret: this.secret,
algorithm: this.algorithm,
digits: this.digits,
counter,
hmac: this.hmac
});
}
/**
* Validates an HOTP token.
* @param {Object} config Configuration options.
* @param {string} config.token Token value.
* @param {Secret} config.secret Secret key.
* @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
* @param {number} [config.digits=6] Token length.
* @param {number} [config.counter=0] Counter value.
* @param {number} [config.window=1] Window of counter values to test.
* @param {(algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array} [config.hmac] Custom HMAC function.
* @returns {number|null} Token delta or null if it is not found in the search window, in which case it should be considered invalid.
*/ static validate({ token, secret, algorithm, digits = HOTP.defaults.digits, counter = HOTP.defaults.counter, window = HOTP.defaults.window, hmac = hmacDigest }) {
// Return early if the token length does not match the digit number.
if (token.length !== digits) return null;
let delta = null;
const check = (/** @type {number} */ i)=>{
const generatedToken = HOTP.generate({
secret,
algorithm,
digits,
counter: i,
hmac
});
if (timingSafeEqual(token, generatedToken)) {
delta = i - counter;
}
};
check(counter);
for(let i = 1; i <= window && delta === null; ++i){
check(counter - i);
if (delta !== null) break;
check(counter + i);
if (delta !== null) break;
}
return delta;
}
/**
* Validates an HOTP token.
* @param {Object} config Configuration options.
* @param {string} config.token Token value.
* @param {number} [config.counter=this.counter] Counter value.
* @param {number} [config.window=1] Window of counter values to test.
* @returns {number|null} Token delta or null if it is not found in the search window, in which case it should be considered invalid.
*/ validate({ token, counter = this.counter, window }) {
return HOTP.validate({
token,
secret: this.secret,
algorithm: this.algorithm,
digits: this.digits,
counter,
window,
hmac: this.hmac
});
}
/**
* Returns a Google Authenticator key URI.
* @returns {string} URI.
*/ toString() {
const e = encodeURIComponent;
return "otpauth://hotp/" + `${this.issuer.length > 0 ? this.issuerInLabel ? `${e(this.issuer)}:${e(this.label)}?issuer=${e(this.issuer)}&` : `${e(this.label)}?issuer=${e(this.issuer)}&` : `${e(this.label)}?`}` + `secret=${e(this.secret.base32)}&` + `algorithm=${e(this.algorithm)}&` + `digits=${e(this.digits)}&` + `counter=${e(this.counter)}`;
}
/**
* Creates an HOTP object.
* @param {Object} [config] Configuration options.
* @param {string} [config.issuer=''] Account provider.
* @param {string} [config.label='OTPAuth'] Account label.
* @param {boolean} [config.issuerInLabel=true] Include issuer prefix in label.
* @param {Secret|string} [config.secret=Secret] Secret key.
* @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
* @param {number} [config.digits=6] Token length.
* @param {number} [config.counter=0] Initial counter value.
* @param {(algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array} [config.hmac] Custom HMAC function.
*/ constructor({ issuer = HOTP.defaults.issuer, label = HOTP.defaults.label, issuerInLabel = HOTP.defaults.issuerInLabel, secret = new Secret(), algorithm = HOTP.defaults.algorithm, digits = HOTP.defaults.digits, counter = HOTP.defaults.counter, hmac } = {}){
/**
* Account provider.
* @type {string}
*/ this.issuer = issuer;
/**
* Account label.
* @type {string}
*/ this.label = label;
/**
* Include issuer prefix in label.
* @type {boolean}
*/ this.issuerInLabel = issuerInLabel;
/**
* Secret key.
* @type {Secret}
*/ this.secret = typeof secret === "string" ? Secret.fromBase32(secret) : secret;
/**
* HMAC hashing algorithm.
* @type {string}
*/ this.algorithm = hmac ? algorithm : canonicalizeAlgorithm(algorithm);
/**
* Token length.
* @type {number}
*/ this.digits = digits;
/**
* Initial counter value.
* @type {number}
*/ this.counter = counter;
/**
* Custom HMAC function.
* @type {((algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array)|undefined}
*/ this.hmac = hmac;
}
}
/**
* TOTP: Time-Based One-Time Password Algorithm.
* @see [RFC 6238](https://datatracker.ietf.org/doc/html/rfc6238)
*/ class TOTP {
/**
* Default configuration.
* @type {{
* issuer: string,
* label: string,
* issuerInLabel: boolean,
* algorithm: string,
* digits: number,
* period: number
* window: number
* }}
*/ static get defaults() {
return {
issuer: "",
label: "OTPAuth",
issuerInLabel: true,
algorithm: "SHA1",
digits: 6,
period: 30,
window: 1
};
}
/**
* Calculates the counter. i.e. the number of periods since timestamp 0.
* @param {Object} [config] Configuration options.
* @param {number} [config.period=30] Token time-step duration.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @returns {number} Counter.
*/ static counter({ period = TOTP.defaults.period, timestamp = Date.now() } = {}) {
return Math.floor(timestamp / 1000 / period);
}
/**
* Calculates the counter. i.e. the number of periods since timestamp 0.
* @param {Object} [config] Configuration options.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @returns {number} Counter.
*/ counter({ timestamp = Date.now() } = {}) {
return TOTP.counter({
period: this.period,
timestamp
});
}
/**
* Calculates the remaining time in milliseconds until the next token is generated.
* @param {Object} [config] Configuration options.
* @param {number} [config.period=30] Token time-step duration.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @returns {number} counter.
*/ static remaining({ period = TOTP.defaults.period, timestamp = Date.now() } = {}) {
return period * 1000 - timestamp % (period * 1000);
}
/**
* Calculates the remaining time in milliseconds until the next token is generated.
* @param {Object} [config] Configuration options.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @returns {number} counter.
*/ remaining({ timestamp = Date.now() } = {}) {
return TOTP.remaining({
period: this.period,
timestamp
});
}
/**
* Generates a TOTP token.
* @param {Object} config Configuration options.
* @param {Secret} config.secret Secret key.
* @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
* @param {number} [config.digits=6] Token length.
* @param {number} [config.period=30] Token time-step duration.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @param {(algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array} [config.hmac] Custom HMAC function.
* @returns {string} Token.
*/ static generate({ secret, algorithm, digits, period = TOTP.defaults.period, timestamp = Date.now(), hmac }) {
return HOTP.generate({
secret,
algorithm,
digits,
counter: TOTP.counter({
period,
timestamp
}),
hmac
});
}
/**
* Generates a TOTP token.
* @param {Object} [config] Configuration options.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @returns {string} Token.
*/ generate({ timestamp = Date.now() } = {}) {
return TOTP.generate({
secret: this.secret,
algorithm: this.algorithm,
digits: this.digits,
period: this.period,
timestamp,
hmac: this.hmac
});
}
/**
* Validates a TOTP token.
* @param {Object} config Configuration options.
* @param {string} config.token Token value.
* @param {Secret} config.secret Secret key.
* @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
* @param {number} [config.digits=6] Token length.
* @param {number} [config.period=30] Token time-step duration.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @param {number} [config.window=1] Window of counter values to test.
* @param {(algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array} [config.hmac] Custom HMAC function.
* @returns {number|null} Token delta or null if it is not found in the search window, in which case it should be considered invalid.
*/ static validate({ token, secret, algorithm, digits, period = TOTP.defaults.period, timestamp = Date.now(), window, hmac }) {
return HOTP.validate({
token,
secret,
algorithm,
digits,
counter: TOTP.counter({
period,
timestamp
}),
window,
hmac
});
}
/**
* Validates a TOTP token.
* @param {Object} config Configuration options.
* @param {string} config.token Token value.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @param {number} [config.window=1] Window of counter values to test.
* @returns {number|null} Token delta or null if it is not found in the search window, in which case it should be considered invalid.
*/ validate({ token, timestamp, window }) {
return TOTP.validate({
token,
secret: this.secret,
algorithm: this.algorithm,
digits: this.digits,
period: this.period,
timestamp,
window,
hmac: this.hmac
});
}
/**
* Returns a Google Authenticator key URI.
* @returns {string} URI.
*/ toString() {
const e = encodeURIComponent;
return "otpauth://totp/" + `${this.issuer.length > 0 ? this.issuerInLabel ? `${e(this.issuer)}:${e(this.label)}?issuer=${e(this.issuer)}&` : `${e(this.label)}?issuer=${e(this.issuer)}&` : `${e(this.label)}?`}` + `secret=${e(this.secret.base32)}&` + `algorithm=${e(this.algorithm)}&` + `digits=${e(this.digits)}&` + `period=${e(this.period)}`;
}
/**
* Creates a TOTP object.
* @param {Object} [config] Configuration options.
* @param {string} [config.issuer=''] Account provider.
* @param {string} [config.label='OTPAuth'] Account label.
* @param {boolean} [config.issuerInLabel=true] Include issuer prefix in label.
* @param {Secret|string} [config.secret=Secret] Secret key.
* @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
* @param {number} [config.digits=6] Token length.
* @param {number} [config.period=30] Token time-step duration.
* @param {(algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array} [config.hmac] Custom HMAC function.
*/ constructor({ issuer = TOTP.defaults.issuer, label = TOTP.defaults.label, issuerInLabel = TOTP.defaults.issuerInLabel, secret = new Secret(), algorithm = TOTP.defaults.algorithm, digits = TOTP.defaults.digits, period = TOTP.defaults.period, hmac } = {}){
/**
* Account provider.
* @type {string}
*/ this.issuer = issuer;
/**
* Account label.
* @type {string}
*/ this.label = label;
/**
* Include issuer prefix in label.
* @type {boolean}
*/ this.issuerInLabel = issuerInLabel;
/**
* Secret key.
* @type {Secret}
*/ this.secret = typeof secret === "string" ? Secret.fromBase32(secret) : secret;
/**
* HMAC hashing algorithm.
* @type {string}
*/ this.algorithm = hmac ? algorithm : canonicalizeAlgorithm(algorithm);
/**
* Token length.
* @type {number}
*/ this.digits = digits;
/**
* Token time-step duration.
* @type {number}
*/ this.period = period;
/**
* Custom HMAC function.
* @type {((algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array)|undefined}
*/ this.hmac = hmac;
}
}
/**
* Key URI regex (otpauth://TYPE/[ISSUER:]LABEL?PARAMETERS).
* @type {RegExp}
*/ const OTPURI_REGEX = /^otpauth:\/\/([ht]otp)\/(.+)\?([A-Z0-9.~_-]+=[^?&]*(?:&[A-Z0-9.~_-]+=[^?&]*)*)$/i;
/**
* RFC 4648 base32 alphabet with pad.
* @type {RegExp}
*/ const SECRET_REGEX = /^[2-7A-Z]+=*$/i;
/**
* Regex for supported algorithms in built-in HMAC function.
* @type {RegExp}
*/ const ALGORITHM_REGEX = /^SHA(?:1|224|256|384|512|3-224|3-256|3-384|3-512)$/i;
/**
* Regex for custom algorithms in user-defined HMAC function.
* @type {RegExp}
*/ const ALGORITHM_CUSTOM_REGEX = /^[A-Z0-9]+(?:[_-][A-Z0-9]+)*$/i;
/**
* Integer regex.
* @type {RegExp}
*/ const INTEGER_REGEX = /^[+-]?\d+$/;
/**
* Positive integer regex.
* @type {RegExp}
*/ const POSITIVE_INTEGER_REGEX = /^\+?[1-9]\d*$/;
/**
* HOTP/TOTP object/string conversion.
* @see [Key URI Format](https://github.com/google/google-authenticator/wiki/Key-Uri-Format)
*/ class URI {
/**
* Parses a Google Authenticator key URI and returns an HOTP/TOTP object.
* @param {string} uri Google Authenticator Key URI.
* @param {Object} [config] Configuration options.
* @param {(algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array} [config.hmac] Custom HMAC function.
* @returns {HOTP|TOTP} HOTP/TOTP object.
*/ static parse(uri, { hmac } = {}) {
let uriGroups;
try {
uriGroups = uri.match(OTPURI_REGEX);
// eslint-disable-next-line no-unused-vars
} catch (_) {
/* Handled below */ }
if (!Array.isArray(uriGroups)) {
throw new URIError("Invalid URI format");
}
// Extract URI groups.
const uriType = uriGroups[1].toLowerCase();
const uriLabel = uriGroups[2].split(/(?::|%3A) *(.+)/i, 2).map(decodeURIComponent);
/** @type {Object.<string, string>} */ const uriParams = uriGroups[3].split("&").reduce((acc, cur)=>{
const pairArr = cur.split(/=(.*)/, 2).map(decodeURIComponent);
const pairKey = pairArr[0].toLowerCase();
const pairVal = pairArr[1];
/** @type {Object.<string, string>} */ const pairAcc = acc;
pairAcc[pairKey] = pairVal;
return pairAcc;
}, {});
// 'OTP' will be instantiated with 'config' argument.
let OTP;
const config = {};
if (uriType === "hotp") {
OTP = HOTP;
// Counter: required
if (typeof uriParams.counter !== "undefined" && INTEGER_REGEX.test(uriParams.counter)) {
config.counter = parseInt(uriParams.counter, 10);
} else {
throw new TypeError("Missing or invalid 'counter' parameter");
}
} else if (uriType === "totp") {
OTP = TOTP;
// Period: optional
if (typeof uriParams.period !== "undefined") {
if (POSITIVE_INTEGER_REGEX.test(uriParams.period)) {
config.period = parseInt(uriParams.period, 10);
} else {
throw new TypeError("Invalid 'period' parameter");
}
}
} else {
throw new TypeError("Unknown OTP type");
}
// Label: required
// Issuer: optional
if (typeof uriParams.issuer !== "undefined") {
config.issuer = uriParams.issuer;
}
if (uriLabel.length === 2) {
config.label = uriLabel[1];
if (typeof config.issuer === "undefined" || config.issuer === "") {
config.issuer = uriLabel[0];
} else if (uriLabel[0] === "") {
config.issuerInLabel = false;
}
} else {
config.label = uriLabel[0];
if (typeof config.issuer !== "undefined" && config.issuer !== "") {
config.issuerInLabel = false;
}
}
// Secret: required
if (typeof uriParams.secret !== "undefined" && SECRET_REGEX.test(uriParams.secret)) {
config.secret = uriParams.secret;
} else {
throw new TypeError("Missing or invalid 'secret' parameter");
}
// Algorithm: optional
if (typeof uriParams.algorithm !== "undefined") {
if ((hmac ? ALGORITHM_CUSTOM_REGEX : ALGORITHM_REGEX).test(uriParams.algorithm)) {
config.algorithm = uriParams.algorithm;
} else {
throw new TypeError("Invalid 'algorithm' parameter");
}
}
// Digits: optional
if (typeof uriParams.digits !== "undefined") {
if (POSITIVE_INTEGER_REGEX.test(uriParams.digits)) {
config.digits = parseInt(uriParams.digits, 10);
} else {
throw new TypeError("Invalid 'digits' parameter");
}
}
// HMAC: optional
if (typeof hmac !== "undefined") {
config.hmac = hmac;
}
return new OTP(config);
}
/**
* Converts an HOTP/TOTP object to a Google Authenticator key URI.
* @param {HOTP|TOTP} otp HOTP/TOTP object.
* @returns {string} Google Authenticator Key URI.
*/ static stringify(otp) {
if (otp instanceof HOTP || otp instanceof TOTP) {
return otp.toString();
}
throw new TypeError("Invalid 'HOTP/TOTP' object");
}
}
/**
* Library version.
* @type {string}
*/ const version = "9.5.0";
export { HOTP, Secret, TOTP, URI, version };

View File

@@ -0,0 +1,9 @@
//! otpauth 9.5.0 | (c) Héctor Molinero Fernández | MIT | https://github.com/hectorm/otpauth
/// <reference types="./otpauth.d.ts" />
// @ts-nocheck
const e=(()=>{if("object"==typeof globalThis)return globalThis;Object.defineProperty(Object.prototype,"__GLOBALTHIS__",{get(){return this},configurable:!0});try{if("undefined"!=typeof __GLOBALTHIS__)return __GLOBALTHIS__}finally{delete Object.prototype.__GLOBALTHIS__}return"undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:void 0})(),t=e=>{switch(!0){case/^(?:SHA-?1|SSL3-SHA1)$/i.test(e):return"SHA1";case/^SHA(?:2?-)?224$/i.test(e):return"SHA224";case/^SHA(?:2?-)?256$/i.test(e):return"SHA256";case/^SHA(?:2?-)?384$/i.test(e):return"SHA384";case/^SHA(?:2?-)?512$/i.test(e):return"SHA512";case/^SHA3-224$/i.test(e):return"SHA3-224";case/^SHA3-256$/i.test(e):return"SHA3-256";case/^SHA3-384$/i.test(e):return"SHA3-384";case/^SHA3-512$/i.test(e):return"SHA3-512";default:throw new TypeError(`Unknown hash algorithm: ${e}`)}},r=(e,t,r)=>{throw new Error("Missing HMAC function")},i="ABCDEFGHIJKLMNOPQRSTUVWXYZ234567",s=e=>{let t=(e=e.replace(/ /g,"")).length;for(;"="===e[t-1];)--t;e=(t<e.length?e.substring(0,t):e).toUpperCase();const r=new ArrayBuffer(5*e.length/8|0),s=new Uint8Array(r);let n=0,a=0,o=0;for(let t=0;t<e.length;t++){const r=i.indexOf(e[t]);if(-1===r)throw new TypeError(`Invalid character found: ${e[t]}`);a=a<<5|r,n+=5,n>=8&&(n-=8,s[o++]=a>>>n)}return s},n=e=>{let t=0,r=0,s="";for(let n=0;n<e.length;n++)for(r=r<<8|e[n],t+=8;t>=5;)s+=i[r>>>t-5&31],t-=5;return t>0&&(s+=i[r<<5-t&31]),s},a=e=>{e=e.replace(/ /g,"");const t=new ArrayBuffer(e.length/2),r=new Uint8Array(t);for(let t=0;t<e.length;t+=2)r[t/2]=parseInt(e.substring(t,t+2),16);return r},o=e=>{let t="";for(let r=0;r<e.length;r++){const i=e[r].toString(16);1===i.length&&(t+="0"),t+=i}return t.toUpperCase()},l=e=>{const t=new ArrayBuffer(e.length),r=new Uint8Array(t);for(let t=0;t<e.length;t++)r[t]=255&e.charCodeAt(t);return r},u=e=>{let t="";for(let r=0;r<e.length;r++)t+=String.fromCharCode(e[r]);return t},h=e.TextEncoder?new e.TextEncoder:null,c=e.TextDecoder?new e.TextDecoder:null,d=e=>{
if(!h)throw new Error("Encoding API not available");return h.encode(e)},g=e=>{if(!c)throw new Error("Encoding API not available");return c.decode(e)};class f{static fromLatin1(e){return new f({buffer:l(e).buffer})}static fromUTF8(e){return new f({buffer:d(e).buffer})}static fromBase32(e){return new f({buffer:s(e).buffer})}static fromHex(e){return new f({buffer:a(e).buffer})}get buffer(){return this.bytes.buffer}get latin1(){return Object.defineProperty(this,"latin1",{enumerable:!0,writable:!1,configurable:!1,value:u(this.bytes)}),this.latin1}get utf8(){return Object.defineProperty(this,"utf8",{enumerable:!0,writable:!1,configurable:!1,value:g(this.bytes)}),this.utf8}get base32(){return Object.defineProperty(this,"base32",{enumerable:!0,writable:!1,configurable:!1,value:n(this.bytes)}),this.base32}get hex(){return Object.defineProperty(this,"hex",{enumerable:!0,writable:!1,configurable:!1,value:o(this.bytes)}),this.hex}constructor({buffer:t,size:r=20}={}){this.bytes=void 0===t?(t=>{if(e.crypto?.getRandomValues)return e.crypto.getRandomValues(new Uint8Array(t));throw new Error("Cryptography API not available")})(r):new Uint8Array(t),Object.defineProperty(this,"bytes",{enumerable:!0,writable:!1,configurable:!1,value:this.bytes})}}class m{static get defaults(){return{issuer:"",label:"OTPAuth",issuerInLabel:!0,algorithm:"SHA1",digits:6,counter:0,window:1}}static generate({secret:e,algorithm:t=m.defaults.algorithm,digits:i=m.defaults.digits,counter:s=m.defaults.counter,hmac:n=r}){const a=(e=>{const t=new ArrayBuffer(8),r=new Uint8Array(t);let i=e;for(let e=7;e>=0&&0!==i;e--)r[e]=255&i,i-=r[e],i/=256;return r})(s),o=n(t,e.bytes,a);if(!o?.byteLength||o.byteLength<19)throw new TypeError("Return value must be at least 19 bytes");const l=15&o[o.byteLength-1];return(((127&o[l])<<24|(255&o[l+1])<<16|(255&o[l+2])<<8|255&o[l+3])%10**i).toString().padStart(i,"0")}generate({counter:e=this.counter++}={}){return m.generate({secret:this.secret,algorithm:this.algorithm,digits:this.digits,counter:e,hmac:this.hmac})}
static validate({token:e,secret:t,algorithm:i,digits:s=m.defaults.digits,counter:n=m.defaults.counter,window:a=m.defaults.window,hmac:o=r}){if(e.length!==s)return null;let l=null;const u=r=>{const a=m.generate({secret:t,algorithm:i,digits:s,counter:r,hmac:o});((e,t)=>{{if(e.length!==t.length)throw new TypeError("Input strings must have the same length");let r=-1,i=0;for(;++r<e.length;)i|=e.charCodeAt(r)^t.charCodeAt(r);return 0===i}})(e,a)&&(l=r-n)};u(n);for(let e=1;e<=a&&null===l&&(u(n-e),null===l)&&(u(n+e),null===l);++e);return l}validate({token:e,counter:t=this.counter,window:r}){return m.validate({token:e,secret:this.secret,algorithm:this.algorithm,digits:this.digits,counter:t,window:r,hmac:this.hmac})}toString(){const e=encodeURIComponent;return"otpauth://hotp/"+(this.issuer.length>0?this.issuerInLabel?`${e(this.issuer)}:${e(this.label)}?issuer=${e(this.issuer)}&`:`${e(this.label)}?issuer=${e(this.issuer)}&`:`${e(this.label)}?`)+`secret=${e(this.secret.base32)}&`+`algorithm=${e(this.algorithm)}&`+`digits=${e(this.digits)}&`+`counter=${e(this.counter)}`}constructor({issuer:e=m.defaults.issuer,label:r=m.defaults.label,issuerInLabel:i=m.defaults.issuerInLabel,secret:s=new f,algorithm:n=m.defaults.algorithm,digits:a=m.defaults.digits,counter:o=m.defaults.counter,hmac:l}={}){this.issuer=e,this.label=r,this.issuerInLabel=i,this.secret="string"==typeof s?f.fromBase32(s):s,this.algorithm=l?n:t(n),this.digits=a,this.counter=o,this.hmac=l}}class p{static get defaults(){return{issuer:"",label:"OTPAuth",issuerInLabel:!0,algorithm:"SHA1",digits:6,period:30,window:1}}static counter({period:e=p.defaults.period,timestamp:t=Date.now()}={}){return Math.floor(t/1e3/e)}counter({timestamp:e=Date.now()}={}){return p.counter({period:this.period,timestamp:e})}static remaining({period:e=p.defaults.period,timestamp:t=Date.now()}={}){return 1e3*e-t%(1e3*e)}remaining({timestamp:e=Date.now()}={}){return p.remaining({period:this.period,timestamp:e})}
static generate({secret:e,algorithm:t,digits:r,period:i=p.defaults.period,timestamp:s=Date.now(),hmac:n}){return m.generate({secret:e,algorithm:t,digits:r,counter:p.counter({period:i,timestamp:s}),hmac:n})}generate({timestamp:e=Date.now()}={}){return p.generate({secret:this.secret,algorithm:this.algorithm,digits:this.digits,period:this.period,timestamp:e,hmac:this.hmac})}static validate({token:e,secret:t,algorithm:r,digits:i,period:s=p.defaults.period,timestamp:n=Date.now(),window:a,hmac:o}){return m.validate({token:e,secret:t,algorithm:r,digits:i,counter:p.counter({period:s,timestamp:n}),window:a,hmac:o})}validate({token:e,timestamp:t,window:r}){return p.validate({token:e,secret:this.secret,algorithm:this.algorithm,digits:this.digits,period:this.period,timestamp:t,window:r,hmac:this.hmac})}toString(){const e=encodeURIComponent;return"otpauth://totp/"+(this.issuer.length>0?this.issuerInLabel?`${e(this.issuer)}:${e(this.label)}?issuer=${e(this.issuer)}&`:`${e(this.label)}?issuer=${e(this.issuer)}&`:`${e(this.label)}?`)+`secret=${e(this.secret.base32)}&`+`algorithm=${e(this.algorithm)}&`+`digits=${e(this.digits)}&`+`period=${e(this.period)}`}constructor({issuer:e=p.defaults.issuer,label:r=p.defaults.label,issuerInLabel:i=p.defaults.issuerInLabel,secret:s=new f,algorithm:n=p.defaults.algorithm,digits:a=p.defaults.digits,period:o=p.defaults.period,hmac:l}={}){this.issuer=e,this.label=r,this.issuerInLabel=i,this.secret="string"==typeof s?f.fromBase32(s):s,this.algorithm=l?n:t(n),this.digits=a,this.period=o,this.hmac=l}}const b=/^otpauth:\/\/([ht]otp)\/(.+)\?([A-Z0-9.~_-]+=[^?&]*(?:&[A-Z0-9.~_-]+=[^?&]*)*)$/i,w=/^[2-7A-Z]+=*$/i,y=/^SHA(?:1|224|256|384|512|3-224|3-256|3-384|3-512)$/i,A=/^[A-Z0-9]+(?:[_-][A-Z0-9]+)*$/i,I=/^[+-]?\d+$/,$=/^\+?[1-9]\d*$/;class v{static parse(e,{hmac:t}={}){let r;try{r=e.match(b)}catch(e){}if(!Array.isArray(r))throw new URIError("Invalid URI format");const i=r[1].toLowerCase(),s=r[2].split(/(?::|%3A) *(.+)/i,2).map(decodeURIComponent),n=r[3].split("&").reduce((e,t)=>{
const r=t.split(/=(.*)/,2).map(decodeURIComponent),i=r[0].toLowerCase(),s=r[1],n=e;return n[i]=s,n},{});let a;const o={};if("hotp"===i){if(a=m,void 0===n.counter||!I.test(n.counter))throw new TypeError("Missing or invalid 'counter' parameter");o.counter=parseInt(n.counter,10)}else{if("totp"!==i)throw new TypeError("Unknown OTP type");if(a=p,void 0!==n.period){if(!$.test(n.period))throw new TypeError("Invalid 'period' parameter");o.period=parseInt(n.period,10)}}if(void 0!==n.issuer&&(o.issuer=n.issuer),2===s.length?(o.label=s[1],void 0===o.issuer||""===o.issuer?o.issuer=s[0]:""===s[0]&&(o.issuerInLabel=!1)):(o.label=s[0],void 0!==o.issuer&&""!==o.issuer&&(o.issuerInLabel=!1)),void 0===n.secret||!w.test(n.secret))throw new TypeError("Missing or invalid 'secret' parameter");if(o.secret=n.secret,void 0!==n.algorithm){if(!(t?A:y).test(n.algorithm))throw new TypeError("Invalid 'algorithm' parameter");o.algorithm=n.algorithm}if(void 0!==n.digits){if(!$.test(n.digits))throw new TypeError("Invalid 'digits' parameter");o.digits=parseInt(n.digits,10)}return void 0!==t&&(o.hmac=t),new a(o)}static stringify(e){if(e instanceof m||e instanceof p)return e.toString();throw new TypeError("Invalid 'HOTP/TOTP' object")}}const S="9.5.0";export{m as HOTP,f as Secret,p as TOTP,v as URI,S as version};
//# sourceMappingURL=otpauth.bare.esm.min.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,456 @@
/**
* OTP secret key.
*/
declare class Secret {
/**
* Converts a Latin-1 string to a Secret object.
* @param {string} str Latin-1 string.
* @returns {Secret} Secret object.
*/
static fromLatin1(str: string): Secret;
/**
* Converts an UTF-8 string to a Secret object.
* @param {string} str UTF-8 string.
* @returns {Secret} Secret object.
*/
static fromUTF8(str: string): Secret;
/**
* Converts a base32 string to a Secret object.
* @param {string} str Base32 string.
* @returns {Secret} Secret object.
*/
static fromBase32(str: string): Secret;
/**
* Converts a hexadecimal string to a Secret object.
* @param {string} str Hexadecimal string.
* @returns {Secret} Secret object.
*/
static fromHex(str: string): Secret;
/**
* Creates a secret key object.
* @param {Object} [config] Configuration options.
* @param {ArrayBufferLike} [config.buffer] Secret key buffer.
* @param {number} [config.size=20] Number of random bytes to generate, ignored if 'buffer' is provided.
*/
constructor({ buffer, size }?: {
buffer?: ArrayBufferLike | undefined;
size?: number | undefined;
});
/**
* Secret key.
* @type {Uint8Array}
* @readonly
*/
readonly bytes: Uint8Array;
/**
* Secret key buffer.
* @deprecated For backward compatibility, the "bytes" property should be used instead.
* @type {ArrayBufferLike}
*/
get buffer(): ArrayBufferLike;
/**
* Latin-1 string representation of secret key.
* @type {string}
*/
get latin1(): string;
/**
* UTF-8 string representation of secret key.
* @type {string}
*/
get utf8(): string;
/**
* Base32 string representation of secret key.
* @type {string}
*/
get base32(): string;
/**
* Hexadecimal string representation of secret key.
* @type {string}
*/
get hex(): string;
}
/**
* HOTP: An HMAC-based One-time Password Algorithm.
* @see [RFC 4226](https://datatracker.ietf.org/doc/html/rfc4226)
*/
declare class HOTP {
/**
* Default configuration.
* @type {{
* issuer: string,
* label: string,
* issuerInLabel: boolean,
* algorithm: string,
* digits: number,
* counter: number
* window: number
* }}
*/
static get defaults(): {
issuer: string;
label: string;
issuerInLabel: boolean;
algorithm: string;
digits: number;
counter: number;
window: number;
};
/**
* Generates an HOTP token.
* @param {Object} config Configuration options.
* @param {Secret} config.secret Secret key.
* @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
* @param {number} [config.digits=6] Token length.
* @param {number} [config.counter=0] Counter value.
* @param {(algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array} [config.hmac] Custom HMAC function.
* @returns {string} Token.
*/
static generate({ secret, algorithm, digits, counter, hmac, }: {
secret: Secret;
algorithm?: string | undefined;
digits?: number | undefined;
counter?: number | undefined;
hmac?: ((algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array) | undefined;
}): string;
/**
* Validates an HOTP token.
* @param {Object} config Configuration options.
* @param {string} config.token Token value.
* @param {Secret} config.secret Secret key.
* @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
* @param {number} [config.digits=6] Token length.
* @param {number} [config.counter=0] Counter value.
* @param {number} [config.window=1] Window of counter values to test.
* @param {(algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array} [config.hmac] Custom HMAC function.
* @returns {number|null} Token delta or null if it is not found in the search window, in which case it should be considered invalid.
*/
static validate({ token, secret, algorithm, digits, counter, window, hmac, }: {
token: string;
secret: Secret;
algorithm?: string | undefined;
digits?: number | undefined;
counter?: number | undefined;
window?: number | undefined;
hmac?: ((algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array) | undefined;
}): number | null;
/**
* Creates an HOTP object.
* @param {Object} [config] Configuration options.
* @param {string} [config.issuer=''] Account provider.
* @param {string} [config.label='OTPAuth'] Account label.
* @param {boolean} [config.issuerInLabel=true] Include issuer prefix in label.
* @param {Secret|string} [config.secret=Secret] Secret key.
* @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
* @param {number} [config.digits=6] Token length.
* @param {number} [config.counter=0] Initial counter value.
* @param {(algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array} [config.hmac] Custom HMAC function.
*/
constructor({ issuer, label, issuerInLabel, secret, algorithm, digits, counter, hmac, }?: {
issuer?: string | undefined;
label?: string | undefined;
issuerInLabel?: boolean | undefined;
secret?: string | Secret | undefined;
algorithm?: string | undefined;
digits?: number | undefined;
counter?: number | undefined;
hmac?: ((algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array) | undefined;
});
/**
* Account provider.
* @type {string}
*/
issuer: string;
/**
* Account label.
* @type {string}
*/
label: string;
/**
* Include issuer prefix in label.
* @type {boolean}
*/
issuerInLabel: boolean;
/**
* Secret key.
* @type {Secret}
*/
secret: Secret;
/**
* HMAC hashing algorithm.
* @type {string}
*/
algorithm: string;
/**
* Token length.
* @type {number}
*/
digits: number;
/**
* Initial counter value.
* @type {number}
*/
counter: number;
/**
* Custom HMAC function.
* @type {((algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array)|undefined}
*/
hmac: ((algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array) | undefined;
/**
* Generates an HOTP token.
* @param {Object} [config] Configuration options.
* @param {number} [config.counter=this.counter++] Counter value.
* @returns {string} Token.
*/
generate({ counter }?: {
counter?: number | undefined;
}): string;
/**
* Validates an HOTP token.
* @param {Object} config Configuration options.
* @param {string} config.token Token value.
* @param {number} [config.counter=this.counter] Counter value.
* @param {number} [config.window=1] Window of counter values to test.
* @returns {number|null} Token delta or null if it is not found in the search window, in which case it should be considered invalid.
*/
validate({ token, counter, window }: {
token: string;
counter?: number | undefined;
window?: number | undefined;
}): number | null;
/**
* Returns a Google Authenticator key URI.
* @returns {string} URI.
*/
toString(): string;
}
/**
* TOTP: Time-Based One-Time Password Algorithm.
* @see [RFC 6238](https://datatracker.ietf.org/doc/html/rfc6238)
*/
declare class TOTP {
/**
* Default configuration.
* @type {{
* issuer: string,
* label: string,
* issuerInLabel: boolean,
* algorithm: string,
* digits: number,
* period: number
* window: number
* }}
*/
static get defaults(): {
issuer: string;
label: string;
issuerInLabel: boolean;
algorithm: string;
digits: number;
period: number;
window: number;
};
/**
* Calculates the counter. i.e. the number of periods since timestamp 0.
* @param {Object} [config] Configuration options.
* @param {number} [config.period=30] Token time-step duration.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @returns {number} Counter.
*/
static counter({ period, timestamp }?: {
period?: number | undefined;
timestamp?: number | undefined;
}): number;
/**
* Calculates the remaining time in milliseconds until the next token is generated.
* @param {Object} [config] Configuration options.
* @param {number} [config.period=30] Token time-step duration.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @returns {number} counter.
*/
static remaining({ period, timestamp }?: {
period?: number | undefined;
timestamp?: number | undefined;
}): number;
/**
* Generates a TOTP token.
* @param {Object} config Configuration options.
* @param {Secret} config.secret Secret key.
* @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
* @param {number} [config.digits=6] Token length.
* @param {number} [config.period=30] Token time-step duration.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @param {(algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array} [config.hmac] Custom HMAC function.
* @returns {string} Token.
*/
static generate({ secret, algorithm, digits, period, timestamp, hmac }: {
secret: Secret;
algorithm?: string | undefined;
digits?: number | undefined;
period?: number | undefined;
timestamp?: number | undefined;
hmac?: ((algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array) | undefined;
}): string;
/**
* Validates a TOTP token.
* @param {Object} config Configuration options.
* @param {string} config.token Token value.
* @param {Secret} config.secret Secret key.
* @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
* @param {number} [config.digits=6] Token length.
* @param {number} [config.period=30] Token time-step duration.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @param {number} [config.window=1] Window of counter values to test.
* @param {(algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array} [config.hmac] Custom HMAC function.
* @returns {number|null} Token delta or null if it is not found in the search window, in which case it should be considered invalid.
*/
static validate({ token, secret, algorithm, digits, period, timestamp, window, hmac, }: {
token: string;
secret: Secret;
algorithm?: string | undefined;
digits?: number | undefined;
period?: number | undefined;
timestamp?: number | undefined;
window?: number | undefined;
hmac?: ((algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array) | undefined;
}): number | null;
/**
* Creates a TOTP object.
* @param {Object} [config] Configuration options.
* @param {string} [config.issuer=''] Account provider.
* @param {string} [config.label='OTPAuth'] Account label.
* @param {boolean} [config.issuerInLabel=true] Include issuer prefix in label.
* @param {Secret|string} [config.secret=Secret] Secret key.
* @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
* @param {number} [config.digits=6] Token length.
* @param {number} [config.period=30] Token time-step duration.
* @param {(algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array} [config.hmac] Custom HMAC function.
*/
constructor({ issuer, label, issuerInLabel, secret, algorithm, digits, period, hmac, }?: {
issuer?: string | undefined;
label?: string | undefined;
issuerInLabel?: boolean | undefined;
secret?: string | Secret | undefined;
algorithm?: string | undefined;
digits?: number | undefined;
period?: number | undefined;
hmac?: ((algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array) | undefined;
});
/**
* Account provider.
* @type {string}
*/
issuer: string;
/**
* Account label.
* @type {string}
*/
label: string;
/**
* Include issuer prefix in label.
* @type {boolean}
*/
issuerInLabel: boolean;
/**
* Secret key.
* @type {Secret}
*/
secret: Secret;
/**
* HMAC hashing algorithm.
* @type {string}
*/
algorithm: string;
/**
* Token length.
* @type {number}
*/
digits: number;
/**
* Token time-step duration.
* @type {number}
*/
period: number;
/**
* Custom HMAC function.
* @type {((algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array)|undefined}
*/
hmac: ((algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array) | undefined;
/**
* Calculates the counter. i.e. the number of periods since timestamp 0.
* @param {Object} [config] Configuration options.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @returns {number} Counter.
*/
counter({ timestamp }?: {
timestamp?: number | undefined;
}): number;
/**
* Calculates the remaining time in milliseconds until the next token is generated.
* @param {Object} [config] Configuration options.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @returns {number} counter.
*/
remaining({ timestamp }?: {
timestamp?: number | undefined;
}): number;
/**
* Generates a TOTP token.
* @param {Object} [config] Configuration options.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @returns {string} Token.
*/
generate({ timestamp }?: {
timestamp?: number | undefined;
}): string;
/**
* Validates a TOTP token.
* @param {Object} config Configuration options.
* @param {string} config.token Token value.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @param {number} [config.window=1] Window of counter values to test.
* @returns {number|null} Token delta or null if it is not found in the search window, in which case it should be considered invalid.
*/
validate({ token, timestamp, window }: {
token: string;
timestamp?: number | undefined;
window?: number | undefined;
}): number | null;
/**
* Returns a Google Authenticator key URI.
* @returns {string} URI.
*/
toString(): string;
}
/**
* HOTP/TOTP object/string conversion.
* @see [Key URI Format](https://github.com/google/google-authenticator/wiki/Key-Uri-Format)
*/
declare class URI {
/**
* Parses a Google Authenticator key URI and returns an HOTP/TOTP object.
* @param {string} uri Google Authenticator Key URI.
* @param {Object} [config] Configuration options.
* @param {(algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array} [config.hmac] Custom HMAC function.
* @returns {HOTP|TOTP} HOTP/TOTP object.
*/
static parse(uri: string, { hmac }?: {
hmac?: ((algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array) | undefined;
}): HOTP | TOTP;
/**
* Converts an HOTP/TOTP object to a Google Authenticator key URI.
* @param {HOTP|TOTP} otp HOTP/TOTP object.
* @returns {string} Google Authenticator Key URI.
*/
static stringify(otp: HOTP | TOTP): string;
}
/**
* Library version.
* @type {string}
*/
declare const version: string;
export { HOTP, Secret, TOTP, URI, version };

View File

@@ -0,0 +1,456 @@
/**
* OTP secret key.
*/
declare class Secret {
/**
* Converts a Latin-1 string to a Secret object.
* @param {string} str Latin-1 string.
* @returns {Secret} Secret object.
*/
static fromLatin1(str: string): Secret;
/**
* Converts an UTF-8 string to a Secret object.
* @param {string} str UTF-8 string.
* @returns {Secret} Secret object.
*/
static fromUTF8(str: string): Secret;
/**
* Converts a base32 string to a Secret object.
* @param {string} str Base32 string.
* @returns {Secret} Secret object.
*/
static fromBase32(str: string): Secret;
/**
* Converts a hexadecimal string to a Secret object.
* @param {string} str Hexadecimal string.
* @returns {Secret} Secret object.
*/
static fromHex(str: string): Secret;
/**
* Creates a secret key object.
* @param {Object} [config] Configuration options.
* @param {ArrayBufferLike} [config.buffer] Secret key buffer.
* @param {number} [config.size=20] Number of random bytes to generate, ignored if 'buffer' is provided.
*/
constructor({ buffer, size }?: {
buffer?: ArrayBufferLike | undefined;
size?: number | undefined;
});
/**
* Secret key.
* @type {Uint8Array}
* @readonly
*/
readonly bytes: Uint8Array;
/**
* Secret key buffer.
* @deprecated For backward compatibility, the "bytes" property should be used instead.
* @type {ArrayBufferLike}
*/
get buffer(): ArrayBufferLike;
/**
* Latin-1 string representation of secret key.
* @type {string}
*/
get latin1(): string;
/**
* UTF-8 string representation of secret key.
* @type {string}
*/
get utf8(): string;
/**
* Base32 string representation of secret key.
* @type {string}
*/
get base32(): string;
/**
* Hexadecimal string representation of secret key.
* @type {string}
*/
get hex(): string;
}
/**
* HOTP: An HMAC-based One-time Password Algorithm.
* @see [RFC 4226](https://datatracker.ietf.org/doc/html/rfc4226)
*/
declare class HOTP {
/**
* Default configuration.
* @type {{
* issuer: string,
* label: string,
* issuerInLabel: boolean,
* algorithm: string,
* digits: number,
* counter: number
* window: number
* }}
*/
static get defaults(): {
issuer: string;
label: string;
issuerInLabel: boolean;
algorithm: string;
digits: number;
counter: number;
window: number;
};
/**
* Generates an HOTP token.
* @param {Object} config Configuration options.
* @param {Secret} config.secret Secret key.
* @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
* @param {number} [config.digits=6] Token length.
* @param {number} [config.counter=0] Counter value.
* @param {(algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array} [config.hmac] Custom HMAC function.
* @returns {string} Token.
*/
static generate({ secret, algorithm, digits, counter, hmac, }: {
secret: Secret;
algorithm?: string | undefined;
digits?: number | undefined;
counter?: number | undefined;
hmac?: ((algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array) | undefined;
}): string;
/**
* Validates an HOTP token.
* @param {Object} config Configuration options.
* @param {string} config.token Token value.
* @param {Secret} config.secret Secret key.
* @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
* @param {number} [config.digits=6] Token length.
* @param {number} [config.counter=0] Counter value.
* @param {number} [config.window=1] Window of counter values to test.
* @param {(algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array} [config.hmac] Custom HMAC function.
* @returns {number|null} Token delta or null if it is not found in the search window, in which case it should be considered invalid.
*/
static validate({ token, secret, algorithm, digits, counter, window, hmac, }: {
token: string;
secret: Secret;
algorithm?: string | undefined;
digits?: number | undefined;
counter?: number | undefined;
window?: number | undefined;
hmac?: ((algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array) | undefined;
}): number | null;
/**
* Creates an HOTP object.
* @param {Object} [config] Configuration options.
* @param {string} [config.issuer=''] Account provider.
* @param {string} [config.label='OTPAuth'] Account label.
* @param {boolean} [config.issuerInLabel=true] Include issuer prefix in label.
* @param {Secret|string} [config.secret=Secret] Secret key.
* @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
* @param {number} [config.digits=6] Token length.
* @param {number} [config.counter=0] Initial counter value.
* @param {(algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array} [config.hmac] Custom HMAC function.
*/
constructor({ issuer, label, issuerInLabel, secret, algorithm, digits, counter, hmac, }?: {
issuer?: string | undefined;
label?: string | undefined;
issuerInLabel?: boolean | undefined;
secret?: string | Secret | undefined;
algorithm?: string | undefined;
digits?: number | undefined;
counter?: number | undefined;
hmac?: ((algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array) | undefined;
});
/**
* Account provider.
* @type {string}
*/
issuer: string;
/**
* Account label.
* @type {string}
*/
label: string;
/**
* Include issuer prefix in label.
* @type {boolean}
*/
issuerInLabel: boolean;
/**
* Secret key.
* @type {Secret}
*/
secret: Secret;
/**
* HMAC hashing algorithm.
* @type {string}
*/
algorithm: string;
/**
* Token length.
* @type {number}
*/
digits: number;
/**
* Initial counter value.
* @type {number}
*/
counter: number;
/**
* Custom HMAC function.
* @type {((algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array)|undefined}
*/
hmac: ((algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array) | undefined;
/**
* Generates an HOTP token.
* @param {Object} [config] Configuration options.
* @param {number} [config.counter=this.counter++] Counter value.
* @returns {string} Token.
*/
generate({ counter }?: {
counter?: number | undefined;
}): string;
/**
* Validates an HOTP token.
* @param {Object} config Configuration options.
* @param {string} config.token Token value.
* @param {number} [config.counter=this.counter] Counter value.
* @param {number} [config.window=1] Window of counter values to test.
* @returns {number|null} Token delta or null if it is not found in the search window, in which case it should be considered invalid.
*/
validate({ token, counter, window }: {
token: string;
counter?: number | undefined;
window?: number | undefined;
}): number | null;
/**
* Returns a Google Authenticator key URI.
* @returns {string} URI.
*/
toString(): string;
}
/**
* TOTP: Time-Based One-Time Password Algorithm.
* @see [RFC 6238](https://datatracker.ietf.org/doc/html/rfc6238)
*/
declare class TOTP {
/**
* Default configuration.
* @type {{
* issuer: string,
* label: string,
* issuerInLabel: boolean,
* algorithm: string,
* digits: number,
* period: number
* window: number
* }}
*/
static get defaults(): {
issuer: string;
label: string;
issuerInLabel: boolean;
algorithm: string;
digits: number;
period: number;
window: number;
};
/**
* Calculates the counter. i.e. the number of periods since timestamp 0.
* @param {Object} [config] Configuration options.
* @param {number} [config.period=30] Token time-step duration.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @returns {number} Counter.
*/
static counter({ period, timestamp }?: {
period?: number | undefined;
timestamp?: number | undefined;
}): number;
/**
* Calculates the remaining time in milliseconds until the next token is generated.
* @param {Object} [config] Configuration options.
* @param {number} [config.period=30] Token time-step duration.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @returns {number} counter.
*/
static remaining({ period, timestamp }?: {
period?: number | undefined;
timestamp?: number | undefined;
}): number;
/**
* Generates a TOTP token.
* @param {Object} config Configuration options.
* @param {Secret} config.secret Secret key.
* @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
* @param {number} [config.digits=6] Token length.
* @param {number} [config.period=30] Token time-step duration.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @param {(algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array} [config.hmac] Custom HMAC function.
* @returns {string} Token.
*/
static generate({ secret, algorithm, digits, period, timestamp, hmac }: {
secret: Secret;
algorithm?: string | undefined;
digits?: number | undefined;
period?: number | undefined;
timestamp?: number | undefined;
hmac?: ((algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array) | undefined;
}): string;
/**
* Validates a TOTP token.
* @param {Object} config Configuration options.
* @param {string} config.token Token value.
* @param {Secret} config.secret Secret key.
* @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
* @param {number} [config.digits=6] Token length.
* @param {number} [config.period=30] Token time-step duration.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @param {number} [config.window=1] Window of counter values to test.
* @param {(algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array} [config.hmac] Custom HMAC function.
* @returns {number|null} Token delta or null if it is not found in the search window, in which case it should be considered invalid.
*/
static validate({ token, secret, algorithm, digits, period, timestamp, window, hmac, }: {
token: string;
secret: Secret;
algorithm?: string | undefined;
digits?: number | undefined;
period?: number | undefined;
timestamp?: number | undefined;
window?: number | undefined;
hmac?: ((algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array) | undefined;
}): number | null;
/**
* Creates a TOTP object.
* @param {Object} [config] Configuration options.
* @param {string} [config.issuer=''] Account provider.
* @param {string} [config.label='OTPAuth'] Account label.
* @param {boolean} [config.issuerInLabel=true] Include issuer prefix in label.
* @param {Secret|string} [config.secret=Secret] Secret key.
* @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
* @param {number} [config.digits=6] Token length.
* @param {number} [config.period=30] Token time-step duration.
* @param {(algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array} [config.hmac] Custom HMAC function.
*/
constructor({ issuer, label, issuerInLabel, secret, algorithm, digits, period, hmac, }?: {
issuer?: string | undefined;
label?: string | undefined;
issuerInLabel?: boolean | undefined;
secret?: string | Secret | undefined;
algorithm?: string | undefined;
digits?: number | undefined;
period?: number | undefined;
hmac?: ((algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array) | undefined;
});
/**
* Account provider.
* @type {string}
*/
issuer: string;
/**
* Account label.
* @type {string}
*/
label: string;
/**
* Include issuer prefix in label.
* @type {boolean}
*/
issuerInLabel: boolean;
/**
* Secret key.
* @type {Secret}
*/
secret: Secret;
/**
* HMAC hashing algorithm.
* @type {string}
*/
algorithm: string;
/**
* Token length.
* @type {number}
*/
digits: number;
/**
* Token time-step duration.
* @type {number}
*/
period: number;
/**
* Custom HMAC function.
* @type {((algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array)|undefined}
*/
hmac: ((algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array) | undefined;
/**
* Calculates the counter. i.e. the number of periods since timestamp 0.
* @param {Object} [config] Configuration options.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @returns {number} Counter.
*/
counter({ timestamp }?: {
timestamp?: number | undefined;
}): number;
/**
* Calculates the remaining time in milliseconds until the next token is generated.
* @param {Object} [config] Configuration options.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @returns {number} counter.
*/
remaining({ timestamp }?: {
timestamp?: number | undefined;
}): number;
/**
* Generates a TOTP token.
* @param {Object} [config] Configuration options.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @returns {string} Token.
*/
generate({ timestamp }?: {
timestamp?: number | undefined;
}): string;
/**
* Validates a TOTP token.
* @param {Object} config Configuration options.
* @param {string} config.token Token value.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @param {number} [config.window=1] Window of counter values to test.
* @returns {number|null} Token delta or null if it is not found in the search window, in which case it should be considered invalid.
*/
validate({ token, timestamp, window }: {
token: string;
timestamp?: number | undefined;
window?: number | undefined;
}): number | null;
/**
* Returns a Google Authenticator key URI.
* @returns {string} URI.
*/
toString(): string;
}
/**
* HOTP/TOTP object/string conversion.
* @see [Key URI Format](https://github.com/google/google-authenticator/wiki/Key-Uri-Format)
*/
declare class URI {
/**
* Parses a Google Authenticator key URI and returns an HOTP/TOTP object.
* @param {string} uri Google Authenticator Key URI.
* @param {Object} [config] Configuration options.
* @param {(algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array} [config.hmac] Custom HMAC function.
* @returns {HOTP|TOTP} HOTP/TOTP object.
*/
static parse(uri: string, { hmac }?: {
hmac?: ((algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array) | undefined;
}): HOTP | TOTP;
/**
* Converts an HOTP/TOTP object to a Google Authenticator key URI.
* @param {HOTP|TOTP} otp HOTP/TOTP object.
* @returns {string} Google Authenticator Key URI.
*/
static stringify(otp: HOTP | TOTP): string;
}
/**
* Library version.
* @type {string}
*/
declare const version: string;
export { HOTP, Secret, TOTP, URI, version };

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,19 @@
//! otpauth 9.5.0 | (c) Héctor Molinero Fernández | MIT | https://github.com/hectorm/otpauth
//! noble-hashes 2.0.1 | (c) Paul Miller | MIT | https://github.com/paulmillr/noble-hashes
/// <reference types="./otpauth.d.ts" />
// @ts-nocheck
function t(t,e=""){if(!Number.isSafeInteger(t)||t<0)throw new Error(`${e&&`"${e}" `}expected integer >= 0, got ${t}`)}function e(t,e,s=""){const i=(r=t)instanceof Uint8Array||ArrayBuffer.isView(r)&&"Uint8Array"===r.constructor.name;var r;const n=t?.length,o=void 0!==e;if(!i||o&&n!==e)throw new Error((s&&`"${s}" `)+"expected Uint8Array"+(o?` of length ${e}`:"")+", got "+(i?`length=${n}`:"type="+typeof t));return t}function s(t,e=!0){if(t.destroyed)throw new Error("Hash instance has been destroyed");if(e&&t.finished)throw new Error("Hash#digest() has already been called")}function i(t,s){e(t,void 0,"digestInto() output");const i=s.outputLen;if(t.length<i)throw new Error('"digestInto() output" expected to be of length >='+i)}function r(...t){for(let e=0;e<t.length;e++)t[e].fill(0)}function n(t){return new DataView(t.buffer,t.byteOffset,t.byteLength)}function o(t,e){return t<<32-e|t>>>e}function h(t,e){return t<<e|t>>>32-e>>>0}function a(t){return t<<24&4278190080|t<<8&16711680|t>>>8&65280|t>>>24&255}const c=(()=>68===new Uint8Array(new Uint32Array([287454020]).buffer)[0])()?t=>t:function(t){for(let e=0;e<t.length;e++)t[e]=a(t[e]);return t};function l(t,e={}){const s=(e,s)=>t(s).update(e).digest(),i=t(void 0);return s.outputLen=i.outputLen,s.blockLen=i.blockLen,s.create=e=>t(e),Object.assign(s,e),Object.freeze(s)}const u=t=>({oid:Uint8Array.from([6,9,96,134,72,1,101,3,4,2,t])});class f{update(t){return s(this),this.iHash.update(t),this}digestInto(t){s(this),e(t,this.outputLen,"output"),this.finished=!0,this.iHash.digestInto(t),this.oHash.update(t),this.oHash.digestInto(t),this.destroy()}digest(){const t=new Uint8Array(this.oHash.outputLen);return this.digestInto(t),t}_cloneInto(t){t||(t=Object.create(Object.getPrototypeOf(this),{}));const{oHash:e,iHash:s,finished:i,destroyed:r,blockLen:n,outputLen:o}=this;return t.finished=i,t.destroyed=r,t.blockLen=n,t.outputLen=o,t.oHash=e._cloneInto(t.oHash),t.iHash=s._cloneInto(t.iHash),t}clone(){return this._cloneInto()}destroy(){this.destroyed=!0,this.oHash.destroy(),
this.iHash.destroy()}constructor(s,i){if(this.finished=!1,this.destroyed=!1,function(e){if("function"!=typeof e||"function"!=typeof e.create)throw new Error("Hash must wrapped by utils.createHasher");t(e.outputLen),t(e.blockLen)}(s),e(i,void 0,"key"),this.iHash=s.create(),"function"!=typeof this.iHash.update)throw new Error("Expected instance of class which extends utils.Hash");this.blockLen=this.iHash.blockLen,this.outputLen=this.iHash.outputLen;const n=this.blockLen,o=new Uint8Array(n);o.set(i.length>n?s.create().update(i).digest():i);for(let t=0;t<o.length;t++)o[t]^=54;this.iHash.update(o),this.oHash=s.create();for(let t=0;t<o.length;t++)o[t]^=106;this.oHash.update(o),r(o)}}const d=(t,e,s)=>new f(t,e).update(s).digest();function b(t,e,s){return t&e^~t&s}function g(t,e,s){return t&e^t&s^e&s}d.create=(t,e)=>new f(t,e);class p{update(t){s(this),e(t);const{view:i,buffer:r,blockLen:o}=this,h=t.length;for(let e=0;e<h;){const s=Math.min(o-this.pos,h-e);if(s===o){const s=n(t);for(;o<=h-e;e+=o)this.process(s,e);continue}r.set(t.subarray(e,e+s),this.pos),this.pos+=s,e+=s,this.pos===o&&(this.process(i,0),this.pos=0)}return this.length+=t.length,this.roundClean(),this}digestInto(t){s(this),i(t,this),this.finished=!0;const{buffer:e,view:o,blockLen:h,isLE:a}=this;let{pos:c}=this;e[c++]=128,r(this.buffer.subarray(c)),this.padOffset>h-c&&(this.process(o,0),c=0);for(let t=c;t<h;t++)e[t]=0;o.setBigUint64(h-8,BigInt(8*this.length),a),this.process(o,0);const l=n(t),u=this.outputLen;if(u%4)throw new Error("_sha2: outputLen must be aligned to 32bit");const f=u/4,d=this.get();if(f>d.length)throw new Error("_sha2: outputLen bigger than state");for(let t=0;t<f;t++)l.setUint32(4*t,d[t],a)}digest(){const{buffer:t,outputLen:e}=this;this.digestInto(t);const s=t.slice(0,e);return this.destroy(),s}_cloneInto(t){t||(t=new this.constructor),t.set(...this.get());const{blockLen:e,buffer:s,length:i,finished:r,destroyed:n,pos:o}=this;return t.destroyed=n,t.finished=r,t.length=i,t.pos=o,i%e&&t.buffer.set(s),t}clone(){return this._cloneInto()}
constructor(t,e,s,i){this.finished=!1,this.length=0,this.pos=0,this.destroyed=!1,this.blockLen=t,this.outputLen=e,this.padOffset=s,this.isLE=i,this.buffer=new Uint8Array(t),this.view=n(this.buffer)}}const w=Uint32Array.from([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]),m=Uint32Array.from([3238371032,914150663,812702999,4144912697,4290775857,1750603025,1694076839,3204075428]),y=Uint32Array.from([3418070365,3238371032,1654270250,914150663,2438529370,812702999,355462360,4144912697,1731405415,4290775857,2394180231,1750603025,3675008525,1694076839,1203062813,3204075428]),A=Uint32Array.from([1779033703,4089235720,3144134277,2227873595,1013904242,4271175723,2773480762,1595750129,1359893119,2917565137,2600822924,725511199,528734635,4215389547,1541459225,327033209]),x=Uint32Array.from([1732584193,4023233417,2562383102,271733878,3285377520]),H=new Uint32Array(80);class I extends p{get(){const{A:t,B:e,C:s,D:i,E:r}=this;return[t,e,s,i,r]}set(t,e,s,i,r){this.A=0|t,this.B=0|e,this.C=0|s,this.D=0|i,this.E=0|r}process(t,e){for(let s=0;s<16;s++,e+=4)H[s]=t.getUint32(e,!1);for(let t=16;t<80;t++)H[t]=h(H[t-3]^H[t-8]^H[t-14]^H[t-16],1);let{A:s,B:i,C:r,D:n,E:o}=this;for(let t=0;t<80;t++){let e,a;t<20?(e=b(i,r,n),a=1518500249):t<40?(e=i^r^n,a=1859775393):t<60?(e=g(i,r,n),a=2400959708):(e=i^r^n,a=3395469782);const c=h(s,5)+e+o+a+H[t]|0;o=n,n=r,r=h(i,30),i=s,s=c}s=s+this.A|0,i=i+this.B|0,r=r+this.C|0,n=n+this.D|0,o=o+this.E|0,this.set(s,i,r,n,o)}roundClean(){r(H)}destroy(){this.set(0,0,0,0,0),r(this.buffer)}constructor(){super(64,20,8,!1),this.A=0|x[0],this.B=0|x[1],this.C=0|x[2],this.D=0|x[3],this.E=0|x[4]}}const L=l(()=>new I),E=BigInt(2**32-1),U=BigInt(32);function B(t,e=!1){return e?{h:Number(t&E),l:Number(t>>U&E)}:{h:0|Number(t>>U&E),l:0|Number(t&E)}}function S(t,e=!1){const s=t.length;let i=new Uint32Array(s),r=new Uint32Array(s);for(let n=0;n<s;n++){const{h:s,l:o}=B(t[n],e);[i[n],r[n]]=[s,o]}return[i,r]}
const v=(t,e,s)=>t>>>s,C=(t,e,s)=>t<<32-s|e>>>s,O=(t,e,s)=>t>>>s|e<<32-s,$=(t,e,s)=>t<<32-s|e>>>s,k=(t,e,s)=>t<<64-s|e>>>s-32,D=(t,e,s)=>t>>>s-32|e<<64-s;function T(t,e,s,i){const r=(e>>>0)+(i>>>0);return{h:t+s+(r/2**32|0)|0,l:0|r}}const _=(t,e,s)=>(t>>>0)+(e>>>0)+(s>>>0),F=(t,e,s,i)=>e+s+i+(t/2**32|0)|0,G=(t,e,s,i)=>(t>>>0)+(e>>>0)+(s>>>0)+(i>>>0),P=(t,e,s,i,r)=>e+s+i+r+(t/2**32|0)|0,j=(t,e,s,i,r)=>(t>>>0)+(e>>>0)+(s>>>0)+(i>>>0)+(r>>>0),M=(t,e,s,i,r,n)=>e+s+i+r+n+(t/2**32|0)|0,R=Uint32Array.from([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]),X=new Uint32Array(64);class N extends p{get(){const{A:t,B:e,C:s,D:i,E:r,F:n,G:o,H:h}=this;return[t,e,s,i,r,n,o,h]}set(t,e,s,i,r,n,o,h){this.A=0|t,this.B=0|e,this.C=0|s,this.D=0|i,this.E=0|r,this.F=0|n,this.G=0|o,this.H=0|h}process(t,e){for(let s=0;s<16;s++,e+=4)X[s]=t.getUint32(e,!1);for(let t=16;t<64;t++){const e=X[t-15],s=X[t-2],i=o(e,7)^o(e,18)^e>>>3,r=o(s,17)^o(s,19)^s>>>10;X[t]=r+X[t-7]+i+X[t-16]|0}let{A:s,B:i,C:r,D:n,E:h,F:a,G:c,H:l}=this;for(let t=0;t<64;t++){const e=l+(o(h,6)^o(h,11)^o(h,25))+b(h,a,c)+R[t]+X[t]|0,u=(o(s,2)^o(s,13)^o(s,22))+g(s,i,r)|0;l=c,c=a,a=h,h=n+e|0,n=r,r=i,i=s,s=e+u|0}s=s+this.A|0,i=i+this.B|0,r=r+this.C|0,n=n+this.D|0,h=h+this.E|0,a=a+this.F|0,c=c+this.G|0,l=l+this.H|0,this.set(s,i,r,n,h,a,c,l)}roundClean(){r(X)}destroy(){this.set(0,0,0,0,0,0,0,0),r(this.buffer)}constructor(t){super(64,t,8,!1)}}
class Z extends N{constructor(){super(32),this.A=0|w[0],this.B=0|w[1],this.C=0|w[2],this.D=0|w[3],this.E=0|w[4],this.F=0|w[5],this.G=0|w[6],this.H=0|w[7]}}class V extends N{constructor(){super(28),this.A=0|m[0],this.B=0|m[1],this.C=0|m[2],this.D=0|m[3],this.E=0|m[4],this.F=0|m[5],this.G=0|m[6],this.H=0|m[7]}}
const z=(()=>S(["0x428a2f98d728ae22","0x7137449123ef65cd","0xb5c0fbcfec4d3b2f","0xe9b5dba58189dbbc","0x3956c25bf348b538","0x59f111f1b605d019","0x923f82a4af194f9b","0xab1c5ed5da6d8118","0xd807aa98a3030242","0x12835b0145706fbe","0x243185be4ee4b28c","0x550c7dc3d5ffb4e2","0x72be5d74f27b896f","0x80deb1fe3b1696b1","0x9bdc06a725c71235","0xc19bf174cf692694","0xe49b69c19ef14ad2","0xefbe4786384f25e3","0x0fc19dc68b8cd5b5","0x240ca1cc77ac9c65","0x2de92c6f592b0275","0x4a7484aa6ea6e483","0x5cb0a9dcbd41fbd4","0x76f988da831153b5","0x983e5152ee66dfab","0xa831c66d2db43210","0xb00327c898fb213f","0xbf597fc7beef0ee4","0xc6e00bf33da88fc2","0xd5a79147930aa725","0x06ca6351e003826f","0x142929670a0e6e70","0x27b70a8546d22ffc","0x2e1b21385c26c926","0x4d2c6dfc5ac42aed","0x53380d139d95b3df","0x650a73548baf63de","0x766a0abb3c77b2a8","0x81c2c92e47edaee6","0x92722c851482353b","0xa2bfe8a14cf10364","0xa81a664bbc423001","0xc24b8b70d0f89791","0xc76c51a30654be30","0xd192e819d6ef5218","0xd69906245565a910","0xf40e35855771202a","0x106aa07032bbd1b8","0x19a4c116b8d2d0c8","0x1e376c085141ab53","0x2748774cdf8eeb99","0x34b0bcb5e19b48a8","0x391c0cb3c5c95a63","0x4ed8aa4ae3418acb","0x5b9cca4f7763e373","0x682e6ff3d6b2b8a3","0x748f82ee5defb2fc","0x78a5636f43172f60","0x84c87814a1f0ab72","0x8cc702081a6439ec","0x90befffa23631e28","0xa4506cebde82bde9","0xbef9a3f7b2c67915","0xc67178f2e372532b","0xca273eceea26619c","0xd186b8c721c0c207","0xeada7dd6cde0eb1e","0xf57d4f7fee6ed178","0x06f067aa72176fba","0x0a637dc5a2c898a6","0x113f9804bef90dae","0x1b710b35131c471b","0x28db77f523047d84","0x32caab7b40c72493","0x3c9ebe0a15c9bebc","0x431d67c49c100d4c","0x4cc5d4becb3e42b6","0x597f299cfc657e2a","0x5fcb6fab3ad6faec","0x6c44198c4a475817"].map(t=>BigInt(t))))(),J=(()=>z[0])(),K=(()=>z[1])(),Q=new Uint32Array(80),W=new Uint32Array(80);class Y extends p{get(){const{Ah:t,Al:e,Bh:s,Bl:i,Ch:r,Cl:n,Dh:o,Dl:h,Eh:a,El:c,Fh:l,Fl:u,Gh:f,Gl:d,Hh:b,Hl:g}=this;return[t,e,s,i,r,n,o,h,a,c,l,u,f,d,b,g]}set(t,e,s,i,r,n,o,h,a,c,l,u,f,d,b,g){this.Ah=0|t,this.Al=0|e,this.Bh=0|s,this.Bl=0|i,this.Ch=0|r,
this.Cl=0|n,this.Dh=0|o,this.Dl=0|h,this.Eh=0|a,this.El=0|c,this.Fh=0|l,this.Fl=0|u,this.Gh=0|f,this.Gl=0|d,this.Hh=0|b,this.Hl=0|g}process(t,e){for(let s=0;s<16;s++,e+=4)Q[s]=t.getUint32(e),W[s]=t.getUint32(e+=4);for(let t=16;t<80;t++){const e=0|Q[t-15],s=0|W[t-15],i=O(e,s,1)^O(e,s,8)^v(e,0,7),r=$(e,s,1)^$(e,s,8)^C(e,s,7),n=0|Q[t-2],o=0|W[t-2],h=O(n,o,19)^k(n,o,61)^v(n,0,6),a=$(n,o,19)^D(n,o,61)^C(n,o,6),c=G(r,a,W[t-7],W[t-16]),l=P(c,i,h,Q[t-7],Q[t-16]);Q[t]=0|l,W[t]=0|c}let{Ah:s,Al:i,Bh:r,Bl:n,Ch:o,Cl:h,Dh:a,Dl:c,Eh:l,El:u,Fh:f,Fl:d,Gh:b,Gl:g,Hh:p,Hl:w}=this;for(let t=0;t<80;t++){const e=O(l,u,14)^O(l,u,18)^k(l,u,41),m=$(l,u,14)^$(l,u,18)^D(l,u,41),y=l&f^~l&b,A=j(w,m,u&d^~u&g,K[t],W[t]),x=M(A,p,e,y,J[t],Q[t]),H=0|A,I=O(s,i,28)^k(s,i,34)^k(s,i,39),L=$(s,i,28)^D(s,i,34)^D(s,i,39),E=s&r^s&o^r&o,U=i&n^i&h^n&h;p=0|b,w=0|g,b=0|f,g=0|d,f=0|l,d=0|u,({h:l,l:u}=T(0|a,0|c,0|x,0|H)),a=0|o,c=0|h,o=0|r,h=0|n,r=0|s,n=0|i;const B=_(H,L,U);s=F(B,x,I,E),i=0|B}({h:s,l:i}=T(0|this.Ah,0|this.Al,0|s,0|i)),({h:r,l:n}=T(0|this.Bh,0|this.Bl,0|r,0|n)),({h:o,l:h}=T(0|this.Ch,0|this.Cl,0|o,0|h)),({h:a,l:c}=T(0|this.Dh,0|this.Dl,0|a,0|c)),({h:l,l:u}=T(0|this.Eh,0|this.El,0|l,0|u)),({h:f,l:d}=T(0|this.Fh,0|this.Fl,0|f,0|d)),({h:b,l:g}=T(0|this.Gh,0|this.Gl,0|b,0|g)),({h:p,l:w}=T(0|this.Hh,0|this.Hl,0|p,0|w)),this.set(s,i,r,n,o,h,a,c,l,u,f,d,b,g,p,w)}roundClean(){r(Q,W)}destroy(){r(this.buffer),this.set(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)}constructor(t){super(128,t,16,!1)}}class q extends Y{constructor(){super(64),this.Ah=0|A[0],this.Al=0|A[1],this.Bh=0|A[2],this.Bl=0|A[3],this.Ch=0|A[4],this.Cl=0|A[5],this.Dh=0|A[6],this.Dl=0|A[7],this.Eh=0|A[8],this.El=0|A[9],this.Fh=0|A[10],this.Fl=0|A[11],this.Gh=0|A[12],this.Gl=0|A[13],this.Hh=0|A[14],this.Hl=0|A[15]}}class tt extends Y{constructor(){super(48),this.Ah=0|y[0],this.Al=0|y[1],this.Bh=0|y[2],this.Bl=0|y[3],this.Ch=0|y[4],this.Cl=0|y[5],this.Dh=0|y[6],this.Dl=0|y[7],this.Eh=0|y[8],this.El=0|y[9],this.Fh=0|y[10],this.Fl=0|y[11],this.Gh=0|y[12],this.Gl=0|y[13],this.Hh=0|y[14],this.Hl=0|y[15]}}
const et=l(()=>new Z,u(1)),st=l(()=>new V,u(4)),it=l(()=>new q,u(3)),rt=l(()=>new tt,u(2)),nt=BigInt(0),ot=BigInt(1),ht=BigInt(2),at=BigInt(7),ct=BigInt(256),lt=BigInt(113),ut=[],ft=[],dt=[];for(let t=0,e=ot,s=1,i=0;t<24;t++){[s,i]=[i,(2*s+3*i)%5],ut.push(2*(5*i+s)),ft.push((t+1)*(t+2)/2%64);let r=nt;for(let t=0;t<7;t++)e=(e<<ot^(e>>at)*lt)%ct,e&ht&&(r^=ot<<(ot<<BigInt(t))-ot);dt.push(r)}const bt=S(dt,!0),gt=bt[0],pt=bt[1],wt=(t,e,s)=>s>32?((t,e,s)=>e<<s-32|t>>>64-s)(t,e,s):((t,e,s)=>t<<s|e>>>32-s)(t,e,s),mt=(t,e,s)=>s>32?((t,e,s)=>t<<s-32|e>>>64-s)(t,e,s):((t,e,s)=>e<<s|t>>>32-s)(t,e,s);class yt{clone(){return this._cloneInto()}keccak(){c(this.state32),function(t,e=24){const s=new Uint32Array(10);for(let i=24-e;i<24;i++){for(let e=0;e<10;e++)s[e]=t[e]^t[e+10]^t[e+20]^t[e+30]^t[e+40];for(let e=0;e<10;e+=2){const i=(e+8)%10,r=(e+2)%10,n=s[r],o=s[r+1],h=wt(n,o,1)^s[i],a=mt(n,o,1)^s[i+1];for(let s=0;s<50;s+=10)t[e+s]^=h,t[e+s+1]^=a}let e=t[2],r=t[3];for(let s=0;s<24;s++){const i=ft[s],n=wt(e,r,i),o=mt(e,r,i),h=ut[s];e=t[h],r=t[h+1],t[h]=n,t[h+1]=o}for(let e=0;e<50;e+=10){for(let i=0;i<10;i++)s[i]=t[e+i];for(let i=0;i<10;i++)t[e+i]^=~s[(i+2)%10]&s[(i+4)%10]}t[0]^=gt[i],t[1]^=pt[i]}r(s)}(this.state32,this.rounds),c(this.state32),this.posOut=0,this.pos=0}update(t){s(this),e(t);const{blockLen:i,state:r}=this,n=t.length;for(let e=0;e<n;){const s=Math.min(i-this.pos,n-e);for(let i=0;i<s;i++)r[this.pos++]^=t[e++];this.pos===i&&this.keccak()}return this}finish(){if(this.finished)return;this.finished=!0;const{state:t,suffix:e,pos:s,blockLen:i}=this;t[s]^=e,128&e&&s===i-1&&this.keccak(),t[i-1]^=128,this.keccak()}writeInto(t){s(this,!1),e(t),this.finish();const i=this.state,{blockLen:r}=this;for(let e=0,s=t.length;e<s;){this.posOut>=r&&this.keccak();const n=Math.min(r-this.posOut,s-e);t.set(i.subarray(this.posOut,this.posOut+n),e),this.posOut+=n,e+=n}return t}xofInto(t){if(!this.enableXOF)throw new Error("XOF is not possible for this instance");return this.writeInto(t)}xof(e){return t(e),this.xofInto(new Uint8Array(e))}
digestInto(t){if(i(t,this),this.finished)throw new Error("digest() was already called");return this.writeInto(t),this.destroy(),t}digest(){return this.digestInto(new Uint8Array(this.outputLen))}destroy(){this.destroyed=!0,r(this.state)}_cloneInto(t){const{blockLen:e,suffix:s,outputLen:i,rounds:r,enableXOF:n}=this;return t||(t=new yt(e,s,i,n,r)),t.state32.set(this.state32),t.pos=this.pos,t.posOut=this.posOut,t.finished=this.finished,t.rounds=r,t.suffix=s,t.outputLen=i,t.enableXOF=n,t.destroyed=this.destroyed,t}constructor(e,s,i,r=!1,n=24){if(this.pos=0,this.posOut=0,this.finished=!1,this.destroyed=!1,this.enableXOF=!1,this.blockLen=e,this.suffix=s,this.outputLen=i,this.enableXOF=r,this.rounds=n,t(i,"outputLen"),!(0<e&&e<200))throw new Error("only keccak-f1600 function is supported");var o;this.state=new Uint8Array(200),this.state32=(o=this.state,new Uint32Array(o.buffer,o.byteOffset,Math.floor(o.byteLength/4)))}}const At=(t,e,s,i={})=>l(()=>new yt(e,t,s),i),xt=At(6,144,28,u(7)),Ht=At(6,136,32,u(8)),It=At(6,104,48,u(9)),Lt=At(6,72,64,u(10)),Et=(()=>{if("object"==typeof globalThis)return globalThis;Object.defineProperty(Object.prototype,"__GLOBALTHIS__",{get(){return this},configurable:!0});try{if("undefined"!=typeof __GLOBALTHIS__)return __GLOBALTHIS__}finally{delete Object.prototype.__GLOBALTHIS__}return"undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:void 0})(),Ut={SHA1:L,SHA224:st,SHA256:et,SHA384:rt,SHA512:it,"SHA3-224":xt,"SHA3-256":Ht,"SHA3-384":It,"SHA3-512":Lt},Bt=t=>{switch(!0){case/^(?:SHA-?1|SSL3-SHA1)$/i.test(t):return"SHA1";case/^SHA(?:2?-)?224$/i.test(t):return"SHA224";case/^SHA(?:2?-)?256$/i.test(t):return"SHA256";case/^SHA(?:2?-)?384$/i.test(t):return"SHA384";case/^SHA(?:2?-)?512$/i.test(t):return"SHA512";case/^SHA3-224$/i.test(t):return"SHA3-224";case/^SHA3-256$/i.test(t):return"SHA3-256";case/^SHA3-384$/i.test(t):return"SHA3-384";case/^SHA3-512$/i.test(t):return"SHA3-512";default:throw new TypeError(`Unknown hash algorithm: ${t}`)}},St=(t,e,s)=>{
if(d){const i=Ut[t]??Ut[Bt(t)];return d(i,e,s)}throw new Error("Missing HMAC function")},vt="ABCDEFGHIJKLMNOPQRSTUVWXYZ234567",Ct=t=>{let e=(t=t.replace(/ /g,"")).length;for(;"="===t[e-1];)--e;t=(e<t.length?t.substring(0,e):t).toUpperCase();const s=new ArrayBuffer(5*t.length/8|0),i=new Uint8Array(s);let r=0,n=0,o=0;for(let e=0;e<t.length;e++){const s=vt.indexOf(t[e]);if(-1===s)throw new TypeError(`Invalid character found: ${t[e]}`);n=n<<5|s,r+=5,r>=8&&(r-=8,i[o++]=n>>>r)}return i},Ot=t=>{let e=0,s=0,i="";for(let r=0;r<t.length;r++)for(s=s<<8|t[r],e+=8;e>=5;)i+=vt[s>>>e-5&31],e-=5;return e>0&&(i+=vt[s<<5-e&31]),i},$t=t=>{t=t.replace(/ /g,"");const e=new ArrayBuffer(t.length/2),s=new Uint8Array(e);for(let e=0;e<t.length;e+=2)s[e/2]=parseInt(t.substring(e,e+2),16);return s},kt=t=>{let e="";for(let s=0;s<t.length;s++){const i=t[s].toString(16);1===i.length&&(e+="0"),e+=i}return e.toUpperCase()},Dt=t=>{const e=new ArrayBuffer(t.length),s=new Uint8Array(e);for(let e=0;e<t.length;e++)s[e]=255&t.charCodeAt(e);return s},Tt=t=>{let e="";for(let s=0;s<t.length;s++)e+=String.fromCharCode(t[s]);return e},_t=Et.TextEncoder?new Et.TextEncoder:null,Ft=Et.TextDecoder?new Et.TextDecoder:null,Gt=t=>{if(!_t)throw new Error("Encoding API not available");return _t.encode(t)},Pt=t=>{if(!Ft)throw new Error("Encoding API not available");return Ft.decode(t)};class jt{static fromLatin1(t){return new jt({buffer:Dt(t).buffer})}static fromUTF8(t){return new jt({buffer:Gt(t).buffer})}static fromBase32(t){return new jt({buffer:Ct(t).buffer})}static fromHex(t){return new jt({buffer:$t(t).buffer})}get buffer(){return this.bytes.buffer}get latin1(){return Object.defineProperty(this,"latin1",{enumerable:!0,writable:!1,configurable:!1,value:Tt(this.bytes)}),this.latin1}get utf8(){return Object.defineProperty(this,"utf8",{enumerable:!0,writable:!1,configurable:!1,value:Pt(this.bytes)}),this.utf8}get base32(){return Object.defineProperty(this,"base32",{enumerable:!0,writable:!1,configurable:!1,value:Ot(this.bytes)}),this.base32}get hex(){
return Object.defineProperty(this,"hex",{enumerable:!0,writable:!1,configurable:!1,value:kt(this.bytes)}),this.hex}constructor({buffer:t,size:e=20}={}){this.bytes=void 0===t?(t=>{if(Et.crypto?.getRandomValues)return Et.crypto.getRandomValues(new Uint8Array(t));throw new Error("Cryptography API not available")})(e):new Uint8Array(t),Object.defineProperty(this,"bytes",{enumerable:!0,writable:!1,configurable:!1,value:this.bytes})}}class Mt{static get defaults(){return{issuer:"",label:"OTPAuth",issuerInLabel:!0,algorithm:"SHA1",digits:6,counter:0,window:1}}static generate({secret:t,algorithm:e=Mt.defaults.algorithm,digits:s=Mt.defaults.digits,counter:i=Mt.defaults.counter,hmac:r=St}){const n=(t=>{const e=new ArrayBuffer(8),s=new Uint8Array(e);let i=t;for(let t=7;t>=0&&0!==i;t--)s[t]=255&i,i-=s[t],i/=256;return s})(i),o=r(e,t.bytes,n);if(!o?.byteLength||o.byteLength<19)throw new TypeError("Return value must be at least 19 bytes");const h=15&o[o.byteLength-1];return(((127&o[h])<<24|(255&o[h+1])<<16|(255&o[h+2])<<8|255&o[h+3])%10**s).toString().padStart(s,"0")}generate({counter:t=this.counter++}={}){return Mt.generate({secret:this.secret,algorithm:this.algorithm,digits:this.digits,counter:t,hmac:this.hmac})}static validate({token:t,secret:e,algorithm:s,digits:i=Mt.defaults.digits,counter:r=Mt.defaults.counter,window:n=Mt.defaults.window,hmac:o=St}){if(t.length!==i)return null;let h=null;const a=n=>{const a=Mt.generate({secret:e,algorithm:s,digits:i,counter:n,hmac:o});((t,e)=>{{if(t.length!==e.length)throw new TypeError("Input strings must have the same length");let s=-1,i=0;for(;++s<t.length;)i|=t.charCodeAt(s)^e.charCodeAt(s);return 0===i}})(t,a)&&(h=n-r)};a(r);for(let t=1;t<=n&&null===h&&(a(r-t),null===h)&&(a(r+t),null===h);++t);return h}validate({token:t,counter:e=this.counter,window:s}){return Mt.validate({token:t,secret:this.secret,algorithm:this.algorithm,digits:this.digits,counter:e,window:s,hmac:this.hmac})}toString(){const t=encodeURIComponent
;return"otpauth://hotp/"+(this.issuer.length>0?this.issuerInLabel?`${t(this.issuer)}:${t(this.label)}?issuer=${t(this.issuer)}&`:`${t(this.label)}?issuer=${t(this.issuer)}&`:`${t(this.label)}?`)+`secret=${t(this.secret.base32)}&`+`algorithm=${t(this.algorithm)}&`+`digits=${t(this.digits)}&`+`counter=${t(this.counter)}`}constructor({issuer:t=Mt.defaults.issuer,label:e=Mt.defaults.label,issuerInLabel:s=Mt.defaults.issuerInLabel,secret:i=new jt,algorithm:r=Mt.defaults.algorithm,digits:n=Mt.defaults.digits,counter:o=Mt.defaults.counter,hmac:h}={}){this.issuer=t,this.label=e,this.issuerInLabel=s,this.secret="string"==typeof i?jt.fromBase32(i):i,this.algorithm=h?r:Bt(r),this.digits=n,this.counter=o,this.hmac=h}}class Rt{static get defaults(){return{issuer:"",label:"OTPAuth",issuerInLabel:!0,algorithm:"SHA1",digits:6,period:30,window:1}}static counter({period:t=Rt.defaults.period,timestamp:e=Date.now()}={}){return Math.floor(e/1e3/t)}counter({timestamp:t=Date.now()}={}){return Rt.counter({period:this.period,timestamp:t})}static remaining({period:t=Rt.defaults.period,timestamp:e=Date.now()}={}){return 1e3*t-e%(1e3*t)}remaining({timestamp:t=Date.now()}={}){return Rt.remaining({period:this.period,timestamp:t})}static generate({secret:t,algorithm:e,digits:s,period:i=Rt.defaults.period,timestamp:r=Date.now(),hmac:n}){return Mt.generate({secret:t,algorithm:e,digits:s,counter:Rt.counter({period:i,timestamp:r}),hmac:n})}generate({timestamp:t=Date.now()}={}){return Rt.generate({secret:this.secret,algorithm:this.algorithm,digits:this.digits,period:this.period,timestamp:t,hmac:this.hmac})}static validate({token:t,secret:e,algorithm:s,digits:i,period:r=Rt.defaults.period,timestamp:n=Date.now(),window:o,hmac:h}){return Mt.validate({token:t,secret:e,algorithm:s,digits:i,counter:Rt.counter({period:r,timestamp:n}),window:o,hmac:h})}validate({token:t,timestamp:e,window:s}){return Rt.validate({token:t,secret:this.secret,algorithm:this.algorithm,digits:this.digits,period:this.period,timestamp:e,window:s,hmac:this.hmac})}toString(){
const t=encodeURIComponent;return"otpauth://totp/"+(this.issuer.length>0?this.issuerInLabel?`${t(this.issuer)}:${t(this.label)}?issuer=${t(this.issuer)}&`:`${t(this.label)}?issuer=${t(this.issuer)}&`:`${t(this.label)}?`)+`secret=${t(this.secret.base32)}&`+`algorithm=${t(this.algorithm)}&`+`digits=${t(this.digits)}&`+`period=${t(this.period)}`}constructor({issuer:t=Rt.defaults.issuer,label:e=Rt.defaults.label,issuerInLabel:s=Rt.defaults.issuerInLabel,secret:i=new jt,algorithm:r=Rt.defaults.algorithm,digits:n=Rt.defaults.digits,period:o=Rt.defaults.period,hmac:h}={}){this.issuer=t,this.label=e,this.issuerInLabel=s,this.secret="string"==typeof i?jt.fromBase32(i):i,this.algorithm=h?r:Bt(r),this.digits=n,this.period=o,this.hmac=h}}const Xt=/^otpauth:\/\/([ht]otp)\/(.+)\?([A-Z0-9.~_-]+=[^?&]*(?:&[A-Z0-9.~_-]+=[^?&]*)*)$/i,Nt=/^[2-7A-Z]+=*$/i,Zt=/^SHA(?:1|224|256|384|512|3-224|3-256|3-384|3-512)$/i,Vt=/^[A-Z0-9]+(?:[_-][A-Z0-9]+)*$/i,zt=/^[+-]?\d+$/,Jt=/^\+?[1-9]\d*$/;class Kt{static parse(t,{hmac:e}={}){let s;try{s=t.match(Xt)}catch(t){}if(!Array.isArray(s))throw new URIError("Invalid URI format");const i=s[1].toLowerCase(),r=s[2].split(/(?::|%3A) *(.+)/i,2).map(decodeURIComponent),n=s[3].split("&").reduce((t,e)=>{const s=e.split(/=(.*)/,2).map(decodeURIComponent),i=s[0].toLowerCase(),r=s[1],n=t;return n[i]=r,n},{});let o;const h={};if("hotp"===i){if(o=Mt,void 0===n.counter||!zt.test(n.counter))throw new TypeError("Missing or invalid 'counter' parameter");h.counter=parseInt(n.counter,10)}else{if("totp"!==i)throw new TypeError("Unknown OTP type");if(o=Rt,void 0!==n.period){if(!Jt.test(n.period))throw new TypeError("Invalid 'period' parameter");h.period=parseInt(n.period,10)}}if(void 0!==n.issuer&&(h.issuer=n.issuer),2===r.length?(h.label=r[1],void 0===h.issuer||""===h.issuer?h.issuer=r[0]:""===r[0]&&(h.issuerInLabel=!1)):(h.label=r[0],void 0!==h.issuer&&""!==h.issuer&&(h.issuerInLabel=!1)),void 0===n.secret||!Nt.test(n.secret))throw new TypeError("Missing or invalid 'secret' parameter");if(h.secret=n.secret,
void 0!==n.algorithm){if(!(e?Vt:Zt).test(n.algorithm))throw new TypeError("Invalid 'algorithm' parameter");h.algorithm=n.algorithm}if(void 0!==n.digits){if(!Jt.test(n.digits))throw new TypeError("Invalid 'digits' parameter");h.digits=parseInt(n.digits,10)}return void 0!==e&&(h.hmac=e),new o(h)}static stringify(t){if(t instanceof Mt||t instanceof Rt)return t.toString();throw new TypeError("Invalid 'HOTP/TOTP' object")}}const Qt="9.5.0";export{Mt as HOTP,jt as Secret,Rt as TOTP,Kt as URI,Qt as version};
//# sourceMappingURL=otpauth.esm.min.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,919 @@
//! otpauth 9.5.0 | (c) Héctor Molinero Fernández | MIT | https://github.com/hectorm/otpauth
/// <reference types="./otpauth.d.ts" />
// @ts-nocheck
'use strict';
var crypto = require('node:crypto');
function _interopNamespaceDefault(e) {
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n.default = e;
return Object.freeze(n);
}
var crypto__namespace = /*#__PURE__*/_interopNamespaceDefault(crypto);
/**
* Converts an integer to an Uint8Array.
* @param {number} num Integer.
* @returns {Uint8Array} Uint8Array.
*/ const uintDecode = (num)=>{
const buf = new ArrayBuffer(8);
const arr = new Uint8Array(buf);
let acc = num;
for(let i = 7; i >= 0; i--){
if (acc === 0) break;
arr[i] = acc & 255;
acc -= arr[i];
acc /= 256;
}
return arr;
};
/**
* "globalThis" ponyfill.
* @see [A horrifying globalThis polyfill in universal JavaScript](https://mathiasbynens.be/notes/globalthis)
* @type {Object.<string, *>}
*/ const globalScope = (()=>{
if (typeof globalThis === "object") return globalThis;
else {
Object.defineProperty(Object.prototype, "__GLOBALTHIS__", {
get () {
return this;
},
configurable: true
});
try {
// @ts-expect-error
// eslint-disable-next-line no-undef
if (typeof __GLOBALTHIS__ !== "undefined") return __GLOBALTHIS__;
} finally{
// @ts-expect-error
delete Object.prototype.__GLOBALTHIS__;
}
}
// Still unable to determine "globalThis", fall back to a naive method.
if (typeof self !== "undefined") return self;
else if (typeof window !== "undefined") return window;
else if (typeof global !== "undefined") return global;
return undefined;
})();
/**
* Canonicalizes a hash algorithm name.
* @param {string} algorithm Hash algorithm name.
* @returns {"SHA1"|"SHA224"|"SHA256"|"SHA384"|"SHA512"|"SHA3-224"|"SHA3-256"|"SHA3-384"|"SHA3-512"} Canonicalized hash algorithm name.
*/ const canonicalizeAlgorithm = (algorithm)=>{
switch(true){
case /^(?:SHA-?1|SSL3-SHA1)$/i.test(algorithm):
return "SHA1";
case /^SHA(?:2?-)?224$/i.test(algorithm):
return "SHA224";
case /^SHA(?:2?-)?256$/i.test(algorithm):
return "SHA256";
case /^SHA(?:2?-)?384$/i.test(algorithm):
return "SHA384";
case /^SHA(?:2?-)?512$/i.test(algorithm):
return "SHA512";
case /^SHA3-224$/i.test(algorithm):
return "SHA3-224";
case /^SHA3-256$/i.test(algorithm):
return "SHA3-256";
case /^SHA3-384$/i.test(algorithm):
return "SHA3-384";
case /^SHA3-512$/i.test(algorithm):
return "SHA3-512";
default:
throw new TypeError(`Unknown hash algorithm: ${algorithm}`);
}
};
/**
* Calculates an HMAC digest.
* @param {string} algorithm Algorithm.
* @param {Uint8Array} key Key.
* @param {Uint8Array} message Message.
* @returns {Uint8Array} Digest.
*/ const hmacDigest = (algorithm, key, message)=>{
if (crypto__namespace?.createHmac) {
const hmac = crypto__namespace.createHmac(algorithm, globalScope.Buffer.from(key));
hmac.update(globalScope.Buffer.from(message));
return hmac.digest();
} else {
throw new Error("Missing HMAC function");
}
};
/**
* RFC 4648 base32 alphabet without pad.
* @type {string}
*/ const ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
/**
* Converts a base32 string to an Uint8Array (RFC 4648).
* @see [LinusU/base32-decode](https://github.com/LinusU/base32-decode)
* @param {string} str Base32 string.
* @returns {Uint8Array} Uint8Array.
*/ const base32Decode = (str)=>{
// Remove spaces (although they are not allowed by the spec, some issuers add them for readability).
str = str.replace(/ /g, "");
// Canonicalize to all upper case and remove padding if it exists.
let end = str.length;
while(str[end - 1] === "=")--end;
str = (end < str.length ? str.substring(0, end) : str).toUpperCase();
const buf = new ArrayBuffer(str.length * 5 / 8 | 0);
const arr = new Uint8Array(buf);
let bits = 0;
let value = 0;
let index = 0;
for(let i = 0; i < str.length; i++){
const idx = ALPHABET.indexOf(str[i]);
if (idx === -1) throw new TypeError(`Invalid character found: ${str[i]}`);
value = value << 5 | idx;
bits += 5;
if (bits >= 8) {
bits -= 8;
arr[index++] = value >>> bits;
}
}
return arr;
};
/**
* Converts an Uint8Array to a base32 string (RFC 4648).
* @see [LinusU/base32-encode](https://github.com/LinusU/base32-encode)
* @param {Uint8Array} arr Uint8Array.
* @returns {string} Base32 string.
*/ const base32Encode = (arr)=>{
let bits = 0;
let value = 0;
let str = "";
for(let i = 0; i < arr.length; i++){
value = value << 8 | arr[i];
bits += 8;
while(bits >= 5){
str += ALPHABET[value >>> bits - 5 & 31];
bits -= 5;
}
}
if (bits > 0) {
str += ALPHABET[value << 5 - bits & 31];
}
return str;
};
/**
* Converts a hexadecimal string to an Uint8Array.
* @param {string} str Hexadecimal string.
* @returns {Uint8Array} Uint8Array.
*/ const hexDecode = (str)=>{
// Remove spaces (although they are not allowed by the spec, some issuers add them for readability).
str = str.replace(/ /g, "");
const buf = new ArrayBuffer(str.length / 2);
const arr = new Uint8Array(buf);
for(let i = 0; i < str.length; i += 2){
arr[i / 2] = parseInt(str.substring(i, i + 2), 16);
}
return arr;
};
/**
* Converts an Uint8Array to a hexadecimal string.
* @param {Uint8Array} arr Uint8Array.
* @returns {string} Hexadecimal string.
*/ const hexEncode = (arr)=>{
let str = "";
for(let i = 0; i < arr.length; i++){
const hex = arr[i].toString(16);
if (hex.length === 1) str += "0";
str += hex;
}
return str.toUpperCase();
};
/**
* Converts a Latin-1 string to an Uint8Array.
* @param {string} str Latin-1 string.
* @returns {Uint8Array} Uint8Array.
*/ const latin1Decode = (str)=>{
const buf = new ArrayBuffer(str.length);
const arr = new Uint8Array(buf);
for(let i = 0; i < str.length; i++){
arr[i] = str.charCodeAt(i) & 0xff;
}
return arr;
};
/**
* Converts an Uint8Array to a Latin-1 string.
* @param {Uint8Array} arr Uint8Array.
* @returns {string} Latin-1 string.
*/ const latin1Encode = (arr)=>{
let str = "";
for(let i = 0; i < arr.length; i++){
str += String.fromCharCode(arr[i]);
}
return str;
};
/**
* TextEncoder instance.
* @type {TextEncoder|null}
*/ const ENCODER = globalScope.TextEncoder ? new globalScope.TextEncoder() : null;
/**
* TextDecoder instance.
* @type {TextDecoder|null}
*/ const DECODER = globalScope.TextDecoder ? new globalScope.TextDecoder() : null;
/**
* Converts an UTF-8 string to an Uint8Array.
* @param {string} str String.
* @returns {Uint8Array} Uint8Array.
*/ const utf8Decode = (str)=>{
if (!ENCODER) {
throw new Error("Encoding API not available");
}
return ENCODER.encode(str);
};
/**
* Converts an Uint8Array to an UTF-8 string.
* @param {Uint8Array} arr Uint8Array.
* @returns {string} String.
*/ const utf8Encode = (arr)=>{
if (!DECODER) {
throw new Error("Encoding API not available");
}
return DECODER.decode(arr);
};
/**
* Returns random bytes.
* @param {number} size Size.
* @returns {Uint8Array} Random bytes.
*/ const randomBytes = (size)=>{
if (crypto__namespace?.randomBytes) {
return crypto__namespace.randomBytes(size);
} else if (globalScope.crypto?.getRandomValues) {
return globalScope.crypto.getRandomValues(new Uint8Array(size));
} else {
throw new Error("Cryptography API not available");
}
};
/**
* OTP secret key.
*/ class Secret {
/**
* Converts a Latin-1 string to a Secret object.
* @param {string} str Latin-1 string.
* @returns {Secret} Secret object.
*/ static fromLatin1(str) {
return new Secret({
buffer: latin1Decode(str).buffer
});
}
/**
* Converts an UTF-8 string to a Secret object.
* @param {string} str UTF-8 string.
* @returns {Secret} Secret object.
*/ static fromUTF8(str) {
return new Secret({
buffer: utf8Decode(str).buffer
});
}
/**
* Converts a base32 string to a Secret object.
* @param {string} str Base32 string.
* @returns {Secret} Secret object.
*/ static fromBase32(str) {
return new Secret({
buffer: base32Decode(str).buffer
});
}
/**
* Converts a hexadecimal string to a Secret object.
* @param {string} str Hexadecimal string.
* @returns {Secret} Secret object.
*/ static fromHex(str) {
return new Secret({
buffer: hexDecode(str).buffer
});
}
/**
* Secret key buffer.
* @deprecated For backward compatibility, the "bytes" property should be used instead.
* @type {ArrayBufferLike}
*/ get buffer() {
return this.bytes.buffer;
}
/**
* Latin-1 string representation of secret key.
* @type {string}
*/ get latin1() {
Object.defineProperty(this, "latin1", {
enumerable: true,
writable: false,
configurable: false,
value: latin1Encode(this.bytes)
});
return this.latin1;
}
/**
* UTF-8 string representation of secret key.
* @type {string}
*/ get utf8() {
Object.defineProperty(this, "utf8", {
enumerable: true,
writable: false,
configurable: false,
value: utf8Encode(this.bytes)
});
return this.utf8;
}
/**
* Base32 string representation of secret key.
* @type {string}
*/ get base32() {
Object.defineProperty(this, "base32", {
enumerable: true,
writable: false,
configurable: false,
value: base32Encode(this.bytes)
});
return this.base32;
}
/**
* Hexadecimal string representation of secret key.
* @type {string}
*/ get hex() {
Object.defineProperty(this, "hex", {
enumerable: true,
writable: false,
configurable: false,
value: hexEncode(this.bytes)
});
return this.hex;
}
/**
* Creates a secret key object.
* @param {Object} [config] Configuration options.
* @param {ArrayBufferLike} [config.buffer] Secret key buffer.
* @param {number} [config.size=20] Number of random bytes to generate, ignored if 'buffer' is provided.
*/ constructor({ buffer, size = 20 } = {}){
/**
* Secret key.
* @type {Uint8Array}
* @readonly
*/ this.bytes = typeof buffer === "undefined" ? randomBytes(size) : new Uint8Array(buffer);
// Prevent the "bytes" property from being modified.
Object.defineProperty(this, "bytes", {
enumerable: true,
writable: false,
configurable: false,
value: this.bytes
});
}
}
/**
* Returns true if a is equal to b, without leaking timing information that would allow an attacker to guess one of the values.
* @param {string} a String a.
* @param {string} b String b.
* @returns {boolean} Equality result.
*/ const timingSafeEqual = (a, b)=>{
if (crypto__namespace?.timingSafeEqual) {
return crypto__namespace.timingSafeEqual(globalScope.Buffer.from(a), globalScope.Buffer.from(b));
} else {
if (a.length !== b.length) {
throw new TypeError("Input strings must have the same length");
}
let i = -1;
let out = 0;
while(++i < a.length){
out |= a.charCodeAt(i) ^ b.charCodeAt(i);
}
return out === 0;
}
};
/**
* HOTP: An HMAC-based One-time Password Algorithm.
* @see [RFC 4226](https://datatracker.ietf.org/doc/html/rfc4226)
*/ class HOTP {
/**
* Default configuration.
* @type {{
* issuer: string,
* label: string,
* issuerInLabel: boolean,
* algorithm: string,
* digits: number,
* counter: number
* window: number
* }}
*/ static get defaults() {
return {
issuer: "",
label: "OTPAuth",
issuerInLabel: true,
algorithm: "SHA1",
digits: 6,
counter: 0,
window: 1
};
}
/**
* Generates an HOTP token.
* @param {Object} config Configuration options.
* @param {Secret} config.secret Secret key.
* @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
* @param {number} [config.digits=6] Token length.
* @param {number} [config.counter=0] Counter value.
* @param {(algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array} [config.hmac] Custom HMAC function.
* @returns {string} Token.
*/ static generate({ secret, algorithm = HOTP.defaults.algorithm, digits = HOTP.defaults.digits, counter = HOTP.defaults.counter, hmac = hmacDigest }) {
const message = uintDecode(counter);
const digest = hmac(algorithm, secret.bytes, message);
if (!digest?.byteLength || digest.byteLength < 19) {
throw new TypeError("Return value must be at least 19 bytes");
}
const offset = digest[digest.byteLength - 1] & 15;
const otp = ((digest[offset] & 127) << 24 | (digest[offset + 1] & 255) << 16 | (digest[offset + 2] & 255) << 8 | digest[offset + 3] & 255) % 10 ** digits;
return otp.toString().padStart(digits, "0");
}
/**
* Generates an HOTP token.
* @param {Object} [config] Configuration options.
* @param {number} [config.counter=this.counter++] Counter value.
* @returns {string} Token.
*/ generate({ counter = this.counter++ } = {}) {
return HOTP.generate({
secret: this.secret,
algorithm: this.algorithm,
digits: this.digits,
counter,
hmac: this.hmac
});
}
/**
* Validates an HOTP token.
* @param {Object} config Configuration options.
* @param {string} config.token Token value.
* @param {Secret} config.secret Secret key.
* @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
* @param {number} [config.digits=6] Token length.
* @param {number} [config.counter=0] Counter value.
* @param {number} [config.window=1] Window of counter values to test.
* @param {(algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array} [config.hmac] Custom HMAC function.
* @returns {number|null} Token delta or null if it is not found in the search window, in which case it should be considered invalid.
*/ static validate({ token, secret, algorithm, digits = HOTP.defaults.digits, counter = HOTP.defaults.counter, window = HOTP.defaults.window, hmac = hmacDigest }) {
// Return early if the token length does not match the digit number.
if (token.length !== digits) return null;
let delta = null;
const check = (/** @type {number} */ i)=>{
const generatedToken = HOTP.generate({
secret,
algorithm,
digits,
counter: i,
hmac
});
if (timingSafeEqual(token, generatedToken)) {
delta = i - counter;
}
};
check(counter);
for(let i = 1; i <= window && delta === null; ++i){
check(counter - i);
if (delta !== null) break;
check(counter + i);
if (delta !== null) break;
}
return delta;
}
/**
* Validates an HOTP token.
* @param {Object} config Configuration options.
* @param {string} config.token Token value.
* @param {number} [config.counter=this.counter] Counter value.
* @param {number} [config.window=1] Window of counter values to test.
* @returns {number|null} Token delta or null if it is not found in the search window, in which case it should be considered invalid.
*/ validate({ token, counter = this.counter, window }) {
return HOTP.validate({
token,
secret: this.secret,
algorithm: this.algorithm,
digits: this.digits,
counter,
window,
hmac: this.hmac
});
}
/**
* Returns a Google Authenticator key URI.
* @returns {string} URI.
*/ toString() {
const e = encodeURIComponent;
return "otpauth://hotp/" + `${this.issuer.length > 0 ? this.issuerInLabel ? `${e(this.issuer)}:${e(this.label)}?issuer=${e(this.issuer)}&` : `${e(this.label)}?issuer=${e(this.issuer)}&` : `${e(this.label)}?`}` + `secret=${e(this.secret.base32)}&` + `algorithm=${e(this.algorithm)}&` + `digits=${e(this.digits)}&` + `counter=${e(this.counter)}`;
}
/**
* Creates an HOTP object.
* @param {Object} [config] Configuration options.
* @param {string} [config.issuer=''] Account provider.
* @param {string} [config.label='OTPAuth'] Account label.
* @param {boolean} [config.issuerInLabel=true] Include issuer prefix in label.
* @param {Secret|string} [config.secret=Secret] Secret key.
* @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
* @param {number} [config.digits=6] Token length.
* @param {number} [config.counter=0] Initial counter value.
* @param {(algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array} [config.hmac] Custom HMAC function.
*/ constructor({ issuer = HOTP.defaults.issuer, label = HOTP.defaults.label, issuerInLabel = HOTP.defaults.issuerInLabel, secret = new Secret(), algorithm = HOTP.defaults.algorithm, digits = HOTP.defaults.digits, counter = HOTP.defaults.counter, hmac } = {}){
/**
* Account provider.
* @type {string}
*/ this.issuer = issuer;
/**
* Account label.
* @type {string}
*/ this.label = label;
/**
* Include issuer prefix in label.
* @type {boolean}
*/ this.issuerInLabel = issuerInLabel;
/**
* Secret key.
* @type {Secret}
*/ this.secret = typeof secret === "string" ? Secret.fromBase32(secret) : secret;
/**
* HMAC hashing algorithm.
* @type {string}
*/ this.algorithm = hmac ? algorithm : canonicalizeAlgorithm(algorithm);
/**
* Token length.
* @type {number}
*/ this.digits = digits;
/**
* Initial counter value.
* @type {number}
*/ this.counter = counter;
/**
* Custom HMAC function.
* @type {((algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array)|undefined}
*/ this.hmac = hmac;
}
}
/**
* TOTP: Time-Based One-Time Password Algorithm.
* @see [RFC 6238](https://datatracker.ietf.org/doc/html/rfc6238)
*/ class TOTP {
/**
* Default configuration.
* @type {{
* issuer: string,
* label: string,
* issuerInLabel: boolean,
* algorithm: string,
* digits: number,
* period: number
* window: number
* }}
*/ static get defaults() {
return {
issuer: "",
label: "OTPAuth",
issuerInLabel: true,
algorithm: "SHA1",
digits: 6,
period: 30,
window: 1
};
}
/**
* Calculates the counter. i.e. the number of periods since timestamp 0.
* @param {Object} [config] Configuration options.
* @param {number} [config.period=30] Token time-step duration.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @returns {number} Counter.
*/ static counter({ period = TOTP.defaults.period, timestamp = Date.now() } = {}) {
return Math.floor(timestamp / 1000 / period);
}
/**
* Calculates the counter. i.e. the number of periods since timestamp 0.
* @param {Object} [config] Configuration options.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @returns {number} Counter.
*/ counter({ timestamp = Date.now() } = {}) {
return TOTP.counter({
period: this.period,
timestamp
});
}
/**
* Calculates the remaining time in milliseconds until the next token is generated.
* @param {Object} [config] Configuration options.
* @param {number} [config.period=30] Token time-step duration.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @returns {number} counter.
*/ static remaining({ period = TOTP.defaults.period, timestamp = Date.now() } = {}) {
return period * 1000 - timestamp % (period * 1000);
}
/**
* Calculates the remaining time in milliseconds until the next token is generated.
* @param {Object} [config] Configuration options.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @returns {number} counter.
*/ remaining({ timestamp = Date.now() } = {}) {
return TOTP.remaining({
period: this.period,
timestamp
});
}
/**
* Generates a TOTP token.
* @param {Object} config Configuration options.
* @param {Secret} config.secret Secret key.
* @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
* @param {number} [config.digits=6] Token length.
* @param {number} [config.period=30] Token time-step duration.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @param {(algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array} [config.hmac] Custom HMAC function.
* @returns {string} Token.
*/ static generate({ secret, algorithm, digits, period = TOTP.defaults.period, timestamp = Date.now(), hmac }) {
return HOTP.generate({
secret,
algorithm,
digits,
counter: TOTP.counter({
period,
timestamp
}),
hmac
});
}
/**
* Generates a TOTP token.
* @param {Object} [config] Configuration options.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @returns {string} Token.
*/ generate({ timestamp = Date.now() } = {}) {
return TOTP.generate({
secret: this.secret,
algorithm: this.algorithm,
digits: this.digits,
period: this.period,
timestamp,
hmac: this.hmac
});
}
/**
* Validates a TOTP token.
* @param {Object} config Configuration options.
* @param {string} config.token Token value.
* @param {Secret} config.secret Secret key.
* @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
* @param {number} [config.digits=6] Token length.
* @param {number} [config.period=30] Token time-step duration.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @param {number} [config.window=1] Window of counter values to test.
* @param {(algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array} [config.hmac] Custom HMAC function.
* @returns {number|null} Token delta or null if it is not found in the search window, in which case it should be considered invalid.
*/ static validate({ token, secret, algorithm, digits, period = TOTP.defaults.period, timestamp = Date.now(), window, hmac }) {
return HOTP.validate({
token,
secret,
algorithm,
digits,
counter: TOTP.counter({
period,
timestamp
}),
window,
hmac
});
}
/**
* Validates a TOTP token.
* @param {Object} config Configuration options.
* @param {string} config.token Token value.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @param {number} [config.window=1] Window of counter values to test.
* @returns {number|null} Token delta or null if it is not found in the search window, in which case it should be considered invalid.
*/ validate({ token, timestamp, window }) {
return TOTP.validate({
token,
secret: this.secret,
algorithm: this.algorithm,
digits: this.digits,
period: this.period,
timestamp,
window,
hmac: this.hmac
});
}
/**
* Returns a Google Authenticator key URI.
* @returns {string} URI.
*/ toString() {
const e = encodeURIComponent;
return "otpauth://totp/" + `${this.issuer.length > 0 ? this.issuerInLabel ? `${e(this.issuer)}:${e(this.label)}?issuer=${e(this.issuer)}&` : `${e(this.label)}?issuer=${e(this.issuer)}&` : `${e(this.label)}?`}` + `secret=${e(this.secret.base32)}&` + `algorithm=${e(this.algorithm)}&` + `digits=${e(this.digits)}&` + `period=${e(this.period)}`;
}
/**
* Creates a TOTP object.
* @param {Object} [config] Configuration options.
* @param {string} [config.issuer=''] Account provider.
* @param {string} [config.label='OTPAuth'] Account label.
* @param {boolean} [config.issuerInLabel=true] Include issuer prefix in label.
* @param {Secret|string} [config.secret=Secret] Secret key.
* @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
* @param {number} [config.digits=6] Token length.
* @param {number} [config.period=30] Token time-step duration.
* @param {(algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array} [config.hmac] Custom HMAC function.
*/ constructor({ issuer = TOTP.defaults.issuer, label = TOTP.defaults.label, issuerInLabel = TOTP.defaults.issuerInLabel, secret = new Secret(), algorithm = TOTP.defaults.algorithm, digits = TOTP.defaults.digits, period = TOTP.defaults.period, hmac } = {}){
/**
* Account provider.
* @type {string}
*/ this.issuer = issuer;
/**
* Account label.
* @type {string}
*/ this.label = label;
/**
* Include issuer prefix in label.
* @type {boolean}
*/ this.issuerInLabel = issuerInLabel;
/**
* Secret key.
* @type {Secret}
*/ this.secret = typeof secret === "string" ? Secret.fromBase32(secret) : secret;
/**
* HMAC hashing algorithm.
* @type {string}
*/ this.algorithm = hmac ? algorithm : canonicalizeAlgorithm(algorithm);
/**
* Token length.
* @type {number}
*/ this.digits = digits;
/**
* Token time-step duration.
* @type {number}
*/ this.period = period;
/**
* Custom HMAC function.
* @type {((algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array)|undefined}
*/ this.hmac = hmac;
}
}
/**
* Key URI regex (otpauth://TYPE/[ISSUER:]LABEL?PARAMETERS).
* @type {RegExp}
*/ const OTPURI_REGEX = /^otpauth:\/\/([ht]otp)\/(.+)\?([A-Z0-9.~_-]+=[^?&]*(?:&[A-Z0-9.~_-]+=[^?&]*)*)$/i;
/**
* RFC 4648 base32 alphabet with pad.
* @type {RegExp}
*/ const SECRET_REGEX = /^[2-7A-Z]+=*$/i;
/**
* Regex for supported algorithms in built-in HMAC function.
* @type {RegExp}
*/ const ALGORITHM_REGEX = /^SHA(?:1|224|256|384|512|3-224|3-256|3-384|3-512)$/i;
/**
* Regex for custom algorithms in user-defined HMAC function.
* @type {RegExp}
*/ const ALGORITHM_CUSTOM_REGEX = /^[A-Z0-9]+(?:[_-][A-Z0-9]+)*$/i;
/**
* Integer regex.
* @type {RegExp}
*/ const INTEGER_REGEX = /^[+-]?\d+$/;
/**
* Positive integer regex.
* @type {RegExp}
*/ const POSITIVE_INTEGER_REGEX = /^\+?[1-9]\d*$/;
/**
* HOTP/TOTP object/string conversion.
* @see [Key URI Format](https://github.com/google/google-authenticator/wiki/Key-Uri-Format)
*/ class URI {
/**
* Parses a Google Authenticator key URI and returns an HOTP/TOTP object.
* @param {string} uri Google Authenticator Key URI.
* @param {Object} [config] Configuration options.
* @param {(algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array} [config.hmac] Custom HMAC function.
* @returns {HOTP|TOTP} HOTP/TOTP object.
*/ static parse(uri, { hmac } = {}) {
let uriGroups;
try {
uriGroups = uri.match(OTPURI_REGEX);
// eslint-disable-next-line no-unused-vars
} catch (_) {
/* Handled below */ }
if (!Array.isArray(uriGroups)) {
throw new URIError("Invalid URI format");
}
// Extract URI groups.
const uriType = uriGroups[1].toLowerCase();
const uriLabel = uriGroups[2].split(/(?::|%3A) *(.+)/i, 2).map(decodeURIComponent);
/** @type {Object.<string, string>} */ const uriParams = uriGroups[3].split("&").reduce((acc, cur)=>{
const pairArr = cur.split(/=(.*)/, 2).map(decodeURIComponent);
const pairKey = pairArr[0].toLowerCase();
const pairVal = pairArr[1];
/** @type {Object.<string, string>} */ const pairAcc = acc;
pairAcc[pairKey] = pairVal;
return pairAcc;
}, {});
// 'OTP' will be instantiated with 'config' argument.
let OTP;
const config = {};
if (uriType === "hotp") {
OTP = HOTP;
// Counter: required
if (typeof uriParams.counter !== "undefined" && INTEGER_REGEX.test(uriParams.counter)) {
config.counter = parseInt(uriParams.counter, 10);
} else {
throw new TypeError("Missing or invalid 'counter' parameter");
}
} else if (uriType === "totp") {
OTP = TOTP;
// Period: optional
if (typeof uriParams.period !== "undefined") {
if (POSITIVE_INTEGER_REGEX.test(uriParams.period)) {
config.period = parseInt(uriParams.period, 10);
} else {
throw new TypeError("Invalid 'period' parameter");
}
}
} else {
throw new TypeError("Unknown OTP type");
}
// Label: required
// Issuer: optional
if (typeof uriParams.issuer !== "undefined") {
config.issuer = uriParams.issuer;
}
if (uriLabel.length === 2) {
config.label = uriLabel[1];
if (typeof config.issuer === "undefined" || config.issuer === "") {
config.issuer = uriLabel[0];
} else if (uriLabel[0] === "") {
config.issuerInLabel = false;
}
} else {
config.label = uriLabel[0];
if (typeof config.issuer !== "undefined" && config.issuer !== "") {
config.issuerInLabel = false;
}
}
// Secret: required
if (typeof uriParams.secret !== "undefined" && SECRET_REGEX.test(uriParams.secret)) {
config.secret = uriParams.secret;
} else {
throw new TypeError("Missing or invalid 'secret' parameter");
}
// Algorithm: optional
if (typeof uriParams.algorithm !== "undefined") {
if ((hmac ? ALGORITHM_CUSTOM_REGEX : ALGORITHM_REGEX).test(uriParams.algorithm)) {
config.algorithm = uriParams.algorithm;
} else {
throw new TypeError("Invalid 'algorithm' parameter");
}
}
// Digits: optional
if (typeof uriParams.digits !== "undefined") {
if (POSITIVE_INTEGER_REGEX.test(uriParams.digits)) {
config.digits = parseInt(uriParams.digits, 10);
} else {
throw new TypeError("Invalid 'digits' parameter");
}
}
// HMAC: optional
if (typeof hmac !== "undefined") {
config.hmac = hmac;
}
return new OTP(config);
}
/**
* Converts an HOTP/TOTP object to a Google Authenticator key URI.
* @param {HOTP|TOTP} otp HOTP/TOTP object.
* @returns {string} Google Authenticator Key URI.
*/ static stringify(otp) {
if (otp instanceof HOTP || otp instanceof TOTP) {
return otp.toString();
}
throw new TypeError("Invalid 'HOTP/TOTP' object");
}
}
/**
* Library version.
* @type {string}
*/ const version = "9.5.0";
exports.HOTP = HOTP;
exports.Secret = Secret;
exports.TOTP = TOTP;
exports.URI = URI;
exports.version = version;

View File

@@ -0,0 +1,9 @@
//! otpauth 9.5.0 | (c) Héctor Molinero Fernández | MIT | https://github.com/hectorm/otpauth
/// <reference types="./otpauth.d.ts" />
// @ts-nocheck
"use strict";function e(e){var t=Object.create(null);return e&&Object.keys(e).forEach(function(r){if("default"!==r){var i=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,i.get?i:{enumerable:!0,get:function(){return e[r]}})}}),t.default=e,Object.freeze(t)}var t=e(require("node:crypto"));const r=(()=>{if("object"==typeof globalThis)return globalThis;Object.defineProperty(Object.prototype,"__GLOBALTHIS__",{get(){return this},configurable:!0});try{if("undefined"!=typeof __GLOBALTHIS__)return __GLOBALTHIS__}finally{delete Object.prototype.__GLOBALTHIS__}return"undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:void 0})(),i=e=>{switch(!0){case/^(?:SHA-?1|SSL3-SHA1)$/i.test(e):return"SHA1";case/^SHA(?:2?-)?224$/i.test(e):return"SHA224";case/^SHA(?:2?-)?256$/i.test(e):return"SHA256";case/^SHA(?:2?-)?384$/i.test(e):return"SHA384";case/^SHA(?:2?-)?512$/i.test(e):return"SHA512";case/^SHA3-224$/i.test(e):return"SHA3-224";case/^SHA3-256$/i.test(e):return"SHA3-256";case/^SHA3-384$/i.test(e):return"SHA3-384";case/^SHA3-512$/i.test(e):return"SHA3-512";default:throw new TypeError(`Unknown hash algorithm: ${e}`)}},s=(e,i,s)=>{if(t?.createHmac){const n=t.createHmac(e,r.Buffer.from(i));return n.update(r.Buffer.from(s)),n.digest()}throw new Error("Missing HMAC function")},n="ABCDEFGHIJKLMNOPQRSTUVWXYZ234567",a=e=>{let t=(e=e.replace(/ /g,"")).length;for(;"="===e[t-1];)--t;e=(t<e.length?e.substring(0,t):e).toUpperCase();const r=new ArrayBuffer(5*e.length/8|0),i=new Uint8Array(r);let s=0,a=0,o=0;for(let t=0;t<e.length;t++){const r=n.indexOf(e[t]);if(-1===r)throw new TypeError(`Invalid character found: ${e[t]}`);a=a<<5|r,s+=5,s>=8&&(s-=8,i[o++]=a>>>s)}return i},o=e=>{let t=0,r=0,i="";for(let s=0;s<e.length;s++)for(r=r<<8|e[s],t+=8;t>=5;)i+=n[r>>>t-5&31],t-=5;return t>0&&(i+=n[r<<5-t&31]),i},l=e=>{e=e.replace(/ /g,"");const t=new ArrayBuffer(e.length/2),r=new Uint8Array(t);for(let t=0;t<e.length;t+=2)r[t/2]=parseInt(e.substring(t,t+2),16);return r},u=e=>{let t=""
;for(let r=0;r<e.length;r++){const i=e[r].toString(16);1===i.length&&(t+="0"),t+=i}return t.toUpperCase()},h=e=>{const t=new ArrayBuffer(e.length),r=new Uint8Array(t);for(let t=0;t<e.length;t++)r[t]=255&e.charCodeAt(t);return r},c=e=>{let t="";for(let r=0;r<e.length;r++)t+=String.fromCharCode(e[r]);return t},d=r.TextEncoder?new r.TextEncoder:null,f=r.TextDecoder?new r.TextDecoder:null,g=e=>{if(!d)throw new Error("Encoding API not available");return d.encode(e)},m=e=>{if(!f)throw new Error("Encoding API not available");return f.decode(e)};class p{static fromLatin1(e){return new p({buffer:h(e).buffer})}static fromUTF8(e){return new p({buffer:g(e).buffer})}static fromBase32(e){return new p({buffer:a(e).buffer})}static fromHex(e){return new p({buffer:l(e).buffer})}get buffer(){return this.bytes.buffer}get latin1(){return Object.defineProperty(this,"latin1",{enumerable:!0,writable:!1,configurable:!1,value:c(this.bytes)}),this.latin1}get utf8(){return Object.defineProperty(this,"utf8",{enumerable:!0,writable:!1,configurable:!1,value:m(this.bytes)}),this.utf8}get base32(){return Object.defineProperty(this,"base32",{enumerable:!0,writable:!1,configurable:!1,value:o(this.bytes)}),this.base32}get hex(){return Object.defineProperty(this,"hex",{enumerable:!0,writable:!1,configurable:!1,value:u(this.bytes)}),this.hex}constructor({buffer:e,size:i=20}={}){this.bytes=void 0===e?(e=>{if(t?.randomBytes)return t.randomBytes(e);if(r.crypto?.getRandomValues)return r.crypto.getRandomValues(new Uint8Array(e));throw new Error("Cryptography API not available")})(i):new Uint8Array(e),Object.defineProperty(this,"bytes",{enumerable:!0,writable:!1,configurable:!1,value:this.bytes})}}class b{static get defaults(){return{issuer:"",label:"OTPAuth",issuerInLabel:!0,algorithm:"SHA1",digits:6,counter:0,window:1}}static generate({secret:e,algorithm:t=b.defaults.algorithm,digits:r=b.defaults.digits,counter:i=b.defaults.counter,hmac:n=s}){const a=(e=>{const t=new ArrayBuffer(8),r=new Uint8Array(t);let i=e;for(let e=7;e>=0&&0!==i;e--)r[e]=255&i,
i-=r[e],i/=256;return r})(i),o=n(t,e.bytes,a);if(!o?.byteLength||o.byteLength<19)throw new TypeError("Return value must be at least 19 bytes");const l=15&o[o.byteLength-1];return(((127&o[l])<<24|(255&o[l+1])<<16|(255&o[l+2])<<8|255&o[l+3])%10**r).toString().padStart(r,"0")}generate({counter:e=this.counter++}={}){return b.generate({secret:this.secret,algorithm:this.algorithm,digits:this.digits,counter:e,hmac:this.hmac})}static validate({token:e,secret:i,algorithm:n,digits:a=b.defaults.digits,counter:o=b.defaults.counter,window:l=b.defaults.window,hmac:u=s}){if(e.length!==a)return null;let h=null;const c=s=>{const l=b.generate({secret:i,algorithm:n,digits:a,counter:s,hmac:u});((e,i)=>{if(t?.timingSafeEqual)return t.timingSafeEqual(r.Buffer.from(e),r.Buffer.from(i));{if(e.length!==i.length)throw new TypeError("Input strings must have the same length");let t=-1,r=0;for(;++t<e.length;)r|=e.charCodeAt(t)^i.charCodeAt(t);return 0===r}})(e,l)&&(h=s-o)};c(o);for(let e=1;e<=l&&null===h&&(c(o-e),null===h)&&(c(o+e),null===h);++e);return h}validate({token:e,counter:t=this.counter,window:r}){return b.validate({token:e,secret:this.secret,algorithm:this.algorithm,digits:this.digits,counter:t,window:r,hmac:this.hmac})}toString(){const e=encodeURIComponent;return"otpauth://hotp/"+(this.issuer.length>0?this.issuerInLabel?`${e(this.issuer)}:${e(this.label)}?issuer=${e(this.issuer)}&`:`${e(this.label)}?issuer=${e(this.issuer)}&`:`${e(this.label)}?`)+`secret=${e(this.secret.base32)}&`+`algorithm=${e(this.algorithm)}&`+`digits=${e(this.digits)}&`+`counter=${e(this.counter)}`}constructor({issuer:e=b.defaults.issuer,label:t=b.defaults.label,issuerInLabel:r=b.defaults.issuerInLabel,secret:s=new p,algorithm:n=b.defaults.algorithm,digits:a=b.defaults.digits,counter:o=b.defaults.counter,hmac:l}={}){this.issuer=e,this.label=t,this.issuerInLabel=r,this.secret="string"==typeof s?p.fromBase32(s):s,this.algorithm=l?n:i(n),this.digits=a,this.counter=o,this.hmac=l}}class w{static get defaults(){return{issuer:"",label:"OTPAuth",issuerInLabel:!0,
algorithm:"SHA1",digits:6,period:30,window:1}}static counter({period:e=w.defaults.period,timestamp:t=Date.now()}={}){return Math.floor(t/1e3/e)}counter({timestamp:e=Date.now()}={}){return w.counter({period:this.period,timestamp:e})}static remaining({period:e=w.defaults.period,timestamp:t=Date.now()}={}){return 1e3*e-t%(1e3*e)}remaining({timestamp:e=Date.now()}={}){return w.remaining({period:this.period,timestamp:e})}static generate({secret:e,algorithm:t,digits:r,period:i=w.defaults.period,timestamp:s=Date.now(),hmac:n}){return b.generate({secret:e,algorithm:t,digits:r,counter:w.counter({period:i,timestamp:s}),hmac:n})}generate({timestamp:e=Date.now()}={}){return w.generate({secret:this.secret,algorithm:this.algorithm,digits:this.digits,period:this.period,timestamp:e,hmac:this.hmac})}static validate({token:e,secret:t,algorithm:r,digits:i,period:s=w.defaults.period,timestamp:n=Date.now(),window:a,hmac:o}){return b.validate({token:e,secret:t,algorithm:r,digits:i,counter:w.counter({period:s,timestamp:n}),window:a,hmac:o})}validate({token:e,timestamp:t,window:r}){return w.validate({token:e,secret:this.secret,algorithm:this.algorithm,digits:this.digits,period:this.period,timestamp:t,window:r,hmac:this.hmac})}toString(){const e=encodeURIComponent;return"otpauth://totp/"+(this.issuer.length>0?this.issuerInLabel?`${e(this.issuer)}:${e(this.label)}?issuer=${e(this.issuer)}&`:`${e(this.label)}?issuer=${e(this.issuer)}&`:`${e(this.label)}?`)+`secret=${e(this.secret.base32)}&`+`algorithm=${e(this.algorithm)}&`+`digits=${e(this.digits)}&`+`period=${e(this.period)}`}constructor({issuer:e=w.defaults.issuer,label:t=w.defaults.label,issuerInLabel:r=w.defaults.issuerInLabel,secret:s=new p,algorithm:n=w.defaults.algorithm,digits:a=w.defaults.digits,period:o=w.defaults.period,hmac:l}={}){this.issuer=e,this.label=t,this.issuerInLabel=r,this.secret="string"==typeof s?p.fromBase32(s):s,this.algorithm=l?n:i(n),this.digits=a,this.period=o,this.hmac=l}}
const y=/^otpauth:\/\/([ht]otp)\/(.+)\?([A-Z0-9.~_-]+=[^?&]*(?:&[A-Z0-9.~_-]+=[^?&]*)*)$/i,A=/^[2-7A-Z]+=*$/i,v=/^SHA(?:1|224|256|384|512|3-224|3-256|3-384|3-512)$/i,S=/^[A-Z0-9]+(?:[_-][A-Z0-9]+)*$/i,I=/^[+-]?\d+$/,$=/^\+?[1-9]\d*$/;exports.HOTP=b,exports.Secret=p,exports.TOTP=w,exports.URI=class{static parse(e,{hmac:t}={}){let r;try{r=e.match(y)}catch(e){}if(!Array.isArray(r))throw new URIError("Invalid URI format");const i=r[1].toLowerCase(),s=r[2].split(/(?::|%3A) *(.+)/i,2).map(decodeURIComponent),n=r[3].split("&").reduce((e,t)=>{const r=t.split(/=(.*)/,2).map(decodeURIComponent),i=r[0].toLowerCase(),s=r[1],n=e;return n[i]=s,n},{});let a;const o={};if("hotp"===i){if(a=b,void 0===n.counter||!I.test(n.counter))throw new TypeError("Missing or invalid 'counter' parameter");o.counter=parseInt(n.counter,10)}else{if("totp"!==i)throw new TypeError("Unknown OTP type");if(a=w,void 0!==n.period){if(!$.test(n.period))throw new TypeError("Invalid 'period' parameter");o.period=parseInt(n.period,10)}}if(void 0!==n.issuer&&(o.issuer=n.issuer),2===s.length?(o.label=s[1],void 0===o.issuer||""===o.issuer?o.issuer=s[0]:""===s[0]&&(o.issuerInLabel=!1)):(o.label=s[0],void 0!==o.issuer&&""!==o.issuer&&(o.issuerInLabel=!1)),void 0===n.secret||!A.test(n.secret))throw new TypeError("Missing or invalid 'secret' parameter");if(o.secret=n.secret,void 0!==n.algorithm){if(!(t?S:v).test(n.algorithm))throw new TypeError("Invalid 'algorithm' parameter");o.algorithm=n.algorithm}if(void 0!==n.digits){if(!$.test(n.digits))throw new TypeError("Invalid 'digits' parameter");o.digits=parseInt(n.digits,10)}return void 0!==t&&(o.hmac=t),new a(o)}static stringify(e){if(e instanceof b||e instanceof w)return e.toString();throw new TypeError("Invalid 'HOTP/TOTP' object")}},exports.version="9.5.0";
//# sourceMappingURL=otpauth.node.min.cjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,9 @@
//! otpauth 9.5.0 | (c) Héctor Molinero Fernández | MIT | https://github.com/hectorm/otpauth
/// <reference types="./otpauth.d.ts" />
// @ts-nocheck
import*as e from"node:crypto";const t=(()=>{if("object"==typeof globalThis)return globalThis;Object.defineProperty(Object.prototype,"__GLOBALTHIS__",{get(){return this},configurable:!0});try{if("undefined"!=typeof __GLOBALTHIS__)return __GLOBALTHIS__}finally{delete Object.prototype.__GLOBALTHIS__}return"undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:void 0})(),r=e=>{switch(!0){case/^(?:SHA-?1|SSL3-SHA1)$/i.test(e):return"SHA1";case/^SHA(?:2?-)?224$/i.test(e):return"SHA224";case/^SHA(?:2?-)?256$/i.test(e):return"SHA256";case/^SHA(?:2?-)?384$/i.test(e):return"SHA384";case/^SHA(?:2?-)?512$/i.test(e):return"SHA512";case/^SHA3-224$/i.test(e):return"SHA3-224";case/^SHA3-256$/i.test(e):return"SHA3-256";case/^SHA3-384$/i.test(e):return"SHA3-384";case/^SHA3-512$/i.test(e):return"SHA3-512";default:throw new TypeError(`Unknown hash algorithm: ${e}`)}},i=(r,i,s)=>{if(e?.createHmac){const n=e.createHmac(r,t.Buffer.from(i));return n.update(t.Buffer.from(s)),n.digest()}throw new Error("Missing HMAC function")},s="ABCDEFGHIJKLMNOPQRSTUVWXYZ234567",n=e=>{let t=(e=e.replace(/ /g,"")).length;for(;"="===e[t-1];)--t;e=(t<e.length?e.substring(0,t):e).toUpperCase();const r=new ArrayBuffer(5*e.length/8|0),i=new Uint8Array(r);let n=0,a=0,o=0;for(let t=0;t<e.length;t++){const r=s.indexOf(e[t]);if(-1===r)throw new TypeError(`Invalid character found: ${e[t]}`);a=a<<5|r,n+=5,n>=8&&(n-=8,i[o++]=a>>>n)}return i},a=e=>{let t=0,r=0,i="";for(let n=0;n<e.length;n++)for(r=r<<8|e[n],t+=8;t>=5;)i+=s[r>>>t-5&31],t-=5;return t>0&&(i+=s[r<<5-t&31]),i},o=e=>{e=e.replace(/ /g,"");const t=new ArrayBuffer(e.length/2),r=new Uint8Array(t);for(let t=0;t<e.length;t+=2)r[t/2]=parseInt(e.substring(t,t+2),16);return r},l=e=>{let t="";for(let r=0;r<e.length;r++){const i=e[r].toString(16);1===i.length&&(t+="0"),t+=i}return t.toUpperCase()},u=e=>{const t=new ArrayBuffer(e.length),r=new Uint8Array(t);for(let t=0;t<e.length;t++)r[t]=255&e.charCodeAt(t);return r},h=e=>{let t=""
;for(let r=0;r<e.length;r++)t+=String.fromCharCode(e[r]);return t},c=t.TextEncoder?new t.TextEncoder:null,d=t.TextDecoder?new t.TextDecoder:null,f=e=>{if(!c)throw new Error("Encoding API not available");return c.encode(e)},g=e=>{if(!d)throw new Error("Encoding API not available");return d.decode(e)};class m{static fromLatin1(e){return new m({buffer:u(e).buffer})}static fromUTF8(e){return new m({buffer:f(e).buffer})}static fromBase32(e){return new m({buffer:n(e).buffer})}static fromHex(e){return new m({buffer:o(e).buffer})}get buffer(){return this.bytes.buffer}get latin1(){return Object.defineProperty(this,"latin1",{enumerable:!0,writable:!1,configurable:!1,value:h(this.bytes)}),this.latin1}get utf8(){return Object.defineProperty(this,"utf8",{enumerable:!0,writable:!1,configurable:!1,value:g(this.bytes)}),this.utf8}get base32(){return Object.defineProperty(this,"base32",{enumerable:!0,writable:!1,configurable:!1,value:a(this.bytes)}),this.base32}get hex(){return Object.defineProperty(this,"hex",{enumerable:!0,writable:!1,configurable:!1,value:l(this.bytes)}),this.hex}constructor({buffer:r,size:i=20}={}){this.bytes=void 0===r?(r=>{if(e?.randomBytes)return e.randomBytes(r);if(t.crypto?.getRandomValues)return t.crypto.getRandomValues(new Uint8Array(r));throw new Error("Cryptography API not available")})(i):new Uint8Array(r),Object.defineProperty(this,"bytes",{enumerable:!0,writable:!1,configurable:!1,value:this.bytes})}}class p{static get defaults(){return{issuer:"",label:"OTPAuth",issuerInLabel:!0,algorithm:"SHA1",digits:6,counter:0,window:1}}static generate({secret:e,algorithm:t=p.defaults.algorithm,digits:r=p.defaults.digits,counter:s=p.defaults.counter,hmac:n=i}){const a=(e=>{const t=new ArrayBuffer(8),r=new Uint8Array(t);let i=e;for(let e=7;e>=0&&0!==i;e--)r[e]=255&i,i-=r[e],i/=256;return r})(s),o=n(t,e.bytes,a);if(!o?.byteLength||o.byteLength<19)throw new TypeError("Return value must be at least 19 bytes");const l=15&o[o.byteLength-1]
;return(((127&o[l])<<24|(255&o[l+1])<<16|(255&o[l+2])<<8|255&o[l+3])%10**r).toString().padStart(r,"0")}generate({counter:e=this.counter++}={}){return p.generate({secret:this.secret,algorithm:this.algorithm,digits:this.digits,counter:e,hmac:this.hmac})}static validate({token:r,secret:s,algorithm:n,digits:a=p.defaults.digits,counter:o=p.defaults.counter,window:l=p.defaults.window,hmac:u=i}){if(r.length!==a)return null;let h=null;const c=i=>{const l=p.generate({secret:s,algorithm:n,digits:a,counter:i,hmac:u});((r,i)=>{if(e?.timingSafeEqual)return e.timingSafeEqual(t.Buffer.from(r),t.Buffer.from(i));{if(r.length!==i.length)throw new TypeError("Input strings must have the same length");let e=-1,t=0;for(;++e<r.length;)t|=r.charCodeAt(e)^i.charCodeAt(e);return 0===t}})(r,l)&&(h=i-o)};c(o);for(let e=1;e<=l&&null===h&&(c(o-e),null===h)&&(c(o+e),null===h);++e);return h}validate({token:e,counter:t=this.counter,window:r}){return p.validate({token:e,secret:this.secret,algorithm:this.algorithm,digits:this.digits,counter:t,window:r,hmac:this.hmac})}toString(){const e=encodeURIComponent;return"otpauth://hotp/"+(this.issuer.length>0?this.issuerInLabel?`${e(this.issuer)}:${e(this.label)}?issuer=${e(this.issuer)}&`:`${e(this.label)}?issuer=${e(this.issuer)}&`:`${e(this.label)}?`)+`secret=${e(this.secret.base32)}&`+`algorithm=${e(this.algorithm)}&`+`digits=${e(this.digits)}&`+`counter=${e(this.counter)}`}constructor({issuer:e=p.defaults.issuer,label:t=p.defaults.label,issuerInLabel:i=p.defaults.issuerInLabel,secret:s=new m,algorithm:n=p.defaults.algorithm,digits:a=p.defaults.digits,counter:o=p.defaults.counter,hmac:l}={}){this.issuer=e,this.label=t,this.issuerInLabel=i,this.secret="string"==typeof s?m.fromBase32(s):s,this.algorithm=l?n:r(n),this.digits=a,this.counter=o,this.hmac=l}}class b{static get defaults(){return{issuer:"",label:"OTPAuth",issuerInLabel:!0,algorithm:"SHA1",digits:6,period:30,window:1}}static counter({period:e=b.defaults.period,timestamp:t=Date.now()}={}){return Math.floor(t/1e3/e)}
counter({timestamp:e=Date.now()}={}){return b.counter({period:this.period,timestamp:e})}static remaining({period:e=b.defaults.period,timestamp:t=Date.now()}={}){return 1e3*e-t%(1e3*e)}remaining({timestamp:e=Date.now()}={}){return b.remaining({period:this.period,timestamp:e})}static generate({secret:e,algorithm:t,digits:r,period:i=b.defaults.period,timestamp:s=Date.now(),hmac:n}){return p.generate({secret:e,algorithm:t,digits:r,counter:b.counter({period:i,timestamp:s}),hmac:n})}generate({timestamp:e=Date.now()}={}){return b.generate({secret:this.secret,algorithm:this.algorithm,digits:this.digits,period:this.period,timestamp:e,hmac:this.hmac})}static validate({token:e,secret:t,algorithm:r,digits:i,period:s=b.defaults.period,timestamp:n=Date.now(),window:a,hmac:o}){return p.validate({token:e,secret:t,algorithm:r,digits:i,counter:b.counter({period:s,timestamp:n}),window:a,hmac:o})}validate({token:e,timestamp:t,window:r}){return b.validate({token:e,secret:this.secret,algorithm:this.algorithm,digits:this.digits,period:this.period,timestamp:t,window:r,hmac:this.hmac})}toString(){const e=encodeURIComponent;return"otpauth://totp/"+(this.issuer.length>0?this.issuerInLabel?`${e(this.issuer)}:${e(this.label)}?issuer=${e(this.issuer)}&`:`${e(this.label)}?issuer=${e(this.issuer)}&`:`${e(this.label)}?`)+`secret=${e(this.secret.base32)}&`+`algorithm=${e(this.algorithm)}&`+`digits=${e(this.digits)}&`+`period=${e(this.period)}`}constructor({issuer:e=b.defaults.issuer,label:t=b.defaults.label,issuerInLabel:i=b.defaults.issuerInLabel,secret:s=new m,algorithm:n=b.defaults.algorithm,digits:a=b.defaults.digits,period:o=b.defaults.period,hmac:l}={}){this.issuer=e,this.label=t,this.issuerInLabel=i,this.secret="string"==typeof s?m.fromBase32(s):s,this.algorithm=l?n:r(n),this.digits=a,this.period=o,this.hmac=l}}
const w=/^otpauth:\/\/([ht]otp)\/(.+)\?([A-Z0-9.~_-]+=[^?&]*(?:&[A-Z0-9.~_-]+=[^?&]*)*)$/i,y=/^[2-7A-Z]+=*$/i,A=/^SHA(?:1|224|256|384|512|3-224|3-256|3-384|3-512)$/i,S=/^[A-Z0-9]+(?:[_-][A-Z0-9]+)*$/i,I=/^[+-]?\d+$/,$=/^\+?[1-9]\d*$/;class v{static parse(e,{hmac:t}={}){let r;try{r=e.match(w)}catch(e){}if(!Array.isArray(r))throw new URIError("Invalid URI format");const i=r[1].toLowerCase(),s=r[2].split(/(?::|%3A) *(.+)/i,2).map(decodeURIComponent),n=r[3].split("&").reduce((e,t)=>{const r=t.split(/=(.*)/,2).map(decodeURIComponent),i=r[0].toLowerCase(),s=r[1],n=e;return n[i]=s,n},{});let a;const o={};if("hotp"===i){if(a=p,void 0===n.counter||!I.test(n.counter))throw new TypeError("Missing or invalid 'counter' parameter");o.counter=parseInt(n.counter,10)}else{if("totp"!==i)throw new TypeError("Unknown OTP type");if(a=b,void 0!==n.period){if(!$.test(n.period))throw new TypeError("Invalid 'period' parameter");o.period=parseInt(n.period,10)}}if(void 0!==n.issuer&&(o.issuer=n.issuer),2===s.length?(o.label=s[1],void 0===o.issuer||""===o.issuer?o.issuer=s[0]:""===s[0]&&(o.issuerInLabel=!1)):(o.label=s[0],void 0!==o.issuer&&""!==o.issuer&&(o.issuerInLabel=!1)),void 0===n.secret||!y.test(n.secret))throw new TypeError("Missing or invalid 'secret' parameter");if(o.secret=n.secret,void 0!==n.algorithm){if(!(t?S:A).test(n.algorithm))throw new TypeError("Invalid 'algorithm' parameter");o.algorithm=n.algorithm}if(void 0!==n.digits){if(!$.test(n.digits))throw new TypeError("Invalid 'digits' parameter");o.digits=parseInt(n.digits,10)}return void 0!==t&&(o.hmac=t),new a(o)}static stringify(e){if(e instanceof p||e instanceof b)return e.toString();throw new TypeError("Invalid 'HOTP/TOTP' object")}}const H="9.5.0";export{p as HOTP,m as Secret,b as TOTP,v as URI,H as version};
//# sourceMappingURL=otpauth.node.min.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,894 @@
//! otpauth 9.5.0 | (c) Héctor Molinero Fernández | MIT | https://github.com/hectorm/otpauth
/// <reference types="./otpauth.d.ts" />
// @ts-nocheck
import * as crypto from 'node:crypto';
/**
* Converts an integer to an Uint8Array.
* @param {number} num Integer.
* @returns {Uint8Array} Uint8Array.
*/ const uintDecode = (num)=>{
const buf = new ArrayBuffer(8);
const arr = new Uint8Array(buf);
let acc = num;
for(let i = 7; i >= 0; i--){
if (acc === 0) break;
arr[i] = acc & 255;
acc -= arr[i];
acc /= 256;
}
return arr;
};
/**
* "globalThis" ponyfill.
* @see [A horrifying globalThis polyfill in universal JavaScript](https://mathiasbynens.be/notes/globalthis)
* @type {Object.<string, *>}
*/ const globalScope = (()=>{
if (typeof globalThis === "object") return globalThis;
else {
Object.defineProperty(Object.prototype, "__GLOBALTHIS__", {
get () {
return this;
},
configurable: true
});
try {
// @ts-expect-error
// eslint-disable-next-line no-undef
if (typeof __GLOBALTHIS__ !== "undefined") return __GLOBALTHIS__;
} finally{
// @ts-expect-error
delete Object.prototype.__GLOBALTHIS__;
}
}
// Still unable to determine "globalThis", fall back to a naive method.
if (typeof self !== "undefined") return self;
else if (typeof window !== "undefined") return window;
else if (typeof global !== "undefined") return global;
return undefined;
})();
/**
* Canonicalizes a hash algorithm name.
* @param {string} algorithm Hash algorithm name.
* @returns {"SHA1"|"SHA224"|"SHA256"|"SHA384"|"SHA512"|"SHA3-224"|"SHA3-256"|"SHA3-384"|"SHA3-512"} Canonicalized hash algorithm name.
*/ const canonicalizeAlgorithm = (algorithm)=>{
switch(true){
case /^(?:SHA-?1|SSL3-SHA1)$/i.test(algorithm):
return "SHA1";
case /^SHA(?:2?-)?224$/i.test(algorithm):
return "SHA224";
case /^SHA(?:2?-)?256$/i.test(algorithm):
return "SHA256";
case /^SHA(?:2?-)?384$/i.test(algorithm):
return "SHA384";
case /^SHA(?:2?-)?512$/i.test(algorithm):
return "SHA512";
case /^SHA3-224$/i.test(algorithm):
return "SHA3-224";
case /^SHA3-256$/i.test(algorithm):
return "SHA3-256";
case /^SHA3-384$/i.test(algorithm):
return "SHA3-384";
case /^SHA3-512$/i.test(algorithm):
return "SHA3-512";
default:
throw new TypeError(`Unknown hash algorithm: ${algorithm}`);
}
};
/**
* Calculates an HMAC digest.
* @param {string} algorithm Algorithm.
* @param {Uint8Array} key Key.
* @param {Uint8Array} message Message.
* @returns {Uint8Array} Digest.
*/ const hmacDigest = (algorithm, key, message)=>{
if (crypto?.createHmac) {
const hmac = crypto.createHmac(algorithm, globalScope.Buffer.from(key));
hmac.update(globalScope.Buffer.from(message));
return hmac.digest();
} else {
throw new Error("Missing HMAC function");
}
};
/**
* RFC 4648 base32 alphabet without pad.
* @type {string}
*/ const ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
/**
* Converts a base32 string to an Uint8Array (RFC 4648).
* @see [LinusU/base32-decode](https://github.com/LinusU/base32-decode)
* @param {string} str Base32 string.
* @returns {Uint8Array} Uint8Array.
*/ const base32Decode = (str)=>{
// Remove spaces (although they are not allowed by the spec, some issuers add them for readability).
str = str.replace(/ /g, "");
// Canonicalize to all upper case and remove padding if it exists.
let end = str.length;
while(str[end - 1] === "=")--end;
str = (end < str.length ? str.substring(0, end) : str).toUpperCase();
const buf = new ArrayBuffer(str.length * 5 / 8 | 0);
const arr = new Uint8Array(buf);
let bits = 0;
let value = 0;
let index = 0;
for(let i = 0; i < str.length; i++){
const idx = ALPHABET.indexOf(str[i]);
if (idx === -1) throw new TypeError(`Invalid character found: ${str[i]}`);
value = value << 5 | idx;
bits += 5;
if (bits >= 8) {
bits -= 8;
arr[index++] = value >>> bits;
}
}
return arr;
};
/**
* Converts an Uint8Array to a base32 string (RFC 4648).
* @see [LinusU/base32-encode](https://github.com/LinusU/base32-encode)
* @param {Uint8Array} arr Uint8Array.
* @returns {string} Base32 string.
*/ const base32Encode = (arr)=>{
let bits = 0;
let value = 0;
let str = "";
for(let i = 0; i < arr.length; i++){
value = value << 8 | arr[i];
bits += 8;
while(bits >= 5){
str += ALPHABET[value >>> bits - 5 & 31];
bits -= 5;
}
}
if (bits > 0) {
str += ALPHABET[value << 5 - bits & 31];
}
return str;
};
/**
* Converts a hexadecimal string to an Uint8Array.
* @param {string} str Hexadecimal string.
* @returns {Uint8Array} Uint8Array.
*/ const hexDecode = (str)=>{
// Remove spaces (although they are not allowed by the spec, some issuers add them for readability).
str = str.replace(/ /g, "");
const buf = new ArrayBuffer(str.length / 2);
const arr = new Uint8Array(buf);
for(let i = 0; i < str.length; i += 2){
arr[i / 2] = parseInt(str.substring(i, i + 2), 16);
}
return arr;
};
/**
* Converts an Uint8Array to a hexadecimal string.
* @param {Uint8Array} arr Uint8Array.
* @returns {string} Hexadecimal string.
*/ const hexEncode = (arr)=>{
let str = "";
for(let i = 0; i < arr.length; i++){
const hex = arr[i].toString(16);
if (hex.length === 1) str += "0";
str += hex;
}
return str.toUpperCase();
};
/**
* Converts a Latin-1 string to an Uint8Array.
* @param {string} str Latin-1 string.
* @returns {Uint8Array} Uint8Array.
*/ const latin1Decode = (str)=>{
const buf = new ArrayBuffer(str.length);
const arr = new Uint8Array(buf);
for(let i = 0; i < str.length; i++){
arr[i] = str.charCodeAt(i) & 0xff;
}
return arr;
};
/**
* Converts an Uint8Array to a Latin-1 string.
* @param {Uint8Array} arr Uint8Array.
* @returns {string} Latin-1 string.
*/ const latin1Encode = (arr)=>{
let str = "";
for(let i = 0; i < arr.length; i++){
str += String.fromCharCode(arr[i]);
}
return str;
};
/**
* TextEncoder instance.
* @type {TextEncoder|null}
*/ const ENCODER = globalScope.TextEncoder ? new globalScope.TextEncoder() : null;
/**
* TextDecoder instance.
* @type {TextDecoder|null}
*/ const DECODER = globalScope.TextDecoder ? new globalScope.TextDecoder() : null;
/**
* Converts an UTF-8 string to an Uint8Array.
* @param {string} str String.
* @returns {Uint8Array} Uint8Array.
*/ const utf8Decode = (str)=>{
if (!ENCODER) {
throw new Error("Encoding API not available");
}
return ENCODER.encode(str);
};
/**
* Converts an Uint8Array to an UTF-8 string.
* @param {Uint8Array} arr Uint8Array.
* @returns {string} String.
*/ const utf8Encode = (arr)=>{
if (!DECODER) {
throw new Error("Encoding API not available");
}
return DECODER.decode(arr);
};
/**
* Returns random bytes.
* @param {number} size Size.
* @returns {Uint8Array} Random bytes.
*/ const randomBytes = (size)=>{
if (crypto?.randomBytes) {
return crypto.randomBytes(size);
} else if (globalScope.crypto?.getRandomValues) {
return globalScope.crypto.getRandomValues(new Uint8Array(size));
} else {
throw new Error("Cryptography API not available");
}
};
/**
* OTP secret key.
*/ class Secret {
/**
* Converts a Latin-1 string to a Secret object.
* @param {string} str Latin-1 string.
* @returns {Secret} Secret object.
*/ static fromLatin1(str) {
return new Secret({
buffer: latin1Decode(str).buffer
});
}
/**
* Converts an UTF-8 string to a Secret object.
* @param {string} str UTF-8 string.
* @returns {Secret} Secret object.
*/ static fromUTF8(str) {
return new Secret({
buffer: utf8Decode(str).buffer
});
}
/**
* Converts a base32 string to a Secret object.
* @param {string} str Base32 string.
* @returns {Secret} Secret object.
*/ static fromBase32(str) {
return new Secret({
buffer: base32Decode(str).buffer
});
}
/**
* Converts a hexadecimal string to a Secret object.
* @param {string} str Hexadecimal string.
* @returns {Secret} Secret object.
*/ static fromHex(str) {
return new Secret({
buffer: hexDecode(str).buffer
});
}
/**
* Secret key buffer.
* @deprecated For backward compatibility, the "bytes" property should be used instead.
* @type {ArrayBufferLike}
*/ get buffer() {
return this.bytes.buffer;
}
/**
* Latin-1 string representation of secret key.
* @type {string}
*/ get latin1() {
Object.defineProperty(this, "latin1", {
enumerable: true,
writable: false,
configurable: false,
value: latin1Encode(this.bytes)
});
return this.latin1;
}
/**
* UTF-8 string representation of secret key.
* @type {string}
*/ get utf8() {
Object.defineProperty(this, "utf8", {
enumerable: true,
writable: false,
configurable: false,
value: utf8Encode(this.bytes)
});
return this.utf8;
}
/**
* Base32 string representation of secret key.
* @type {string}
*/ get base32() {
Object.defineProperty(this, "base32", {
enumerable: true,
writable: false,
configurable: false,
value: base32Encode(this.bytes)
});
return this.base32;
}
/**
* Hexadecimal string representation of secret key.
* @type {string}
*/ get hex() {
Object.defineProperty(this, "hex", {
enumerable: true,
writable: false,
configurable: false,
value: hexEncode(this.bytes)
});
return this.hex;
}
/**
* Creates a secret key object.
* @param {Object} [config] Configuration options.
* @param {ArrayBufferLike} [config.buffer] Secret key buffer.
* @param {number} [config.size=20] Number of random bytes to generate, ignored if 'buffer' is provided.
*/ constructor({ buffer, size = 20 } = {}){
/**
* Secret key.
* @type {Uint8Array}
* @readonly
*/ this.bytes = typeof buffer === "undefined" ? randomBytes(size) : new Uint8Array(buffer);
// Prevent the "bytes" property from being modified.
Object.defineProperty(this, "bytes", {
enumerable: true,
writable: false,
configurable: false,
value: this.bytes
});
}
}
/**
* Returns true if a is equal to b, without leaking timing information that would allow an attacker to guess one of the values.
* @param {string} a String a.
* @param {string} b String b.
* @returns {boolean} Equality result.
*/ const timingSafeEqual = (a, b)=>{
if (crypto?.timingSafeEqual) {
return crypto.timingSafeEqual(globalScope.Buffer.from(a), globalScope.Buffer.from(b));
} else {
if (a.length !== b.length) {
throw new TypeError("Input strings must have the same length");
}
let i = -1;
let out = 0;
while(++i < a.length){
out |= a.charCodeAt(i) ^ b.charCodeAt(i);
}
return out === 0;
}
};
/**
* HOTP: An HMAC-based One-time Password Algorithm.
* @see [RFC 4226](https://datatracker.ietf.org/doc/html/rfc4226)
*/ class HOTP {
/**
* Default configuration.
* @type {{
* issuer: string,
* label: string,
* issuerInLabel: boolean,
* algorithm: string,
* digits: number,
* counter: number
* window: number
* }}
*/ static get defaults() {
return {
issuer: "",
label: "OTPAuth",
issuerInLabel: true,
algorithm: "SHA1",
digits: 6,
counter: 0,
window: 1
};
}
/**
* Generates an HOTP token.
* @param {Object} config Configuration options.
* @param {Secret} config.secret Secret key.
* @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
* @param {number} [config.digits=6] Token length.
* @param {number} [config.counter=0] Counter value.
* @param {(algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array} [config.hmac] Custom HMAC function.
* @returns {string} Token.
*/ static generate({ secret, algorithm = HOTP.defaults.algorithm, digits = HOTP.defaults.digits, counter = HOTP.defaults.counter, hmac = hmacDigest }) {
const message = uintDecode(counter);
const digest = hmac(algorithm, secret.bytes, message);
if (!digest?.byteLength || digest.byteLength < 19) {
throw new TypeError("Return value must be at least 19 bytes");
}
const offset = digest[digest.byteLength - 1] & 15;
const otp = ((digest[offset] & 127) << 24 | (digest[offset + 1] & 255) << 16 | (digest[offset + 2] & 255) << 8 | digest[offset + 3] & 255) % 10 ** digits;
return otp.toString().padStart(digits, "0");
}
/**
* Generates an HOTP token.
* @param {Object} [config] Configuration options.
* @param {number} [config.counter=this.counter++] Counter value.
* @returns {string} Token.
*/ generate({ counter = this.counter++ } = {}) {
return HOTP.generate({
secret: this.secret,
algorithm: this.algorithm,
digits: this.digits,
counter,
hmac: this.hmac
});
}
/**
* Validates an HOTP token.
* @param {Object} config Configuration options.
* @param {string} config.token Token value.
* @param {Secret} config.secret Secret key.
* @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
* @param {number} [config.digits=6] Token length.
* @param {number} [config.counter=0] Counter value.
* @param {number} [config.window=1] Window of counter values to test.
* @param {(algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array} [config.hmac] Custom HMAC function.
* @returns {number|null} Token delta or null if it is not found in the search window, in which case it should be considered invalid.
*/ static validate({ token, secret, algorithm, digits = HOTP.defaults.digits, counter = HOTP.defaults.counter, window = HOTP.defaults.window, hmac = hmacDigest }) {
// Return early if the token length does not match the digit number.
if (token.length !== digits) return null;
let delta = null;
const check = (/** @type {number} */ i)=>{
const generatedToken = HOTP.generate({
secret,
algorithm,
digits,
counter: i,
hmac
});
if (timingSafeEqual(token, generatedToken)) {
delta = i - counter;
}
};
check(counter);
for(let i = 1; i <= window && delta === null; ++i){
check(counter - i);
if (delta !== null) break;
check(counter + i);
if (delta !== null) break;
}
return delta;
}
/**
* Validates an HOTP token.
* @param {Object} config Configuration options.
* @param {string} config.token Token value.
* @param {number} [config.counter=this.counter] Counter value.
* @param {number} [config.window=1] Window of counter values to test.
* @returns {number|null} Token delta or null if it is not found in the search window, in which case it should be considered invalid.
*/ validate({ token, counter = this.counter, window }) {
return HOTP.validate({
token,
secret: this.secret,
algorithm: this.algorithm,
digits: this.digits,
counter,
window,
hmac: this.hmac
});
}
/**
* Returns a Google Authenticator key URI.
* @returns {string} URI.
*/ toString() {
const e = encodeURIComponent;
return "otpauth://hotp/" + `${this.issuer.length > 0 ? this.issuerInLabel ? `${e(this.issuer)}:${e(this.label)}?issuer=${e(this.issuer)}&` : `${e(this.label)}?issuer=${e(this.issuer)}&` : `${e(this.label)}?`}` + `secret=${e(this.secret.base32)}&` + `algorithm=${e(this.algorithm)}&` + `digits=${e(this.digits)}&` + `counter=${e(this.counter)}`;
}
/**
* Creates an HOTP object.
* @param {Object} [config] Configuration options.
* @param {string} [config.issuer=''] Account provider.
* @param {string} [config.label='OTPAuth'] Account label.
* @param {boolean} [config.issuerInLabel=true] Include issuer prefix in label.
* @param {Secret|string} [config.secret=Secret] Secret key.
* @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
* @param {number} [config.digits=6] Token length.
* @param {number} [config.counter=0] Initial counter value.
* @param {(algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array} [config.hmac] Custom HMAC function.
*/ constructor({ issuer = HOTP.defaults.issuer, label = HOTP.defaults.label, issuerInLabel = HOTP.defaults.issuerInLabel, secret = new Secret(), algorithm = HOTP.defaults.algorithm, digits = HOTP.defaults.digits, counter = HOTP.defaults.counter, hmac } = {}){
/**
* Account provider.
* @type {string}
*/ this.issuer = issuer;
/**
* Account label.
* @type {string}
*/ this.label = label;
/**
* Include issuer prefix in label.
* @type {boolean}
*/ this.issuerInLabel = issuerInLabel;
/**
* Secret key.
* @type {Secret}
*/ this.secret = typeof secret === "string" ? Secret.fromBase32(secret) : secret;
/**
* HMAC hashing algorithm.
* @type {string}
*/ this.algorithm = hmac ? algorithm : canonicalizeAlgorithm(algorithm);
/**
* Token length.
* @type {number}
*/ this.digits = digits;
/**
* Initial counter value.
* @type {number}
*/ this.counter = counter;
/**
* Custom HMAC function.
* @type {((algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array)|undefined}
*/ this.hmac = hmac;
}
}
/**
* TOTP: Time-Based One-Time Password Algorithm.
* @see [RFC 6238](https://datatracker.ietf.org/doc/html/rfc6238)
*/ class TOTP {
/**
* Default configuration.
* @type {{
* issuer: string,
* label: string,
* issuerInLabel: boolean,
* algorithm: string,
* digits: number,
* period: number
* window: number
* }}
*/ static get defaults() {
return {
issuer: "",
label: "OTPAuth",
issuerInLabel: true,
algorithm: "SHA1",
digits: 6,
period: 30,
window: 1
};
}
/**
* Calculates the counter. i.e. the number of periods since timestamp 0.
* @param {Object} [config] Configuration options.
* @param {number} [config.period=30] Token time-step duration.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @returns {number} Counter.
*/ static counter({ period = TOTP.defaults.period, timestamp = Date.now() } = {}) {
return Math.floor(timestamp / 1000 / period);
}
/**
* Calculates the counter. i.e. the number of periods since timestamp 0.
* @param {Object} [config] Configuration options.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @returns {number} Counter.
*/ counter({ timestamp = Date.now() } = {}) {
return TOTP.counter({
period: this.period,
timestamp
});
}
/**
* Calculates the remaining time in milliseconds until the next token is generated.
* @param {Object} [config] Configuration options.
* @param {number} [config.period=30] Token time-step duration.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @returns {number} counter.
*/ static remaining({ period = TOTP.defaults.period, timestamp = Date.now() } = {}) {
return period * 1000 - timestamp % (period * 1000);
}
/**
* Calculates the remaining time in milliseconds until the next token is generated.
* @param {Object} [config] Configuration options.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @returns {number} counter.
*/ remaining({ timestamp = Date.now() } = {}) {
return TOTP.remaining({
period: this.period,
timestamp
});
}
/**
* Generates a TOTP token.
* @param {Object} config Configuration options.
* @param {Secret} config.secret Secret key.
* @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
* @param {number} [config.digits=6] Token length.
* @param {number} [config.period=30] Token time-step duration.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @param {(algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array} [config.hmac] Custom HMAC function.
* @returns {string} Token.
*/ static generate({ secret, algorithm, digits, period = TOTP.defaults.period, timestamp = Date.now(), hmac }) {
return HOTP.generate({
secret,
algorithm,
digits,
counter: TOTP.counter({
period,
timestamp
}),
hmac
});
}
/**
* Generates a TOTP token.
* @param {Object} [config] Configuration options.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @returns {string} Token.
*/ generate({ timestamp = Date.now() } = {}) {
return TOTP.generate({
secret: this.secret,
algorithm: this.algorithm,
digits: this.digits,
period: this.period,
timestamp,
hmac: this.hmac
});
}
/**
* Validates a TOTP token.
* @param {Object} config Configuration options.
* @param {string} config.token Token value.
* @param {Secret} config.secret Secret key.
* @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
* @param {number} [config.digits=6] Token length.
* @param {number} [config.period=30] Token time-step duration.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @param {number} [config.window=1] Window of counter values to test.
* @param {(algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array} [config.hmac] Custom HMAC function.
* @returns {number|null} Token delta or null if it is not found in the search window, in which case it should be considered invalid.
*/ static validate({ token, secret, algorithm, digits, period = TOTP.defaults.period, timestamp = Date.now(), window, hmac }) {
return HOTP.validate({
token,
secret,
algorithm,
digits,
counter: TOTP.counter({
period,
timestamp
}),
window,
hmac
});
}
/**
* Validates a TOTP token.
* @param {Object} config Configuration options.
* @param {string} config.token Token value.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @param {number} [config.window=1] Window of counter values to test.
* @returns {number|null} Token delta or null if it is not found in the search window, in which case it should be considered invalid.
*/ validate({ token, timestamp, window }) {
return TOTP.validate({
token,
secret: this.secret,
algorithm: this.algorithm,
digits: this.digits,
period: this.period,
timestamp,
window,
hmac: this.hmac
});
}
/**
* Returns a Google Authenticator key URI.
* @returns {string} URI.
*/ toString() {
const e = encodeURIComponent;
return "otpauth://totp/" + `${this.issuer.length > 0 ? this.issuerInLabel ? `${e(this.issuer)}:${e(this.label)}?issuer=${e(this.issuer)}&` : `${e(this.label)}?issuer=${e(this.issuer)}&` : `${e(this.label)}?`}` + `secret=${e(this.secret.base32)}&` + `algorithm=${e(this.algorithm)}&` + `digits=${e(this.digits)}&` + `period=${e(this.period)}`;
}
/**
* Creates a TOTP object.
* @param {Object} [config] Configuration options.
* @param {string} [config.issuer=''] Account provider.
* @param {string} [config.label='OTPAuth'] Account label.
* @param {boolean} [config.issuerInLabel=true] Include issuer prefix in label.
* @param {Secret|string} [config.secret=Secret] Secret key.
* @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
* @param {number} [config.digits=6] Token length.
* @param {number} [config.period=30] Token time-step duration.
* @param {(algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array} [config.hmac] Custom HMAC function.
*/ constructor({ issuer = TOTP.defaults.issuer, label = TOTP.defaults.label, issuerInLabel = TOTP.defaults.issuerInLabel, secret = new Secret(), algorithm = TOTP.defaults.algorithm, digits = TOTP.defaults.digits, period = TOTP.defaults.period, hmac } = {}){
/**
* Account provider.
* @type {string}
*/ this.issuer = issuer;
/**
* Account label.
* @type {string}
*/ this.label = label;
/**
* Include issuer prefix in label.
* @type {boolean}
*/ this.issuerInLabel = issuerInLabel;
/**
* Secret key.
* @type {Secret}
*/ this.secret = typeof secret === "string" ? Secret.fromBase32(secret) : secret;
/**
* HMAC hashing algorithm.
* @type {string}
*/ this.algorithm = hmac ? algorithm : canonicalizeAlgorithm(algorithm);
/**
* Token length.
* @type {number}
*/ this.digits = digits;
/**
* Token time-step duration.
* @type {number}
*/ this.period = period;
/**
* Custom HMAC function.
* @type {((algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array)|undefined}
*/ this.hmac = hmac;
}
}
/**
* Key URI regex (otpauth://TYPE/[ISSUER:]LABEL?PARAMETERS).
* @type {RegExp}
*/ const OTPURI_REGEX = /^otpauth:\/\/([ht]otp)\/(.+)\?([A-Z0-9.~_-]+=[^?&]*(?:&[A-Z0-9.~_-]+=[^?&]*)*)$/i;
/**
* RFC 4648 base32 alphabet with pad.
* @type {RegExp}
*/ const SECRET_REGEX = /^[2-7A-Z]+=*$/i;
/**
* Regex for supported algorithms in built-in HMAC function.
* @type {RegExp}
*/ const ALGORITHM_REGEX = /^SHA(?:1|224|256|384|512|3-224|3-256|3-384|3-512)$/i;
/**
* Regex for custom algorithms in user-defined HMAC function.
* @type {RegExp}
*/ const ALGORITHM_CUSTOM_REGEX = /^[A-Z0-9]+(?:[_-][A-Z0-9]+)*$/i;
/**
* Integer regex.
* @type {RegExp}
*/ const INTEGER_REGEX = /^[+-]?\d+$/;
/**
* Positive integer regex.
* @type {RegExp}
*/ const POSITIVE_INTEGER_REGEX = /^\+?[1-9]\d*$/;
/**
* HOTP/TOTP object/string conversion.
* @see [Key URI Format](https://github.com/google/google-authenticator/wiki/Key-Uri-Format)
*/ class URI {
/**
* Parses a Google Authenticator key URI and returns an HOTP/TOTP object.
* @param {string} uri Google Authenticator Key URI.
* @param {Object} [config] Configuration options.
* @param {(algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array} [config.hmac] Custom HMAC function.
* @returns {HOTP|TOTP} HOTP/TOTP object.
*/ static parse(uri, { hmac } = {}) {
let uriGroups;
try {
uriGroups = uri.match(OTPURI_REGEX);
// eslint-disable-next-line no-unused-vars
} catch (_) {
/* Handled below */ }
if (!Array.isArray(uriGroups)) {
throw new URIError("Invalid URI format");
}
// Extract URI groups.
const uriType = uriGroups[1].toLowerCase();
const uriLabel = uriGroups[2].split(/(?::|%3A) *(.+)/i, 2).map(decodeURIComponent);
/** @type {Object.<string, string>} */ const uriParams = uriGroups[3].split("&").reduce((acc, cur)=>{
const pairArr = cur.split(/=(.*)/, 2).map(decodeURIComponent);
const pairKey = pairArr[0].toLowerCase();
const pairVal = pairArr[1];
/** @type {Object.<string, string>} */ const pairAcc = acc;
pairAcc[pairKey] = pairVal;
return pairAcc;
}, {});
// 'OTP' will be instantiated with 'config' argument.
let OTP;
const config = {};
if (uriType === "hotp") {
OTP = HOTP;
// Counter: required
if (typeof uriParams.counter !== "undefined" && INTEGER_REGEX.test(uriParams.counter)) {
config.counter = parseInt(uriParams.counter, 10);
} else {
throw new TypeError("Missing or invalid 'counter' parameter");
}
} else if (uriType === "totp") {
OTP = TOTP;
// Period: optional
if (typeof uriParams.period !== "undefined") {
if (POSITIVE_INTEGER_REGEX.test(uriParams.period)) {
config.period = parseInt(uriParams.period, 10);
} else {
throw new TypeError("Invalid 'period' parameter");
}
}
} else {
throw new TypeError("Unknown OTP type");
}
// Label: required
// Issuer: optional
if (typeof uriParams.issuer !== "undefined") {
config.issuer = uriParams.issuer;
}
if (uriLabel.length === 2) {
config.label = uriLabel[1];
if (typeof config.issuer === "undefined" || config.issuer === "") {
config.issuer = uriLabel[0];
} else if (uriLabel[0] === "") {
config.issuerInLabel = false;
}
} else {
config.label = uriLabel[0];
if (typeof config.issuer !== "undefined" && config.issuer !== "") {
config.issuerInLabel = false;
}
}
// Secret: required
if (typeof uriParams.secret !== "undefined" && SECRET_REGEX.test(uriParams.secret)) {
config.secret = uriParams.secret;
} else {
throw new TypeError("Missing or invalid 'secret' parameter");
}
// Algorithm: optional
if (typeof uriParams.algorithm !== "undefined") {
if ((hmac ? ALGORITHM_CUSTOM_REGEX : ALGORITHM_REGEX).test(uriParams.algorithm)) {
config.algorithm = uriParams.algorithm;
} else {
throw new TypeError("Invalid 'algorithm' parameter");
}
}
// Digits: optional
if (typeof uriParams.digits !== "undefined") {
if (POSITIVE_INTEGER_REGEX.test(uriParams.digits)) {
config.digits = parseInt(uriParams.digits, 10);
} else {
throw new TypeError("Invalid 'digits' parameter");
}
}
// HMAC: optional
if (typeof hmac !== "undefined") {
config.hmac = hmac;
}
return new OTP(config);
}
/**
* Converts an HOTP/TOTP object to a Google Authenticator key URI.
* @param {HOTP|TOTP} otp HOTP/TOTP object.
* @returns {string} Google Authenticator Key URI.
*/ static stringify(otp) {
if (otp instanceof HOTP || otp instanceof TOTP) {
return otp.toString();
}
throw new TypeError("Invalid 'HOTP/TOTP' object");
}
}
/**
* Library version.
* @type {string}
*/ const version = "9.5.0";
export { HOTP, Secret, TOTP, URI, version };

View File

@@ -0,0 +1,907 @@
//! otpauth 9.5.0 | (c) Héctor Molinero Fernández | MIT | https://github.com/hectorm/otpauth
//! noble-hashes 2.0.1 | (c) Paul Miller | MIT | https://github.com/paulmillr/noble-hashes
/// <reference types="./otpauth.d.ts" />
// @ts-nocheck
import { hmac } from '@noble/hashes/hmac.js';
import { sha1 } from '@noble/hashes/legacy.js';
import { sha512, sha384, sha256, sha224 } from '@noble/hashes/sha2.js';
import { sha3_512, sha3_384, sha3_256, sha3_224 } from '@noble/hashes/sha3.js';
/**
* Converts an integer to an Uint8Array.
* @param {number} num Integer.
* @returns {Uint8Array} Uint8Array.
*/ const uintDecode = (num)=>{
const buf = new ArrayBuffer(8);
const arr = new Uint8Array(buf);
let acc = num;
for(let i = 7; i >= 0; i--){
if (acc === 0) break;
arr[i] = acc & 255;
acc -= arr[i];
acc /= 256;
}
return arr;
};
/**
* "globalThis" ponyfill.
* @see [A horrifying globalThis polyfill in universal JavaScript](https://mathiasbynens.be/notes/globalthis)
* @type {Object.<string, *>}
*/ const globalScope = (()=>{
if (typeof globalThis === "object") return globalThis;
else {
Object.defineProperty(Object.prototype, "__GLOBALTHIS__", {
get () {
return this;
},
configurable: true
});
try {
// @ts-expect-error
// eslint-disable-next-line no-undef
if (typeof __GLOBALTHIS__ !== "undefined") return __GLOBALTHIS__;
} finally{
// @ts-expect-error
delete Object.prototype.__GLOBALTHIS__;
}
}
// Still unable to determine "globalThis", fall back to a naive method.
if (typeof self !== "undefined") return self;
else if (typeof window !== "undefined") return window;
else if (typeof global !== "undefined") return global;
return undefined;
})();
/**
* @noble/hashes hash functions.
* @type {Object.<string, sha1|sha224|sha256|sha384|sha512|sha3_224|sha3_256|sha3_384|sha3_512>}
*/ const nobleHashes = {
SHA1: sha1,
SHA224: sha224,
SHA256: sha256,
SHA384: sha384,
SHA512: sha512,
"SHA3-224": sha3_224,
"SHA3-256": sha3_256,
"SHA3-384": sha3_384,
"SHA3-512": sha3_512
};
/**
* Canonicalizes a hash algorithm name.
* @param {string} algorithm Hash algorithm name.
* @returns {"SHA1"|"SHA224"|"SHA256"|"SHA384"|"SHA512"|"SHA3-224"|"SHA3-256"|"SHA3-384"|"SHA3-512"} Canonicalized hash algorithm name.
*/ const canonicalizeAlgorithm = (algorithm)=>{
switch(true){
case /^(?:SHA-?1|SSL3-SHA1)$/i.test(algorithm):
return "SHA1";
case /^SHA(?:2?-)?224$/i.test(algorithm):
return "SHA224";
case /^SHA(?:2?-)?256$/i.test(algorithm):
return "SHA256";
case /^SHA(?:2?-)?384$/i.test(algorithm):
return "SHA384";
case /^SHA(?:2?-)?512$/i.test(algorithm):
return "SHA512";
case /^SHA3-224$/i.test(algorithm):
return "SHA3-224";
case /^SHA3-256$/i.test(algorithm):
return "SHA3-256";
case /^SHA3-384$/i.test(algorithm):
return "SHA3-384";
case /^SHA3-512$/i.test(algorithm):
return "SHA3-512";
default:
throw new TypeError(`Unknown hash algorithm: ${algorithm}`);
}
};
/**
* Calculates an HMAC digest.
* @param {string} algorithm Algorithm.
* @param {Uint8Array} key Key.
* @param {Uint8Array} message Message.
* @returns {Uint8Array} Digest.
*/ const hmacDigest = (algorithm, key, message)=>{
if (hmac) {
const hash = nobleHashes[algorithm] ?? nobleHashes[canonicalizeAlgorithm(algorithm)];
return hmac(hash, key, message);
} else {
throw new Error("Missing HMAC function");
}
};
/**
* RFC 4648 base32 alphabet without pad.
* @type {string}
*/ const ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
/**
* Converts a base32 string to an Uint8Array (RFC 4648).
* @see [LinusU/base32-decode](https://github.com/LinusU/base32-decode)
* @param {string} str Base32 string.
* @returns {Uint8Array} Uint8Array.
*/ const base32Decode = (str)=>{
// Remove spaces (although they are not allowed by the spec, some issuers add them for readability).
str = str.replace(/ /g, "");
// Canonicalize to all upper case and remove padding if it exists.
let end = str.length;
while(str[end - 1] === "=")--end;
str = (end < str.length ? str.substring(0, end) : str).toUpperCase();
const buf = new ArrayBuffer(str.length * 5 / 8 | 0);
const arr = new Uint8Array(buf);
let bits = 0;
let value = 0;
let index = 0;
for(let i = 0; i < str.length; i++){
const idx = ALPHABET.indexOf(str[i]);
if (idx === -1) throw new TypeError(`Invalid character found: ${str[i]}`);
value = value << 5 | idx;
bits += 5;
if (bits >= 8) {
bits -= 8;
arr[index++] = value >>> bits;
}
}
return arr;
};
/**
* Converts an Uint8Array to a base32 string (RFC 4648).
* @see [LinusU/base32-encode](https://github.com/LinusU/base32-encode)
* @param {Uint8Array} arr Uint8Array.
* @returns {string} Base32 string.
*/ const base32Encode = (arr)=>{
let bits = 0;
let value = 0;
let str = "";
for(let i = 0; i < arr.length; i++){
value = value << 8 | arr[i];
bits += 8;
while(bits >= 5){
str += ALPHABET[value >>> bits - 5 & 31];
bits -= 5;
}
}
if (bits > 0) {
str += ALPHABET[value << 5 - bits & 31];
}
return str;
};
/**
* Converts a hexadecimal string to an Uint8Array.
* @param {string} str Hexadecimal string.
* @returns {Uint8Array} Uint8Array.
*/ const hexDecode = (str)=>{
// Remove spaces (although they are not allowed by the spec, some issuers add them for readability).
str = str.replace(/ /g, "");
const buf = new ArrayBuffer(str.length / 2);
const arr = new Uint8Array(buf);
for(let i = 0; i < str.length; i += 2){
arr[i / 2] = parseInt(str.substring(i, i + 2), 16);
}
return arr;
};
/**
* Converts an Uint8Array to a hexadecimal string.
* @param {Uint8Array} arr Uint8Array.
* @returns {string} Hexadecimal string.
*/ const hexEncode = (arr)=>{
let str = "";
for(let i = 0; i < arr.length; i++){
const hex = arr[i].toString(16);
if (hex.length === 1) str += "0";
str += hex;
}
return str.toUpperCase();
};
/**
* Converts a Latin-1 string to an Uint8Array.
* @param {string} str Latin-1 string.
* @returns {Uint8Array} Uint8Array.
*/ const latin1Decode = (str)=>{
const buf = new ArrayBuffer(str.length);
const arr = new Uint8Array(buf);
for(let i = 0; i < str.length; i++){
arr[i] = str.charCodeAt(i) & 0xff;
}
return arr;
};
/**
* Converts an Uint8Array to a Latin-1 string.
* @param {Uint8Array} arr Uint8Array.
* @returns {string} Latin-1 string.
*/ const latin1Encode = (arr)=>{
let str = "";
for(let i = 0; i < arr.length; i++){
str += String.fromCharCode(arr[i]);
}
return str;
};
/**
* TextEncoder instance.
* @type {TextEncoder|null}
*/ const ENCODER = globalScope.TextEncoder ? new globalScope.TextEncoder() : null;
/**
* TextDecoder instance.
* @type {TextDecoder|null}
*/ const DECODER = globalScope.TextDecoder ? new globalScope.TextDecoder() : null;
/**
* Converts an UTF-8 string to an Uint8Array.
* @param {string} str String.
* @returns {Uint8Array} Uint8Array.
*/ const utf8Decode = (str)=>{
if (!ENCODER) {
throw new Error("Encoding API not available");
}
return ENCODER.encode(str);
};
/**
* Converts an Uint8Array to an UTF-8 string.
* @param {Uint8Array} arr Uint8Array.
* @returns {string} String.
*/ const utf8Encode = (arr)=>{
if (!DECODER) {
throw new Error("Encoding API not available");
}
return DECODER.decode(arr);
};
/**
* Returns random bytes.
* @param {number} size Size.
* @returns {Uint8Array} Random bytes.
*/ const randomBytes = (size)=>{
if (globalScope.crypto?.getRandomValues) {
return globalScope.crypto.getRandomValues(new Uint8Array(size));
} else {
throw new Error("Cryptography API not available");
}
};
/**
* OTP secret key.
*/ class Secret {
/**
* Converts a Latin-1 string to a Secret object.
* @param {string} str Latin-1 string.
* @returns {Secret} Secret object.
*/ static fromLatin1(str) {
return new Secret({
buffer: latin1Decode(str).buffer
});
}
/**
* Converts an UTF-8 string to a Secret object.
* @param {string} str UTF-8 string.
* @returns {Secret} Secret object.
*/ static fromUTF8(str) {
return new Secret({
buffer: utf8Decode(str).buffer
});
}
/**
* Converts a base32 string to a Secret object.
* @param {string} str Base32 string.
* @returns {Secret} Secret object.
*/ static fromBase32(str) {
return new Secret({
buffer: base32Decode(str).buffer
});
}
/**
* Converts a hexadecimal string to a Secret object.
* @param {string} str Hexadecimal string.
* @returns {Secret} Secret object.
*/ static fromHex(str) {
return new Secret({
buffer: hexDecode(str).buffer
});
}
/**
* Secret key buffer.
* @deprecated For backward compatibility, the "bytes" property should be used instead.
* @type {ArrayBufferLike}
*/ get buffer() {
return this.bytes.buffer;
}
/**
* Latin-1 string representation of secret key.
* @type {string}
*/ get latin1() {
Object.defineProperty(this, "latin1", {
enumerable: true,
writable: false,
configurable: false,
value: latin1Encode(this.bytes)
});
return this.latin1;
}
/**
* UTF-8 string representation of secret key.
* @type {string}
*/ get utf8() {
Object.defineProperty(this, "utf8", {
enumerable: true,
writable: false,
configurable: false,
value: utf8Encode(this.bytes)
});
return this.utf8;
}
/**
* Base32 string representation of secret key.
* @type {string}
*/ get base32() {
Object.defineProperty(this, "base32", {
enumerable: true,
writable: false,
configurable: false,
value: base32Encode(this.bytes)
});
return this.base32;
}
/**
* Hexadecimal string representation of secret key.
* @type {string}
*/ get hex() {
Object.defineProperty(this, "hex", {
enumerable: true,
writable: false,
configurable: false,
value: hexEncode(this.bytes)
});
return this.hex;
}
/**
* Creates a secret key object.
* @param {Object} [config] Configuration options.
* @param {ArrayBufferLike} [config.buffer] Secret key buffer.
* @param {number} [config.size=20] Number of random bytes to generate, ignored if 'buffer' is provided.
*/ constructor({ buffer, size = 20 } = {}){
/**
* Secret key.
* @type {Uint8Array}
* @readonly
*/ this.bytes = typeof buffer === "undefined" ? randomBytes(size) : new Uint8Array(buffer);
// Prevent the "bytes" property from being modified.
Object.defineProperty(this, "bytes", {
enumerable: true,
writable: false,
configurable: false,
value: this.bytes
});
}
}
/**
* Returns true if a is equal to b, without leaking timing information that would allow an attacker to guess one of the values.
* @param {string} a String a.
* @param {string} b String b.
* @returns {boolean} Equality result.
*/ const timingSafeEqual = (a, b)=>{
{
if (a.length !== b.length) {
throw new TypeError("Input strings must have the same length");
}
let i = -1;
let out = 0;
while(++i < a.length){
out |= a.charCodeAt(i) ^ b.charCodeAt(i);
}
return out === 0;
}
};
/**
* HOTP: An HMAC-based One-time Password Algorithm.
* @see [RFC 4226](https://datatracker.ietf.org/doc/html/rfc4226)
*/ class HOTP {
/**
* Default configuration.
* @type {{
* issuer: string,
* label: string,
* issuerInLabel: boolean,
* algorithm: string,
* digits: number,
* counter: number
* window: number
* }}
*/ static get defaults() {
return {
issuer: "",
label: "OTPAuth",
issuerInLabel: true,
algorithm: "SHA1",
digits: 6,
counter: 0,
window: 1
};
}
/**
* Generates an HOTP token.
* @param {Object} config Configuration options.
* @param {Secret} config.secret Secret key.
* @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
* @param {number} [config.digits=6] Token length.
* @param {number} [config.counter=0] Counter value.
* @param {(algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array} [config.hmac] Custom HMAC function.
* @returns {string} Token.
*/ static generate({ secret, algorithm = HOTP.defaults.algorithm, digits = HOTP.defaults.digits, counter = HOTP.defaults.counter, hmac = hmacDigest }) {
const message = uintDecode(counter);
const digest = hmac(algorithm, secret.bytes, message);
if (!digest?.byteLength || digest.byteLength < 19) {
throw new TypeError("Return value must be at least 19 bytes");
}
const offset = digest[digest.byteLength - 1] & 15;
const otp = ((digest[offset] & 127) << 24 | (digest[offset + 1] & 255) << 16 | (digest[offset + 2] & 255) << 8 | digest[offset + 3] & 255) % 10 ** digits;
return otp.toString().padStart(digits, "0");
}
/**
* Generates an HOTP token.
* @param {Object} [config] Configuration options.
* @param {number} [config.counter=this.counter++] Counter value.
* @returns {string} Token.
*/ generate({ counter = this.counter++ } = {}) {
return HOTP.generate({
secret: this.secret,
algorithm: this.algorithm,
digits: this.digits,
counter,
hmac: this.hmac
});
}
/**
* Validates an HOTP token.
* @param {Object} config Configuration options.
* @param {string} config.token Token value.
* @param {Secret} config.secret Secret key.
* @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
* @param {number} [config.digits=6] Token length.
* @param {number} [config.counter=0] Counter value.
* @param {number} [config.window=1] Window of counter values to test.
* @param {(algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array} [config.hmac] Custom HMAC function.
* @returns {number|null} Token delta or null if it is not found in the search window, in which case it should be considered invalid.
*/ static validate({ token, secret, algorithm, digits = HOTP.defaults.digits, counter = HOTP.defaults.counter, window = HOTP.defaults.window, hmac = hmacDigest }) {
// Return early if the token length does not match the digit number.
if (token.length !== digits) return null;
let delta = null;
const check = (/** @type {number} */ i)=>{
const generatedToken = HOTP.generate({
secret,
algorithm,
digits,
counter: i,
hmac
});
if (timingSafeEqual(token, generatedToken)) {
delta = i - counter;
}
};
check(counter);
for(let i = 1; i <= window && delta === null; ++i){
check(counter - i);
if (delta !== null) break;
check(counter + i);
if (delta !== null) break;
}
return delta;
}
/**
* Validates an HOTP token.
* @param {Object} config Configuration options.
* @param {string} config.token Token value.
* @param {number} [config.counter=this.counter] Counter value.
* @param {number} [config.window=1] Window of counter values to test.
* @returns {number|null} Token delta or null if it is not found in the search window, in which case it should be considered invalid.
*/ validate({ token, counter = this.counter, window }) {
return HOTP.validate({
token,
secret: this.secret,
algorithm: this.algorithm,
digits: this.digits,
counter,
window,
hmac: this.hmac
});
}
/**
* Returns a Google Authenticator key URI.
* @returns {string} URI.
*/ toString() {
const e = encodeURIComponent;
return "otpauth://hotp/" + `${this.issuer.length > 0 ? this.issuerInLabel ? `${e(this.issuer)}:${e(this.label)}?issuer=${e(this.issuer)}&` : `${e(this.label)}?issuer=${e(this.issuer)}&` : `${e(this.label)}?`}` + `secret=${e(this.secret.base32)}&` + `algorithm=${e(this.algorithm)}&` + `digits=${e(this.digits)}&` + `counter=${e(this.counter)}`;
}
/**
* Creates an HOTP object.
* @param {Object} [config] Configuration options.
* @param {string} [config.issuer=''] Account provider.
* @param {string} [config.label='OTPAuth'] Account label.
* @param {boolean} [config.issuerInLabel=true] Include issuer prefix in label.
* @param {Secret|string} [config.secret=Secret] Secret key.
* @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
* @param {number} [config.digits=6] Token length.
* @param {number} [config.counter=0] Initial counter value.
* @param {(algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array} [config.hmac] Custom HMAC function.
*/ constructor({ issuer = HOTP.defaults.issuer, label = HOTP.defaults.label, issuerInLabel = HOTP.defaults.issuerInLabel, secret = new Secret(), algorithm = HOTP.defaults.algorithm, digits = HOTP.defaults.digits, counter = HOTP.defaults.counter, hmac } = {}){
/**
* Account provider.
* @type {string}
*/ this.issuer = issuer;
/**
* Account label.
* @type {string}
*/ this.label = label;
/**
* Include issuer prefix in label.
* @type {boolean}
*/ this.issuerInLabel = issuerInLabel;
/**
* Secret key.
* @type {Secret}
*/ this.secret = typeof secret === "string" ? Secret.fromBase32(secret) : secret;
/**
* HMAC hashing algorithm.
* @type {string}
*/ this.algorithm = hmac ? algorithm : canonicalizeAlgorithm(algorithm);
/**
* Token length.
* @type {number}
*/ this.digits = digits;
/**
* Initial counter value.
* @type {number}
*/ this.counter = counter;
/**
* Custom HMAC function.
* @type {((algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array)|undefined}
*/ this.hmac = hmac;
}
}
/**
* TOTP: Time-Based One-Time Password Algorithm.
* @see [RFC 6238](https://datatracker.ietf.org/doc/html/rfc6238)
*/ class TOTP {
/**
* Default configuration.
* @type {{
* issuer: string,
* label: string,
* issuerInLabel: boolean,
* algorithm: string,
* digits: number,
* period: number
* window: number
* }}
*/ static get defaults() {
return {
issuer: "",
label: "OTPAuth",
issuerInLabel: true,
algorithm: "SHA1",
digits: 6,
period: 30,
window: 1
};
}
/**
* Calculates the counter. i.e. the number of periods since timestamp 0.
* @param {Object} [config] Configuration options.
* @param {number} [config.period=30] Token time-step duration.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @returns {number} Counter.
*/ static counter({ period = TOTP.defaults.period, timestamp = Date.now() } = {}) {
return Math.floor(timestamp / 1000 / period);
}
/**
* Calculates the counter. i.e. the number of periods since timestamp 0.
* @param {Object} [config] Configuration options.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @returns {number} Counter.
*/ counter({ timestamp = Date.now() } = {}) {
return TOTP.counter({
period: this.period,
timestamp
});
}
/**
* Calculates the remaining time in milliseconds until the next token is generated.
* @param {Object} [config] Configuration options.
* @param {number} [config.period=30] Token time-step duration.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @returns {number} counter.
*/ static remaining({ period = TOTP.defaults.period, timestamp = Date.now() } = {}) {
return period * 1000 - timestamp % (period * 1000);
}
/**
* Calculates the remaining time in milliseconds until the next token is generated.
* @param {Object} [config] Configuration options.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @returns {number} counter.
*/ remaining({ timestamp = Date.now() } = {}) {
return TOTP.remaining({
period: this.period,
timestamp
});
}
/**
* Generates a TOTP token.
* @param {Object} config Configuration options.
* @param {Secret} config.secret Secret key.
* @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
* @param {number} [config.digits=6] Token length.
* @param {number} [config.period=30] Token time-step duration.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @param {(algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array} [config.hmac] Custom HMAC function.
* @returns {string} Token.
*/ static generate({ secret, algorithm, digits, period = TOTP.defaults.period, timestamp = Date.now(), hmac }) {
return HOTP.generate({
secret,
algorithm,
digits,
counter: TOTP.counter({
period,
timestamp
}),
hmac
});
}
/**
* Generates a TOTP token.
* @param {Object} [config] Configuration options.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @returns {string} Token.
*/ generate({ timestamp = Date.now() } = {}) {
return TOTP.generate({
secret: this.secret,
algorithm: this.algorithm,
digits: this.digits,
period: this.period,
timestamp,
hmac: this.hmac
});
}
/**
* Validates a TOTP token.
* @param {Object} config Configuration options.
* @param {string} config.token Token value.
* @param {Secret} config.secret Secret key.
* @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
* @param {number} [config.digits=6] Token length.
* @param {number} [config.period=30] Token time-step duration.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @param {number} [config.window=1] Window of counter values to test.
* @param {(algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array} [config.hmac] Custom HMAC function.
* @returns {number|null} Token delta or null if it is not found in the search window, in which case it should be considered invalid.
*/ static validate({ token, secret, algorithm, digits, period = TOTP.defaults.period, timestamp = Date.now(), window, hmac }) {
return HOTP.validate({
token,
secret,
algorithm,
digits,
counter: TOTP.counter({
period,
timestamp
}),
window,
hmac
});
}
/**
* Validates a TOTP token.
* @param {Object} config Configuration options.
* @param {string} config.token Token value.
* @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
* @param {number} [config.window=1] Window of counter values to test.
* @returns {number|null} Token delta or null if it is not found in the search window, in which case it should be considered invalid.
*/ validate({ token, timestamp, window }) {
return TOTP.validate({
token,
secret: this.secret,
algorithm: this.algorithm,
digits: this.digits,
period: this.period,
timestamp,
window,
hmac: this.hmac
});
}
/**
* Returns a Google Authenticator key URI.
* @returns {string} URI.
*/ toString() {
const e = encodeURIComponent;
return "otpauth://totp/" + `${this.issuer.length > 0 ? this.issuerInLabel ? `${e(this.issuer)}:${e(this.label)}?issuer=${e(this.issuer)}&` : `${e(this.label)}?issuer=${e(this.issuer)}&` : `${e(this.label)}?`}` + `secret=${e(this.secret.base32)}&` + `algorithm=${e(this.algorithm)}&` + `digits=${e(this.digits)}&` + `period=${e(this.period)}`;
}
/**
* Creates a TOTP object.
* @param {Object} [config] Configuration options.
* @param {string} [config.issuer=''] Account provider.
* @param {string} [config.label='OTPAuth'] Account label.
* @param {boolean} [config.issuerInLabel=true] Include issuer prefix in label.
* @param {Secret|string} [config.secret=Secret] Secret key.
* @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
* @param {number} [config.digits=6] Token length.
* @param {number} [config.period=30] Token time-step duration.
* @param {(algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array} [config.hmac] Custom HMAC function.
*/ constructor({ issuer = TOTP.defaults.issuer, label = TOTP.defaults.label, issuerInLabel = TOTP.defaults.issuerInLabel, secret = new Secret(), algorithm = TOTP.defaults.algorithm, digits = TOTP.defaults.digits, period = TOTP.defaults.period, hmac } = {}){
/**
* Account provider.
* @type {string}
*/ this.issuer = issuer;
/**
* Account label.
* @type {string}
*/ this.label = label;
/**
* Include issuer prefix in label.
* @type {boolean}
*/ this.issuerInLabel = issuerInLabel;
/**
* Secret key.
* @type {Secret}
*/ this.secret = typeof secret === "string" ? Secret.fromBase32(secret) : secret;
/**
* HMAC hashing algorithm.
* @type {string}
*/ this.algorithm = hmac ? algorithm : canonicalizeAlgorithm(algorithm);
/**
* Token length.
* @type {number}
*/ this.digits = digits;
/**
* Token time-step duration.
* @type {number}
*/ this.period = period;
/**
* Custom HMAC function.
* @type {((algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array)|undefined}
*/ this.hmac = hmac;
}
}
/**
* Key URI regex (otpauth://TYPE/[ISSUER:]LABEL?PARAMETERS).
* @type {RegExp}
*/ const OTPURI_REGEX = /^otpauth:\/\/([ht]otp)\/(.+)\?([A-Z0-9.~_-]+=[^?&]*(?:&[A-Z0-9.~_-]+=[^?&]*)*)$/i;
/**
* RFC 4648 base32 alphabet with pad.
* @type {RegExp}
*/ const SECRET_REGEX = /^[2-7A-Z]+=*$/i;
/**
* Regex for supported algorithms in built-in HMAC function.
* @type {RegExp}
*/ const ALGORITHM_REGEX = /^SHA(?:1|224|256|384|512|3-224|3-256|3-384|3-512)$/i;
/**
* Regex for custom algorithms in user-defined HMAC function.
* @type {RegExp}
*/ const ALGORITHM_CUSTOM_REGEX = /^[A-Z0-9]+(?:[_-][A-Z0-9]+)*$/i;
/**
* Integer regex.
* @type {RegExp}
*/ const INTEGER_REGEX = /^[+-]?\d+$/;
/**
* Positive integer regex.
* @type {RegExp}
*/ const POSITIVE_INTEGER_REGEX = /^\+?[1-9]\d*$/;
/**
* HOTP/TOTP object/string conversion.
* @see [Key URI Format](https://github.com/google/google-authenticator/wiki/Key-Uri-Format)
*/ class URI {
/**
* Parses a Google Authenticator key URI and returns an HOTP/TOTP object.
* @param {string} uri Google Authenticator Key URI.
* @param {Object} [config] Configuration options.
* @param {(algorithm: string, key: Uint8Array, message: Uint8Array) => Uint8Array} [config.hmac] Custom HMAC function.
* @returns {HOTP|TOTP} HOTP/TOTP object.
*/ static parse(uri, { hmac } = {}) {
let uriGroups;
try {
uriGroups = uri.match(OTPURI_REGEX);
// eslint-disable-next-line no-unused-vars
} catch (_) {
/* Handled below */ }
if (!Array.isArray(uriGroups)) {
throw new URIError("Invalid URI format");
}
// Extract URI groups.
const uriType = uriGroups[1].toLowerCase();
const uriLabel = uriGroups[2].split(/(?::|%3A) *(.+)/i, 2).map(decodeURIComponent);
/** @type {Object.<string, string>} */ const uriParams = uriGroups[3].split("&").reduce((acc, cur)=>{
const pairArr = cur.split(/=(.*)/, 2).map(decodeURIComponent);
const pairKey = pairArr[0].toLowerCase();
const pairVal = pairArr[1];
/** @type {Object.<string, string>} */ const pairAcc = acc;
pairAcc[pairKey] = pairVal;
return pairAcc;
}, {});
// 'OTP' will be instantiated with 'config' argument.
let OTP;
const config = {};
if (uriType === "hotp") {
OTP = HOTP;
// Counter: required
if (typeof uriParams.counter !== "undefined" && INTEGER_REGEX.test(uriParams.counter)) {
config.counter = parseInt(uriParams.counter, 10);
} else {
throw new TypeError("Missing or invalid 'counter' parameter");
}
} else if (uriType === "totp") {
OTP = TOTP;
// Period: optional
if (typeof uriParams.period !== "undefined") {
if (POSITIVE_INTEGER_REGEX.test(uriParams.period)) {
config.period = parseInt(uriParams.period, 10);
} else {
throw new TypeError("Invalid 'period' parameter");
}
}
} else {
throw new TypeError("Unknown OTP type");
}
// Label: required
// Issuer: optional
if (typeof uriParams.issuer !== "undefined") {
config.issuer = uriParams.issuer;
}
if (uriLabel.length === 2) {
config.label = uriLabel[1];
if (typeof config.issuer === "undefined" || config.issuer === "") {
config.issuer = uriLabel[0];
} else if (uriLabel[0] === "") {
config.issuerInLabel = false;
}
} else {
config.label = uriLabel[0];
if (typeof config.issuer !== "undefined" && config.issuer !== "") {
config.issuerInLabel = false;
}
}
// Secret: required
if (typeof uriParams.secret !== "undefined" && SECRET_REGEX.test(uriParams.secret)) {
config.secret = uriParams.secret;
} else {
throw new TypeError("Missing or invalid 'secret' parameter");
}
// Algorithm: optional
if (typeof uriParams.algorithm !== "undefined") {
if ((hmac ? ALGORITHM_CUSTOM_REGEX : ALGORITHM_REGEX).test(uriParams.algorithm)) {
config.algorithm = uriParams.algorithm;
} else {
throw new TypeError("Invalid 'algorithm' parameter");
}
}
// Digits: optional
if (typeof uriParams.digits !== "undefined") {
if (POSITIVE_INTEGER_REGEX.test(uriParams.digits)) {
config.digits = parseInt(uriParams.digits, 10);
} else {
throw new TypeError("Invalid 'digits' parameter");
}
}
// HMAC: optional
if (typeof hmac !== "undefined") {
config.hmac = hmac;
}
return new OTP(config);
}
/**
* Converts an HOTP/TOTP object to a Google Authenticator key URI.
* @param {HOTP|TOTP} otp HOTP/TOTP object.
* @returns {string} Google Authenticator Key URI.
*/ static stringify(otp) {
if (otp instanceof HOTP || otp instanceof TOTP) {
return otp.toString();
}
throw new TypeError("Invalid 'HOTP/TOTP' object");
}
}
/**
* Library version.
* @type {string}
*/ const version = "9.5.0";
export { HOTP, Secret, TOTP, URI, version };

View File

@@ -0,0 +1,10 @@
//! otpauth 9.5.0 | (c) Héctor Molinero Fernández | MIT | https://github.com/hectorm/otpauth
//! noble-hashes 2.0.1 | (c) Paul Miller | MIT | https://github.com/paulmillr/noble-hashes
/// <reference types="./otpauth.d.ts" />
// @ts-nocheck
import{hmac as e}from"@noble/hashes/hmac.js";import{sha1 as t}from"@noble/hashes/legacy.js";import{sha512 as r,sha384 as i,sha256 as s,sha224 as n}from"@noble/hashes/sha2.js";import{sha3_512 as o,sha3_384 as a,sha3_256 as l,sha3_224 as u}from"@noble/hashes/sha3.js";const h=(()=>{if("object"==typeof globalThis)return globalThis;Object.defineProperty(Object.prototype,"__GLOBALTHIS__",{get(){return this},configurable:!0});try{if("undefined"!=typeof __GLOBALTHIS__)return __GLOBALTHIS__}finally{delete Object.prototype.__GLOBALTHIS__}return"undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:void 0})(),c={SHA1:t,SHA224:n,SHA256:s,SHA384:i,SHA512:r,"SHA3-224":u,"SHA3-256":l,"SHA3-384":a,"SHA3-512":o},d=e=>{switch(!0){case/^(?:SHA-?1|SSL3-SHA1)$/i.test(e):return"SHA1";case/^SHA(?:2?-)?224$/i.test(e):return"SHA224";case/^SHA(?:2?-)?256$/i.test(e):return"SHA256";case/^SHA(?:2?-)?384$/i.test(e):return"SHA384";case/^SHA(?:2?-)?512$/i.test(e):return"SHA512";case/^SHA3-224$/i.test(e):return"SHA3-224";case/^SHA3-256$/i.test(e):return"SHA3-256";case/^SHA3-384$/i.test(e):return"SHA3-384";case/^SHA3-512$/i.test(e):return"SHA3-512";default:throw new TypeError(`Unknown hash algorithm: ${e}`)}},g=(t,r,i)=>{if(e){const s=c[t]??c[d(t)];return e(s,r,i)}throw new Error("Missing HMAC function")},f="ABCDEFGHIJKLMNOPQRSTUVWXYZ234567",m=e=>{let t=(e=e.replace(/ /g,"")).length;for(;"="===e[t-1];)--t;e=(t<e.length?e.substring(0,t):e).toUpperCase();const r=new ArrayBuffer(5*e.length/8|0),i=new Uint8Array(r);let s=0,n=0,o=0;for(let t=0;t<e.length;t++){const r=f.indexOf(e[t]);if(-1===r)throw new TypeError(`Invalid character found: ${e[t]}`);n=n<<5|r,s+=5,s>=8&&(s-=8,i[o++]=n>>>s)}return i},p=e=>{let t=0,r=0,i="";for(let s=0;s<e.length;s++)for(r=r<<8|e[s],t+=8;t>=5;)i+=f[r>>>t-5&31],t-=5;return t>0&&(i+=f[r<<5-t&31]),i},b=e=>{e=e.replace(/ /g,"");const t=new ArrayBuffer(e.length/2),r=new Uint8Array(t);for(let t=0;t<e.length;t+=2)r[t/2]=parseInt(e.substring(t,t+2),16);return r},w=e=>{let t=""
;for(let r=0;r<e.length;r++){const i=e[r].toString(16);1===i.length&&(t+="0"),t+=i}return t.toUpperCase()},A=e=>{const t=new ArrayBuffer(e.length),r=new Uint8Array(t);for(let t=0;t<e.length;t++)r[t]=255&e.charCodeAt(t);return r},y=e=>{let t="";for(let r=0;r<e.length;r++)t+=String.fromCharCode(e[r]);return t},S=h.TextEncoder?new h.TextEncoder:null,H=h.TextDecoder?new h.TextDecoder:null,I=e=>{if(!S)throw new Error("Encoding API not available");return S.encode(e)},$=e=>{if(!H)throw new Error("Encoding API not available");return H.decode(e)};class v{static fromLatin1(e){return new v({buffer:A(e).buffer})}static fromUTF8(e){return new v({buffer:I(e).buffer})}static fromBase32(e){return new v({buffer:m(e).buffer})}static fromHex(e){return new v({buffer:b(e).buffer})}get buffer(){return this.bytes.buffer}get latin1(){return Object.defineProperty(this,"latin1",{enumerable:!0,writable:!1,configurable:!1,value:y(this.bytes)}),this.latin1}get utf8(){return Object.defineProperty(this,"utf8",{enumerable:!0,writable:!1,configurable:!1,value:$(this.bytes)}),this.utf8}get base32(){return Object.defineProperty(this,"base32",{enumerable:!0,writable:!1,configurable:!1,value:p(this.bytes)}),this.base32}get hex(){return Object.defineProperty(this,"hex",{enumerable:!0,writable:!1,configurable:!1,value:w(this.bytes)}),this.hex}constructor({buffer:e,size:t=20}={}){this.bytes=void 0===e?(e=>{if(h.crypto?.getRandomValues)return h.crypto.getRandomValues(new Uint8Array(e));throw new Error("Cryptography API not available")})(t):new Uint8Array(e),Object.defineProperty(this,"bytes",{enumerable:!0,writable:!1,configurable:!1,value:this.bytes})}}class T{static get defaults(){return{issuer:"",label:"OTPAuth",issuerInLabel:!0,algorithm:"SHA1",digits:6,counter:0,window:1}}static generate({secret:e,algorithm:t=T.defaults.algorithm,digits:r=T.defaults.digits,counter:i=T.defaults.counter,hmac:s=g}){const n=(e=>{const t=new ArrayBuffer(8),r=new Uint8Array(t);let i=e;for(let e=7;e>=0&&0!==i;e--)r[e]=255&i,i-=r[e],i/=256;return r})(i),o=s(t,e.bytes,n)
;if(!o?.byteLength||o.byteLength<19)throw new TypeError("Return value must be at least 19 bytes");const a=15&o[o.byteLength-1];return(((127&o[a])<<24|(255&o[a+1])<<16|(255&o[a+2])<<8|255&o[a+3])%10**r).toString().padStart(r,"0")}generate({counter:e=this.counter++}={}){return T.generate({secret:this.secret,algorithm:this.algorithm,digits:this.digits,counter:e,hmac:this.hmac})}static validate({token:e,secret:t,algorithm:r,digits:i=T.defaults.digits,counter:s=T.defaults.counter,window:n=T.defaults.window,hmac:o=g}){if(e.length!==i)return null;let a=null;const l=n=>{const l=T.generate({secret:t,algorithm:r,digits:i,counter:n,hmac:o});((e,t)=>{{if(e.length!==t.length)throw new TypeError("Input strings must have the same length");let r=-1,i=0;for(;++r<e.length;)i|=e.charCodeAt(r)^t.charCodeAt(r);return 0===i}})(e,l)&&(a=n-s)};l(s);for(let e=1;e<=n&&null===a&&(l(s-e),null===a)&&(l(s+e),null===a);++e);return a}validate({token:e,counter:t=this.counter,window:r}){return T.validate({token:e,secret:this.secret,algorithm:this.algorithm,digits:this.digits,counter:t,window:r,hmac:this.hmac})}toString(){const e=encodeURIComponent;return"otpauth://hotp/"+(this.issuer.length>0?this.issuerInLabel?`${e(this.issuer)}:${e(this.label)}?issuer=${e(this.issuer)}&`:`${e(this.label)}?issuer=${e(this.issuer)}&`:`${e(this.label)}?`)+`secret=${e(this.secret.base32)}&`+`algorithm=${e(this.algorithm)}&`+`digits=${e(this.digits)}&`+`counter=${e(this.counter)}`}constructor({issuer:e=T.defaults.issuer,label:t=T.defaults.label,issuerInLabel:r=T.defaults.issuerInLabel,secret:i=new v,algorithm:s=T.defaults.algorithm,digits:n=T.defaults.digits,counter:o=T.defaults.counter,hmac:a}={}){this.issuer=e,this.label=t,this.issuerInLabel=r,this.secret="string"==typeof i?v.fromBase32(i):i,this.algorithm=a?s:d(s),this.digits=n,this.counter=o,this.hmac=a}}class L{static get defaults(){return{issuer:"",label:"OTPAuth",issuerInLabel:!0,algorithm:"SHA1",digits:6,period:30,window:1}}static counter({period:e=L.defaults.period,timestamp:t=Date.now()}={}){
return Math.floor(t/1e3/e)}counter({timestamp:e=Date.now()}={}){return L.counter({period:this.period,timestamp:e})}static remaining({period:e=L.defaults.period,timestamp:t=Date.now()}={}){return 1e3*e-t%(1e3*e)}remaining({timestamp:e=Date.now()}={}){return L.remaining({period:this.period,timestamp:e})}static generate({secret:e,algorithm:t,digits:r,period:i=L.defaults.period,timestamp:s=Date.now(),hmac:n}){return T.generate({secret:e,algorithm:t,digits:r,counter:L.counter({period:i,timestamp:s}),hmac:n})}generate({timestamp:e=Date.now()}={}){return L.generate({secret:this.secret,algorithm:this.algorithm,digits:this.digits,period:this.period,timestamp:e,hmac:this.hmac})}static validate({token:e,secret:t,algorithm:r,digits:i,period:s=L.defaults.period,timestamp:n=Date.now(),window:o,hmac:a}){return T.validate({token:e,secret:t,algorithm:r,digits:i,counter:L.counter({period:s,timestamp:n}),window:o,hmac:a})}validate({token:e,timestamp:t,window:r}){return L.validate({token:e,secret:this.secret,algorithm:this.algorithm,digits:this.digits,period:this.period,timestamp:t,window:r,hmac:this.hmac})}toString(){const e=encodeURIComponent;return"otpauth://totp/"+(this.issuer.length>0?this.issuerInLabel?`${e(this.issuer)}:${e(this.label)}?issuer=${e(this.issuer)}&`:`${e(this.label)}?issuer=${e(this.issuer)}&`:`${e(this.label)}?`)+`secret=${e(this.secret.base32)}&`+`algorithm=${e(this.algorithm)}&`+`digits=${e(this.digits)}&`+`period=${e(this.period)}`}constructor({issuer:e=L.defaults.issuer,label:t=L.defaults.label,issuerInLabel:r=L.defaults.issuerInLabel,secret:i=new v,algorithm:s=L.defaults.algorithm,digits:n=L.defaults.digits,period:o=L.defaults.period,hmac:a}={}){this.issuer=e,this.label=t,this.issuerInLabel=r,this.secret="string"==typeof i?v.fromBase32(i):i,this.algorithm=a?s:d(s),this.digits=n,this.period=o,this.hmac=a}}
const E=/^otpauth:\/\/([ht]otp)\/(.+)\?([A-Z0-9.~_-]+=[^?&]*(?:&[A-Z0-9.~_-]+=[^?&]*)*)$/i,O=/^[2-7A-Z]+=*$/i,_=/^SHA(?:1|224|256|384|512|3-224|3-256|3-384|3-512)$/i,U=/^[A-Z0-9]+(?:[_-][A-Z0-9]+)*$/i,C=/^[+-]?\d+$/,P=/^\+?[1-9]\d*$/;class j{static parse(e,{hmac:t}={}){let r;try{r=e.match(E)}catch(e){}if(!Array.isArray(r))throw new URIError("Invalid URI format");const i=r[1].toLowerCase(),s=r[2].split(/(?::|%3A) *(.+)/i,2).map(decodeURIComponent),n=r[3].split("&").reduce((e,t)=>{const r=t.split(/=(.*)/,2).map(decodeURIComponent),i=r[0].toLowerCase(),s=r[1],n=e;return n[i]=s,n},{});let o;const a={};if("hotp"===i){if(o=T,void 0===n.counter||!C.test(n.counter))throw new TypeError("Missing or invalid 'counter' parameter");a.counter=parseInt(n.counter,10)}else{if("totp"!==i)throw new TypeError("Unknown OTP type");if(o=L,void 0!==n.period){if(!P.test(n.period))throw new TypeError("Invalid 'period' parameter");a.period=parseInt(n.period,10)}}if(void 0!==n.issuer&&(a.issuer=n.issuer),2===s.length?(a.label=s[1],void 0===a.issuer||""===a.issuer?a.issuer=s[0]:""===s[0]&&(a.issuerInLabel=!1)):(a.label=s[0],void 0!==a.issuer&&""!==a.issuer&&(a.issuerInLabel=!1)),void 0===n.secret||!O.test(n.secret))throw new TypeError("Missing or invalid 'secret' parameter");if(a.secret=n.secret,void 0!==n.algorithm){if(!(t?U:_).test(n.algorithm))throw new TypeError("Invalid 'algorithm' parameter");a.algorithm=n.algorithm}if(void 0!==n.digits){if(!P.test(n.digits))throw new TypeError("Invalid 'digits' parameter");a.digits=parseInt(n.digits,10)}return void 0!==t&&(a.hmac=t),new o(a)}static stringify(e){if(e instanceof T||e instanceof L)return e.toString();throw new TypeError("Invalid 'HOTP/TOTP' object")}}const B="9.5.0";export{T as HOTP,v as Secret,L as TOTP,j as URI,B as version};
//# sourceMappingURL=otpauth.slim.esm.min.js.map

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,19 @@
//! otpauth 9.5.0 | (c) Héctor Molinero Fernández | MIT | https://github.com/hectorm/otpauth
//! noble-hashes 2.0.1 | (c) Paul Miller | MIT | https://github.com/paulmillr/noble-hashes
/// <reference types="./otpauth.d.ts" />
// @ts-nocheck
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).OTPAuth={})}(this,function(t){"use strict";function e(t,e=""){if(!Number.isSafeInteger(t)||t<0)throw new Error(`${e&&`"${e}" `}expected integer >= 0, got ${t}`)}function s(t,e,s=""){const i=(r=t)instanceof Uint8Array||ArrayBuffer.isView(r)&&"Uint8Array"===r.constructor.name;var r;const n=t?.length,o=void 0!==e;if(!i||o&&n!==e)throw new Error((s&&`"${s}" `)+"expected Uint8Array"+(o?` of length ${e}`:"")+", got "+(i?`length=${n}`:"type="+typeof t));return t}function i(t,e=!0){if(t.destroyed)throw new Error("Hash instance has been destroyed");if(e&&t.finished)throw new Error("Hash#digest() has already been called")}function r(t,e){s(t,void 0,"digestInto() output");const i=e.outputLen;if(t.length<i)throw new Error('"digestInto() output" expected to be of length >='+i)}function n(...t){for(let e=0;e<t.length;e++)t[e].fill(0)}function o(t){return new DataView(t.buffer,t.byteOffset,t.byteLength)}function h(t,e){return t<<32-e|t>>>e}function a(t,e){return t<<e|t>>>32-e>>>0}function c(t){return t<<24&4278190080|t<<8&16711680|t>>>8&65280|t>>>24&255}const l=(()=>68===new Uint8Array(new Uint32Array([287454020]).buffer)[0])()?t=>t:function(t){for(let e=0;e<t.length;e++)t[e]=c(t[e]);return t};function u(t,e={}){const s=(e,s)=>t(s).update(e).digest(),i=t(void 0);return s.outputLen=i.outputLen,s.blockLen=i.blockLen,s.create=e=>t(e),Object.assign(s,e),Object.freeze(s)}const f=t=>({oid:Uint8Array.from([6,9,96,134,72,1,101,3,4,2,t])});class d{update(t){return i(this),this.iHash.update(t),this}digestInto(t){i(this),s(t,this.outputLen,"output"),this.finished=!0,this.iHash.digestInto(t),this.oHash.update(t),this.oHash.digestInto(t),this.destroy()}digest(){const t=new Uint8Array(this.oHash.outputLen);return this.digestInto(t),t}_cloneInto(t){t||(t=Object.create(Object.getPrototypeOf(this),{}))
;const{oHash:e,iHash:s,finished:i,destroyed:r,blockLen:n,outputLen:o}=this;return t.finished=i,t.destroyed=r,t.blockLen=n,t.outputLen=o,t.oHash=e._cloneInto(t.oHash),t.iHash=s._cloneInto(t.iHash),t}clone(){return this._cloneInto()}destroy(){this.destroyed=!0,this.oHash.destroy(),this.iHash.destroy()}constructor(t,i){if(this.finished=!1,this.destroyed=!1,function(t){if("function"!=typeof t||"function"!=typeof t.create)throw new Error("Hash must wrapped by utils.createHasher");e(t.outputLen),e(t.blockLen)}(t),s(i,void 0,"key"),this.iHash=t.create(),"function"!=typeof this.iHash.update)throw new Error("Expected instance of class which extends utils.Hash");this.blockLen=this.iHash.blockLen,this.outputLen=this.iHash.outputLen;const r=this.blockLen,o=new Uint8Array(r);o.set(i.length>r?t.create().update(i).digest():i);for(let t=0;t<o.length;t++)o[t]^=54;this.iHash.update(o),this.oHash=t.create();for(let t=0;t<o.length;t++)o[t]^=106;this.oHash.update(o),n(o)}}const b=(t,e,s)=>new d(t,e).update(s).digest();function g(t,e,s){return t&e^~t&s}function p(t,e,s){return t&e^t&s^e&s}b.create=(t,e)=>new d(t,e);class w{update(t){i(this),s(t);const{view:e,buffer:r,blockLen:n}=this,h=t.length;for(let s=0;s<h;){const i=Math.min(n-this.pos,h-s);if(i===n){const e=o(t);for(;n<=h-s;s+=n)this.process(e,s);continue}r.set(t.subarray(s,s+i),this.pos),this.pos+=i,s+=i,this.pos===n&&(this.process(e,0),this.pos=0)}return this.length+=t.length,this.roundClean(),this}digestInto(t){i(this),r(t,this),this.finished=!0;const{buffer:e,view:s,blockLen:h,isLE:a}=this;let{pos:c}=this;e[c++]=128,n(this.buffer.subarray(c)),this.padOffset>h-c&&(this.process(s,0),c=0);for(let t=c;t<h;t++)e[t]=0;s.setBigUint64(h-8,BigInt(8*this.length),a),this.process(s,0);const l=o(t),u=this.outputLen;if(u%4)throw new Error("_sha2: outputLen must be aligned to 32bit");const f=u/4,d=this.get();if(f>d.length)throw new Error("_sha2: outputLen bigger than state");for(let t=0;t<f;t++)l.setUint32(4*t,d[t],a)}digest(){const{buffer:t,outputLen:e}=this;this.digestInto(t)
;const s=t.slice(0,e);return this.destroy(),s}_cloneInto(t){t||(t=new this.constructor),t.set(...this.get());const{blockLen:e,buffer:s,length:i,finished:r,destroyed:n,pos:o}=this;return t.destroyed=n,t.finished=r,t.length=i,t.pos=o,i%e&&t.buffer.set(s),t}clone(){return this._cloneInto()}constructor(t,e,s,i){this.finished=!1,this.length=0,this.pos=0,this.destroyed=!1,this.blockLen=t,this.outputLen=e,this.padOffset=s,this.isLE=i,this.buffer=new Uint8Array(t),this.view=o(this.buffer)}}const m=Uint32Array.from([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]),y=Uint32Array.from([3238371032,914150663,812702999,4144912697,4290775857,1750603025,1694076839,3204075428]),A=Uint32Array.from([3418070365,3238371032,1654270250,914150663,2438529370,812702999,355462360,4144912697,1731405415,4290775857,2394180231,1750603025,3675008525,1694076839,1203062813,3204075428]),x=Uint32Array.from([1779033703,4089235720,3144134277,2227873595,1013904242,4271175723,2773480762,1595750129,1359893119,2917565137,2600822924,725511199,528734635,4215389547,1541459225,327033209]),H=Uint32Array.from([1732584193,4023233417,2562383102,271733878,3285377520]),I=new Uint32Array(80);class L extends w{get(){const{A:t,B:e,C:s,D:i,E:r}=this;return[t,e,s,i,r]}set(t,e,s,i,r){this.A=0|t,this.B=0|e,this.C=0|s,this.D=0|i,this.E=0|r}process(t,e){for(let s=0;s<16;s++,e+=4)I[s]=t.getUint32(e,!1);for(let t=16;t<80;t++)I[t]=a(I[t-3]^I[t-8]^I[t-14]^I[t-16],1);let{A:s,B:i,C:r,D:n,E:o}=this;for(let t=0;t<80;t++){let e,h;t<20?(e=g(i,r,n),h=1518500249):t<40?(e=i^r^n,h=1859775393):t<60?(e=p(i,r,n),h=2400959708):(e=i^r^n,h=3395469782);const c=a(s,5)+e+o+h+I[t]|0;o=n,n=r,r=a(i,30),i=s,s=c}s=s+this.A|0,i=i+this.B|0,r=r+this.C|0,n=n+this.D|0,o=o+this.E|0,this.set(s,i,r,n,o)}roundClean(){n(I)}destroy(){this.set(0,0,0,0,0),n(this.buffer)}constructor(){super(64,20,8,!1),this.A=0|H[0],this.B=0|H[1],this.C=0|H[2],this.D=0|H[3],this.E=0|H[4]}}const E=u(()=>new L),U=BigInt(2**32-1),B=BigInt(32);function S(t,e=!1){return e?{h:Number(t&U),
l:Number(t>>B&U)}:{h:0|Number(t>>B&U),l:0|Number(t&U)}}function v(t,e=!1){const s=t.length;let i=new Uint32Array(s),r=new Uint32Array(s);for(let n=0;n<s;n++){const{h:s,l:o}=S(t[n],e);[i[n],r[n]]=[s,o]}return[i,r]}const O=(t,e,s)=>t>>>s,C=(t,e,s)=>t<<32-s|e>>>s,$=(t,e,s)=>t>>>s|e<<32-s,k=(t,e,s)=>t<<32-s|e>>>s,T=(t,e,s)=>t<<64-s|e>>>s-32,D=(t,e,s)=>t>>>s-32|e<<64-s;function _(t,e,s,i){const r=(e>>>0)+(i>>>0);return{h:t+s+(r/2**32|0)|0,l:0|r}}const F=(t,e,s)=>(t>>>0)+(e>>>0)+(s>>>0),G=(t,e,s,i)=>e+s+i+(t/2**32|0)|0,P=(t,e,s,i)=>(t>>>0)+(e>>>0)+(s>>>0)+(i>>>0),j=(t,e,s,i,r)=>e+s+i+r+(t/2**32|0)|0,R=(t,e,s,i,r)=>(t>>>0)+(e>>>0)+(s>>>0)+(i>>>0)+(r>>>0),M=(t,e,s,i,r,n)=>e+s+i+r+n+(t/2**32|0)|0,X=Uint32Array.from([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]),N=new Uint32Array(64);class Z extends w{get(){const{A:t,B:e,C:s,D:i,E:r,F:n,G:o,H:h}=this;return[t,e,s,i,r,n,o,h]}set(t,e,s,i,r,n,o,h){this.A=0|t,this.B=0|e,this.C=0|s,this.D=0|i,this.E=0|r,this.F=0|n,this.G=0|o,this.H=0|h}process(t,e){for(let s=0;s<16;s++,e+=4)N[s]=t.getUint32(e,!1);for(let t=16;t<64;t++){const e=N[t-15],s=N[t-2],i=h(e,7)^h(e,18)^e>>>3,r=h(s,17)^h(s,19)^s>>>10;N[t]=r+N[t-7]+i+N[t-16]|0}let{A:s,B:i,C:r,D:n,E:o,F:a,G:c,H:l}=this;for(let t=0;t<64;t++){const e=l+(h(o,6)^h(o,11)^h(o,25))+g(o,a,c)+X[t]+N[t]|0,u=(h(s,2)^h(s,13)^h(s,22))+p(s,i,r)|0;l=c,c=a,a=o,o=n+e|0,n=r,r=i,i=s,s=e+u|0}s=s+this.A|0,i=i+this.B|0,
r=r+this.C|0,n=n+this.D|0,o=o+this.E|0,a=a+this.F|0,c=c+this.G|0,l=l+this.H|0,this.set(s,i,r,n,o,a,c,l)}roundClean(){n(N)}destroy(){this.set(0,0,0,0,0,0,0,0),n(this.buffer)}constructor(t){super(64,t,8,!1)}}class V extends Z{constructor(){super(32),this.A=0|m[0],this.B=0|m[1],this.C=0|m[2],this.D=0|m[3],this.E=0|m[4],this.F=0|m[5],this.G=0|m[6],this.H=0|m[7]}}class z extends Z{constructor(){super(28),this.A=0|y[0],this.B=0|y[1],this.C=0|y[2],this.D=0|y[3],this.E=0|y[4],this.F=0|y[5],this.G=0|y[6],this.H=0|y[7]}}
const J=(()=>v(["0x428a2f98d728ae22","0x7137449123ef65cd","0xb5c0fbcfec4d3b2f","0xe9b5dba58189dbbc","0x3956c25bf348b538","0x59f111f1b605d019","0x923f82a4af194f9b","0xab1c5ed5da6d8118","0xd807aa98a3030242","0x12835b0145706fbe","0x243185be4ee4b28c","0x550c7dc3d5ffb4e2","0x72be5d74f27b896f","0x80deb1fe3b1696b1","0x9bdc06a725c71235","0xc19bf174cf692694","0xe49b69c19ef14ad2","0xefbe4786384f25e3","0x0fc19dc68b8cd5b5","0x240ca1cc77ac9c65","0x2de92c6f592b0275","0x4a7484aa6ea6e483","0x5cb0a9dcbd41fbd4","0x76f988da831153b5","0x983e5152ee66dfab","0xa831c66d2db43210","0xb00327c898fb213f","0xbf597fc7beef0ee4","0xc6e00bf33da88fc2","0xd5a79147930aa725","0x06ca6351e003826f","0x142929670a0e6e70","0x27b70a8546d22ffc","0x2e1b21385c26c926","0x4d2c6dfc5ac42aed","0x53380d139d95b3df","0x650a73548baf63de","0x766a0abb3c77b2a8","0x81c2c92e47edaee6","0x92722c851482353b","0xa2bfe8a14cf10364","0xa81a664bbc423001","0xc24b8b70d0f89791","0xc76c51a30654be30","0xd192e819d6ef5218","0xd69906245565a910","0xf40e35855771202a","0x106aa07032bbd1b8","0x19a4c116b8d2d0c8","0x1e376c085141ab53","0x2748774cdf8eeb99","0x34b0bcb5e19b48a8","0x391c0cb3c5c95a63","0x4ed8aa4ae3418acb","0x5b9cca4f7763e373","0x682e6ff3d6b2b8a3","0x748f82ee5defb2fc","0x78a5636f43172f60","0x84c87814a1f0ab72","0x8cc702081a6439ec","0x90befffa23631e28","0xa4506cebde82bde9","0xbef9a3f7b2c67915","0xc67178f2e372532b","0xca273eceea26619c","0xd186b8c721c0c207","0xeada7dd6cde0eb1e","0xf57d4f7fee6ed178","0x06f067aa72176fba","0x0a637dc5a2c898a6","0x113f9804bef90dae","0x1b710b35131c471b","0x28db77f523047d84","0x32caab7b40c72493","0x3c9ebe0a15c9bebc","0x431d67c49c100d4c","0x4cc5d4becb3e42b6","0x597f299cfc657e2a","0x5fcb6fab3ad6faec","0x6c44198c4a475817"].map(t=>BigInt(t))))(),K=(()=>J[0])(),Q=(()=>J[1])(),W=new Uint32Array(80),Y=new Uint32Array(80);class q extends w{get(){const{Ah:t,Al:e,Bh:s,Bl:i,Ch:r,Cl:n,Dh:o,Dl:h,Eh:a,El:c,Fh:l,Fl:u,Gh:f,Gl:d,Hh:b,Hl:g}=this;return[t,e,s,i,r,n,o,h,a,c,l,u,f,d,b,g]}set(t,e,s,i,r,n,o,h,a,c,l,u,f,d,b,g){this.Ah=0|t,this.Al=0|e,this.Bh=0|s,this.Bl=0|i,this.Ch=0|r,
this.Cl=0|n,this.Dh=0|o,this.Dl=0|h,this.Eh=0|a,this.El=0|c,this.Fh=0|l,this.Fl=0|u,this.Gh=0|f,this.Gl=0|d,this.Hh=0|b,this.Hl=0|g}process(t,e){for(let s=0;s<16;s++,e+=4)W[s]=t.getUint32(e),Y[s]=t.getUint32(e+=4);for(let t=16;t<80;t++){const e=0|W[t-15],s=0|Y[t-15],i=$(e,s,1)^$(e,s,8)^O(e,0,7),r=k(e,s,1)^k(e,s,8)^C(e,s,7),n=0|W[t-2],o=0|Y[t-2],h=$(n,o,19)^T(n,o,61)^O(n,0,6),a=k(n,o,19)^D(n,o,61)^C(n,o,6),c=P(r,a,Y[t-7],Y[t-16]),l=j(c,i,h,W[t-7],W[t-16]);W[t]=0|l,Y[t]=0|c}let{Ah:s,Al:i,Bh:r,Bl:n,Ch:o,Cl:h,Dh:a,Dl:c,Eh:l,El:u,Fh:f,Fl:d,Gh:b,Gl:g,Hh:p,Hl:w}=this;for(let t=0;t<80;t++){const e=$(l,u,14)^$(l,u,18)^T(l,u,41),m=k(l,u,14)^k(l,u,18)^D(l,u,41),y=l&f^~l&b,A=R(w,m,u&d^~u&g,Q[t],Y[t]),x=M(A,p,e,y,K[t],W[t]),H=0|A,I=$(s,i,28)^T(s,i,34)^T(s,i,39),L=k(s,i,28)^D(s,i,34)^D(s,i,39),E=s&r^s&o^r&o,U=i&n^i&h^n&h;p=0|b,w=0|g,b=0|f,g=0|d,f=0|l,d=0|u,({h:l,l:u}=_(0|a,0|c,0|x,0|H)),a=0|o,c=0|h,o=0|r,h=0|n,r=0|s,n=0|i;const B=F(H,L,U);s=G(B,x,I,E),i=0|B}({h:s,l:i}=_(0|this.Ah,0|this.Al,0|s,0|i)),({h:r,l:n}=_(0|this.Bh,0|this.Bl,0|r,0|n)),({h:o,l:h}=_(0|this.Ch,0|this.Cl,0|o,0|h)),({h:a,l:c}=_(0|this.Dh,0|this.Dl,0|a,0|c)),({h:l,l:u}=_(0|this.Eh,0|this.El,0|l,0|u)),({h:f,l:d}=_(0|this.Fh,0|this.Fl,0|f,0|d)),({h:b,l:g}=_(0|this.Gh,0|this.Gl,0|b,0|g)),({h:p,l:w}=_(0|this.Hh,0|this.Hl,0|p,0|w)),this.set(s,i,r,n,o,h,a,c,l,u,f,d,b,g,p,w)}roundClean(){n(W,Y)}destroy(){n(this.buffer),this.set(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)}constructor(t){super(128,t,16,!1)}}class tt extends q{constructor(){super(64),this.Ah=0|x[0],this.Al=0|x[1],this.Bh=0|x[2],this.Bl=0|x[3],this.Ch=0|x[4],this.Cl=0|x[5],this.Dh=0|x[6],this.Dl=0|x[7],this.Eh=0|x[8],this.El=0|x[9],this.Fh=0|x[10],this.Fl=0|x[11],this.Gh=0|x[12],this.Gl=0|x[13],this.Hh=0|x[14],this.Hl=0|x[15]}}class et extends q{constructor(){super(48),this.Ah=0|A[0],this.Al=0|A[1],this.Bh=0|A[2],this.Bl=0|A[3],this.Ch=0|A[4],this.Cl=0|A[5],this.Dh=0|A[6],this.Dl=0|A[7],this.Eh=0|A[8],this.El=0|A[9],this.Fh=0|A[10],this.Fl=0|A[11],this.Gh=0|A[12],this.Gl=0|A[13],this.Hh=0|A[14],this.Hl=0|A[15]}}
const st=u(()=>new V,f(1)),it=u(()=>new z,f(4)),rt=u(()=>new tt,f(3)),nt=u(()=>new et,f(2)),ot=BigInt(0),ht=BigInt(1),at=BigInt(2),ct=BigInt(7),lt=BigInt(256),ut=BigInt(113),ft=[],dt=[],bt=[];for(let t=0,e=ht,s=1,i=0;t<24;t++){[s,i]=[i,(2*s+3*i)%5],ft.push(2*(5*i+s)),dt.push((t+1)*(t+2)/2%64);let r=ot;for(let t=0;t<7;t++)e=(e<<ht^(e>>ct)*ut)%lt,e&at&&(r^=ht<<(ht<<BigInt(t))-ht);bt.push(r)}const gt=v(bt,!0),pt=gt[0],wt=gt[1],mt=(t,e,s)=>s>32?((t,e,s)=>e<<s-32|t>>>64-s)(t,e,s):((t,e,s)=>t<<s|e>>>32-s)(t,e,s),yt=(t,e,s)=>s>32?((t,e,s)=>t<<s-32|e>>>64-s)(t,e,s):((t,e,s)=>e<<s|t>>>32-s)(t,e,s);class At{clone(){return this._cloneInto()}keccak(){l(this.state32),function(t,e=24){const s=new Uint32Array(10);for(let i=24-e;i<24;i++){for(let e=0;e<10;e++)s[e]=t[e]^t[e+10]^t[e+20]^t[e+30]^t[e+40];for(let e=0;e<10;e+=2){const i=(e+8)%10,r=(e+2)%10,n=s[r],o=s[r+1],h=mt(n,o,1)^s[i],a=yt(n,o,1)^s[i+1];for(let s=0;s<50;s+=10)t[e+s]^=h,t[e+s+1]^=a}let e=t[2],r=t[3];for(let s=0;s<24;s++){const i=dt[s],n=mt(e,r,i),o=yt(e,r,i),h=ft[s];e=t[h],r=t[h+1],t[h]=n,t[h+1]=o}for(let e=0;e<50;e+=10){for(let i=0;i<10;i++)s[i]=t[e+i];for(let i=0;i<10;i++)t[e+i]^=~s[(i+2)%10]&s[(i+4)%10]}t[0]^=pt[i],t[1]^=wt[i]}n(s)}(this.state32,this.rounds),l(this.state32),this.posOut=0,this.pos=0}update(t){i(this),s(t);const{blockLen:e,state:r}=this,n=t.length;for(let s=0;s<n;){const i=Math.min(e-this.pos,n-s);for(let e=0;e<i;e++)r[this.pos++]^=t[s++];this.pos===e&&this.keccak()}return this}finish(){if(this.finished)return;this.finished=!0;const{state:t,suffix:e,pos:s,blockLen:i}=this;t[s]^=e,128&e&&s===i-1&&this.keccak(),t[i-1]^=128,this.keccak()}writeInto(t){i(this,!1),s(t),this.finish();const e=this.state,{blockLen:r}=this;for(let s=0,i=t.length;s<i;){this.posOut>=r&&this.keccak();const n=Math.min(r-this.posOut,i-s);t.set(e.subarray(this.posOut,this.posOut+n),s),this.posOut+=n,s+=n}return t}xofInto(t){if(!this.enableXOF)throw new Error("XOF is not possible for this instance");return this.writeInto(t)}xof(t){return e(t),this.xofInto(new Uint8Array(t))}
digestInto(t){if(r(t,this),this.finished)throw new Error("digest() was already called");return this.writeInto(t),this.destroy(),t}digest(){return this.digestInto(new Uint8Array(this.outputLen))}destroy(){this.destroyed=!0,n(this.state)}_cloneInto(t){const{blockLen:e,suffix:s,outputLen:i,rounds:r,enableXOF:n}=this;return t||(t=new At(e,s,i,n,r)),t.state32.set(this.state32),t.pos=this.pos,t.posOut=this.posOut,t.finished=this.finished,t.rounds=r,t.suffix=s,t.outputLen=i,t.enableXOF=n,t.destroyed=this.destroyed,t}constructor(t,s,i,r=!1,n=24){if(this.pos=0,this.posOut=0,this.finished=!1,this.destroyed=!1,this.enableXOF=!1,this.blockLen=t,this.suffix=s,this.outputLen=i,this.enableXOF=r,this.rounds=n,e(i,"outputLen"),!(0<t&&t<200))throw new Error("only keccak-f1600 function is supported");var o;this.state=new Uint8Array(200),this.state32=(o=this.state,new Uint32Array(o.buffer,o.byteOffset,Math.floor(o.byteLength/4)))}}const xt=(t,e,s,i={})=>u(()=>new At(e,t,s),i),Ht=xt(6,144,28,f(7)),It=xt(6,136,32,f(8)),Lt=xt(6,104,48,f(9)),Et=xt(6,72,64,f(10)),Ut=(()=>{if("object"==typeof globalThis)return globalThis;Object.defineProperty(Object.prototype,"__GLOBALTHIS__",{get(){return this},configurable:!0});try{if("undefined"!=typeof __GLOBALTHIS__)return __GLOBALTHIS__}finally{delete Object.prototype.__GLOBALTHIS__}return"undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:void 0})(),Bt={SHA1:E,SHA224:it,SHA256:st,SHA384:nt,SHA512:rt,"SHA3-224":Ht,"SHA3-256":It,"SHA3-384":Lt,"SHA3-512":Et},St=t=>{switch(!0){case/^(?:SHA-?1|SSL3-SHA1)$/i.test(t):return"SHA1";case/^SHA(?:2?-)?224$/i.test(t):return"SHA224";case/^SHA(?:2?-)?256$/i.test(t):return"SHA256";case/^SHA(?:2?-)?384$/i.test(t):return"SHA384";case/^SHA(?:2?-)?512$/i.test(t):return"SHA512";case/^SHA3-224$/i.test(t):return"SHA3-224";case/^SHA3-256$/i.test(t):return"SHA3-256";case/^SHA3-384$/i.test(t):return"SHA3-384";case/^SHA3-512$/i.test(t):return"SHA3-512";default:throw new TypeError(`Unknown hash algorithm: ${t}`)}},vt=(t,e,s)=>{
if(b){const i=Bt[t]??Bt[St(t)];return b(i,e,s)}throw new Error("Missing HMAC function")},Ot="ABCDEFGHIJKLMNOPQRSTUVWXYZ234567",Ct=t=>{let e=(t=t.replace(/ /g,"")).length;for(;"="===t[e-1];)--e;t=(e<t.length?t.substring(0,e):t).toUpperCase();const s=new ArrayBuffer(5*t.length/8|0),i=new Uint8Array(s);let r=0,n=0,o=0;for(let e=0;e<t.length;e++){const s=Ot.indexOf(t[e]);if(-1===s)throw new TypeError(`Invalid character found: ${t[e]}`);n=n<<5|s,r+=5,r>=8&&(r-=8,i[o++]=n>>>r)}return i},$t=t=>{let e=0,s=0,i="";for(let r=0;r<t.length;r++)for(s=s<<8|t[r],e+=8;e>=5;)i+=Ot[s>>>e-5&31],e-=5;return e>0&&(i+=Ot[s<<5-e&31]),i},kt=t=>{t=t.replace(/ /g,"");const e=new ArrayBuffer(t.length/2),s=new Uint8Array(e);for(let e=0;e<t.length;e+=2)s[e/2]=parseInt(t.substring(e,e+2),16);return s},Tt=t=>{let e="";for(let s=0;s<t.length;s++){const i=t[s].toString(16);1===i.length&&(e+="0"),e+=i}return e.toUpperCase()},Dt=t=>{const e=new ArrayBuffer(t.length),s=new Uint8Array(e);for(let e=0;e<t.length;e++)s[e]=255&t.charCodeAt(e);return s},_t=t=>{let e="";for(let s=0;s<t.length;s++)e+=String.fromCharCode(t[s]);return e},Ft=Ut.TextEncoder?new Ut.TextEncoder:null,Gt=Ut.TextDecoder?new Ut.TextDecoder:null,Pt=t=>{if(!Ft)throw new Error("Encoding API not available");return Ft.encode(t)},jt=t=>{if(!Gt)throw new Error("Encoding API not available");return Gt.decode(t)};class Rt{static fromLatin1(t){return new Rt({buffer:Dt(t).buffer})}static fromUTF8(t){return new Rt({buffer:Pt(t).buffer})}static fromBase32(t){return new Rt({buffer:Ct(t).buffer})}static fromHex(t){return new Rt({buffer:kt(t).buffer})}get buffer(){return this.bytes.buffer}get latin1(){return Object.defineProperty(this,"latin1",{enumerable:!0,writable:!1,configurable:!1,value:_t(this.bytes)}),this.latin1}get utf8(){return Object.defineProperty(this,"utf8",{enumerable:!0,writable:!1,configurable:!1,value:jt(this.bytes)}),this.utf8}get base32(){return Object.defineProperty(this,"base32",{enumerable:!0,writable:!1,configurable:!1,value:$t(this.bytes)}),this.base32}get hex(){
return Object.defineProperty(this,"hex",{enumerable:!0,writable:!1,configurable:!1,value:Tt(this.bytes)}),this.hex}constructor({buffer:t,size:e=20}={}){this.bytes=void 0===t?(t=>{if(Ut.crypto?.getRandomValues)return Ut.crypto.getRandomValues(new Uint8Array(t));throw new Error("Cryptography API not available")})(e):new Uint8Array(t),Object.defineProperty(this,"bytes",{enumerable:!0,writable:!1,configurable:!1,value:this.bytes})}}class Mt{static get defaults(){return{issuer:"",label:"OTPAuth",issuerInLabel:!0,algorithm:"SHA1",digits:6,counter:0,window:1}}static generate({secret:t,algorithm:e=Mt.defaults.algorithm,digits:s=Mt.defaults.digits,counter:i=Mt.defaults.counter,hmac:r=vt}){const n=(t=>{const e=new ArrayBuffer(8),s=new Uint8Array(e);let i=t;for(let t=7;t>=0&&0!==i;t--)s[t]=255&i,i-=s[t],i/=256;return s})(i),o=r(e,t.bytes,n);if(!o?.byteLength||o.byteLength<19)throw new TypeError("Return value must be at least 19 bytes");const h=15&o[o.byteLength-1];return(((127&o[h])<<24|(255&o[h+1])<<16|(255&o[h+2])<<8|255&o[h+3])%10**s).toString().padStart(s,"0")}generate({counter:t=this.counter++}={}){return Mt.generate({secret:this.secret,algorithm:this.algorithm,digits:this.digits,counter:t,hmac:this.hmac})}static validate({token:t,secret:e,algorithm:s,digits:i=Mt.defaults.digits,counter:r=Mt.defaults.counter,window:n=Mt.defaults.window,hmac:o=vt}){if(t.length!==i)return null;let h=null;const a=n=>{const a=Mt.generate({secret:e,algorithm:s,digits:i,counter:n,hmac:o});((t,e)=>{{if(t.length!==e.length)throw new TypeError("Input strings must have the same length");let s=-1,i=0;for(;++s<t.length;)i|=t.charCodeAt(s)^e.charCodeAt(s);return 0===i}})(t,a)&&(h=n-r)};a(r);for(let t=1;t<=n&&null===h&&(a(r-t),null===h)&&(a(r+t),null===h);++t);return h}validate({token:t,counter:e=this.counter,window:s}){return Mt.validate({token:t,secret:this.secret,algorithm:this.algorithm,digits:this.digits,counter:e,window:s,hmac:this.hmac})}toString(){const t=encodeURIComponent
;return"otpauth://hotp/"+(this.issuer.length>0?this.issuerInLabel?`${t(this.issuer)}:${t(this.label)}?issuer=${t(this.issuer)}&`:`${t(this.label)}?issuer=${t(this.issuer)}&`:`${t(this.label)}?`)+`secret=${t(this.secret.base32)}&`+`algorithm=${t(this.algorithm)}&`+`digits=${t(this.digits)}&`+`counter=${t(this.counter)}`}constructor({issuer:t=Mt.defaults.issuer,label:e=Mt.defaults.label,issuerInLabel:s=Mt.defaults.issuerInLabel,secret:i=new Rt,algorithm:r=Mt.defaults.algorithm,digits:n=Mt.defaults.digits,counter:o=Mt.defaults.counter,hmac:h}={}){this.issuer=t,this.label=e,this.issuerInLabel=s,this.secret="string"==typeof i?Rt.fromBase32(i):i,this.algorithm=h?r:St(r),this.digits=n,this.counter=o,this.hmac=h}}class Xt{static get defaults(){return{issuer:"",label:"OTPAuth",issuerInLabel:!0,algorithm:"SHA1",digits:6,period:30,window:1}}static counter({period:t=Xt.defaults.period,timestamp:e=Date.now()}={}){return Math.floor(e/1e3/t)}counter({timestamp:t=Date.now()}={}){return Xt.counter({period:this.period,timestamp:t})}static remaining({period:t=Xt.defaults.period,timestamp:e=Date.now()}={}){return 1e3*t-e%(1e3*t)}remaining({timestamp:t=Date.now()}={}){return Xt.remaining({period:this.period,timestamp:t})}static generate({secret:t,algorithm:e,digits:s,period:i=Xt.defaults.period,timestamp:r=Date.now(),hmac:n}){return Mt.generate({secret:t,algorithm:e,digits:s,counter:Xt.counter({period:i,timestamp:r}),hmac:n})}generate({timestamp:t=Date.now()}={}){return Xt.generate({secret:this.secret,algorithm:this.algorithm,digits:this.digits,period:this.period,timestamp:t,hmac:this.hmac})}static validate({token:t,secret:e,algorithm:s,digits:i,period:r=Xt.defaults.period,timestamp:n=Date.now(),window:o,hmac:h}){return Mt.validate({token:t,secret:e,algorithm:s,digits:i,counter:Xt.counter({period:r,timestamp:n}),window:o,hmac:h})}validate({token:t,timestamp:e,window:s}){return Xt.validate({token:t,secret:this.secret,algorithm:this.algorithm,digits:this.digits,period:this.period,timestamp:e,window:s,hmac:this.hmac})}toString(){
const t=encodeURIComponent;return"otpauth://totp/"+(this.issuer.length>0?this.issuerInLabel?`${t(this.issuer)}:${t(this.label)}?issuer=${t(this.issuer)}&`:`${t(this.label)}?issuer=${t(this.issuer)}&`:`${t(this.label)}?`)+`secret=${t(this.secret.base32)}&`+`algorithm=${t(this.algorithm)}&`+`digits=${t(this.digits)}&`+`period=${t(this.period)}`}constructor({issuer:t=Xt.defaults.issuer,label:e=Xt.defaults.label,issuerInLabel:s=Xt.defaults.issuerInLabel,secret:i=new Rt,algorithm:r=Xt.defaults.algorithm,digits:n=Xt.defaults.digits,period:o=Xt.defaults.period,hmac:h}={}){this.issuer=t,this.label=e,this.issuerInLabel=s,this.secret="string"==typeof i?Rt.fromBase32(i):i,this.algorithm=h?r:St(r),this.digits=n,this.period=o,this.hmac=h}}const Nt=/^otpauth:\/\/([ht]otp)\/(.+)\?([A-Z0-9.~_-]+=[^?&]*(?:&[A-Z0-9.~_-]+=[^?&]*)*)$/i,Zt=/^[2-7A-Z]+=*$/i,Vt=/^SHA(?:1|224|256|384|512|3-224|3-256|3-384|3-512)$/i,zt=/^[A-Z0-9]+(?:[_-][A-Z0-9]+)*$/i,Jt=/^[+-]?\d+$/,Kt=/^\+?[1-9]\d*$/;t.HOTP=Mt,t.Secret=Rt,t.TOTP=Xt,t.URI=class{static parse(t,{hmac:e}={}){let s;try{s=t.match(Nt)}catch(t){}if(!Array.isArray(s))throw new URIError("Invalid URI format");const i=s[1].toLowerCase(),r=s[2].split(/(?::|%3A) *(.+)/i,2).map(decodeURIComponent),n=s[3].split("&").reduce((t,e)=>{const s=e.split(/=(.*)/,2).map(decodeURIComponent),i=s[0].toLowerCase(),r=s[1],n=t;return n[i]=r,n},{});let o;const h={};if("hotp"===i){if(o=Mt,void 0===n.counter||!Jt.test(n.counter))throw new TypeError("Missing or invalid 'counter' parameter");h.counter=parseInt(n.counter,10)}else{if("totp"!==i)throw new TypeError("Unknown OTP type");if(o=Xt,void 0!==n.period){if(!Kt.test(n.period))throw new TypeError("Invalid 'period' parameter");h.period=parseInt(n.period,10)}}if(void 0!==n.issuer&&(h.issuer=n.issuer),2===r.length?(h.label=r[1],void 0===h.issuer||""===h.issuer?h.issuer=r[0]:""===r[0]&&(h.issuerInLabel=!1)):(h.label=r[0],void 0!==h.issuer&&""!==h.issuer&&(h.issuerInLabel=!1)),
void 0===n.secret||!Zt.test(n.secret))throw new TypeError("Missing or invalid 'secret' parameter");if(h.secret=n.secret,void 0!==n.algorithm){if(!(e?zt:Vt).test(n.algorithm))throw new TypeError("Invalid 'algorithm' parameter");h.algorithm=n.algorithm}if(void 0!==n.digits){if(!Kt.test(n.digits))throw new TypeError("Invalid 'digits' parameter");h.digits=parseInt(n.digits,10)}return void 0!==e&&(h.hmac=e),new o(h)}static stringify(t){if(t instanceof Mt||t instanceof Xt)return t.toString();throw new TypeError("Invalid 'HOTP/TOTP' object")}},t.version="9.5.0"});
//# sourceMappingURL=otpauth.umd.min.js.map

File diff suppressed because one or more lines are too long