import bcrypt from "bcryptjs"; import { NextResponse } from "next/server"; import { randomUUID } from "crypto"; import { prisma } from "../../../lib/prisma"; import { isAdminEmail, isSuperAdminEmail } from "../../../lib/auth"; import { sendMail } from "../../../lib/mailer"; import { checkRateLimit, getRateLimitConfig } from "../../../lib/rate-limit"; import { getClientIp } from "../../../lib/request"; import { getEmailVerificationRequired } from "../../../lib/system-settings"; export async function POST(request: Request) { const registrationSetting = await prisma.setting.findUnique({ where: { key: "registration_enabled" } }); if (registrationSetting?.value === "false") { return NextResponse.json( { error: "Registrierung ist derzeit deaktiviert." }, { status: 403 } ); } const body = await request.json(); const { email, name, password } = body || {}; const normalizedEmail = String(email || "").trim().toLowerCase(); if (!normalizedEmail || !password) { return NextResponse.json({ error: "Email und Passwort sind erforderlich." }, { status: 400 }); } const ip = getClientIp(request); const rateKey = `register:${normalizedEmail}:${ip}`; const rateConfig = getRateLimitConfig("RATE_LIMIT_REGISTER", 5); 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 existing = await prisma.user.findUnique({ where: { email: normalizedEmail } }); if (existing) { return NextResponse.json({ error: "Account existiert bereits." }, { status: 409 }); } const passwordHash = await bcrypt.hash(password, 10); const superAdmin = isSuperAdminEmail(normalizedEmail); const admin = isAdminEmail(normalizedEmail) || superAdmin; const emailVerificationRequired = await getEmailVerificationRequired(); const shouldVerifyEmail = emailVerificationRequired && !admin; const emailVerified = admin || !emailVerificationRequired; const user = await prisma.user.create({ data: { email: normalizedEmail, name: name || null, passwordHash, role: superAdmin ? "SUPERADMIN" : admin ? "ADMIN" : "USER", status: admin ? "ACTIVE" : "PENDING", emailVerified } }); const categories = await prisma.category.findMany({ select: { id: true } }); const view = await prisma.userView.create({ data: { name: "Meine Ansicht", token: randomUUID(), user: { connect: { id: user.id } } } }); if (categories.length > 0) { await prisma.userViewCategory.createMany({ data: categories.map((category) => ({ viewId: view.id, categoryId: category.id })) }); } if (shouldVerifyEmail) { 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({ id: user.id, email: user.email }); }