import { NextResponse } from "next/server"; import { z } from "zod"; import { createAuditTrailSafe } from "@/lib/audit-trail"; import { hashPassword, verifyPassword } from "@/lib/auth"; import { requireApiAccess } from "@/lib/authorization"; import { prisma } from "@/lib/prisma"; const changePasswordSchema = z .object({ current_password: z.string().min(1, "Password saat ini wajib diisi"), password: z.string().min(8, "Password baru minimal 8 karakter"), password_confirmation: z.string().min(8, "Konfirmasi password minimal 8 karakter") }) .refine((value) => value.password === value.password_confirmation, { message: "Konfirmasi password tidak sama", path: ["password_confirmation"] }); export async function POST(request: Request) { const auth = requireApiAccess(request); if (!auth.ok) return auth.response; try { const body = await request.json(); const parsed = changePasswordSchema.safeParse(body); if (!parsed.success) { return NextResponse.json( { message: "Validasi gagal", errors: parsed.error.flatten().fieldErrors }, { status: 422 } ); } const user = await prisma.user.findUnique({ where: { id: BigInt(auth.user.id) } }); if (!user || !user.passwordHash) { return NextResponse.json({ message: "User tidak ditemukan" }, { status: 404 }); } if (!verifyPassword(parsed.data.current_password, user.passwordHash)) { return NextResponse.json( { message: "Password saat ini tidak valid" }, { status: 422 } ); } await prisma.user.update({ where: { id: user.id }, data: { passwordHash: hashPassword(parsed.data.password) } }); await createAuditTrailSafe({ userId: user.id, action: "PASSWORD_CHANGED", entityType: "AUTH", entityId: user.id, method: request.method, pathname: new URL(request.url).pathname, statusCode: 200, summary: "User mengganti password akun sendiri" }); return NextResponse.json({ message: "Password berhasil diperbarui" }); } catch (error) { return NextResponse.json( { message: error instanceof Error ? error.message : "Gagal mengganti password" }, { status: 500 } ); } }