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)
}
}