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 = `pwreset:${normalizedEmail}:${ip}`; const rateConfig = getRateLimitConfig("RATE_LIMIT_PASSWORD_RESET", 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) { const existingToken = await prisma.passwordResetToken.findFirst({ where: { userId: user.id, createdAt: { gt: new Date(Date.now() - 15 * 60 * 1000) } }, orderBy: { createdAt: "desc" } }); if (existingToken) { return NextResponse.json({ ok: true }); } await prisma.passwordResetToken.deleteMany({ where: { userId: user.id } }); const token = randomUUID(); const expiresAt = new Date(Date.now() + 60 * 60 * 1000); await prisma.passwordResetToken.create({ data: { userId: user.id, token, expiresAt } }); const baseUrl = process.env.NEXTAUTH_URL || "http://localhost:3000"; const resetUrl = `${baseUrl}/reset/confirm?token=${token}`; await sendMail({ to: normalizedEmail, subject: "Passwort zurücksetzen", text: `Passwort zurücksetzen: ${resetUrl}` }); } return NextResponse.json({ ok: true }); }