fix: hide login key and sub-keys from sub-key sessions
This commit is contained in:
parent
c56af82053
commit
eeb0318c4d
|
|
@ -72,13 +72,12 @@ function redirect(to: string) {
|
||||||
return new Response(null, { status: 302, headers: { Location: to } });
|
return new Response(null, { status: 302, headers: { Location: to } });
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getAccountId(cookie: any, headers: any): Promise<string | null> {
|
async function getAccountId(cookie: any, headers: any): Promise<{ accountId: string; keyId: string | null } | null> {
|
||||||
const authHeader = headers["authorization"] ?? "";
|
const authHeader = headers["authorization"] ?? "";
|
||||||
const bearer = authHeader.match(/^bearer\s+(.+)$/i)?.[1]?.trim();
|
const bearer = authHeader.match(/^bearer\s+(.+)$/i)?.[1]?.trim();
|
||||||
const key = cookie?.pingql_key?.value || bearer;
|
const key = cookie?.pingql_key?.value || bearer;
|
||||||
if (!key) return null;
|
if (!key) return null;
|
||||||
const resolved = await resolveKey(key);
|
return await resolveKey(key) ?? null;
|
||||||
return resolved?.accountId ?? null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const dashDir = resolve(import.meta.dir, "../dashboard");
|
const dashDir = resolve(import.meta.dir, "../dashboard");
|
||||||
|
|
@ -112,7 +111,9 @@ export const dashboard = new Elysia()
|
||||||
|
|
||||||
// Home — SSR monitor list
|
// Home — SSR monitor list
|
||||||
.get("/dashboard/home", async ({ cookie, headers }) => {
|
.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");
|
if (!accountId) return redirect("/dashboard");
|
||||||
|
|
||||||
const monitors = await sql`
|
const monitors = await sql`
|
||||||
|
|
@ -150,26 +151,33 @@ export const dashboard = new Elysia()
|
||||||
|
|
||||||
// Settings — SSR account info
|
// Settings — SSR account info
|
||||||
.get("/dashboard/settings", async ({ cookie, headers }) => {
|
.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");
|
if (!accountId) return redirect("/dashboard");
|
||||||
|
|
||||||
const [acc] = await sql`SELECT id, email_hash, created_at FROM accounts WHERE id = ${accountId}`;
|
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 isSubKey = !!keyId;
|
||||||
const loginKey = cookie?.pingql_key?.value ?? null;
|
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
|
// New monitor
|
||||||
.get("/dashboard/monitors/new", async ({ cookie, headers }) => {
|
.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");
|
if (!accountId) return redirect("/dashboard");
|
||||||
return html("new", { nav: "monitors", scripts: ["/dashboard/query-builder.js"] });
|
return html("new", { nav: "monitors", scripts: ["/dashboard/query-builder.js"] });
|
||||||
})
|
})
|
||||||
|
|
||||||
// Home data endpoint for polling (monitor list change detection)
|
// Home data endpoint for polling (monitor list change detection)
|
||||||
.get("/dashboard/home/data", async ({ cookie, headers }) => {
|
.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 });
|
if (!accountId) return new Response(JSON.stringify({ error: "Unauthorized" }), { status: 401 });
|
||||||
|
|
||||||
const monitors = await sql`
|
const monitors = await sql`
|
||||||
|
|
@ -182,7 +190,9 @@ export const dashboard = new Elysia()
|
||||||
|
|
||||||
// Monitor detail — SSR with initial data
|
// Monitor detail — SSR with initial data
|
||||||
.get("/dashboard/monitors/:id", async ({ cookie, headers, params }) => {
|
.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");
|
if (!accountId) return redirect("/dashboard");
|
||||||
|
|
||||||
const [monitor] = await sql`
|
const [monitor] = await sql`
|
||||||
|
|
@ -200,7 +210,9 @@ export const dashboard = new Elysia()
|
||||||
|
|
||||||
// Chart partial endpoint — returns just the latency chart SVG
|
// Chart partial endpoint — returns just the latency chart SVG
|
||||||
.get("/dashboard/monitors/:id/chart", async ({ cookie, headers, params }) => {
|
.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 });
|
if (!accountId) return new Response("Unauthorized", { status: 401 });
|
||||||
|
|
||||||
const [monitor] = await sql`
|
const [monitor] = await sql`
|
||||||
|
|
@ -220,7 +232,9 @@ export const dashboard = new Elysia()
|
||||||
|
|
||||||
// Sparkline partial — returns just the SVG for one monitor
|
// Sparkline partial — returns just the SVG for one monitor
|
||||||
.get("/dashboard/monitors/:id/sparkline", async ({ cookie, headers, params }) => {
|
.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 });
|
if (!accountId) return new Response("Unauthorized", { status: 401 });
|
||||||
|
|
||||||
const [monitor] = await sql`
|
const [monitor] = await sql`
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
<section class="bg-gray-900 rounded-xl border border-gray-800 p-6">
|
<section class="bg-gray-900 rounded-xl border border-gray-800 p-6">
|
||||||
<h2 class="text-sm font-semibold text-gray-300 mb-4">Account</h2>
|
<h2 class="text-sm font-semibold text-gray-300 mb-4">Account</h2>
|
||||||
<div class="space-y-3">
|
<div class="space-y-3">
|
||||||
|
<% if (!it.isSubKey) { %>
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-xs text-gray-500 mb-1">Login Key</label>
|
<label class="block text-xs text-gray-500 mb-1">Login Key</label>
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
|
|
@ -22,6 +23,7 @@
|
||||||
<button onclick="confirmReset()" class="px-3 bg-gray-800 hover:bg-gray-700 border border-red-900/50 hover:border-red-700/50 text-red-400 rounded-lg text-xs transition-colors">Rotate</button>
|
<button onclick="confirmReset()" class="px-3 bg-gray-800 hover:bg-gray-700 border border-red-900/50 hover:border-red-700/50 text-red-400 rounded-lg text-xs transition-colors">Rotate</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<% } %>
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-xs text-gray-500 mb-1">Member since</label>
|
<label class="block text-xs text-gray-500 mb-1">Member since</label>
|
||||||
<p id="created-at" class="text-sm text-gray-400"><%= createdDate %></p>
|
<p id="created-at" class="text-sm text-gray-400"><%= createdDate %></p>
|
||||||
|
|
@ -45,7 +47,8 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Sub-keys -->
|
<!-- Sub-keys (hidden for sub-key sessions) -->
|
||||||
|
<% if (!it.isSubKey) { %>
|
||||||
<section class="bg-gray-900 rounded-xl border border-gray-800 p-6">
|
<section class="bg-gray-900 rounded-xl border border-gray-800 p-6">
|
||||||
<div class="flex items-center justify-between mb-4">
|
<div class="flex items-center justify-between mb-4">
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -87,6 +90,7 @@
|
||||||
<% } %>
|
<% } %>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
<% } %>
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue