mirror of
https://github.com/sipeed/picoclaw.git
synced 2026-06-12 18:08:54 +00:00
refactor(web): secure Pico websocket access behind launcher auth
- stop exposing the raw Pico token to the frontend - add /api/pico/info for non-secret Pico connection metadata - proxy /pico/ws through the launcher with same-origin and dashboard auth checks - inject the upstream Pico websocket protocol server-side - update frontend chat connection flow and Vite websocket proxy path - refresh related docs and tests
This commit is contained in:
@@ -218,6 +218,10 @@ func validLauncherDashboardAuth(r *http.Request, cfg LauncherDashboardAuthConfig
|
||||
}
|
||||
|
||||
func rejectLauncherDashboardAuth(w http.ResponseWriter, r *http.Request, canonicalPath string) {
|
||||
if canonicalPath == "/pico/ws" {
|
||||
http.Error(w, "unauthorized", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
if strings.HasPrefix(canonicalPath, "/api/") {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
|
||||
@@ -40,6 +40,7 @@ func TestLauncherDashboardAuth_AllowsPublicPaths(t *testing.T) {
|
||||
{http.MethodPost, "/api/auth/logout", http.StatusTeapot},
|
||||
{http.MethodGet, "/api/auth/logout", http.StatusUnauthorized},
|
||||
{http.MethodGet, "/api/config", http.StatusUnauthorized},
|
||||
{http.MethodGet, "/pico/ws", http.StatusUnauthorized},
|
||||
} {
|
||||
rec := httptest.NewRecorder()
|
||||
req := httptest.NewRequest(tc.method, tc.path, nil)
|
||||
@@ -160,3 +161,22 @@ func TestLauncherDashboardAuth_CookieAndBearer(t *testing.T) {
|
||||
t.Fatalf("bearer auth: status = %d", rec2.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLauncherDashboardAuth_WebSocketUnauthorizedDoesNotRedirect(t *testing.T) {
|
||||
cfg := LauncherDashboardAuthConfig{ExpectedCookie: "deadbeef", Token: "x"}
|
||||
next := http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {
|
||||
t.Fatal("next handler should not run without auth")
|
||||
})
|
||||
h := LauncherDashboardAuth(cfg, next)
|
||||
|
||||
rec := httptest.NewRecorder()
|
||||
req := httptest.NewRequest(http.MethodGet, "/pico/ws", nil)
|
||||
h.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusUnauthorized {
|
||||
t.Fatalf("status = %d, want %d", rec.Code, http.StatusUnauthorized)
|
||||
}
|
||||
if got := rec.Header().Get("Location"); got != "" {
|
||||
t.Fatalf("Location = %q, want empty", got)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user