"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }// src/errors.ts var InputError = class extends Error { constructor(message) { super(message); this.name = "InputError"; } }; var DictError = class extends Error { constructor(message) { super(message); this.name = "DictError"; } }; var PassphrasesExpiredError = class extends Error { constructor(message) { super(message); this.name = "PassphrasesExpiredError"; } }; var PassphrasesMismatchError = class extends Error { constructor(message) { super(message); this.name = "PassphrasesMismatchError"; } }; // src/utils/index.ts var _base64url = require('base64url'); var _base64url2 = _interopRequireDefault(_base64url); // src/utils/timestamp.ts var MINUTE = 6e4; var getStartOfDate = (dayOfMonth) => { const startOfYesterday2 = /* @__PURE__ */ new Date(); startOfYesterday2.setDate(dayOfMonth); startOfYesterday2.setUTCHours(0, 0, 0, 0); return startOfYesterday2.getTime(); }; var startOfYesterday = () => { const now = /* @__PURE__ */ new Date(); return getStartOfDate(now.getDate() - 1); }; var toTimeDiff = (date, since = startOfYesterday()) => { return Math.ceil((date - since) / MINUTE); }; var fromTimeDiff = (diff, since = startOfYesterday()) => { const ts = diff * MINUTE + since; return ts; }; // src/utils/index.ts var calcChunkSize = (dict) => { const chunkSize = Math.floor(Math.log2(dict.length)); return chunkSize; }; var encode = (str) => _base64url2.default.encode(str); var hexToBin = (hex) => BigInt(`0x${hex}`).toString(2); var binToDecimal = (bin) => BigInt(`0b${bin}`).toString(10); var binToWords = async (binStr, chunkSize, dict) => { const chunks = binStr.padEnd(Math.ceil(binStr.length / chunkSize) * chunkSize, "0").match(new RegExp(`.{${chunkSize}}`, "g")); if (!chunks) return []; return await Promise.all( chunks.map(async (c) => { return await dict.get(+binToDecimal(c)); }) ); }; // src/utils/sign.ts var sign = async (data, secret, algorithm = "sha256") => { const enc = new TextEncoder(); const algo = { name: "HMAC", hash: algorithm === "sha256" ? "SHA-256" : "SHA-512" }; const key = await crypto.subtle.importKey( "raw", enc.encode(secret), algo, false, ["sign", "verify"] ); const signature = await crypto.subtle.sign(algo.name, key, enc.encode(data)); const hashArray = Array.from(new Uint8Array(signature)); const digest = hashArray.map((b) => b.toString(16).padStart(2, "0")).join(""); return digest; }; // src/generate.ts var generate = async ({ sigPayload, sigExp, sigAlgorithm = "sha256", sigSecret, sigDict, expDict, expDictDiffSince, take }) => { if (!sigSecret || sigSecret.length <= 0) throw new InputError("`sigSecret` is required."); const normalizedExp = toTimeDiff(sigExp, expDictDiffSince); const payload = encode( JSON.stringify({ ...sigPayload, exp: normalizedExp, since: expDictDiffSince }) ); const header = encode(JSON.stringify({ alg: sigAlgorithm })); const signature = await sign(`${header}.${payload}`, sigSecret, sigAlgorithm); const chunkSize = calcChunkSize(sigDict); let words = []; try { words = await binToWords(hexToBin(signature), chunkSize, sigDict); } catch (err) { throw new DictError("Unable to convert signature to words."); } if (!words) throw new DictError("Unable to convert signature to words."); let expWord = void 0; try { expWord = await expDict.get(toTimeDiff(sigExp, expDictDiffSince)); } catch (err) { throw new DictError("Unable to convert exp to word."); } if (!expWord) throw new DictError("Unable to convert exp to word."); const result = [expWord, ...words].slice(0, take); if (take && result.length < take) throw new DictError("Not enough words."); return result; }; // src/verify.ts var verify = async ({ passphrases, expIndexDict, expDictDiffSince, ...props }) => { const [expWord] = passphrases; const exp = await expIndexDict.get(expWord); if (!exp || exp < 0) throw new DictError("Unable to convert expWord to exp."); const expirationDate = fromTimeDiff(exp, expDictDiffSince); if (expirationDate < Date.now()) { throw new PassphrasesExpiredError("Passphrases expired."); } const newPassphrases = await generate({ ...props, sigExp: expirationDate, expDictDiffSince }); const isSame = passphrases.join("") === newPassphrases.join(""); if (!isSame) { throw new PassphrasesMismatchError("Passphrases mismatch."); } return true; }; exports.DictError = DictError; exports.InputError = InputError; exports.PassphrasesExpiredError = PassphrasesExpiredError; exports.PassphrasesMismatchError = PassphrasesMismatchError; exports.binToDecimal = binToDecimal; exports.binToWords = binToWords; exports.calcChunkSize = calcChunkSize; exports.encode = encode; exports.fromTimeDiff = fromTimeDiff; exports.generate = generate; exports.getStartOfDate = getStartOfDate; exports.hexToBin = hexToBin; exports.startOfYesterday = startOfYesterday; exports.toTimeDiff = toTimeDiff; exports.verify = verify; //# sourceMappingURL=index.cjs.map