import { NextRequest, NextResponse } from "next/server"; import { z } from "zod"; import { getPrisma } from "../../../../lib/db"; import { verifyPassword } from "../../../../lib/auth/password"; import { signSession } from "../../../../lib/auth/jwt"; import { verifyCaptcha } from "../../../../lib/captcha"; import { cookies } from "next/headers"; export const runtime = "nodejs"; const Body = z.object({ email: z.string().email(), password: z.string().min(1), captchaId: z.string().optional(), captchaCode: z.string().optional(), }); export async function POST(req: NextRequest) { const prisma = await getPrisma(); const body = Body.safeParse(await req.json().catch(() => ({}))); if (!body.success) { return NextResponse.json({ ok: false, message: "Invalid input" }, { status: 400 }); } if (!prisma) { return NextResponse.json({ ok: false, message: "Database not configured" }, { status: 503 }); } // Validate CAPTCHA if provided if (body.data.captchaId && body.data.captchaCode) { const captchaResult = verifyCaptcha(body.data.captchaId, body.data.captchaCode); if (!captchaResult.success) { return NextResponse.json({ ok: false, message: captchaResult.error || "CAPTCHA verification failed. Please try again." }, { status: 400 }); } } const email = body.data.email.toLowerCase(); const password = body.data.password; console.log("[LOGIN] Login attempt for:", email); try { const user = await prisma.user.findUnique({ where: { email }, include: { credential: true }, }); if (!user) { console.log("[LOGIN] User not found:", email); return NextResponse.json({ ok: false, message: "Invalid email or password" }, { status: 401 }); } if (!user.credential || !user.credential.password) { console.log("[LOGIN] No password credential for user:", email); return NextResponse.json({ ok: false, message: "Please use Google sign-in for this account" }, { status: 401 }); } const valid = await verifyPassword(password, user.credential.password); if (!valid) { console.log("[LOGIN] Invalid password for:", email); return NextResponse.json({ ok: false, message: "Invalid email or password" }, { status: 401 }); } if (!user.isActive) { console.log("[LOGIN] Inactive account:", email); return NextResponse.json({ ok: false, message: "Account is inactive. Please contact support." }, { status: 403 }); } // Create session token const token = await signSession({ sub: user.id, role: user.role as "ADMIN" | "USER", email: user.email, forcePasswordReset: user.forcePasswordReset || false, }); console.log("[LOGIN] Session created for:", email, "with role:", user.role); // Set cookie const cookieStore = await cookies(); cookieStore.set("ep_session", token, { httpOnly: true, secure: process.env.NODE_ENV === "production", sameSite: "lax", maxAge: 7 * 24 * 60 * 60, // 7 days path: "/", }); console.log("[LOGIN] Login successful for:", email); return NextResponse.json({ ok: true, user: { id: user.id, email: user.email, role: user.role, firstName: user.firstName, lastName: user.lastName, emailVerified: user.emailVerified, forcePasswordReset: user.forcePasswordReset, }, }); } catch (e: any) { console.error("[LOGIN] Error:", e); return NextResponse.json({ ok: false, message: "Server error: Unable to process request" }, { status: 500 }); } }