package handler import ( "encoding/json" "net/http" "net/http/httptest" "net/url" "strings" "testing" "time" "silk-server-go/internal/model" "github.com/gin-gonic/gin" ) func TestCameraResponseNeverContainsSecrets(t *testing.T) { password := "secret-password" camera := model.Camera{ PasswordEnc: &password, GbAuthPassword: &password, } raw, err := json.Marshal(camera) if err != nil { t.Fatalf("marshal camera: %v", err) } body := string(raw) if strings.Contains(body, "passwordEnc") || strings.Contains(body, password) { t.Fatalf("camera JSON must not contain password fields: %s", body) } if strings.Contains(body, "gbAuthPassword") { t.Fatalf("camera JSON must not contain gbAuthPassword: %s", body) } } func TestIssueAndValidateVideoToken(t *testing.T) { SetVideoTokenSecret("test-secret") token, err := IssueVideoToken("user-1", "camera", "12", time.Minute) if err != nil { t.Fatalf("issue video token: %v", err) } if token == "" { t.Fatal("expected non-empty video token") } if err := ValidateVideoToken(token, "camera", "12"); err != nil { t.Fatalf("valid video token rejected: %v", err) } if err := ValidateVideoToken(token, "camera", "13"); err == nil { t.Fatal("expected resource mismatch error") } if err := ValidateVideoToken(token, "clip", "12"); err == nil { t.Fatal("expected resource type mismatch error") } } func TestValidateVideoTokenForUserRejectsMismatch(t *testing.T) { SetVideoTokenSecret("test-secret") token, err := IssueVideoToken("user-1", "camera", "12", time.Minute) if err != nil { t.Fatalf("issue video token: %v", err) } if err := ValidateVideoTokenForUser(token, "camera", "12", "user-1"); err != nil { t.Fatalf("same-user token rejected: %v", err) } if err := ValidateVideoTokenForUser(token, "camera", "12", "user-2"); err == nil { t.Fatal("expected cross-user token rejection") } } func TestVideoTokenExpires(t *testing.T) { SetVideoTokenSecret("test-secret") token, err := IssueVideoToken("user-1", "camera", "12", -time.Second) if err != nil { t.Fatalf("issue expired token: %v", err) } if err := ValidateVideoToken(token, "camera", "12"); err == nil { t.Fatal("expected expired token rejection") } } func TestVideoStreamRequiresValidToken(t *testing.T) { SetVideoTokenSecret("test-secret") gin.SetMode(gin.TestMode) rec := httptest.NewRecorder() c, _ := gin.CreateTestContext(rec) c.Request = &http.Request{URL: &url.URL{RawQuery: ""}} if requireVideoToken(c, "camera", "12") { t.Fatal("missing token should be rejected") } if rec.Code != http.StatusUnauthorized { t.Fatalf("missing token status = %d, want 401", rec.Code) } token, err := IssueVideoToken("user-1", "camera", "13", time.Minute) if err != nil { t.Fatalf("issue token: %v", err) } rec2 := httptest.NewRecorder() c2, _ := gin.CreateTestContext(rec2) c2.Request = &http.Request{URL: &url.URL{RawQuery: "videoToken=" + token}} if requireVideoToken(c2, "camera", "12") { t.Fatal("wrong resource token should be rejected") } if rec2.Code != http.StatusForbidden { t.Fatalf("wrong resource token status = %d, want 403", rec2.Code) } }