import { createUser, getUserByUsername, getUserByEmail, checkRateLimit, createSession } from '~/server/utils/database' import { setAuthCookie, generateSessionToken } from '~/server/utils/auth' import { generateCsrfToken, setCsrfCookie } from '~/server/utils/csrf' export default defineEventHandler(async (event) => { // Get real client IP from proxy headers (prioritize x-real-ip for NPM) const xRealIp = getHeader(event, 'x-real-ip') const xForwardedFor = getHeader(event, 'x-forwarded-for') const cfConnectingIp = getHeader(event, 'cf-connecting-ip') // Use x-real-ip first (set by NPM), then x-forwarded-for, then cf-connecting-ip, then fallback const clientIp = xRealIp || (xForwardedFor ? xForwardedFor.split(',')[0].trim() : null) || cfConnectingIp || getRequestIP(event) || 'unknown' // Log IP for verification console.log(`[REGISTER ATTEMPT] IP: ${clientIp}, Headers:`, { 'x-forwarded-for': xForwardedFor, 'x-real-ip': xRealIp, 'cf-connecting-ip': cfConnectingIp, 'getRequestIP': getRequestIP(event) }) // Check rate limit: 3 attempts per hour if (!checkRateLimit(clientIp, 'register', 3, 60)) { throw createError({ statusCode: 429, message: 'Too many registration attempts. Please try again in 1 hour.' }) } const body = await readBody(event) const { username, password, email, firstName, lastName } = body if (!username || !password || !email || !firstName || !lastName) { throw createError({ statusCode: 400, message: 'All fields are required' }) } // Validate email format const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ if (!emailRegex.test(email)) { throw createError({ statusCode: 400, message: 'Invalid email format' }) } // Validate username format if (username.length < 3) { throw createError({ statusCode: 400, message: 'Username must be at least 3 characters long' }) } // Validate password strength if (password.length < 8) { throw createError({ statusCode: 400, message: 'Password must be at least 8 characters long' }) } if (!/[A-Z]/.test(password)) { throw createError({ statusCode: 400, message: 'Password must contain at least one uppercase letter' }) } if (!/[a-z]/.test(password)) { throw createError({ statusCode: 400, message: 'Password must contain at least one lowercase letter' }) } if (!/[0-9!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(password)) { throw createError({ statusCode: 400, message: 'Password must contain at least one number or symbol' }) } // Check if username already exists const existingUser = getUserByUsername(username.toLowerCase()) if (existingUser) { throw createError({ statusCode: 409, message: 'Username already exists' }) } // Check if email already exists const existingEmail = getUserByEmail(email.toLowerCase()) if (existingEmail) { throw createError({ statusCode: 409, message: 'Email already exists' }) } try { // Create the new user with all fields createUser(username.toLowerCase(), password, email.toLowerCase(), firstName, lastName) // Generate session token and CSRF token for auto-login const sessionToken = generateSessionToken() const csrfToken = generateCsrfToken() const expiresAt = new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString() // 24 hours // Create session with CSRF token createSession(sessionToken, username.toLowerCase(), expiresAt, csrfToken) // Set session cookie setAuthCookie(event, sessionToken) // Set CSRF cookie setCsrfCookie(event, csrfToken) // Log successful registration console.log(`[REGISTER SUCCESS] User: ${username.toLowerCase()}, IP: ${clientIp}`) return { success: true, username: username.toLowerCase() } } catch (error) { throw createError({ statusCode: 500, message: 'Failed to create user account' }) } })