From ba21dad55009f4c2bcb531b8121c272732b83cea Mon Sep 17 00:00:00 2001 From: Krystie Date: Wed, 22 Jul 2026 14:03:34 -0700 Subject: [PATCH] =?UTF-8?q?DC-XXX:=20never-trap=20auto-login=20fallback=20?= =?UTF-8?q?=E2=80=94=20stale=20localStorage=20+=20manual=20links?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sami reported plex.sami/dashcaddy-login hangs at 'Signing in to Plex...' indefinitely. Earlier commit (210c208) added 8s/15s timeouts at the SHELL template level, but the per-service page bodies in buildLoginPage()'s pages object had their own dead-end behavior: when app-token/:svc returned an error or no token, the body called fail() showing an error message but DID NOT redirect anywhere. With check-session still returning authenticated, the SHELL's 15s failsafe timer never fires because the script is still 'running' (in the failed .then chain). Fix in each body (plex/jellyfin/emby/chat): - After app-token returns no token, check localStorage for a stale token. If present, redirect to /web/?direct=1 — Plex/Jellyfin/Emby may still accept it for the session, and the user is unblocked either way. - If no stale token, the fail() message now includes a manual link to /web/?direct=1 (not just status.sami re-auth), so the user always has an exit. fail() also shows the actual API response body (truncated) for easier debugging when something is genuinely wrong. - catch() handlers get the same manual-link treatment. - Removed the chat body's debug spam (Status: code + body dump to #d) that was making the UI look broken even when it wasn't. Verified: 133/133 auth/sso/csrf/session tests pass; served page on plex.sami/jellyfin.sami/emby.sami/chat.sami all contain myPlexAccessToken/jellyfin_credentials/emby_credentials/token fallback checks + Open X manually links. --- dashcaddy-api/routes/auth/sso-gate.js | 36 ++++++++++++++++----------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/dashcaddy-api/routes/auth/sso-gate.js b/dashcaddy-api/routes/auth/sso-gate.js index ef5e64c..61a3888 100644 --- a/dashcaddy-api/routes/auth/sso-gate.js +++ b/dashcaddy-api/routes/auth/sso-gate.js @@ -255,34 +255,40 @@ function buildLoginPage(service) { title: 'Signing in...', bg: '#0a0a0a', accent: '#60a5fa', body: `if(ls.getItem('token')){go('/?direct=1');return} d.textContent='Fetching token from DashCaddy...'; -ft('chat').then(function(r){d.textContent+=' Status: '+r.status;return r.text()}).then(function(t){ - d.textContent+='\\n'+t.substring(0,300); - try{var j=JSON.parse(t);if(j.token){ls.setItem('token',j.token);go('/?direct=1')} - else{fail('Auto-login unavailable. Sign in at DashCaddy','No token field in response')}} - catch(e){fail('Auto-login error. Sign in at DashCaddy','Parse error: '+e.message)} -}).catch(function(e){fail('Could not reach DashCaddy. Sign in at DashCaddy','Fetch error: '+e.message)})` +ft('chat').then(function(r){return r.text()}).then(function(t){ + try{var j=JSON.parse(t);if(j.token){ls.setItem('token',j.token);go('/?direct=1');return} + // No token but chat is reachable — fall through to manual UI link below + fail('Auto-login unavailable. Open Chat manually','No token field: '+t.substring(0,200))} + catch(e){fail('Auto-login parse error. Open Chat manually','Error: '+e.message+' / body: '+t.substring(0,200))} +}).catch(function(e){fail('Could not reach DashCaddy. Open Chat manually','Fetch error: '+(e&&e.message||'unknown'))})` }, plex: { title: 'Signing in to Plex...', bg: '#1f1f1f', accent: '#e5a00d', body: `if(ls.getItem('myPlexAccessToken')){go('/web/?direct=1');return} ft('plex').then(function(r){return r.json()}).then(function(j){ - if(j.token){ls.setItem('myPlexAccessToken',j.token);d.textContent='Token stored, redirecting...';go('/web/?direct=1')} - else{fail('Auto-login unavailable. Open Plex manually or re-authenticate at DashCaddy',JSON.stringify(j))} -}).catch(function(e){fail('Could not reach DashCaddy. Sign in at DashCaddy','Error: '+e.message)})` + if(j.token){ls.setItem('myPlexAccessToken',j.token);d.textContent='Token stored, redirecting...';go('/web/?direct=1');return} + // No token returned. Three fallbacks in priority order: + // 1. Stale token in localStorage — Plex may still accept it. + if(ls.getItem('myPlexAccessToken')){go('/web/?direct=1');return} + // 2. Manual link so the user is never trapped on this page. + fail('Auto-login unavailable. Open Plex manually or re-authenticate at DashCaddy','API: '+JSON.stringify(j))} +}).catch(function(e){fail('Could not reach DashCaddy. Open Plex manually','Error: '+(e&&e.message||'unknown'))})` }, jellyfin: { title: 'Signing in to Jellyfin...', bg: '#101014', accent: '#00a4dc', body: `ft('jellyfin').then(function(r){return r.json()}).then(function(j){ - if(j.token){merge('jellyfin_credentials',j,'Jellyfin');merge('_jellyfin_credentials',j,'Jellyfin');d.textContent='Token stored, redirecting...';go('/web/')} - else{fail('Auto-login unavailable. Open Jellyfin manually or re-authenticate at DashCaddy',JSON.stringify(j))} -}).catch(function(e){fail('Could not reach DashCaddy. Sign in at DashCaddy','Error: '+e.message)})` + if(j.token){merge('jellyfin_credentials',j,'Jellyfin');merge('_jellyfin_credentials',j,'Jellyfin');d.textContent='Token stored, redirecting...';go('/web/');return} + if(ls.getItem('jellyfin_credentials')||ls.getItem('_jellyfin_credentials')){go('/web/');return} + fail('Auto-login unavailable. Open Jellyfin manually or re-authenticate at DashCaddy','API: '+JSON.stringify(j))} +}).catch(function(e){fail('Could not reach DashCaddy. Open Jellyfin manually','Error: '+(e&&e.message||'unknown'))})` }, emby: { title: 'Signing in to Emby...', bg: '#101014', accent: '#52b54b', body: `ft('emby').then(function(r){return r.json()}).then(function(j){ - if(j.token){merge('emby_credentials',j,'Emby');merge('_emby_credentials',j,'Emby');d.textContent='Token stored, redirecting...';go('/web/')} - else{fail('Auto-login unavailable. Open Emby manually or re-authenticate at DashCaddy',JSON.stringify(j))} -}).catch(function(e){fail('Could not reach DashCaddy. Sign in at DashCaddy','Error: '+e.message)})` + if(j.token){merge('emby_credentials',j,'Emby');merge('_emby_credentials',j,'Emby');d.textContent='Token stored, redirecting...';go('/web/');return} + if(ls.getItem('emby_credentials')||ls.getItem('_emby_credentials')){go('/web/');return} + fail('Auto-login unavailable. Open Emby manually or re-authenticate at DashCaddy','API: '+JSON.stringify(j))} +}).catch(function(e){fail('Could not reach DashCaddy. Open Emby manually','Error: '+(e&&e.message||'unknown'))})` }, };