feat(ST-l9kkxh2m): /reset-password pagina + resetPasswordAction + hashPassword
- lib/auth.ts: hashPassword(password) geëxporteerd (bcrypt, rounds=12) - actions/auth.ts: resetPasswordAction met Zod-validatie (min 8, superRefine gelijkheid), prisma.user.update (password_hash + must_reset_password=false), redirect /dashboard - app/(auth)/reset-password/page.tsx: server guard (userId check + must_reset_password check) - app/(auth)/reset-password/reset-form.tsx: client form (nieuw wachtwoord + bevestiging) - __tests__/actions/auth.test.ts: 3 tests voor resetPasswordAction
This commit is contained in:
parent
71281038ff
commit
a19ae89e37
5 changed files with 206 additions and 3 deletions
|
|
@ -4,10 +4,12 @@ import { redirect } from 'next/navigation'
|
|||
import { cookies, headers } from 'next/headers'
|
||||
import { getIronSession } from 'iron-session'
|
||||
import { z } from 'zod'
|
||||
import { registerUser, verifyUser } from '@/lib/auth'
|
||||
import { prisma } from '@/lib/prisma'
|
||||
import { registerUser, verifyUser, hashPassword } from '@/lib/auth'
|
||||
import { SessionData, sessionOptions } from '@/lib/session'
|
||||
import { checkRateLimit } from '@/lib/rate-limit'
|
||||
import { isPhoneUA } from '@/lib/user-agent'
|
||||
import { requireSession } from '@/lib/auth-guard'
|
||||
|
||||
async function getClientIp(): Promise<string> {
|
||||
const h = await headers()
|
||||
|
|
@ -90,3 +92,39 @@ export async function logoutAction() {
|
|||
session.destroy()
|
||||
redirect('/login')
|
||||
}
|
||||
|
||||
const resetPasswordSchema = z
|
||||
.object({
|
||||
password: z.string().min(8, 'Wachtwoord moet minimaal 8 tekens bevatten'),
|
||||
confirm: z.string(),
|
||||
})
|
||||
.superRefine((data, ctx) => {
|
||||
if (data.password !== data.confirm) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: 'Wachtwoorden komen niet overeen',
|
||||
path: ['confirm'],
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
export async function resetPasswordAction(_prevState: unknown, formData: FormData) {
|
||||
const session = await requireSession()
|
||||
|
||||
const parsed = resetPasswordSchema.safeParse({
|
||||
password: formData.get('password'),
|
||||
confirm: formData.get('confirm'),
|
||||
})
|
||||
|
||||
if (!parsed.success) {
|
||||
return { error: parsed.error.flatten().fieldErrors }
|
||||
}
|
||||
|
||||
const hash = await hashPassword(parsed.data.password)
|
||||
await prisma.user.update({
|
||||
where: { id: session.userId },
|
||||
data: { password_hash: hash, must_reset_password: false },
|
||||
})
|
||||
|
||||
redirect('/dashboard')
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue