{"version":3,"sources":["../../../src/auth/hardware/ledger.ts","../../../src/auth/hardware/yubikey.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * ledger.ts — Ledger hardware wallet signer for AirAccount M7.\n *\n * Produces an ECDSA (algId=0x02) UserOp signature using a Ledger device\n * connected via WebHID in the browser.\n *\n * Signature format (66 bytes):\n *   [0x02][r(32)][s(32)][v(1)]\n *\n * The contract's _validateECDSA applies EIP-191 prefix, so Ledger's\n * signPersonalMessage (which also adds EIP-191 prefix) matches exactly.\n *\n * Requirements:\n *   - Browser environment with WebHID support (Chrome/Edge 89+)\n *   - @ledgerhq/hw-transport-webhid\n *   - @ledgerhq/hw-app-eth\n */\n\n// Dynamic imports keep Ledger packages out of the main bundle for non-Ledger users.\n// Call connectLedger() once and keep the signer for the session.\n\nexport interface LedgerSignerConfig {\n  /**\n   * BIP-44 derivation path. Defaults to the first Ethereum account.\n   * Use Ledger Live's \"m/44'/60'/0'/0/0\" for the default account.\n   */\n  derivationPath?: string;\n}\n\n/** Ledger signer instance returned by connectLedger(). */\nexport interface LedgerSigner {\n  /**\n   * Returns the account address for the configured derivation path.\n   * Use this to verify the Ledger matches the expected account owner.\n   */\n  getAddress(): Promise<string>;\n\n  /**\n   * Signs the UserOp hash and returns a 66-byte hex signature\n   * formatted as [0x02][r(32)][s(32)][v(1)] for algId=0x02 (ECDSA).\n   *\n   * Compatible with the `signer` field of AirAccountProviderConfig.\n   */\n  sign(userOpHash: `0x${string}`): Promise<`0x${string}`>;\n\n  /** Disconnect and release the WebHID device. */\n  disconnect(): Promise<void>;\n}\n\n/**\n * Connect to a Ledger device via WebHID and return a LedgerSigner.\n *\n * Must be called in response to a user gesture (button click, etc.) because\n * WebHID requestDevice() requires user activation.\n *\n * @example\n * ```ts\n * const signer = await connectLedger();\n * const address = await signer.getAddress();\n * const provider = new AirAccountEIP1193Provider({\n *   ...,\n *   accountAddress: myAirAccountAddress,\n *   signer: (hash) => signer.sign(hash),\n * });\n * ```\n */\nexport async function connectLedger(config: LedgerSignerConfig = {}): Promise<LedgerSigner> {\n  const path = config.derivationPath ?? \"m/44'/60'/0'/0/0\";\n\n  // Dynamic imports — only loaded when Ledger is actually used\n  const [{ default: TransportWebHID }, { default: AppEth }] = await Promise.all([\n    import(\"@ledgerhq/hw-transport-webhid\"),\n    import(\"@ledgerhq/hw-app-eth\"),\n  ]);\n\n  const transport = await TransportWebHID.create();\n  const eth = new AppEth(transport);\n\n  return {\n    async getAddress(): Promise<string> {\n      const result = await eth.getAddress(path);\n      return result.address;\n    },\n\n    async sign(userOpHash: `0x${string}`): Promise<`0x${string}`> {\n      // Strip \"0x\" — Ledger signPersonalMessage takes raw hex (no prefix)\n      const msgHex = userOpHash.slice(2);\n      const result = await eth.signPersonalMessage(path, msgHex);\n\n      // Ledger returns v as decimal number, r and s as hex strings without \"0x\"\n      const v = result.v;\n      const r = result.r.padStart(64, \"0\");\n      const s = result.s.padStart(64, \"0\");\n\n      // Normalize v: Ledger returns 0/1 or 27/28; contract normalizes internally (v<27 → v+=27)\n      // but we send the raw value and let the contract handle it.\n      const vHex = v.toString(16).padStart(2, \"0\");\n\n      // Format: algId=0x02 + r(32) + s(32) + v(1) = 66 bytes\n      return `0x02${r}${s}${vHex}`;\n    },\n\n    async disconnect(): Promise<void> {\n      await transport.close();\n    },\n  };\n}\n","/**\n * yubikey.ts — YubiKey / FIDO2 hardware wallet signer for AirAccount M7.\n *\n * Uses navigator.credentials.get() (WebAuthn CTAP2) to produce a P256\n * signature from a YubiKey or any FIDO2 security key that stores a P-256\n * credential.\n *\n * Signature format (65 bytes):\n *   [0x03][r(32)][s(32)]\n *\n * Compatible with AirAccount algId=0x03 (P256) when the account has been\n * initialized with the matching P256 public key via setP256Key(x, y).\n *\n * ⚠ WebAuthn authentication note:\n *   Standard WebAuthn signs `authData || SHA256(clientDataJSON)`, not the\n *   raw userOpHash. The P256 signature is VALID for the WebAuthn assertion\n *   but NOT directly verifiable by the contract's _validateP256() which\n *   expects a signature directly over `userOpHash`.\n *\n *   Use cases:\n *   1. Tier 2/3 composite signatures (server-verifies WebAuthn assertion).\n *   2. Standalone algId=0x03: requires EIP-7212 raw P256 signing, which is\n *      NOT standard WebAuthn. For this use case, pair with a server that\n *      relays the FIDO2 assertion and verifies it off-chain, or use a\n *      purpose-built Ethereum app on the YubiKey (e.g. Keystone firmware).\n *\n * Requirements:\n *   - Browser environment with WebAuthn support\n *   - YubiKey or FIDO2 device with a P-256 credential registered\n */\n\nexport interface YubiKeySigner {\n  /**\n   * Trigger a WebAuthn assertion and return the raw P256 signature bytes\n   * formatted as [0x03][r(32)][s(32)] for AirAccount algId=0x03.\n   *\n   * The `challenge` is set to the userOpHash bytes so the assertion is\n   * cryptographically bound to this specific UserOp.\n   *\n   * Compatible with the `signer` field of AirAccountProviderConfig (for\n   * Tier 2/3 flows where the server validates the WebAuthn assertion).\n   */\n  sign(userOpHash: `0x${string}`): Promise<`0x${string}`>;\n}\n\nexport interface YubiKeySignerConfig {\n  /**\n   * The credential ID(s) of the registered YubiKey P256 credential.\n   * If empty, any FIDO2 resident credential is allowed (discoverable mode).\n   */\n  credentialIds?: Uint8Array[];\n\n  /**\n   * Relying Party ID (rpId), typically the website's eTLD+1.\n   * Defaults to window.location.hostname.\n   */\n  rpId?: string;\n\n  /**\n   * Timeout for the WebAuthn request in milliseconds. Default: 60 000.\n   */\n  timeout?: number;\n}\n\n/**\n * Create a YubiKey / FIDO2 P256 signer using WebAuthn.\n *\n * @example Tier 2/3 server-composite signing (server verifies the WebAuthn assertion)\n * ```ts\n * const signer = createYubiKeySigner({\n *   credentialIds: [base64UrlToBuffer(storedCredentialId)],\n * });\n * // signer.sign() returns the raw WebAuthn P256 signature bytes.\n * // ⚠ This is NOT directly valid for standalone algId=0x03 on-chain verification\n * //   because the contract expects a signature over userOpHash directly, but\n * //   WebAuthn signs authData || SHA256(clientDataJSON) instead.\n * // For standalone algId=0x03 you need an EIP-7212-compatible Ethereum app on\n * //   the security key (e.g. Keystone firmware), NOT standard WebAuthn CTAP2.\n * //\n * // Correct Tier 2/3 flow:\n * const webAuthnAssertion = await signer.sign(userOpHash);\n * // Send webAuthnAssertion to your Tier 2/3 server, which verifies the WebAuthn\n * // assertion off-chain and returns a composite signature for the UserOp.\n * ```\n */\nexport function createYubiKeySigner(config: YubiKeySignerConfig = {}): YubiKeySigner {\n  return {\n    async sign(userOpHash: `0x${string}`): Promise<`0x${string}`> {\n      const challenge = hexToBytes(userOpHash);\n      const rpId = config.rpId ?? window.location.hostname;\n\n      const allowCredentials: PublicKeyCredentialDescriptor[] = (config.credentialIds ?? []).map(\n        (id) => ({ type: \"public-key\", id }),\n      );\n\n      const assertion = await navigator.credentials.get({\n        publicKey: {\n          challenge,\n          rpId,\n          timeout: config.timeout ?? 60_000,\n          userVerification: \"preferred\",\n          allowCredentials: allowCredentials.length > 0 ? allowCredentials : undefined,\n        },\n      });\n\n      if (!assertion || assertion.type !== \"public-key\") {\n        throw new Error(\"WebAuthn assertion failed or no credential returned\");\n      }\n\n      const authAssertion = assertion as PublicKeyCredential;\n      const response = authAssertion.response as AuthenticatorAssertionResponse;\n\n      // Extract raw (r, s) from DER-encoded P256 signature\n      const { r, s } = decodeDerSignature(new Uint8Array(response.signature));\n\n      // Format: algId=0x03 + r(32) + s(32) = 65 bytes\n      return `0x03${bytesToHex(r)}${bytesToHex(s)}`;\n    },\n  };\n}\n\n// ── Helpers ──────────────────────────────────────────────────────────────────\n\n/** Decode ASN.1 DER-encoded ECDSA signature into raw (r, s) bytes (32 bytes each). */\nfunction decodeDerSignature(der: Uint8Array): { r: Uint8Array; s: Uint8Array } {\n  // DER format: 0x30 [total-len] 0x02 [r-len] [r-bytes] 0x02 [s-len] [s-bytes]\n  if (der[0] !== 0x30) throw new Error(\"Invalid DER signature: expected SEQUENCE tag 0x30\");\n\n  let offset = 2; // skip 0x30 and total-length byte\n\n  if (der[offset] !== 0x02) throw new Error(\"Invalid DER signature: expected INTEGER tag 0x02\");\n  offset++;\n  const rLen = der[offset++];\n  // DER may prefix 0x00 for positive integers (rLen=33); or omit leading zeros (rLen<32)\n  const rStart = rLen > 32 ? offset + 1 : offset;\n  const rActualLen = rLen > 32 ? rLen - 1 : rLen;\n  const r = der.slice(rStart, rStart + rActualLen);\n  offset += rLen;\n\n  if (der[offset] !== 0x02) throw new Error(\"Invalid DER signature: expected INTEGER tag 0x02\");\n  offset++;\n  const sLen = der[offset++];\n  const sStart = sLen > 32 ? offset + 1 : offset;\n  const sActualLen = sLen > 32 ? sLen - 1 : sLen;\n  const s = der.slice(sStart, sStart + sActualLen);\n\n  return { r: padTo32(r), s: padTo32(s) };\n}\n\n/** Left-pad byte array to 32 bytes. */\nfunction padTo32(bytes: Uint8Array): Uint8Array {\n  if (bytes.length === 32) return bytes;\n  const padded = new Uint8Array(32);\n  padded.set(bytes, 32 - bytes.length);\n  return padded;\n}\n\n/** Convert hex string (with or without \"0x\") to Uint8Array. */\nfunction hexToBytes(hex: string): Uint8Array {\n  const clean = hex.startsWith(\"0x\") ? hex.slice(2) : hex;\n  const bytes = new Uint8Array(clean.length / 2);\n  for (let i = 0; i < bytes.length; i++) {\n    bytes[i] = parseInt(clean.slice(i * 2, i * 2 + 2), 16);\n  }\n  return bytes;\n}\n\n/** Convert Uint8Array to lowercase hex string (without \"0x\"). */\nfunction bytesToHex(bytes: Uint8Array): string {\n  return Array.from(bytes)\n    .map((b) => b.toString(16).padStart(2, \"0\"))\n    .join(\"\");\n}\n"]}