Merge pull request #618 from Luca-Timo/fix/maintenance-locks-out-admin-login
Enabling maintenance mode locks every admin out of the panel
This commit is contained in:
@@ -64,10 +64,15 @@ async function checkMaintenanceMode() {
|
|||||||
|
|
||||||
// Middleware to enforce maintenance mode
|
// Middleware to enforce maintenance mode
|
||||||
async function maintenanceMiddleware(req, res, next) {
|
async function maintenanceMiddleware(req, res, next) {
|
||||||
// Skip maintenance check for certain paths
|
// Skip maintenance check for certain paths. Admin auth MUST work during
|
||||||
|
// maintenance — otherwise enabling it locks every admin out, including
|
||||||
|
// already-logged-in ones (their /auth/session check would 503 and read as
|
||||||
|
// logged-out). These are the REAL endpoints: the admin login + session
|
||||||
|
// routes live under /api/auth, NOT /api/admin (the old /api/admin/login
|
||||||
|
// entries here matched nothing, which is exactly why the lockout happened).
|
||||||
const skipPaths = [
|
const skipPaths = [
|
||||||
'/api/admin/login',
|
'/api/auth/admin/login',
|
||||||
'/api/admin/auth/login',
|
'/api/auth/session',
|
||||||
'/api/public/settings',
|
'/api/public/settings',
|
||||||
'/health'
|
'/health'
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,60 +1,39 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import { useLocation } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
import { MaintenanceMode } from './MaintenanceMode';
|
import { MaintenanceMode } from './MaintenanceMode';
|
||||||
import { useMaintenanceMode } from '../contexts/MaintenanceContext';
|
import { useMaintenanceMode } from '../contexts/MaintenanceContext';
|
||||||
import { setMaintenanceModeCallback, api } from '../config/api';
|
import { setMaintenanceModeCallback } from '../config/api';
|
||||||
|
|
||||||
interface MaintenanceWrapperProps {
|
interface MaintenanceWrapperProps {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Maintenance detection now lives in two places:
|
// Maintenance detection lives in two places:
|
||||||
// 1. The axios interceptor in config/api.ts flips the flag on any 503 response.
|
// 1. The axios interceptor in config/api.ts flips the flag on any 503 response.
|
||||||
// 2. MaintenanceContext polls /public/settings every 30s and reads the explicit
|
// 2. MaintenanceContext polls /public/settings every 30s and reads the explicit
|
||||||
// maintenance_mode field (via the shared usePublicSettings hook).
|
// maintenance_mode field (via the shared usePublicSettings hook).
|
||||||
// This wrapper only needs to gate the rendered tree on the resulting state.
|
//
|
||||||
|
// The maintenance screen ONLY blocks customer/gallery/public routes. Admin
|
||||||
|
// routes (/admin/*) are never blocked: an admin must always be able to reach
|
||||||
|
// the panel to turn maintenance back off, and the admin auth layer already
|
||||||
|
// handles access (AdminLayout redirects a logged-out admin to /admin/login).
|
||||||
|
// Gating /admin/* here on an "is the admin logged in?" check is what caused the
|
||||||
|
// lockout — it hid the login page itself, and after login the check went stale
|
||||||
|
// (login → dashboard is a client-side nav within /admin, so it never re-ran),
|
||||||
|
// leaving a logged-in admin stuck on the maintenance screen.
|
||||||
export const MaintenanceWrapper: React.FC<MaintenanceWrapperProps> = ({ children }) => {
|
export const MaintenanceWrapper: React.FC<MaintenanceWrapperProps> = ({ children }) => {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const { isMaintenanceMode, setMaintenanceMode } = useMaintenanceMode();
|
const { isMaintenanceMode, setMaintenanceMode } = useMaintenanceMode();
|
||||||
const [hasAdminSession, setHasAdminSession] = useState(false);
|
|
||||||
|
|
||||||
const isAdminRoute = location.pathname.startsWith('/admin');
|
const isAdminRoute = location.pathname.startsWith('/admin');
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
let isMounted = true;
|
|
||||||
|
|
||||||
const checkAdminSession = async () => {
|
|
||||||
if (!isAdminRoute) {
|
|
||||||
setHasAdminSession(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await api.get<{ valid: boolean; type: string }>('/auth/session');
|
|
||||||
if (isMounted) {
|
|
||||||
setHasAdminSession(Boolean(response.data?.valid && response.data.type === 'admin'));
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
if (isMounted) {
|
|
||||||
setHasAdminSession(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
checkAdminSession();
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
isMounted = false;
|
|
||||||
};
|
|
||||||
}, [isAdminRoute]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setMaintenanceModeCallback((enabled: boolean) => {
|
setMaintenanceModeCallback((enabled: boolean) => {
|
||||||
setMaintenanceMode(enabled);
|
setMaintenanceMode(enabled);
|
||||||
});
|
});
|
||||||
}, [setMaintenanceMode]);
|
}, [setMaintenanceMode]);
|
||||||
|
|
||||||
if (isMaintenanceMode && (!isAdminRoute || !hasAdminSession)) {
|
if (isMaintenanceMode && !isAdminRoute) {
|
||||||
return <MaintenanceMode />;
|
return <MaintenanceMode />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user