import { NextResponse } from "next/server"; import bcrypt from "bcryptjs"; import { z } from "zod"; const resetSchema = z.object({ token: z.string().min(1, "Token is required"), password: z.string().min(6, "Password must be at least 6 characters"), }); export async function POST(request) { try { const body = await request.json(); const { token, password } = resetSchema.parse(body); // Import database here to avoid edge runtime issues const { default: db } = await import("@/lib/db.js"); // Check if token exists and is valid const resetToken = db .prepare( ` SELECT prt.*, u.username, u.name FROM password_reset_tokens prt JOIN users u ON prt.user_id = u.id WHERE prt.token = ? AND prt.used = 0 AND prt.expires_at > datetime('now') ` ) .get(token); if (!resetToken) { return NextResponse.json( { error: "Invalid or expired token" }, { status: 400 } ); } // Hash the new password const hashedPassword = await bcrypt.hash(password, 12); // Update user password db.prepare("UPDATE users SET password_hash = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?") .run(hashedPassword, resetToken.user_id); // Mark token as used db.prepare("UPDATE password_reset_tokens SET used = 1 WHERE id = ?") .run(resetToken.id); // Log audit event try { const { logAuditEventSafe, AUDIT_ACTIONS, RESOURCE_TYPES } = await import("@/lib/auditLogSafe.js"); await logAuditEventSafe({ action: AUDIT_ACTIONS.PASSWORD_RESET, userId: resetToken.user_id, resourceType: RESOURCE_TYPES.USER, details: { username: resetToken.username }, }); } catch (auditError) { console.error("Failed to log audit event:", auditError); } return NextResponse.json({ message: "Password has been reset successfully", }); } catch (error) { console.error("Password reset error:", error); return NextResponse.json( { error: "Internal server error" }, { status: 500 } ); } }