fix(engineering-dashboard): read token from URL/meta under CSP

Remove the inline token script blocked by script-src 'self', so the
live page no longer calls the snapshot API with token=undefined.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
weichen
2026-09-17 07:39:21 +00:00
co-authored by Cursor
parent ce2a561d4d
commit 7fd7fb8a2a
3 changed files with 60 additions and 3 deletions
+19 -2
View File
@@ -1,5 +1,13 @@
(function () {
const token = window.__DASHBOARD_TOKEN__;
function resolveToken() {
const fromURL = new URL(window.location.href).searchParams.get("token");
if (fromURL) return fromURL;
const meta = document.querySelector('meta[name="engineering-dashboard-token"]');
const fromMeta = meta && meta.getAttribute("content");
if (fromMeta && fromMeta !== "__TOKEN__") return fromMeta;
return "";
}
const token = resolveToken();
const state = {
snap: null,
view: "overview",
@@ -25,7 +33,7 @@
function syncURL() {
const u = new URL(window.location.href);
u.searchParams.set("token", token);
if (token) u.searchParams.set("token", token);
u.searchParams.set("view", state.view);
if (state.q) u.searchParams.set("q", state.q); else u.searchParams.delete("q");
if (state.selectedDoc) u.searchParams.set("doc", state.selectedDoc); else u.searchParams.delete("doc");
@@ -44,6 +52,11 @@
}
async function fetchSnapshot(force) {
if (!token) {
el.status.textContent = "缺少访问令牌";
renderHardError("缺少 token:请使用服务启动时打印的完整 URL(含 ?token=)打开页面");
return false;
}
el.status.textContent = state.snap ? "刷新中…" : "首次加载中…";
const url = "/api/v1/snapshot?token=" + encodeURIComponent(token) + (force ? "&refresh=1" : "");
const headers = {};
@@ -281,6 +294,10 @@
async function loop() {
loadURL();
if (!token) {
renderHardError("缺少 token:请使用服务启动时打印的完整 URL(含 ?token=)打开页面");
return;
}
try {
const changed = await fetchSnapshot(true);
if (changed || state.snap) render();
@@ -3,6 +3,7 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="engineering-dashboard-token" content="__TOKEN__">
<title>个人工程中控台</title>
<link rel="stylesheet" href="/assets/app.css?token=__TOKEN__">
</head>
@@ -37,7 +38,6 @@
<div id="content"></div>
</main>
</div>
<script>window.__DASHBOARD_TOKEN__ = "__TOKEN__";</script>
<script src="/assets/app.js?token=__TOKEN__"></script>
</body>
</html>
@@ -128,3 +128,43 @@ func TestServer_CrossOriginDenied(t *testing.T) {
t.Fatalf("got %d", rr.Code)
}
}
func TestServer_IndexUsesMetaTokenNoInlineScript(t *testing.T) {
c := NewCollector(t.TempDir(), &FakeRunner{})
c.mu.Lock()
c.current = &Snapshot{RevisionID: "r", GenerationID: "g", GeneratedAt: time.Now().UTC()}
c.mu.Unlock()
srv, err := NewServer(c)
if err != nil {
t.Fatal(err)
}
req := httptest.NewRequest(http.MethodGet, "/?token="+srv.Token, nil)
req.Host = "127.0.0.1:8787"
rr := httptest.NewRecorder()
srv.Handler().ServeHTTP(rr, req)
if rr.Code != http.StatusOK {
t.Fatalf("index: %d %s", rr.Code, rr.Body.String())
}
body := rr.Body.String()
if strings.Contains(body, "window.__DASHBOARD_TOKEN__") {
t.Fatal("index must not use inline token script (CSP script-src 'self')")
}
meta := `name="engineering-dashboard-token" content="` + srv.Token + `"`
if !strings.Contains(body, meta) {
t.Fatalf("missing token meta: %s", body[:min(400, len(body))])
}
if !strings.Contains(rr.Header().Get("Content-Security-Policy"), "script-src 'self'") {
t.Fatalf("unexpected CSP: %s", rr.Header().Get("Content-Security-Policy"))
}
// app.js must not reference the removed global
js, err := readAsset("assets/app.js")
if err != nil {
t.Fatal(err)
}
if strings.Contains(string(js), "__DASHBOARD_TOKEN__") {
t.Fatal("app.js still references __DASHBOARD_TOKEN__")
}
if !strings.Contains(string(js), "engineering-dashboard-token") {
t.Fatal("app.js should read meta engineering-dashboard-token")
}
}