import { z } from "zod"; import { eq } from "drizzle-orm"; import { db, schema } from "@/db"; import { hashPassword, verifyPassword, passwordPolicy } from "@/lib/auth/password"; import { getSession, revokeOtherSessions, rotateSession, setSessionCookie } from "@/lib/auth/session"; import { assertSameOrigin, jsonError, HttpError } from "@/lib/auth/guard"; import { verifyCsrf } from "@/lib/auth/session"; import { audit } from "@/lib/audit"; export async function POST(req: Request) { try { await assertSameOrigin(); const s = await getSession(); if (!s) throw new HttpError(401, "Unauthenticated"); if (s.totpEnabled && !s.mfaPassed) throw new HttpError(403, "MFA required"); if (!verifyCsrf(s, req.headers.get("x-csrf-token"))) throw new HttpError(403, "CSRF token invalid"); const { current, next } = z.object({ current: z.string().max(500), next: z.string().max(500) }).parse(await req.json()); const policy = passwordPolicy(next); if (policy) throw new HttpError(400, policy); const [u] = await db.select().from(schema.users).where(eq(schema.users.id, s.id)); if (!(await verifyPassword(u.passwordHash, current))) throw new HttpError(401, "Current password is incorrect"); await db.update(schema.users).set({ passwordHash: await hashPassword(next), mustChangePassword: false, updatedAt: new Date() }).where(eq(schema.users.id, s.id)); await revokeOtherSessions(s.id, s.sessionId); const t = await rotateSession(s.sessionId); await setSessionCookie(t); await audit({ id: s.id, name: s.email }, "auth.password_changed"); return Response.json({ ok: true }); } catch (e) { return jsonError(e); } }