diff --git a/project.inlang/messages/de.json b/project.inlang/messages/de.json index eb96005..88f5c18 100644 --- a/project.inlang/messages/de.json +++ b/project.inlang/messages/de.json @@ -109,9 +109,13 @@ "action": "Passkey setzen", "success": "Passkey eingerichtet. Logge Dich damit jetzt ein.", "successKeyPairSaved": "Schlüsselpaar erfolgreich gespeichert.", + "confirmPrfRetrival": "Jetzt verwende den neu erstellten Passkey, um damit die Verschlüsselung zu aktivieren.", "error": "Passkey konnte nicht gesetzt werden", "errorKeyPairDataMissing": "Konnte Schlüsselpaar nicht generieren. Fehlende Daten.", - "errorKeyPairNotSaved": "Schlüsselpaar konnte nicht gespeichert werden." + "errorKeyPairNotSaved": "Schlüsselpaar konnte nicht gespeichert werden.", + "errorPrfOutputNotTriggered": "Sie müssen der Verwendung des Passkeys zustimmen.", + "errorAuthenticatorNotSupported": "Dieser Authentifikator unterstützt nicht die erforderliche Sicherheitserweiterung (PRF). Bitte verwenden Sie einen modernen Authentifikator wie YubiKey 5.2.3+, Apple Touch ID oder Android.", + "errorGettingPrfOutput": "Fehler beim Abrufen der Sicherheitsdaten vom Passkey. Bitte verwenden Sie einen modernen Authentifikator, der die PRF-Erweiterung unterstützt." }, "logout": { "title": "Erfolgreich abgemeldet", diff --git a/project.inlang/messages/en.json b/project.inlang/messages/en.json index f828024..824b680 100644 --- a/project.inlang/messages/en.json +++ b/project.inlang/messages/en.json @@ -42,9 +42,13 @@ "action": "Set Passkey", "success": "Passkey set. Login with it now.", "successKeyPairSaved": "Key pair saved successfully.", + "confirmPrfRetrival": "Now use your newly created passkey to enable encryption with it.", "error": "Passkey could not be set", "errorKeyPairDataMissing": "Could not generate key pair. Missing data.", - "errorKeyPairNotSaved": "Key pair could not be saved." + "errorKeyPairNotSaved": "Key pair could not be saved.", + "errorPrfOutputNotTriggered": "You have to confirm using the passkey.", + "errorAuthenticatorNotSupported": "This authenticator does not support the required security extension (PRF). Please use a modern authenticator like YubiKey 5.2.3+, Apple Touch ID or Android.", + "errorGettingPrfOutput": "Failed to retrieve security data from passkey. Please use a modern authenticator that supports PRF extension." }, "slogan": "End-to-End encrypted appointment booking platform.", "logo": "OpenReception Logo: A 3D pixel art with calendar that's also a lock", diff --git a/src/routes/(pages)/confirm/setup-passkey/setup-passkey-form.svelte b/src/routes/(pages)/confirm/setup-passkey/setup-passkey-form.svelte index 75afa9a..632c7d6 100644 --- a/src/routes/(pages)/confirm/setup-passkey/setup-passkey-form.svelte +++ b/src/routes/(pages)/confirm/setup-passkey/setup-passkey-form.svelte @@ -35,7 +35,7 @@ let passkeyId: string | undefined = $state(); let prfOutput: ArrayBuffer | undefined = $state(); let kyberKeyPair: { publicKey: Uint8Array; privateKey: Uint8Array } | undefined = $state(); - let registrationChallenge: string | undefined = $state(); // Store first challenge for form submission + let registrationChallenge: string | undefined = $state(); const form = superForm(data.form, { validators: zodClient(formSchema), @@ -111,9 +111,7 @@ email: $formData.email, extensions: extensionResults, }); - toast.error( - "This authenticator does not support the required security extension (PRF). Please use a modern authenticator like YubiKey 5.2.3+, Titan Gen2, Windows Hello, Touch ID, or Android.", - ); + toast.warning(m["setupPasskey.errorAuthenticatorNotSupported"]()); return; } @@ -121,6 +119,15 @@ const attestationObjectResp = passkeyResp.response.attestationObject; const clientDataJSONResp = passkeyResp.response.clientDataJSON; + // UX Primer for second passkey UI + const isConfirmed = confirm(m["setupPasskey.confirmPrfRetrival"]()); + if (!isConfirmed) { + $passkeyLoading = "error"; + toast.error(m["setupPasskey.errorPrfOutputNotTriggered"]()); + logger.warn("PRF challenge primer not confirmed"); + return; + } + // CRITICAL: Get PRF output immediately after passkey creation // This is the only time we can retrieve the PRF output // Uses email as salt for multi-passkey support @@ -149,9 +156,7 @@ passkeyId: passkeyResp.id, error, }); - toast.error( - "Failed to retrieve security data from passkey. Please use a modern authenticator that supports PRF extension.", - ); + toast.error(m["setupPasskey.errorGettingPrfOutput"]()); return; } diff --git a/src/routes/(pages)/login/+page.server.ts b/src/routes/(pages)/login/+page.server.ts index 8edabff..02ef423 100644 --- a/src/routes/(pages)/login/+page.server.ts +++ b/src/routes/(pages)/login/+page.server.ts @@ -11,7 +11,7 @@ const log = logger.setContext(import.meta.filename); export const load: PageServerLoad = async () => { return { - form: await superValidate(zod(formSchema)), + form: await superValidate({ type: "passkey" }, zod(formSchema)), }; };