import { generateRegistrationOptions } from '@simplewebauthn/server' import { getUserFromToken, hasAnyRole } from '../../../utils/auth.js' import { getWebAuthnConfig } from '../../../utils/webauthn-config.js' import { setRegistrationChallenge } from '../../../utils/webauthn-challenges.js' import { writeAuditLog } from '../../../utils/audit-log.js' export default defineEventHandler(async (event) => { const token = getCookie(event, 'auth_token') const user = token ? await getUserFromToken(token) : null if (!user) { throw createError({ statusCode: 401, statusMessage: 'Nicht authentifiziert' }) } // Mindestens für Admin/Vorstand anbieten (und auch für Mitglieder ok) if (!hasAnyRole(user, 'admin', 'vorstand', 'mitglied', 'newsletter')) { throw createError({ statusCode: 403, statusMessage: 'Keine Berechtigung' }) } const { rpId, rpName } = getWebAuthnConfig() const existing = Array.isArray(user.passkeys) ? user.passkeys : [] const excludeCredentials = existing .filter(pk => pk && pk.credentialId) .map(pk => ({ id: pk.credentialId, type: 'public-key', transports: pk.transports || undefined })) const options = await generateRegistrationOptions({ rpName, rpID: rpId, // @simplewebauthn/server erwartet inzwischen Uint8Array/Buffer statt String userID: new TextEncoder().encode(String(user.id)), userName: user.email, // Keine Attestation-Daten speichern attestationType: 'none', authenticatorSelection: { residentKey: 'preferred', userVerification: 'preferred' }, excludeCredentials }) setRegistrationChallenge(user.id, options.challenge) await writeAuditLog('auth.passkey.registration.options', { userId: user.id }) return { success: true, options } })