package main import ( "net/http" "net/http/httptest" "os" "strings" "testing" ) // 登录页必须跟随系统深浅色,并提供手动切换(原 portal-auth 的行为, // 重写模板时曾漏掉)。 func TestLoginPageThemeSupport(t *testing.T) { rec := httptest.NewRecorder() renderPortalLogin(rec, "https://dashy.example.com/", "") body := rec.Body.String() for _, want := range []string{ "prefers-color-scheme:dark", "[data-theme=\"dark\"]", "localStorage.setItem('theme'", "toggle", "aria-label", } { if want == "toggle" { if !strings.Contains(body, "切换深浅色") { t.Fatalf("缺少手动切换按钮") } continue } if !strings.Contains(body, want) { t.Fatalf("登录页缺少 %q", want) } } if !strings.Contains(rec.Header().Get("Content-Type"), "text/html") { t.Fatalf("Content-Type 不对") } if rec.Header().Get("Cache-Control") != "no-store" { t.Fatalf("登录页不应被缓存") } } // redirect 必须被 HTML 转义后写入表单 action,避免注入。 func TestLoginPageEscapesRedirect(t *testing.T) { dir := t.TempDir() oldConf, oldURL := confFile, historyBaseURL confFile, historyBaseURL = dir+"/conf.yml", "http://127.0.0.1:1" defer func() { confFile, historyBaseURL = oldConf, oldURL }() _ = os.WriteFile(confFile, []byte("sections: []\n"), 0o644) rec := httptest.NewRecorder() req := httptest.NewRequest(http.MethodGet, "/login?redirect=https://evil.example/\">", nil) handlePortalLogin(rec, req) body := rec.Body.String() if strings.Contains(body, "") { t.Fatalf("redirect 未转义,存在注入:%s", body) } }