SPB Git forge

spb/immbot-ai

Public
1commits 1branches 0releases
1.5 MBsize
maindefault branch
20 days agolast push
TypeScript 98.3% CSS 0.9% Shell 0.7%
2.1 KB · 52 lines typescript
Raw Blame History
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