Self-service password reset

This commit is contained in:
2025-10-06 18:26:01 -04:00
parent 53c9ba8fd7
commit c127ea35f6
13 changed files with 683 additions and 21 deletions

View File

@@ -0,0 +1,50 @@
import { getPasswordResetCode, resetPasswordByEmail, deletePasswordResetCode } from '~/server/utils/database'
export default defineEventHandler(async (event) => {
const body = await readBody(event)
const { email, code, newPassword } = body
if (!email || !code || !newPassword) {
throw createError({
statusCode: 400,
message: 'Email, code, and new password are required',
})
}
// Validate password requirements
if (newPassword.length < 8) {
throw createError({
statusCode: 400,
message: 'Password must be at least 8 characters long',
})
}
const hasUpperCase = /[A-Z]/.test(newPassword)
const hasLowerCase = /[a-z]/.test(newPassword)
const hasNumberOrSymbol = /[0-9!@#$%^&*(),.?":{}|<>]/.test(newPassword)
if (!hasUpperCase || !hasLowerCase || !hasNumberOrSymbol) {
throw createError({
statusCode: 400,
message: 'Password must contain uppercase, lowercase, and number/symbol',
})
}
// Verify code exists and hasn't expired
const resetCode = getPasswordResetCode(email, code)
if (!resetCode) {
throw createError({
statusCode: 400,
message: 'Invalid or expired reset code',
})
}
// Reset password
resetPasswordByEmail(email, newPassword)
// Delete used reset code
deletePasswordResetCode(email)
return { success: true, message: 'Password reset successfully' }
})