{"version":3,"sources":["../src/otpauth.ts","../src/recovery.ts","../src/index.ts"],"names":["normalizeAlgorithm","getCrypto","timingSafeEqual","sha256Hex","normalizeCode"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * otpauth:// URI parser — the inverse of `keyuri`.\n *\n * Reads the standard Key URI Format shared by Google Authenticator, Authy,\n * 1Password, etc., so you can import a secret a user pastes/scans back in.\n * Pure string work — no crypto, no network — so it runs anywhere `keyuri` does.\n */\n\nimport type { OtpAlgorithm } from \"./index\";\n\nexport interface ParsedOtpauthUri {\n  /** `totp` (time-based) or `hotp` (counter-based). */\n  type: \"totp\" | \"hotp\";\n  /** Account label (issuer prefix stripped), e.g. the user's email. */\n  label: string;\n  /** Issuer / app name, if present. */\n  issuer?: string;\n  /** Base32 shared secret. */\n  secret: string;\n  /** Normalised HMAC hash — always `SHA-1` | `SHA-256` | `SHA-512`. */\n  algorithm: OtpAlgorithm;\n  /** Number of digits in the code. */\n  digits: number;\n  /** Time step in seconds (totp only). */\n  period?: number;\n  /** Moving counter (hotp only). */\n  counter?: number;\n}\n\nfunction normalizeAlgorithm(raw: string | null): OtpAlgorithm {\n  const v = (raw ?? \"SHA1\").toUpperCase().replace(/-/g, \"\");\n  if (v === \"SHA256\") return \"SHA-256\";\n  if (v === \"SHA512\") return \"SHA-512\";\n  if (v === \"SHA1\") return \"SHA-1\";\n  throw new Error(`unsupported otpauth algorithm \"${raw}\"`);\n}\n\n/**\n * Parse an `otpauth://` provisioning URI into its parts. Throws if the URI is\n * not a valid `otpauth://totp|hotp/...` string with a `secret`. Round-trips\n * with {@link keyuri}.\n */\nexport function parseOtpauthUri(uri: string): ParsedOtpauthUri {\n  const trimmed = String(uri).trim();\n  const m = /^otpauth:\\/\\/(totp|hotp)\\/([^?]*)(?:\\?(.*))?$/i.exec(trimmed);\n  if (!m) throw new Error(\"not an otpauth:// URI\");\n  const type = m[1]!.toLowerCase() as \"totp\" | \"hotp\";\n\n  let label = decodeURIComponent(m[2] ?? \"\");\n  const params = new URLSearchParams(m[3] ?? \"\");\n\n  let issuer = params.get(\"issuer\") ?? undefined;\n  // Label may carry an \"Issuer:account\" prefix.\n  const colon = label.indexOf(\":\");\n  if (colon !== -1) {\n    const prefix = label.slice(0, colon).trim();\n    label = label.slice(colon + 1).trim();\n    if (!issuer && prefix) issuer = prefix;\n  }\n\n  const secret = params.get(\"secret\");\n  if (!secret) throw new Error(\"otpauth:// URI is missing its secret\");\n\n  const out: ParsedOtpauthUri = {\n    type,\n    label,\n    issuer,\n    secret,\n    algorithm: normalizeAlgorithm(params.get(\"algorithm\")),\n    digits: params.has(\"digits\") ? Number(params.get(\"digits\")) : 6,\n  };\n  if (type === \"totp\") out.period = params.has(\"period\") ? Number(params.get(\"period\")) : 30;\n  if (type === \"hotp\") out.counter = params.has(\"counter\") ? Number(params.get(\"counter\")) : 0;\n  return out;\n}\n","/**\n * Recovery / backup codes — an options-object API on top of the same idea as\n * {@link generateBackupCodes}, with configurable count, length and format, and\n * a verify helper that reports the remaining (unused) hashes so callers can\n * persist single-use semantics in one step.\n *\n * Codes are cryptographically random (Web Crypto CSPRNG); only SHA-256 hashes\n * are ever stored. Self-contained — no crypto helpers leak into the public API.\n */\n\nfunction getCrypto(): Crypto {\n  const c = (globalThis as { crypto?: Crypto }).crypto;\n  if (!c || !c.subtle) {\n    throw new Error(\"Web Crypto API unavailable — @lacspace/otp needs Node 18+, an edge runtime, or a browser\");\n  }\n  return c;\n}\n\nasync function sha256Hex(input: string): Promise<string> {\n  const c = getCrypto();\n  const buf = await c.subtle.digest(\"SHA-256\", new TextEncoder().encode(input) as unknown as BufferSource);\n  const bytes = new Uint8Array(buf);\n  let out = \"\";\n  for (const b of bytes) out += b.toString(16).padStart(2, \"0\");\n  return out;\n}\n\nfunction timingSafeEqual(a: string, b: string): boolean {\n  if (a.length !== b.length) return false;\n  let diff = 0;\n  for (let i = 0; i < a.length; i++) diff |= a.charCodeAt(i) ^ b.charCodeAt(i);\n  return diff === 0;\n}\n\n/** Normalise for comparison: upper-case, strip separators/whitespace. */\nfunction normalizeCode(code: string): string {\n  return code.toUpperCase().replace(/[\\s-]/g, \"\");\n}\n\n/** How the visible characters of a recovery code are drawn. */\nexport type RecoveryCodeFormat = \"alphanumeric\" | \"numeric\" | \"hex\";\n\nconst ALPHABETS: Record<RecoveryCodeFormat, string> = {\n  // No ambiguous characters (no 0/O/1/I).\n  alphanumeric: \"ABCDEFGHJKLMNPQRSTUVWXYZ23456789\",\n  numeric: \"0123456789\",\n  hex: \"0123456789ABCDEF\",\n};\n\nexport interface RecoveryCodesOptions {\n  /** How many codes to generate (default 10). */\n  count?: number;\n  /** Number of dash-separated groups per code (default 2). */\n  groups?: number;\n  /** Characters per group (default 5). */\n  groupLength?: number;\n  /** Character set — `alphanumeric` (default), `numeric` or `hex`. */\n  format?: RecoveryCodeFormat;\n  /** Group separator (default `-`). */\n  separator?: string;\n}\n\nexport interface RecoveryCodesResult {\n  /** Show these to the user ONCE. */\n  codes: string[];\n  /** Store THESE (SHA-256 hex hashes) — verify against them, mark used. */\n  hashes: string[];\n}\n\nfunction drawCode(alphabet: string, groups: number, groupLen: number, separator: string): string {\n  const total = groups * groupLen;\n  // Rejection-free unbiased-enough draw for a code alphabet (256 % len bias is\n  // negligible for these small alphabets); mirrors the existing backup-code path.\n  const bytes = new Uint8Array(total);\n  getCrypto().getRandomValues(bytes);\n  const parts: string[] = [];\n  let i = 0;\n  for (let g = 0; g < groups; g++) {\n    let s = \"\";\n    for (let j = 0; j < groupLen; j++) s += alphabet[bytes[i++]! % alphabet.length];\n    parts.push(s);\n  }\n  return parts.join(separator);\n}\n\n/**\n * Generate a set of single-use recovery codes. Returns the plaintext `codes`\n * (show the user once) and their SHA-256 `hashes` (persist these). Every call\n * yields fresh, cryptographically-random codes.\n */\nexport async function generateRecoveryCodes(opts: RecoveryCodesOptions = {}): Promise<RecoveryCodesResult> {\n  const count = opts.count ?? 10;\n  const groups = opts.groups ?? 2;\n  const groupLen = opts.groupLength ?? 5;\n  const separator = opts.separator ?? \"-\";\n  const alphabet = ALPHABETS[opts.format ?? \"alphanumeric\"];\n  const codes = Array.from({ length: count }, () => drawCode(alphabet, groups, groupLen, separator));\n  const hashes = await Promise.all(codes.map((c) => sha256Hex(normalizeCode(c))));\n  return { codes, hashes };\n}\n\nexport interface RecoveryCodeVerification {\n  /** Did the code match an unused hash? */\n  ok: boolean;\n  /** Index of the matched hash in the supplied set, or -1. */\n  index: number;\n  /** The stored set with the used hash removed — persist this. Unchanged on miss. */\n  remaining: string[];\n}\n\n/**\n * Verify a recovery code against a stored set of SHA-256 hashes and consume it.\n * On a match returns `ok: true`, the matched `index`, and `remaining` (the set\n * minus the used hash) — persist `remaining` to enforce single use. On no match\n * returns `ok: false`, `index: -1`, and the original set untouched.\n */\nexport async function verifyRecoveryCode(code: string, hashedSet: string[]): Promise<RecoveryCodeVerification> {\n  const target = await sha256Hex(normalizeCode(code));\n  let index = -1;\n  // Scan all entries (don't short-circuit) to avoid leaking position via timing.\n  for (let i = 0; i < hashedSet.length; i++) {\n    if (timingSafeEqual(hashedSet[i]!, target)) index = i;\n  }\n  if (index === -1) return { ok: false, index: -1, remaining: hashedSet };\n  return { ok: true, index, remaining: hashedSet.filter((_, i) => i !== index) };\n}\n","/**\n * @lacspace/otp\n * TOTP & HOTP two-factor auth — Google Authenticator compatible.\n *\n * Generate secrets, compute and verify time-based (TOTP) and counter-based\n * (HOTP) one-time codes, and build the `otpauth://` URI you turn into a QR code.\n * Built on the Web Crypto API, so it runs on Node 18+, edge runtimes and the\n * browser alike.\n *\n * Zero dependencies · isomorphic · fully typed.\n */\n\nexport type OtpAlgorithm = \"SHA-1\" | \"SHA-256\" | \"SHA-512\";\n\n/**\n * Accept the spellings people actually meet — `SHA1` from an otpauth URI (the\n * Key URI spec writes it without the dash, and so does this package's own\n * keyuri()), `sha256` from a config file — and hand Web Crypto the one form it\n * understands. The type still guides TypeScript users to the canonical names;\n * this stops a JavaScript caller getting a raw \"Unrecognized algorithm name\".\n */\nfunction normalizeAlgorithm(alg: string | undefined): OtpAlgorithm {\n  if (!alg) return \"SHA-1\";\n  const m = /^sha-?(1|256|512)$/i.exec(alg.trim());\n  if (!m) throw new Error(`unsupported OTP algorithm \"${alg}\" (use SHA-1, SHA-256 or SHA-512)`);\n  return `SHA-${m[1]}` as OtpAlgorithm;\n}\n\nexport interface OtpOptions {\n  /** Number of digits in the code (default 6). */\n  digits?: number;\n  /** HMAC hash (default SHA-1 — what authenticator apps use). */\n  algorithm?: OtpAlgorithm;\n}\n\nexport interface TotpOptions extends OtpOptions {\n  /** Time step in seconds (default 30). */\n  period?: number;\n  /** Override \"now\" (ms since epoch) — for testing. */\n  timestamp?: number;\n}\n\nconst B32_ALPHABET = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567\";\n\nfunction getCrypto(): Crypto {\n  const c = (globalThis as { crypto?: Crypto }).crypto;\n  if (!c || !c.subtle) {\n    throw new Error(\"Web Crypto API unavailable — @lacspace/otp needs Node 18+, an edge runtime, or a browser\");\n  }\n  return c;\n}\n\n/* ------------------------------ base32 ------------------------------ */\n\n/** Encode bytes to RFC 4648 base32 (no padding). */\nexport function base32Encode(bytes: Uint8Array): string {\n  let bits = 0;\n  let value = 0;\n  let out = \"\";\n  for (const b of bytes) {\n    value = (value << 8) | b;\n    bits += 8;\n    while (bits >= 5) {\n      out += B32_ALPHABET[(value >>> (bits - 5)) & 31];\n      bits -= 5;\n    }\n  }\n  if (bits > 0) out += B32_ALPHABET[(value << (5 - bits)) & 31];\n  return out;\n}\n\n/** Decode an RFC 4648 base32 string (padding and spaces tolerated). */\nexport function base32Decode(input: string): Uint8Array {\n  const clean = input.toUpperCase().replace(/=+$/, \"\").replace(/\\s/g, \"\");\n  let bits = 0;\n  let value = 0;\n  const out: number[] = [];\n  for (const ch of clean) {\n    const idx = B32_ALPHABET.indexOf(ch);\n    if (idx === -1) throw new Error(`invalid base32 character \"${ch}\"`);\n    value = (value << 5) | idx;\n    bits += 5;\n    if (bits >= 8) {\n      out.push((value >>> (bits - 8)) & 0xff);\n      bits -= 8;\n    }\n  }\n  return new Uint8Array(out);\n}\n\n/** Generate a random base32 secret (default 20 bytes / 160 bits). */\nexport function generateSecret(bytes = 20): string {\n  const buf = new Uint8Array(bytes);\n  getCrypto().getRandomValues(buf);\n  return base32Encode(buf);\n}\n\n/* ------------------------------ core ------------------------------ */\n\nasync function hmac(algorithm: OtpAlgorithm, key: Uint8Array, message: Uint8Array): Promise<Uint8Array> {\n  const c = getCrypto();\n  const cryptoKey = await c.subtle.importKey(\n    \"raw\",\n    key as unknown as BufferSource,\n    { name: \"HMAC\", hash: algorithm },\n    false,\n    [\"sign\"],\n  );\n  const sig = await c.subtle.sign(\"HMAC\", cryptoKey, message as unknown as BufferSource);\n  return new Uint8Array(sig);\n}\n\nfunction counterBytes(counter: number): Uint8Array {\n  const buf = new Uint8Array(8);\n  let n = counter;\n  for (let i = 7; i >= 0; i--) {\n    buf[i] = n & 0xff;\n    n = Math.floor(n / 256);\n  }\n  return buf;\n}\n\nfunction truncate(hash: Uint8Array, digits: number): string {\n  const offset = hash[hash.length - 1]! & 0x0f;\n  const bin =\n    ((hash[offset]! & 0x7f) << 24) |\n    ((hash[offset + 1]! & 0xff) << 16) |\n    ((hash[offset + 2]! & 0xff) << 8) |\n    (hash[offset + 3]! & 0xff);\n  return (bin % 10 ** digits).toString().padStart(digits, \"0\");\n}\n\n/** Compute an HOTP code for a given counter. */\nexport async function hotp(secret: string, counter: number, opts: OtpOptions = {}): Promise<string> {\n  const digits = opts.digits ?? 6;\n  const algorithm = normalizeAlgorithm(opts.algorithm);\n  const hash = await hmac(algorithm, base32Decode(secret), counterBytes(counter));\n  return truncate(hash, digits);\n}\n\n/** Compute the current TOTP code. */\nexport async function totp(secret: string, opts: TotpOptions = {}): Promise<string> {\n  const period = opts.period ?? 30;\n  const now = opts.timestamp ?? Date.now();\n  const counter = Math.floor(now / 1000 / period);\n  return hotp(secret, counter, opts);\n}\n\n/** Seconds remaining before the current TOTP code rolls over. */\nexport function timeRemaining(opts: TotpOptions = {}): number {\n  const period = opts.period ?? 30;\n  const now = opts.timestamp ?? Date.now();\n  return period - (Math.floor(now / 1000) % period);\n}\n\nfunction timingSafeEqual(a: string, b: string): boolean {\n  if (a.length !== b.length) return false;\n  let diff = 0;\n  for (let i = 0; i < a.length; i++) diff |= a.charCodeAt(i) ^ b.charCodeAt(i);\n  return diff === 0;\n}\n\n/**\n * Verify a TOTP token, tolerating clock drift of ±`window` periods (default 1).\n * @returns the matched step offset (0 = current, ±1 = adjacent), or null if no match.\n */\nexport async function verifyTotp(\n  token: string,\n  secret: string,\n  opts: TotpOptions & { window?: number } = {},\n): Promise<number | null> {\n  const window = opts.window ?? 1;\n  const period = opts.period ?? 30;\n  const now = opts.timestamp ?? Date.now();\n  const base = Math.floor(now / 1000 / period);\n  const digits = opts.digits ?? 6;\n  const algorithm = normalizeAlgorithm(opts.algorithm);\n  const key = base32Decode(secret);\n  const clean = token.replace(/\\s/g, \"\");\n  for (let offset = -window; offset <= window; offset++) {\n    const hash = await hmac(algorithm, key, counterBytes(base + offset));\n    if (timingSafeEqual(clean, truncate(hash, digits))) return offset;\n  }\n  return null;\n}\n\n/**\n * Verify an HOTP token, scanning forward up to `window` counters (default 0).\n * @returns the matched counter, or null if no match.\n */\nexport async function verifyHotp(\n  token: string,\n  secret: string,\n  counter: number,\n  opts: OtpOptions & { window?: number } = {},\n): Promise<number | null> {\n  const window = opts.window ?? 0;\n  const clean = token.replace(/\\s/g, \"\");\n  for (let i = 0; i <= window; i++) {\n    if (timingSafeEqual(clean, await hotp(secret, counter + i, opts))) return counter + i;\n  }\n  return null;\n}\n\n/* ------------------------------ provisioning ------------------------------ */\n\nexport interface KeyUriInput extends OtpOptions {\n  secret: string;\n  /** Account label, e.g. the user's email. */\n  label: string;\n  /** Issuer / app name shown in the authenticator. */\n  issuer?: string;\n  period?: number;\n  type?: \"totp\" | \"hotp\";\n  /** Required for hotp. */\n  counter?: number;\n}\n\n/**\n * Build an `otpauth://` URI — feed it to a QR code generator so users can scan\n * it into Google Authenticator, Authy, 1Password, etc.\n */\nexport function keyuri(o: KeyUriInput): string {\n  const type = o.type ?? \"totp\";\n  const label = o.issuer ? `${o.issuer}:${o.label}` : o.label;\n  const params = new URLSearchParams({\n    secret: o.secret,\n    algorithm: (o.algorithm ?? \"SHA-1\").replace(\"-\", \"\"),\n    digits: String(o.digits ?? 6),\n  });\n  if (o.issuer) params.set(\"issuer\", o.issuer);\n  if (type === \"totp\") params.set(\"period\", String(o.period ?? 30));\n  if (type === \"hotp\") params.set(\"counter\", String(o.counter ?? 0));\n  return `otpauth://${type}/${encodeURIComponent(label)}?${params.toString()}`;\n}\n\n/* ------------------------------ replay guard ------------------------------ */\n\n/**\n * Verify a TOTP token AND reject replays: pass the last accepted step\n * (`lastStep`); a code at or before it is refused even if otherwise valid.\n * @returns the matched step (persist it as the new `lastStep`), or null.\n */\nexport async function verifyTotpOnce(\n  token: string,\n  secret: string,\n  lastStep: number | null | undefined,\n  opts: TotpOptions & { window?: number } = {},\n): Promise<number | null> {\n  const period = opts.period ?? 30;\n  const now = opts.timestamp ?? Date.now();\n  const base = Math.floor(now / 1000 / period);\n  const offset = await verifyTotp(token, secret, opts);\n  if (offset === null) return null;\n  const step = base + offset;\n  if (lastStep != null && step <= lastStep) return null; // replay\n  return step;\n}\n\n/* ------------------------------ enrollment ------------------------------ */\n\nexport interface SetupTotpInput {\n  /** Account label, e.g. the user's email. */\n  account: string;\n  /** Issuer / app name shown in the authenticator. */\n  issuer?: string;\n  /** Secret length in bytes (default 20). */\n  bytes?: number;\n  digits?: number;\n  period?: number;\n  algorithm?: OtpAlgorithm;\n}\n\nexport interface TotpSetup {\n  /** Store this (encrypted) against the user. */\n  secret: string;\n  /** `otpauth://…` — render as a QR code (any QR lib) for the user to scan. */\n  uri: string;\n}\n\n/** One-call TOTP enrollment: a fresh secret + the `otpauth://` URI to show as a QR. */\nexport function setupTotp(input: SetupTotpInput): TotpSetup {\n  const secret = generateSecret(input.bytes ?? 20);\n  const uri = keyuri({\n    secret,\n    label: input.account,\n    issuer: input.issuer,\n    digits: input.digits,\n    period: input.period,\n    algorithm: input.algorithm,\n  });\n  return { secret, uri };\n}\n\n/* ------------------------------ backup codes ------------------------------ */\n\nexport interface BackupCodesResult {\n  /** Show these to the user ONCE. */\n  codes: string[];\n  /** Store THESE (SHA-256 hashes) — verify against them, mark used. */\n  hashes: string[];\n}\n\nasync function sha256Hex(input: string): Promise<string> {\n  const c = getCrypto();\n  const buf = await c.subtle.digest(\"SHA-256\", new TextEncoder().encode(input) as unknown as BufferSource);\n  const bytes = new Uint8Array(buf);\n  let out = \"\";\n  for (const b of bytes) out += b.toString(16).padStart(2, \"0\");\n  return out;\n}\n\nfunction randomCode(groups: number, groupLen: number): string {\n  const alphabet = \"ABCDEFGHJKLMNPQRSTUVWXYZ23456789\"; // no ambiguous chars\n  const bytes = new Uint8Array(groups * groupLen);\n  getCrypto().getRandomValues(bytes);\n  const parts: string[] = [];\n  let i = 0;\n  for (let g = 0; g < groups; g++) {\n    let s = \"\";\n    for (let j = 0; j < groupLen; j++) s += alphabet[bytes[i++]! % alphabet.length];\n    parts.push(s);\n  }\n  return parts.join(\"-\");\n}\n\n/** Generate single-use recovery codes: show `codes` once, persist `hashes`. */\nexport async function generateBackupCodes(\n  count = 10,\n  opts: { groups?: number; groupLength?: number } = {},\n): Promise<BackupCodesResult> {\n  const groups = opts.groups ?? 2;\n  const groupLen = opts.groupLength ?? 5;\n  const codes = Array.from({ length: count }, () => randomCode(groups, groupLen));\n  const hashes = await Promise.all(codes.map((c) => sha256Hex(normalizeCode(c))));\n  return { codes, hashes };\n}\n\nfunction normalizeCode(code: string): string {\n  return code.toUpperCase().replace(/[\\s-]/g, \"\");\n}\n\n/**\n * Verify a backup code against stored hashes (single-use). Returns the index of\n * the matched hash (remove/mark it used), or -1 if none match.\n */\nexport async function verifyBackupCode(code: string, hashes: string[]): Promise<number> {\n  const target = await sha256Hex(normalizeCode(code));\n  let match = -1;\n  // constant-ish: scan all\n  for (let i = 0; i < hashes.length; i++) {\n    if (timingSafeEqual(hashes[i]!, target)) match = i;\n  }\n  return match;\n}\n\n/* ------------------------------ new in 1.2.0 ------------------------------ */\n\n// otpauth:// URI parser — the inverse of `keyuri` (build a URI with `keyuri`).\nexport { parseOtpauthUri } from \"./otpauth\";\nexport type { ParsedOtpauthUri } from \"./otpauth\";\n\n// Recovery codes with a configurable options-object API + single-use verify\n// that reports the remaining hashes.\nexport { generateRecoveryCodes, verifyRecoveryCode } from \"./recovery\";\nexport type {\n  RecoveryCodeFormat,\n  RecoveryCodesOptions,\n  RecoveryCodesResult,\n  RecoveryCodeVerification,\n} from \"./recovery\";\n"]}