import { randomUUID } from "crypto"; import { NextResponse } from "next/server"; import { prisma } from "../../../../lib/prisma"; import { sendMail } from "../../../../lib/mailer"; import { checkRateLimit, getRateLimitConfig } from "../../../../lib/rate-limit"; import { getClientIp } from "../../../../lib/request"; export async function POST(request: Request) { const body = await request.json(); const { email } = body || {}; if (!email) { return NextResponse.json({ error: "E-Mail erforderlich." }, { status: 400 }); } const normalizedEmail = String(email).trim().toLowerCase(); const ip = getClientIp(request); const rateKey = `verify:${normalizedEmail}:${ip}`; const rateConfig = getRateLimitConfig("RATE_LIMIT_VERIFY_EMAIL", 3); const rate = await checkRateLimit({ key: rateKey, limit: rateConfig.limit, windowMs: rateConfig.windowMs }); if (!rate.ok) { return NextResponse.json( { error: "Zu viele Anfragen. Bitte später erneut versuchen." }, { status: 429 } ); } const user = await prisma.user.findUnique({ where: { email: normalizedEmail } }); if (!user) { return NextResponse.json({ ok: true }); } if (user.emailVerified) { return NextResponse.json({ ok: true }); } const existingToken = await prisma.verificationToken.findFirst({ where: { identifier: normalizedEmail, expires: { gt: new Date() } } }); if (existingToken) { return NextResponse.json({ ok: true }); } await prisma.verificationToken.deleteMany({ where: { identifier: normalizedEmail } }); const token = randomUUID(); const expires = new Date(Date.now() + 24 * 60 * 60 * 1000); await prisma.verificationToken.create({ data: { identifier: normalizedEmail, token, expires } }); const baseUrl = process.env.NEXTAUTH_URL || "http://localhost:3000"; const verifyUrl = `${baseUrl}/verify/confirm?token=${token}`; await sendMail({ to: normalizedEmail, subject: "E-Mail verifizieren", text: `Bitte verifiziere deine E-Mail: ${verifyUrl}` }); return NextResponse.json({ ok: true }); }