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() {