feat: implement auth system, passkeys, and user management

Add PostgreSQL and Redis integration for users and sessions
Implement password and WebAuthn passkey login flows
Add Docker stack, super-admin seeding, and protected routes
This commit is contained in:
2026-04-12 20:16:43 +08:00
parent a649c509c2
commit 377a9617be
45 changed files with 3620 additions and 104 deletions

View File

@@ -0,0 +1,60 @@
import { MIN_PASSWORD_LENGTH } from '~~/shared/auth'
import { requireAuth } from '../../utils/auth'
import { hashPassword, verifyPassword } from '../../utils/password'
import { getUserById, updateUserPassword } from '../../utils/user-repository'
export default defineEventHandler(async (event) => {
const auth = await requireAuth(event)
const body = await readBody<{
currentPassword?: string
newPassword?: string
}>(event)
const currentPassword = body.currentPassword?.trim() || ''
const newPassword = body.newPassword?.trim() || ''
if (!currentPassword || !newPassword) {
throw createError({
statusCode: 400,
statusMessage: 'Current password and new password are required'
})
}
if (newPassword.length < MIN_PASSWORD_LENGTH) {
throw createError({
statusCode: 400,
statusMessage: `New password must be at least ${MIN_PASSWORD_LENGTH} characters`
})
}
if (currentPassword === newPassword) {
throw createError({
statusCode: 400,
statusMessage: 'New password must be different from the current password'
})
}
const currentPasswordMatches = await verifyPassword(currentPassword, auth.user.passwordHash)
if (!currentPasswordMatches) {
throw createError({
statusCode: 400,
statusMessage: 'Current password is incorrect'
})
}
const passwordHash = await hashPassword(newPassword)
await updateUserPassword({
userId: auth.user.id,
passwordHash,
mustChangePassword: false
})
const updatedUser = await getUserById(auth.user.id)
return {
user: updatedUser
}
})