import { NextRequest, NextResponse } from 'next/server'; import { checkRateLimit, getRateLimitHeaders } from '@/lib/auth'; export async function POST(request: NextRequest) { try { // Rate limiting const ip = request.headers.get('x-forwarded-for') || request.headers.get('x-real-ip') || 'unknown'; if (!checkRateLimit(ip, 20, 60000)) { // 20 login attempts per minute return new NextResponse( JSON.stringify({ error: 'Rate limit exceeded' }), { status: 429, headers: { 'Content-Type': 'application/json', ...getRateLimitHeaders(ip, 20, 60000) } } ); } const { password, csrfToken } = await request.json(); if (!password) { return new NextResponse( JSON.stringify({ error: 'Password required' }), { status: 400, headers: { 'Content-Type': 'application/json' } } ); } // CSRF Protection const expectedCSRF = request.headers.get('x-csrf-token'); if (!csrfToken || !expectedCSRF || csrfToken !== expectedCSRF) { return new NextResponse( JSON.stringify({ error: 'CSRF token validation failed' }), { status: 403, headers: { 'Content-Type': 'application/json' } } ); } // Get admin credentials from environment const adminAuth = process.env.ADMIN_BASIC_AUTH || 'admin:default_password_change_me'; const [, expectedPassword] = adminAuth.split(':'); // Secure password comparison using constant-time comparison const crypto = await import('crypto'); const passwordBuffer = Buffer.from(password, 'utf8'); const expectedBuffer = Buffer.from(expectedPassword, 'utf8'); // Use constant-time comparison to prevent timing attacks if (passwordBuffer.length === expectedBuffer.length && crypto.timingSafeEqual(passwordBuffer, expectedBuffer)) { // Generate cryptographically secure session token const timestamp = Date.now(); const randomBytes = crypto.randomBytes(32); const randomString = randomBytes.toString('hex'); // Create session data const sessionData = { timestamp, random: randomString, ip: ip, userAgent: request.headers.get('user-agent') || 'unknown' }; // Encode session data (base64 is sufficient for this use case) const sessionJson = JSON.stringify(sessionData); const sessionToken = Buffer.from(sessionJson).toString('base64'); return new NextResponse( JSON.stringify({ success: true, message: 'Login successful', sessionToken }), { status: 200, headers: { 'Content-Type': 'application/json', 'X-Content-Type-Options': 'nosniff', 'X-Frame-Options': 'DENY', 'X-XSS-Protection': '1; mode=block' } } ); } else { return new NextResponse( JSON.stringify({ error: 'Invalid password' }), { status: 401, headers: { 'Content-Type': 'application/json' } } ); } } catch { return new NextResponse( JSON.stringify({ error: 'Internal server error' }), { status: 500, headers: { 'Content-Type': 'application/json' } } ); } }