/** * Resolve the per-format options blob a caller supplied via * `attestationOptions`. The value at `attestationOptions[fmt]` wins; * a hyphen-stripped key (`androidsafetynet` for `android-safetynet`) * is accepted as a fallback for callers who prefer a single-word * config name. Returns an empty object when nothing matches. * * Exported for tests — the real code path calls this once per verify. * * @param {string} fmt * @param {Record> | undefined} attestationOptions * @returns {Record} */ export function resolveAttestationOptions(fmt: string, attestationOptions: Record> | undefined): Record; /** * @param {object} params * @param {object} params.response * The `PublicKeyCredential` shape the browser produced, with * base64url-encoded fields (JSON-transport form): * { id, rawId, type: 'public-key', * response: { clientDataJSON, attestationObject, transports? }, * clientExtensionResults? } * @param {string} params.challengeToken * @param {string | string[]} params.expectedRpId * @param {string | string[] | RegExp} params.expectedOrigin * @param {string | Buffer} params.challengeSecret * @param {import('@exortek/challenge').IncrStore} params.challengeStore * @param {string} [params.expectedUserId] * @param {boolean} [params.requireUserVerification=true] * @param {boolean} [params.requireBackupEligible=false] * @param {boolean} [params.requireBackedUp=false] * @param {boolean} [params.allowCrossOriginCeremony=false] * Opt in to accepting `clientDataJSON.crossOrigin === true`. Off by * default: WebAuthn L3 §7.1 step 12 lets the RP set policy, and * most deployments should not accept cross-origin registration * ceremonies. * @param {number[]} [params.supportedAlgorithms] * @param {Record>} [params.trustAnchors] * Per-format trust anchor arrays; each entry is a certificate * accepted by `x509/chain.toCertificate` (PEM string / DER / X509). * @param {Record>} [params.attestationOptions] * Per-format extra options, keyed by format name (same convention as * `trustAnchors`). Passed verbatim to the format's verifier — used * today by `android-safetynet` (`enforceCtsCheck`, * `timestampWindowMs`, `now`); new formats add knobs here without * further signature changes. * @param {boolean} [params.requireTrustAnchor=false] * When true, reject a chain-bearing attestation format that resolved * to `trustPath: 'no-anchor'` (i.e. the caller supplied no anchors * for it). Turns the "attestation silently unverified" footgun into * an explicit `ATTESTATION_TRUST_ANCHOR_MISSING`. `none` and packed * self-attestation are unaffected. Leave false for the passkey common * case (`attestation: 'none'`). * @param {string} [params.challengePrefix] * @returns {Promise<{ * credential: { * id: string, * idBytes: Uint8Array, * publicKey: import('node:crypto').KeyObject, * publicKeyJwk: Record, * publicKeyCose: Map, * algorithm: number, * counter: number, * transports?: string[], * }, * aaguid: string, * deviceType: 'singleDevice' | 'multiDevice', * backedUp: boolean, * attestation: { * format: string, * trustPath: string, * aaguidExtensionOk?: boolean, * certChain?: import('node:crypto').X509Certificate[], * }, * extensionResults: { client: object, authenticator: object }, * rpId: string, * }>} */ export function finish(params: { response: object; challengeToken: string; expectedRpId: string | string[]; expectedOrigin: string | string[] | RegExp; challengeSecret: string | Buffer; challengeStore: import("@exortek/challenge").IncrStore; expectedUserId?: string | undefined; requireUserVerification?: boolean | undefined; requireBackupEligible?: boolean | undefined; requireBackedUp?: boolean | undefined; allowCrossOriginCeremony?: boolean | undefined; supportedAlgorithms?: number[] | undefined; trustAnchors?: Record | undefined; attestationOptions?: Record> | undefined; requireTrustAnchor?: boolean | undefined; challengePrefix?: string | undefined; }): Promise<{ credential: { id: string; idBytes: Uint8Array; publicKey: any; publicKeyJwk: Record; publicKeyCose: Map; algorithm: number; counter: number; transports?: string[]; }; aaguid: string; deviceType: "singleDevice" | "multiDevice"; backedUp: boolean; attestation: { format: string; trustPath: string; aaguidExtensionOk?: boolean; certChain?: any[]; }; extensionResults: { client: object; authenticator: object; }; rpId: string; }>;