import { getUserByUsername, checkRateLimit, resetRateLimit, createSession } from '~/server/utils/database' import { setAuthCookie, generateSessionToken } from '~/server/utils/auth' import bcrypt from 'bcrypt' 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(`[LOGIN ATTEMPT] IP: ${clientIp}, Headers:`, { 'x-forwarded-for': xForwardedFor, 'x-real-ip': xRealIp, 'cf-connecting-ip': cfConnectingIp, 'getRequestIP': getRequestIP(event) }) const body = await readBody(event) const { username, password } = body if (!username || !password) { throw createError({ statusCode: 400, message: 'Username and password are required' }) } const user = getUserByUsername(username.toLowerCase()) if (!user) { // Check rate limit ONLY on failed attempt if (!checkRateLimit(clientIp, 'login', 5, 15)) { console.log(`[LOGIN BLOCKED] Rate limited - Username not found: ${username.toLowerCase()}, IP: ${clientIp}`) throw createError({ statusCode: 429, message: 'Too many login attempts. Please try again in 15 minutes.' }) } console.log(`[LOGIN FAILED] Username not found: ${username.toLowerCase()}, IP: ${clientIp}`) throw createError({ statusCode: 401, message: 'Invalid credentials' }) } // Compare the provided password with the hashed password in the database const passwordMatch = await bcrypt.compare(password, user.password) if (!passwordMatch) { // Check rate limit ONLY on failed attempt if (!checkRateLimit(clientIp, 'login', 5, 15)) { console.log(`[LOGIN BLOCKED] Rate limited - Invalid password for user: ${username.toLowerCase()}, IP: ${clientIp}`) throw createError({ statusCode: 429, message: 'Too many login attempts. Please try again in 15 minutes.' }) } console.log(`[LOGIN FAILED] Invalid password for user: ${username.toLowerCase()}, IP: ${clientIp}`) throw createError({ statusCode: 401, message: 'Invalid credentials' }) } // Generate session token and create session const sessionToken = generateSessionToken() const expiresAt = new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString() // 24 hours createSession(sessionToken, user.username, expiresAt) // Set session cookie setAuthCookie(event, sessionToken) // Reset rate limit on successful login resetRateLimit(clientIp, 'login') // Log successful login console.log(`[LOGIN SUCCESS] User: ${user.username}, IP: ${clientIp}`) return { success: true, username: user.username } })