import { NextRequest } from "next/server"; import { z } from "zod"; import { getSession } from "../../../../lib/auth/session"; import { getPrisma } from "../../../../lib/db"; import { hashPassword, verifyPassword } from "../../../../lib/auth/password"; import { isStrongPassword } from "../../../../lib/auth/validation"; import { ok, fail } from "../../../../lib/http"; export const runtime = "nodejs"; const Body = z.object({ currentPassword: z.string().min(1), newPassword: z.string().min(8), confirmPassword: z.string().min(8), }); export async function POST(req: NextRequest) { const session = await getSession(); if (!session) return fail(new Error("Unauthorized"), { status: 401 }); const prisma = await getPrisma(); if (!prisma) return fail(new Error("Database not configured"), { status: 503, isAdmin: session.role === "ADMIN" }); const parsed = Body.safeParse(await req.json().catch(() => ({}))); if (!parsed.success) return fail(new Error("Invalid input")); const user = await prisma.user.findUnique({ where: { id: session.sub }, include: { credential: true } }); if (!user || !user.credential) return fail(new Error("Invalid user or no password set")); if (parsed.data.newPassword !== parsed.data.confirmPassword) { return fail(new Error("Passwords do not match")); } if (!isStrongPassword(parsed.data.newPassword)) { return fail(new Error("Password is not strong enough")); } // 🔥 Only verify current password if NOT forced reset if (!user.forcePasswordReset) { const okPw = await verifyPassword( parsed.data.currentPassword, user.credential.password ); if (!okPw) return fail(new Error("Invalid password")); } const newHash = await hashPassword(parsed.data.newPassword); await prisma.credential.update({ where: { userId: user.id }, data: { password: newHash }, }); // Clear force password reset flag if it was set if (user.forcePasswordReset) { await prisma.user.update({ where: { id: user.id }, data: { forcePasswordReset: false }, }); } return ok({ message: "Password updated" }); }