passkey-utils.ts
1/**2 * passkey-utils.ts — WebAuthn relying-party-id validation.3 *4 * The native browser enforces that a page may only request a passkey whose5 * rpId is a registrable-domain-suffix of the page's own origin. On Firefox,6 * Peach intercepts `navigator.credentials` in a MAIN-world content script and7 * services the ceremony itself, so Peach — not the browser — must re-impose8 * that rule. Without it a page at `evil.com` could request (and Peach would9 * happily mint) a credential scoped to `google.com` (SEV-1-A).10 */1112import { parse } from "tldts";1314/**15 * Validates that `rpId` is equal to, or a registrable-domain-suffix of, the16 * hostname of `callerOrigin`. Mirrors WebAuthn §7.1 step 6 / §7.2 step 8.17 * Private suffixes are enabled because services such as github.io host18 * unrelated tenants beneath the same public suffix.19 */20export function isValidRpId(rpId: string, callerOrigin: string): boolean {21 let callerHost: string;22 try {23 callerHost = new URL(callerOrigin).hostname;24 } catch {25 return false;26 }27 if (!rpId || !callerHost) return false;2829 const id = rpId.toLowerCase();30 const host = callerHost.toLowerCase();31 if (!id.includes(".")) return false;3233 const rp = parse(id, { allowPrivateDomains: true });34 const caller = parse(host, { allowPrivateDomains: true });35 return rp.domain === id && caller.domain === rp.domain;36}