feat: production deployment configuration for dk0.dev
- Fixed authentication system (removed HTTP Basic Auth popup) - Added session-based authentication with proper logout - Updated rate limiting (20 req/s for login, 5 req/m for admin) - Created production deployment scripts and configs - Updated nginx configuration for dk0.dev domain - Added comprehensive production deployment guide - Fixed logout button functionality - Optimized for production with proper resource limits
This commit is contained in:
68
lib/auth.ts
68
lib/auth.ts
@@ -31,8 +31,59 @@ export function requireAdminAuth(request: NextRequest): Response | null {
|
||||
{
|
||||
status: 401,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'WWW-Authenticate': 'Basic realm="Admin Access"'
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Session-based authentication (no browser popup)
|
||||
export function verifySessionAuth(request: NextRequest): boolean {
|
||||
// Check for session token in headers
|
||||
const sessionToken = request.headers.get('x-session-token');
|
||||
if (!sessionToken) return false;
|
||||
|
||||
try {
|
||||
// Decode and validate session token
|
||||
const decodedJson = atob(sessionToken);
|
||||
const sessionData = JSON.parse(decodedJson);
|
||||
|
||||
// Validate session data structure
|
||||
if (!sessionData.timestamp || !sessionData.random || !sessionData.ip || !sessionData.userAgent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if session is still valid (2 hours)
|
||||
const sessionTime = sessionData.timestamp;
|
||||
const now = Date.now();
|
||||
const sessionDuration = 2 * 60 * 60 * 1000; // 2 hours
|
||||
|
||||
if (now - sessionTime > sessionDuration) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate IP address (optional, but good security practice)
|
||||
const currentIp = request.headers.get('x-forwarded-for') || request.headers.get('x-real-ip') || 'unknown';
|
||||
if (sessionData.ip !== currentIp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function requireSessionAuth(request: NextRequest): Response | null {
|
||||
if (!verifySessionAuth(request)) {
|
||||
return new Response(
|
||||
JSON.stringify({ error: 'Session expired or invalid' }),
|
||||
{
|
||||
status: 401,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -43,6 +94,19 @@ export function requireAdminAuth(request: NextRequest): Response | null {
|
||||
// Rate limiting for admin endpoints
|
||||
const rateLimitMap = new Map<string, { count: number; resetTime: number }>();
|
||||
|
||||
// Clear rate limit cache on startup
|
||||
if (typeof window === 'undefined') {
|
||||
// Server-side: clear cache periodically
|
||||
setInterval(() => {
|
||||
const now = Date.now();
|
||||
for (const [key, value] of rateLimitMap.entries()) {
|
||||
if (now > value.resetTime) {
|
||||
rateLimitMap.delete(key);
|
||||
}
|
||||
}
|
||||
}, 60000); // Clear every minute
|
||||
}
|
||||
|
||||
export function checkRateLimit(ip: string, maxRequests: number = 10, windowMs: number = 60000): boolean {
|
||||
const now = Date.now();
|
||||
const key = `admin_${ip}`;
|
||||
|
||||
Reference in New Issue
Block a user