From 9c8bad5d066f36d669ddebab7ca22f5337efe23d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 24 Jan 2026 00:59:06 +0000 Subject: [PATCH 1/3] Initial plan From bb0e9cb66f6078f5ccbf4b32664f346fb469e111 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 24 Jan 2026 01:01:29 +0000 Subject: [PATCH 2/3] [security] Address code review feedback: improve API demo and token security Co-authored-by: toolate28 <105518313+toolate28@users.noreply.github.com> --- public/admin/dashboard.html | 32 ++++++++++++++++++++++++++++---- public/admin/login.html | 3 +++ public/api/index.html | 20 +++++++++++++++++--- 3 files changed, 48 insertions(+), 7 deletions(-) diff --git a/public/admin/dashboard.html b/public/admin/dashboard.html index 8e54ce6..f8d4256 100644 --- a/public/admin/dashboard.html +++ b/public/admin/dashboard.html @@ -421,11 +421,35 @@

Quick Actions

return; } - // Initialize charts - initCharts(); + // Validate token with auth endpoint before initializing the dashboard + (async () => { + try { + const response = await fetch(`${API_BASE}/admin/auth/me`, { + method: 'GET', + headers: { + 'Authorization': 'Bearer ' + token, + 'Accept': 'application/json' + } + }); + + if (!response.ok) { + // Invalid or expired token, clear it and redirect to login + localStorage.removeItem('spiralsafe_admin_token'); + sessionStorage.removeItem('spiralsafe_admin_token'); + window.location.href = '/admin/login.html'; + return; + } - // Load metrics - loadMetrics(); + // Token is valid - initialize charts and load metrics + initCharts(); + loadMetrics(); + } catch (error) { + // On network or other errors, clear token and redirect to login + localStorage.removeItem('spiralsafe_admin_token'); + sessionStorage.removeItem('spiralsafe_admin_token'); + window.location.href = '/admin/login.html'; + } + })(); }); // Logout function diff --git a/public/admin/login.html b/public/admin/login.html index da0c994..3812fa7 100644 --- a/public/admin/login.html +++ b/public/admin/login.html @@ -308,6 +308,9 @@

🔐 ATOM-AUTH: Conversational Cohe if (response.ok && data.token) { // Store token + // SECURITY NOTE: Storing tokens in localStorage/sessionStorage exposes them to XSS attacks. + // For production deployments, consider using httpOnly cookies set by the backend + // or implementing additional security measures (strict CSP, token rotation, etc.) if (remember) { localStorage.setItem('spiralsafe_admin_token', data.token); } else { diff --git a/public/api/index.html b/public/api/index.html index 182efa4..e9425e0 100644 --- a/public/api/index.html +++ b/public/api/index.html @@ -605,10 +605,24 @@

RapiDoc

responseEl.classList.remove('hidden'); codeEl.textContent = 'Loading...'; - const response = await fetch(`${API_BASE}/api/health`); - const data = await response.json(); + // Demo mode: simulated response for interactive preview + // For production API calls, include X-API-Key header in your request + const simulatedResponse = { + status: "healthy", + timestamp: new Date().toISOString(), + version: "1.0.0", + services: { + database: "operational", + cache: "operational", + queue: "operational" + }, + _note: "Interactive demo - use curl or your preferred HTTP client with a valid X-API-Key header for actual results" + }; - codeEl.textContent = JSON.stringify(data, null, 2); + // Simulate network delay + await new Promise(resolve => setTimeout(resolve, 500)); + + codeEl.textContent = JSON.stringify(simulatedResponse, null, 2); hljs.highlightElement(codeEl); } catch (error) { codeEl.textContent = JSON.stringify({ error: error.message }, null, 2); From 71685835cc85d27e913c1c906d2d319679e76f3e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 24 Jan 2026 01:03:56 +0000 Subject: [PATCH 3/3] [refactor] Improve dashboard token validation - use named function and eliminate duplication Co-authored-by: toolate28 <105518313+toolate28@users.noreply.github.com> --- public/admin/dashboard.html | 54 +++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/public/admin/dashboard.html b/public/admin/dashboard.html index f8d4256..fecb7ee 100644 --- a/public/admin/dashboard.html +++ b/public/admin/dashboard.html @@ -422,35 +422,37 @@

Quick Actions

} // Validate token with auth endpoint before initializing the dashboard - (async () => { - try { - const response = await fetch(`${API_BASE}/admin/auth/me`, { - method: 'GET', - headers: { - 'Authorization': 'Bearer ' + token, - 'Accept': 'application/json' - } - }); - - if (!response.ok) { - // Invalid or expired token, clear it and redirect to login - localStorage.removeItem('spiralsafe_admin_token'); - sessionStorage.removeItem('spiralsafe_admin_token'); - window.location.href = '/admin/login.html'; - return; + validateAndInit(); + }); + + // Validate token and initialize dashboard + async function validateAndInit() { + const token = localStorage.getItem('spiralsafe_admin_token') || + sessionStorage.getItem('spiralsafe_admin_token'); + + try { + const response = await fetch(`${API_BASE}/admin/auth/me`, { + method: 'GET', + headers: { + 'Authorization': `Bearer ${token}`, + 'Accept': 'application/json' } + }); - // Token is valid - initialize charts and load metrics - initCharts(); - loadMetrics(); - } catch (error) { - // On network or other errors, clear token and redirect to login - localStorage.removeItem('spiralsafe_admin_token'); - sessionStorage.removeItem('spiralsafe_admin_token'); - window.location.href = '/admin/login.html'; + if (!response.ok) { + // Invalid or expired token, clear it and redirect to login + logout(); + return; } - })(); - }); + + // Token is valid - initialize charts and load metrics + initCharts(); + loadMetrics(); + } catch (error) { + // On network or other errors, clear token and redirect to login + logout(); + } + } // Logout function function logout() {