Files
panel/src/app/api/auth/password-reset/reset/route.js

71 lines
1.9 KiB
JavaScript

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 }
);
}
}