import SiteConfig from "../models/SiteConfig.js"; import { verifyAccessToken } from "../utils/jwt.js"; import User from "../models/User.js"; /** * Middleware to check if site is in maintenance mode * Allows admins and whitelisted users to access during maintenance */ export const checkMaintenance = async (request, reply) => { try { const currentPath = request.url.split("?")[0]; // Remove query params // Skip maintenance check for public health endpoints and auth routes const publicEndpoints = [ "/health", "/api/health", "/api/config/public", "/api/config/announcements", "/api/config/status", "/api/config/promotions", ]; // Allow all auth routes (needed for Steam OAuth flow) const authRoutes = [ "/auth/steam", "/auth/steam/return", "/api/auth/steam", "/api/auth/steam/return", "/api/auth/me", "/api/auth/verify", "/api/auth/refresh", "/api/auth/logout", ]; if ( publicEndpoints.includes(currentPath) || authRoutes.includes(currentPath) || currentPath.startsWith("/auth/") || currentPath.startsWith("/api/auth/") ) { return; } const config = await SiteConfig.getConfig(); // If maintenance mode is not enabled, allow all requests if (!config.isMaintenanceActive()) { return; } // Try to verify user authentication manually if not already done let authenticatedUser = request.user; if (!authenticatedUser) { // Try to get token from cookies or Authorization header let token = null; // Check Authorization header const authHeader = request.headers.authorization; if (authHeader && authHeader.startsWith("Bearer ")) { token = authHeader.substring(7); } // Check cookies if no header if (!token && request.cookies && request.cookies.accessToken) { token = request.cookies.accessToken; } // If we have a token, verify it if (token) { try { const decoded = verifyAccessToken(token); if (decoded && decoded.userId) { // Fetch user from database authenticatedUser = await User.findById(decoded.userId); } } catch (error) { // Token invalid or expired - user will be treated as unauthenticated console.log( "⚠️ Token verification failed in maintenance check:", error.message ); } } } // If user is authenticated, check if they're allowed during maintenance if (authenticatedUser) { // Check if user is admin (staff level 3+) if (authenticatedUser.staffLevel >= 3) { console.log( `✅ Admin ${authenticatedUser.username} bypassing maintenance mode for ${currentPath}` ); return; // Allow all admin access } // Check if user's steamId is in the allowed list if (config.canAccessDuringMaintenance(authenticatedUser.steamId)) { console.log( `✅ Whitelisted user ${authenticatedUser.username} bypassing maintenance mode` ); return; } } // User is not allowed during maintenance console.log(`⚠️ Blocking request during maintenance: ${currentPath}`); // For API calls, return JSON if (currentPath.startsWith("/api/")) { return reply.status(503).send({ success: false, maintenance: true, message: config.maintenance.message || "We're currently performing maintenance. Please check back soon!", scheduledEnd: config.maintenance.scheduledEnd, redirectTo: "/maintenance", }); } // For regular page requests, redirect to maintenance page // (This will be handled by frontend router) return reply.status(503).send({ success: false, maintenance: true, message: config.maintenance.message || "We're currently performing maintenance. Please check back soon!", scheduledEnd: config.maintenance.scheduledEnd, redirectTo: "/maintenance", }); } catch (error) { console.error("❌ Maintenance check error:", error); // On error, allow the request to proceed (fail open) return; } }; /** * Optional middleware - only check maintenance for specific routes */ export const maintenanceExempt = async (request, reply) => { // This middleware does nothing - it's used to mark routes that should bypass maintenance return; };