Files
Commilitia-Drop/desktop/platform/sessioninject_test.go
T
admin f21fa5b5e8 cdrop — 跨 OS 剪贴板与文件传输服务
Commilitia Drop:自托管的跨设备剪贴板同步与点对点文件传输。

- 后端 Go(chi / SQLite WAL / SSE Hub / WebRTC signaling + 状态机 / Relay ring buffer),编译进单个 distroless 镜像(前端 go:embed)。
- 前端 React + TanStack Router + Zustand,自实现 SSE + WebRTC P2P,NAT 受阻时回退服务端中继;聚珍(Juzhen)CJK 综合排版。
- 桌面端 Wails v2(macOS / Windows),瘦客户端复用 web。
- 鉴权 OIDC PKCE(自建 Casdoor 等),refresh_token 信封加密存系统密钥库;iOS Shortcut 用 HS256 scoped token。

架构文档与变更记录见 docs 分支(PROJECT_BRIEF / FRONTEND_DESIGN / CHANGELOG)。

本次为公开发布初始提交:完整开发历史(含部署细节)留存于私有归档,公开仓库自此干净起步。
2026-06-15 21:38:28 +08:00

110 lines
4.0 KiB
Go

package platform
import (
"net/http"
"net/http/httptest"
"strings"
"testing"
)
const htmlDoc = "<html><head><title>cdrop</title></head><body></body></html>"
func htmlHandler() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(htmlDoc))
})
}
func TestSessionInjectIntoDocument(t *testing.T) {
session := &LoginResult{
AccessToken: "acc-token",
RefreshToken: "ref-token",
User: UserInfo{ID: "u-1", Name: "alice"},
}
h := SessionInjectMiddleware(session, "my-host", "", "macos")(htmlHandler())
rec := httptest.NewRecorder()
h.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/", nil))
body := rec.Body.String()
if !strings.Contains(body, "window.__CDROP_BOOT__") {
t.Fatalf("boot global not injected:\n%s", body)
}
if !strings.Contains(body, `"access_token":"acc-token"`) {
t.Errorf("access token not in injected payload:\n%s", body)
}
// Credential policy: the refresh_token must NEVER reach the page.
if strings.Contains(body, "ref-token") || strings.Contains(body, "refresh_token") {
t.Errorf("refresh_token must not be injected into the page:\n%s", body)
}
if !strings.Contains(body, `"device_name":"my-host"`) {
t.Errorf("device name not in injected payload:\n%s", body)
}
if !strings.Contains(body, `"device_type":"macos"`) {
t.Errorf("device type not in injected payload:\n%s", body)
}
// Injected before </head> so it runs before the deferred module bundle.
if strings.Index(body, "__CDROP_BOOT__") > strings.Index(body, "</head>") {
t.Error("injection must precede </head>")
}
}
func TestSessionInjectPassesThroughNonDocument(t *testing.T) {
apiBody := "streamed-api-body"
next := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
_, _ = w.Write([]byte(apiBody))
})
h := SessionInjectMiddleware(&LoginResult{AccessToken: "x"}, "h", "", "")(next)
rec := httptest.NewRecorder()
h.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/api/hub/events", nil))
if rec.Body.String() != apiBody {
t.Errorf("non-document request must pass through unchanged, got %q", rec.Body.String())
}
}
func TestSessionInjectNilSessionStillInjectsDeviceBoot(t *testing.T) {
// Logged out, the boot state is still injected — the page needs the device
// name / api_base / device_type before login — but with a null session, and
// no token of any kind leaks.
h := SessionInjectMiddleware(nil, "my-host", "http://127.0.0.1:5000", "windows")(htmlHandler())
rec := httptest.NewRecorder()
h.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/", nil))
body := rec.Body.String()
if !strings.Contains(body, "window.__CDROP_BOOT__") {
t.Fatalf("boot global must be injected even when logged out:\n%s", body)
}
if !strings.Contains(body, `"session":null`) {
t.Errorf("logged-out boot must carry a null session:\n%s", body)
}
if !strings.Contains(body, `"device_name":"my-host"`) ||
!strings.Contains(body, `"device_type":"windows"`) ||
!strings.Contains(body, `"api_base":"http://127.0.0.1:5000"`) {
t.Errorf("device boot fields not injected:\n%s", body)
}
if strings.Contains(body, "access_token") {
t.Errorf("no token must appear when logged out:\n%s", body)
}
}
func TestSessionInjectEscapesScriptBreakout(t *testing.T) {
// A display name containing </script> must not break out of the inline tag.
session := &LoginResult{AccessToken: "acc", User: UserInfo{Name: "</script><b>x"}}
h := SessionInjectMiddleware(session, "h", "", "")(htmlHandler())
rec := httptest.NewRecorder()
h.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/", nil))
body := rec.Body.String()
// The literal closing tag from the name must NOT appear verbatim; encoding/json
// HTML-escapes < / > to < / > by default.
if strings.Contains(body, "</script><b>x") {
t.Errorf("script breakout not escaped:\n%s", body)
}
if !strings.Contains(body, `</script>`) {
t.Errorf("expected HTML-escaped name in payload:\n%s", body)
}
}