Files
harheimertc/server/api/auth/register-passkey-options.post.js
Torsten Schulz (local) b34a6fc155
Some checks failed
Code Analysis (JS/Vue) / analyze (push) Failing after 49s
Enhance passkey registration handling with error checks and CORS support
Add validation for server response in the registration process, ensuring the presence of necessary options. Implement CORS headers for cross-device authentication and increase the timeout for registration to 5 minutes. Include debug logging for options structure to aid in troubleshooting.
2026-01-07 21:24:11 +01:00

84 lines
2.6 KiB
JavaScript

import crypto from 'crypto'
import { generateRegistrationOptions } from '@simplewebauthn/server'
import { readUsers } from '../../utils/auth.js'
import { getWebAuthnConfig } from '../../utils/webauthn-config.js'
import { setPreRegistration } from '../../utils/webauthn-challenges.js'
import { writeAuditLog } from '../../utils/audit-log.js'
function isValidEmail(email) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(String(email || ''))
}
export default defineEventHandler(async (event) => {
const body = await readBody(event)
const name = String(body?.name || '').trim()
const email = String(body?.email || '').trim().toLowerCase()
const phone = String(body?.phone || '').trim()
if (!name || !email) {
throw createError({ statusCode: 400, message: 'Name und E-Mail sind erforderlich' })
}
if (!isValidEmail(email)) {
throw createError({ statusCode: 400, message: 'Ungültige E-Mail-Adresse' })
}
const users = await readUsers()
if (users.some(u => String(u.email || '').toLowerCase() === email)) {
throw createError({ statusCode: 409, message: 'Ein Benutzer mit dieser E-Mail-Adresse existiert bereits' })
}
const { rpId, rpName } = getWebAuthnConfig()
const userId = crypto.randomUUID()
const registrationId = crypto.randomBytes(16).toString('hex')
const options = await generateRegistrationOptions({
rpName,
rpID: rpId,
userID: new TextEncoder().encode(String(userId)),
userName: email,
userDisplayName: name,
attestationType: 'none',
authenticatorSelection: {
residentKey: 'preferred',
userVerification: 'preferred'
},
// Timeout erhöhen für Cross-Device (Standard: 60s, hier: 5 Minuten)
timeout: 300000
})
setPreRegistration(registrationId, {
challenge: options.challenge,
userId,
name,
email,
phone
})
await writeAuditLog('auth.passkey.prereg.options', { email })
// CORS-Header für Cross-Device Authentication
const requestOrigin = getHeader(event, 'origin')
if (requestOrigin) {
setHeader(event, 'Access-Control-Allow-Origin', requestOrigin)
setHeader(event, 'Access-Control-Allow-Credentials', 'true')
setHeader(event, 'Access-Control-Allow-Methods', 'POST, OPTIONS')
setHeader(event, 'Access-Control-Allow-Headers', 'Content-Type, Authorization')
}
if (getMethod(event) === 'OPTIONS') {
return { success: true }
}
// Debug: Log Options-Struktur
console.log('[WebAuthn Pre-Registration Options]', {
hasChallenge: !!options.challenge,
rpId: options.rp?.id,
userId: options.user?.id ? 'present' : 'missing',
timeout: options.timeout
})
return { success: true, registrationId, options }
})