112 lines
3.1 KiB
Go
112 lines
3.1 KiB
Go
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)
|
|
}
|
|
}
|