TypeScript 98.3%
CSS 0.9%
Shell 0.7%
1import { NextResponse } from "next/server";2import { z } from "zod";3import { apiError, parseBody } from "@/lib/api.ts";4import { hashPassword, passwordPolicyError, verifyPassword } from "@/lib/auth/password.ts";5import { assertSameOrigin, destroyAllSessions, logAuthEvent, requireUser, SESSION_COOKIE, createSession } from "@/lib/auth/session.ts";6import { get, run } from "@/lib/db/index.ts";78const schema = z.object({9 currentPassword: z.string().max(200),10 newPassword: z.string().max(200),11});1213export async function POST(req: Request) {14 try {15 await assertSameOrigin();16 const user = await requireUser();17 const { currentPassword, newPassword } = await parseBody(req, schema);1819 const row = get<{ password_hash: string }>("SELECT password_hash FROM users WHERE id = ?", user.id);20 if (!row || !verifyPassword(currentPassword, row.password_hash)) {21 return NextResponse.json({ error: "Mot de passe actuel incorrect." }, { status: 401 });22 }23 const policyErr = passwordPolicyError(newPassword);24 if (policyErr) return NextResponse.json({ error: policyErr }, { status: 400 });25 if (newPassword === currentPassword) {26 return NextResponse.json({ error: "Le nouveau mot de passe doit être différent de l'actuel." }, { status: 400 });27 }2829 run(30 "UPDATE users SET password_hash = ?, must_change_password = 0 WHERE id = ?",31 hashPassword(newPassword), user.id32 );33 // Révoque toutes les sessions puis en recrée une propre.34 destroyAllSessions(user.id);35 const ip = req.headers.get("x-forwarded-for")?.split(",")[0]?.trim() || "local";36 const { token, expiresAt } = createSession(user.id, ip, req.headers.get("user-agent") ?? undefined);37 logAuthEvent("password-changed", { userId: user.id, username: user.username, ip });3839 const res = NextResponse.json({ ok: true });40 res.cookies.set(SESSION_COOKIE, token, {41 httpOnly: true,42 sameSite: "lax",43 secure: process.env.NODE_ENV === "production" && (process.env.APP_URL ?? "").startsWith("https"),44 expires: expiresAt,45 path: "/",46 });47 return res;48 } catch (e) {49 return apiError(e);50 }51}52