feat(profile): Passkey-Labels, Sicherheits-Checkliste und Geräte-Block

Erweitert die Profilseite um benennbare Passkeys, Sicherheitsübersicht,
Gerät/Sync-Status, Backup-Hinweis in der Gefahrenzone und Dialog beim
Löschen des letzten Passkeys.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-31 09:43:28 +02:00
co-authored by Cursor
parent 86cb4d92ec
commit d4538ec06e
8 changed files with 404 additions and 14 deletions
+14 -2
View File
@@ -546,6 +546,7 @@ export async function deleteAccount(): Promise<boolean> {
export interface UserProfileCredential {
id: string
label: string | null
credentialIdPreview: string
transports: string[]
}
@@ -579,7 +580,7 @@ async function enrollPrfFromMasterKey(masterKey: ArrayBuffer, prfFirst: ArrayBuf
})
}
export async function addPasskey(): Promise<void> {
export async function addPasskey(label?: string): Promise<void> {
await reauthWithPasskey()
const options = await apiJson<any>(`${API_BASE}/add-credential-options`, {
@@ -613,7 +614,11 @@ export async function addPasskey(): Promise<void> {
await apiJson(`${API_BASE}/add-credential-verify`, {
method: 'POST',
body: JSON.stringify({ credentialResponse, challenge: options.challenge })
body: JSON.stringify({
credentialResponse,
challenge: options.challenge,
...(label?.trim() ? { label: label.trim() } : {})
})
})
const masterKey = getActiveMasterKey()
@@ -639,3 +644,10 @@ export async function removePasskey(credentialDbId: string): Promise<void> {
throw new Error(body.error || 'Failed to remove passkey')
}
}
export async function renamePasskey(credentialDbId: string, label: string): Promise<void> {
await apiJson(`${API_BASE}/credentials/${credentialDbId}`, {
method: 'PATCH',
body: JSON.stringify({ label })
})
}