From 31cfd19b6beb09b50b2cd9bc2f13555556fc8d23 Mon Sep 17 00:00:00 2001 From: shuaiplus <2327005759@qq.com> Date: Sun, 28 Jun 2026 14:02:51 +0800 Subject: [PATCH] feat: add support for excluding PRF extensions in credential options --- webapp/src/lib/account-passkeys.ts | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/webapp/src/lib/account-passkeys.ts b/webapp/src/lib/account-passkeys.ts index 87ce7a3..060bcf3 100644 --- a/webapp/src/lib/account-passkeys.ts +++ b/webapp/src/lib/account-passkeys.ts @@ -136,6 +136,19 @@ function withPrfExtension( }; } +function withoutPrfExtension(options: T): T { + const extensions = { ...(((options as any).extensions || {}) as Record) }; + delete extensions.prf; + if (!Object.keys(extensions).length) { + const { extensions: _extensions, ...rest } = options as any; + return rest as T; + } + return { + ...options, + extensions: extensions as any, + }; +} + function readPrfFirstResult(credential: PublicKeyCredential): ArrayBuffer | undefined { const result = (credential.getClientExtensionResults() as any).prf?.results?.first; return result instanceof ArrayBuffer ? result : undefined; @@ -171,6 +184,14 @@ async function getPublicKeyCredentialWithPrf( salt: Uint8Array, credentialIds: string[] = [] ): Promise { + const baseOptions = withoutPrfExtension(options); + if (!(await canRequestPrfExtension())) { + const credential = await navigator.credentials.get({ publicKey: baseOptions }); + if (!(credential instanceof PublicKeyCredential)) { + throw new Error(t('txt_no_passkey_selected')); + } + return credential; + } const attempts = credentialIds.length ? [ buildCredentialPrfExtension(salt, credentialIds), @@ -181,7 +202,7 @@ async function getPublicKeyCredentialWithPrf( for (let index = 0; index < attempts.length; index += 1) { try { const credential = await navigator.credentials.get({ - publicKey: withPrfExtension(options, attempts[index]), + publicKey: withPrfExtension(baseOptions, attempts[index]), }); if (!(credential instanceof PublicKeyCredential)) { throw new Error(t('txt_no_passkey_selected')); @@ -287,7 +308,7 @@ export async function createAccountPasskeyCredential( if (!window.PublicKeyCredential || !navigator.credentials) { throw new Error(t('txt_passkey_browser_not_supported')); } - const nativeOptions = cloneCreationOptions(response.options); + const nativeOptions = withoutPrfExtension(cloneCreationOptions(response.options)); const createWithOptions = async (options: PublicKeyCredentialCreationOptions): Promise => { const credential = await navigator.credentials.create({ publicKey: options }); if (!(credential instanceof PublicKeyCredential)) {