61 lines
1.8 KiB
JavaScript
61 lines
1.8 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'
|
|
}
|
|
})
|
|
|
|
setPreRegistration(registrationId, {
|
|
challenge: options.challenge,
|
|
userId,
|
|
name,
|
|
email,
|
|
phone
|
|
})
|
|
|
|
await writeAuditLog('auth.passkey.prereg.options', { email })
|
|
|
|
return { success: true, registrationId, options }
|
|
})
|
|
|