From eeb0318c4d68c9efbb2110a38ece76134df0b63d Mon Sep 17 00:00:00 2001 From: M1 Date: Wed, 18 Mar 2026 11:48:51 +0400 Subject: [PATCH] fix: hide login key and sub-keys from sub-key sessions --- apps/web/src/routes/dashboard.ts | 40 +++++++++++++++++++++----------- apps/web/src/views/settings.ejs | 6 ++++- 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/apps/web/src/routes/dashboard.ts b/apps/web/src/routes/dashboard.ts index a3f5d86..157cd5a 100644 --- a/apps/web/src/routes/dashboard.ts +++ b/apps/web/src/routes/dashboard.ts @@ -72,13 +72,12 @@ function redirect(to: string) { return new Response(null, { status: 302, headers: { Location: to } }); } -async function getAccountId(cookie: any, headers: any): Promise { +async function getAccountId(cookie: any, headers: any): Promise<{ accountId: string; keyId: string | null } | null> { const authHeader = headers["authorization"] ?? ""; const bearer = authHeader.match(/^bearer\s+(.+)$/i)?.[1]?.trim(); const key = cookie?.pingql_key?.value || bearer; if (!key) return null; - const resolved = await resolveKey(key); - return resolved?.accountId ?? null; + return await resolveKey(key) ?? null; } const dashDir = resolve(import.meta.dir, "../dashboard"); @@ -112,7 +111,9 @@ export const dashboard = new Elysia() // Home — SSR monitor list .get("/dashboard/home", async ({ cookie, headers }) => { - const accountId = await getAccountId(cookie, headers); + const resolved = await getAccountId(cookie, headers); + const accountId = resolved?.accountId ?? null; + const keyId = resolved?.keyId ?? null; if (!accountId) return redirect("/dashboard"); const monitors = await sql` @@ -150,26 +151,33 @@ export const dashboard = new Elysia() // Settings — SSR account info .get("/dashboard/settings", async ({ cookie, headers }) => { - const accountId = await getAccountId(cookie, headers); + const resolved = await getAccountId(cookie, headers); + const accountId = resolved?.accountId ?? null; + const keyId = resolved?.keyId ?? null; if (!accountId) return redirect("/dashboard"); const [acc] = await sql`SELECT id, email_hash, created_at FROM accounts WHERE id = ${accountId}`; - const apiKeys = await sql`SELECT id, key, label, created_at, last_used_at FROM api_keys WHERE account_id = ${accountId} ORDER BY created_at DESC`; - const loginKey = cookie?.pingql_key?.value ?? null; + const isSubKey = !!keyId; + const apiKeys = isSubKey ? [] : await sql`SELECT id, key, label, created_at, last_used_at FROM api_keys WHERE account_id = ${accountId} ORDER BY created_at DESC`; + const loginKey = isSubKey ? null : (cookie?.pingql_key?.value ?? null); - return html("settings", { nav: "settings", account: acc, apiKeys, accountId, loginKey }); + return html("settings", { nav: "settings", account: acc, apiKeys, accountId, loginKey, isSubKey }); }) // New monitor .get("/dashboard/monitors/new", async ({ cookie, headers }) => { - const accountId = await getAccountId(cookie, headers); + const resolved = await getAccountId(cookie, headers); + const accountId = resolved?.accountId ?? null; + const keyId = resolved?.keyId ?? null; if (!accountId) return redirect("/dashboard"); return html("new", { nav: "monitors", scripts: ["/dashboard/query-builder.js"] }); }) // Home data endpoint for polling (monitor list change detection) .get("/dashboard/home/data", async ({ cookie, headers }) => { - const accountId = await getAccountId(cookie, headers); + const resolved = await getAccountId(cookie, headers); + const accountId = resolved?.accountId ?? null; + const keyId = resolved?.keyId ?? null; if (!accountId) return new Response(JSON.stringify({ error: "Unauthorized" }), { status: 401 }); const monitors = await sql` @@ -182,7 +190,9 @@ export const dashboard = new Elysia() // Monitor detail — SSR with initial data .get("/dashboard/monitors/:id", async ({ cookie, headers, params }) => { - const accountId = await getAccountId(cookie, headers); + const resolved = await getAccountId(cookie, headers); + const accountId = resolved?.accountId ?? null; + const keyId = resolved?.keyId ?? null; if (!accountId) return redirect("/dashboard"); const [monitor] = await sql` @@ -200,7 +210,9 @@ export const dashboard = new Elysia() // Chart partial endpoint — returns just the latency chart SVG .get("/dashboard/monitors/:id/chart", async ({ cookie, headers, params }) => { - const accountId = await getAccountId(cookie, headers); + const resolved = await getAccountId(cookie, headers); + const accountId = resolved?.accountId ?? null; + const keyId = resolved?.keyId ?? null; if (!accountId) return new Response("Unauthorized", { status: 401 }); const [monitor] = await sql` @@ -220,7 +232,9 @@ export const dashboard = new Elysia() // Sparkline partial — returns just the SVG for one monitor .get("/dashboard/monitors/:id/sparkline", async ({ cookie, headers, params }) => { - const accountId = await getAccountId(cookie, headers); + const resolved = await getAccountId(cookie, headers); + const accountId = resolved?.accountId ?? null; + const keyId = resolved?.keyId ?? null; if (!accountId) return new Response("Unauthorized", { status: 401 }); const [monitor] = await sql` diff --git a/apps/web/src/views/settings.ejs b/apps/web/src/views/settings.ejs index 2983cb0..89f3d58 100644 --- a/apps/web/src/views/settings.ejs +++ b/apps/web/src/views/settings.ejs @@ -14,6 +14,7 @@

Account

+ <% if (!it.isSubKey) { %>
@@ -22,6 +23,7 @@
+ <% } %>

<%= createdDate %>

@@ -45,7 +47,8 @@ - + + <% if (!it.isSubKey) { %>
@@ -87,6 +90,7 @@ <% } %>
+ <% } %>