spb/tools-spboucher-ai
Public
1import { z } from "zod";2import { eq } from "drizzle-orm";3import { db, schema } from "@/db";4import { hashPassword, verifyPassword, passwordPolicy } from "@/lib/auth/password";5import { getSession, revokeOtherSessions, rotateSession, setSessionCookie } from "@/lib/auth/session";6import { assertSameOrigin, jsonError, HttpError } from "@/lib/auth/guard";7import { verifyCsrf } from "@/lib/auth/session";8import { audit } from "@/lib/audit";9export async function POST(req: Request) {10 try {11 await assertSameOrigin();12 const s = await getSession(); if (!s) throw new HttpError(401, "Unauthenticated");13 if (s.totpEnabled && !s.mfaPassed) throw new HttpError(403, "MFA required");14 if (!verifyCsrf(s, req.headers.get("x-csrf-token"))) throw new HttpError(403, "CSRF token invalid");15 const { current, next } = z.object({ current: z.string().max(500), next: z.string().max(500) }).parse(await req.json());16 const policy = passwordPolicy(next); if (policy) throw new HttpError(400, policy);17 const [u] = await db.select().from(schema.users).where(eq(schema.users.id, s.id));18 if (!(await verifyPassword(u.passwordHash, current))) throw new HttpError(401, "Current password is incorrect");19 await db.update(schema.users).set({ passwordHash: await hashPassword(next), mustChangePassword: false, updatedAt: new Date() }).where(eq(schema.users.id, s.id));20 await revokeOtherSessions(s.id, s.sessionId); const t = await rotateSession(s.sessionId); await setSessionCookie(t);21 await audit({ id: s.id, name: s.email }, "auth.password_changed");22 return Response.json({ ok: true });23 } catch (e) { return jsonError(e); }24}25