import { NextRequest, NextResponse } from 'next/server'; import bcrypt from 'bcryptjs'; import { cookies } from 'next/headers'; import { db } from '@/lib/db'; import { z } from 'zod'; import { csrfProtection } from '@/lib/csrf'; import { rateLimit, getClientIdentifier, RateLimits } from '@/lib/rateLimit'; import { getAuthCookieOptions } from '@/lib/cookieConfig'; import { signupSchema, validateRequest } from '@/lib/validationSchemas'; export async function POST(request: NextRequest) { try { // CSRF Protection const csrfCheck = csrfProtection(request); if (!csrfCheck.valid) { return NextResponse.json( { error: csrfCheck.error }, { status: 403 } ); } // Rate Limiting const clientId = getClientIdentifier(request); const rateLimitResult = rateLimit(clientId, RateLimits.SIGNUP); if (!rateLimitResult.success) { return NextResponse.json( { error: 'Too many signup attempts. Please try again later.', retryAfter: Math.ceil((rateLimitResult.reset - Date.now()) / 1000) }, { status: 429, headers: { 'X-RateLimit-Limit': rateLimitResult.limit.toString(), 'X-RateLimit-Remaining': rateLimitResult.remaining.toString(), 'X-RateLimit-Reset': rateLimitResult.reset.toString(), } } ); } const body = await request.json(); // Validate request body const validation = await validateRequest(signupSchema, body); if (!validation.success) { return NextResponse.json(validation.error, { status: 400 }); } const { name, email, password } = validation.data; // Check if user already exists const existingUser = await db.user.findUnique({ where: { email }, }); if (existingUser) { return NextResponse.json( { error: 'User already exists' }, { status: 400 } ); } // Hash password const hashedPassword = await bcrypt.hash(password, 12); // Create user const user = await db.user.create({ data: { name, email, password: hashedPassword, }, }); // Set cookie for auto-login after signup cookies().set('userId', user.id, getAuthCookieOptions()); return NextResponse.json({ success: true, user: { id: user.id, name: user.name, email: user.email, }, }); } catch (error) { if (error instanceof z.ZodError) { return NextResponse.json( { error: 'Invalid input', details: error.errors }, { status: 400 } ); } console.error('Signup error:', error); return NextResponse.json( { error: 'Internal server error' }, { status: 500 } ); } }