[object Object]

← back to Api Token Dashboard

chore: lint (security review), refactor (probeURL helper), harden path-traversal + esc() quotes, v1.0.0 (session close)

23ce98deb822f29ae8d356d1e4658610defe4d5f · 2026-07-01 14:35:21 -0700 · Steve Abrams

Files touched

Diff

commit 23ce98deb822f29ae8d356d1e4658610defe4d5f
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Wed Jul 1 14:35:21 2026 -0700

    chore: lint (security review), refactor (probeURL helper), harden path-traversal + esc() quotes, v1.0.0 (session close)
---
 package.json      |  9 +++++++++
 public/index.html |  2 +-
 server.mjs        | 32 +++++++++++++++++++++-----------
 3 files changed, 31 insertions(+), 12 deletions(-)

diff --git a/package.json b/package.json
new file mode 100644
index 0000000..156a8e6
--- /dev/null
+++ b/package.json
@@ -0,0 +1,9 @@
+{
+  "name": "api-token-dashboard",
+  "version": "1.0.0",
+  "private": true,
+  "type": "module",
+  "description": "Read-only live status dashboard for all API keys & OAuth token connections, with per-item fix links.",
+  "main": "server.mjs",
+  "scripts": { "start": "node server.mjs" }
+}
diff --git a/public/index.html b/public/index.html
index aa77ad3..64a7369 100644
--- a/public/index.html
+++ b/public/index.html
@@ -63,7 +63,7 @@
 <script>
 let DATA=[], FILTER='all';
 const SEV={dead:0,missing:1,unknown:2,connected:3};
-function esc(s){return (s||'').replace(/[&<>]/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;'}[c]))}
+function esc(s){return (s||'').replace(/[&<>"']/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]))}
 async function load(){
   document.getElementById('recheck').textContent='Checking…';
   try{
diff --git a/server.mjs b/server.mjs
index 7e41bf8..188b7cb 100644
--- a/server.mjs
+++ b/server.mjs
@@ -38,6 +38,15 @@ const DEAD = (detail) => ({ status: 'dead', detail });
 const MISSING = (detail = 'not configured') => ({ status: 'missing', detail });
 const UNKNOWN = (detail) => ({ status: 'unknown', detail });
 
+// Shared probe for the common pattern: guard missing key → GET url with headers → r.ok ? OK : DEAD.
+async function probeURL(envVal, url, headers) {
+  if (!envVal) return MISSING();
+  try {
+    const r = await fetchT(url, { headers });
+    return r.ok ? OK() : DEAD('http ' + r.status);
+  } catch (e) { return UNKNOWN(e.name === 'AbortError' ? 'timeout' : e.message); }
+}
+
 async function googleRefresh(id, sec, rt) {
   if (!id || !sec || !rt) return MISSING('client id / secret / refresh token absent');
   try {
@@ -122,29 +131,29 @@ function catalog() {
   // ---- Programmatic API keys (read-only verify endpoints) ----
   const key = (o) => add({ ...o, category: o.category || 'API keys' });
   key({ key: 'anthropic', name: 'Anthropic', tag: last4(s.ANTHROPIC_API_KEY), fixUrl: 'https://console.anthropic.com/settings/keys', instructions: 'Rotate at the console → paste new key → secrets skill routes it.', envName: 'ANTHROPIC_API_KEY',
-    probe: async () => { if (!s.ANTHROPIC_API_KEY) return MISSING(); try { const r = await fetchT('https://api.anthropic.com/v1/models', { headers: { 'x-api-key': s.ANTHROPIC_API_KEY, 'anthropic-version': '2023-06-01' } }); return r.ok ? OK() : DEAD('http ' + r.status); } catch (e) { return UNKNOWN(e.message); } } });
+    probe: () => probeURL(s.ANTHROPIC_API_KEY, 'https://api.anthropic.com/v1/models', { 'x-api-key': s.ANTHROPIC_API_KEY, 'anthropic-version': '2023-06-01' }) });
   key({ key: 'openai', name: 'OpenAI', tag: last4(s.OPENAI_API_KEY), fixUrl: 'https://platform.openai.com/api-keys', instructions: 'Rotate at platform.openai.com/api-keys.', envName: 'OPENAI_API_KEY',
-    probe: async () => { if (!s.OPENAI_API_KEY) return MISSING(); try { const r = await fetchT('https://api.openai.com/v1/models', { headers: { Authorization: 'Bearer ' + s.OPENAI_API_KEY } }); return r.ok ? OK() : DEAD('http ' + r.status); } catch (e) { return UNKNOWN(e.message); } } });
+    probe: () => probeURL(s.OPENAI_API_KEY, 'https://api.openai.com/v1/models', { Authorization: 'Bearer ' + s.OPENAI_API_KEY }) });
   key({ key: 'gemini', name: 'Google Gemini', tag: last4(s.GEMINI_API_KEY), fixUrl: 'https://aistudio.google.com/app/apikey', instructions: 'Create/rotate at AI Studio → API keys.', envName: 'GEMINI_API_KEY',
-    probe: async () => { if (!s.GEMINI_API_KEY) return MISSING(); try { const r = await fetchT('https://generativelanguage.googleapis.com/v1beta/models?key=' + s.GEMINI_API_KEY); return r.ok ? OK() : DEAD('http ' + r.status); } catch (e) { return UNKNOWN(e.message); } } });
+    probe: () => probeURL(s.GEMINI_API_KEY, 'https://generativelanguage.googleapis.com/v1beta/models?key=' + s.GEMINI_API_KEY, {}) });
   key({ key: 'replicate', name: 'Replicate', tag: last4(s.REPLICATE_API_TOKEN), fixUrl: 'https://replicate.com/account/api-tokens', instructions: 'Rotate at replicate.com/account/api-tokens.', envName: 'REPLICATE_API_TOKEN',
-    probe: async () => { if (!s.REPLICATE_API_TOKEN) return MISSING(); try { const r = await fetchT('https://api.replicate.com/v1/account', { headers: { Authorization: 'Token ' + s.REPLICATE_API_TOKEN } }); return r.ok ? OK() : DEAD('http ' + r.status); } catch (e) { return UNKNOWN(e.message); } } });
+    probe: () => probeURL(s.REPLICATE_API_TOKEN, 'https://api.replicate.com/v1/account', { Authorization: 'Token ' + s.REPLICATE_API_TOKEN }) });
   key({ key: 'elevenlabs', name: 'ElevenLabs', tag: last4(s.ELEVENLABS_API_KEY), fixUrl: 'https://elevenlabs.io/app/settings/api-keys', instructions: 'Rotate in ElevenLabs settings → API keys.', envName: 'ELEVENLABS_API_KEY',
-    probe: async () => { if (!s.ELEVENLABS_API_KEY) return MISSING(); try { const r = await fetchT('https://api.elevenlabs.io/v1/user', { headers: { 'xi-api-key': s.ELEVENLABS_API_KEY } }); return r.ok ? OK() : DEAD('http ' + r.status); } catch (e) { return UNKNOWN(e.message); } } });
+    probe: () => probeURL(s.ELEVENLABS_API_KEY, 'https://api.elevenlabs.io/v1/user', { 'xi-api-key': s.ELEVENLABS_API_KEY }) });
   key({ key: 'cloudflare', name: 'Cloudflare', tag: last4(s.CLOUDFLARE_API_TOKEN), fixUrl: 'https://dash.cloudflare.com/profile/api-tokens', instructions: 'Roll the token in CF dashboard → API tokens.', envName: 'CLOUDFLARE_API_TOKEN',
     probe: async () => { if (!s.CLOUDFLARE_API_TOKEN) return MISSING(); try { const r = await fetchT('https://api.cloudflare.com/client/v4/user/tokens/verify', { headers: { Authorization: 'Bearer ' + s.CLOUDFLARE_API_TOKEN } }); const j = await r.json().catch(() => ({})); return j.success ? OK() : DEAD('http ' + r.status); } catch (e) { return UNKNOWN(e.message); } } });
   key({ key: 'shopify', name: 'Shopify Admin', tag: last4(s.SHOPIFY_ADMIN_TOKEN), fixUrl: 'https://admin.shopify.com/settings/apps', instructions: 'Reinstall/rotate the custom app token in Shopify admin → Apps.', envName: 'SHOPIFY_ADMIN_TOKEN',
     probe: async () => { const dom = s.SHOPIFY_STORE_DOMAIN, tok = s.SHOPIFY_ADMIN_TOKEN; if (!dom || !tok) return MISSING(); try { const r = await fetchT('https://' + dom + '/admin/api/2024-01/shop.json', { headers: { 'X-Shopify-Access-Token': tok } }); return r.ok ? OK() : DEAD('http ' + r.status); } catch (e) { return UNKNOWN(e.message); } } });
   key({ key: 'stripe', name: 'Stripe', tag: last4(s.STRIPE_SECRET_KEY), fixUrl: 'https://dashboard.stripe.com/apikeys', instructions: 'Roll the secret key in the Stripe dashboard → Developers → API keys.', envName: 'STRIPE_SECRET_KEY',
-    probe: async () => { if (!s.STRIPE_SECRET_KEY) return MISSING(); try { const r = await fetchT('https://api.stripe.com/v1/balance', { headers: { Authorization: 'Bearer ' + s.STRIPE_SECRET_KEY } }); return r.ok ? OK() : DEAD('http ' + r.status); } catch (e) { return UNKNOWN(e.message); } } });
+    probe: () => probeURL(s.STRIPE_SECRET_KEY, 'https://api.stripe.com/v1/balance', { Authorization: 'Bearer ' + s.STRIPE_SECRET_KEY }) });
   key({ key: 'twilio', name: 'Twilio', tag: last4(s.TWILIO_AUTH_TOKEN), fixUrl: 'https://console.twilio.com/', instructions: 'Rotate the auth token in the Twilio console.', envName: 'TWILIO_AUTH_TOKEN',
     probe: async () => { const sid = s.TWILIO_ACCOUNT_SID, tok = s.TWILIO_AUTH_TOKEN; if (!sid || !tok) return MISSING(); try { const r = await fetchT('https://api.twilio.com/2010-04-01/Accounts/' + sid + '.json', { headers: { Authorization: 'Basic ' + Buffer.from(sid + ':' + tok).toString('base64') } }); return r.ok ? OK() : DEAD('http ' + r.status); } catch (e) { return UNKNOWN(e.message); } } });
   key({ key: 'purelymail', name: 'Purelymail', tag: last4(s.PURELYMAIL_API_TOKEN), fixUrl: 'https://purelymail.com/manage/api', instructions: 'Regenerate the API token in Purelymail → Manage → API.', envName: 'PURELYMAIL_API_TOKEN',
     probe: async () => { if (!s.PURELYMAIL_API_TOKEN) return MISSING(); try { const r = await fetchT('https://purelymail.com/api/v0/checkAccountCredit', { method: 'POST', headers: { 'Purelymail-Api-Token': s.PURELYMAIL_API_TOKEN, 'Content-Type': 'application/json' }, body: '{}' }); const j = await r.json().catch(() => ({})); return (j.type === 'success' || j.result) ? OK() : DEAD('http ' + r.status); } catch (e) { return UNKNOWN(e.message); } } });
   key({ key: 'browserbase', name: 'Browserbase', tag: last4(s.BROWSERBASE_API_KEY), fixUrl: 'https://www.browserbase.com/settings', instructions: 'Rotate the API key in Browserbase settings.', envName: 'BROWSERBASE_API_KEY',
-    probe: async () => { if (!s.BROWSERBASE_API_KEY) return MISSING(); try { const r = await fetchT('https://api.browserbase.com/v1/projects', { headers: { 'X-BB-API-Key': s.BROWSERBASE_API_KEY } }); return r.ok ? OK() : DEAD('http ' + r.status); } catch (e) { return UNKNOWN(e.message); } } });
+    probe: () => probeURL(s.BROWSERBASE_API_KEY, 'https://api.browserbase.com/v1/projects', { 'X-BB-API-Key': s.BROWSERBASE_API_KEY }) });
   key({ key: 'moonshot', name: 'Moonshot (Kimi)', tag: last4(s.MOONSHOT_API_KEY), fixUrl: 'https://platform.moonshot.ai/console/api-keys', instructions: 'Rotate the key in the Moonshot console.', envName: 'MOONSHOT_API_KEY',
-    probe: async () => { if (!s.MOONSHOT_API_KEY) return MISSING(); try { const r = await fetchT('https://api.moonshot.ai/v1/models', { headers: { Authorization: 'Bearer ' + s.MOONSHOT_API_KEY } }); return r.ok ? OK() : DEAD('http ' + r.status); } catch (e) { return UNKNOWN(e.message); } } });
+    probe: () => probeURL(s.MOONSHOT_API_KEY, 'https://api.moonshot.ai/v1/models', { Authorization: 'Bearer ' + s.MOONSHOT_API_KEY }) });
   key({ key: 'godaddy', name: 'GoDaddy', tag: last4(s.GODADDY_API_KEY), fixUrl: 'https://developer.godaddy.com/keys', instructions: 'Create a production key at developer.godaddy.com/keys (OTE keys 403 on prod).', envName: 'GODADDY_API_KEY',
     probe: async () => { const k = s.GODADDY_API_KEY, sec = s.GODADDY_API_SECRET; if (!k || !sec) return MISSING(); try { const r = await fetchT('https://api.godaddy.com/v1/domains?limit=1', { headers: { Authorization: 'sso-key ' + k + ':' + sec } }); return r.ok ? OK() : DEAD('http ' + r.status); } catch (e) { return UNKNOWN(e.message); } } });
 
@@ -168,9 +177,10 @@ const server = http.createServer(async (req, res) => {
     res.writeHead(200, { 'Content-Type': 'application/json' });
     return res.end(JSON.stringify({ generatedAt: new Date().toISOString(), results }));
   }
-  // static
-  let f = url.pathname === '/' ? '/index.html' : url.pathname;
-  const fp = path.join(__dirname, 'public', path.normalize(f).replace(/^(\.\.[/\\])+/, ''));
+  // static — resolve then confirm the path stays inside public/ (traversal guard)
+  const root = path.resolve(__dirname, 'public');
+  const fp = path.resolve(root, '.' + path.normalize(url.pathname === '/' ? '/index.html' : url.pathname));
+  if (fp !== root && !fp.startsWith(root + path.sep)) { res.writeHead(403); return res.end('forbidden'); }
   fs.readFile(fp, (err, data) => {
     if (err) { res.writeHead(404); return res.end('not found'); }
     const ext = path.extname(fp);

← 12c500e dashboard: probe George Calendar via the real GMAIL client p  ·  back to Api Token Dashboard  ·  auto-save: 2026-07-07T08:56:34 (1 files) — package-lock.json 9d9e6d4 →