diff --git a/dashcaddy-api/src/app.js b/dashcaddy-api/src/app.js index b9c8595..966e591 100644 --- a/dashcaddy-api/src/app.js +++ b/dashcaddy-api/src/app.js @@ -193,26 +193,35 @@ async function createApp() { // prefix `/api/auth/...`. The canonical mount is `/api/v1`. Hand-maintained // Caddyfiles have repeatedly drifted back to the old prefix and 404'd the SSO // gate (breaking Plex/Jellyfin/Emby/chat). Transparently rewrite ONLY these - // three auth paths to the v1 mount so the gate is tolerant of that drift. + // auth paths to the v1 mount so the gate is tolerant of that drift. // Must run before configureMiddleware() so CSRF/auth see the canonical path. // This is deliberately narrow — NOT a general `/api` -> `/api/v1` alias. // - // Path mapping (legacy -> canonical): + // Path mapping (any -> canonical): // /api/auth/gate/ -> /api/v1/auth/gate/ (mounted at /auth/gate/:serviceId) + // /api/v1/auth/gate/ -> /api/v1/auth/gate/ (drift, gate pre-1.5.0 sometimes used this) // /api/auth/app-token/ -> /api/v1/auth/app-token/ (mounted at /auth/app-token/:serviceId) + // /api/v1/auth/app-token/ -> /api/v1/auth/app-token/ (drift) // /api/auth/totp/check-session -> /api/v1/totp/check-session (mounted at /totp/check-session — no /auth prefix) + // /api/v1/auth/totp/check-session->/api/v1/totp/check-session (drift) // // The totp case drops `/auth` because the canonical route is /totp/check-session - // (no /auth prefix) but the legacy JS still uses /api/auth/totp/check-session. - // Without this rewrite the JS gets a 404 and the page hangs at + // (no /auth prefix) but the legacy JS still uses /api/auth/totp/check-session + // (and a stale-browser version of the page uses /api/v1/auth/totp/check-session). + // Without these rewrites the JS gets a 404 and the page hangs at // "Signing in to Plex..." forever (user-reported 2026-07-09). app.use((req, res, next) => { - if (req.url.startsWith('/api/auth/gate/') || req.url.startsWith('/api/auth/app-token/')) { + if (req.url.startsWith('/api/auth/gate/') || req.url.startsWith('/api/v1/auth/gate/') + || req.url.startsWith('/api/auth/app-token/') || req.url.startsWith('/api/v1/auth/app-token/')) { req.url = '/api/v1' + req.url.slice(4); // '/api'.length === 4 } else if (req.url.startsWith('/api/auth/totp/check-session')) { // Legacy: /api/auth/totp/check-session -> /api/v1/totp/check-session // Drop both '/api' and '/auth' prefixes (9 chars total). req.url = '/api/v1' + req.url.slice(9); // '/api/auth'.length === 9 + } else if (req.url.startsWith('/api/v1/auth/totp/check-session')) { + // Drift: /api/v1/auth/totp/check-session -> /api/v1/totp/check-session + // Drop the '/api/v1' prefix AND the '/auth' middle segment (13 chars total). + req.url = '/api/v1' + req.url.slice(13); // '/api/v1/auth'.length === 13 } next(); });