package onvif import ( "context" "fmt" "net/http" "net/http/httptest" "strings" "testing" "time" ) func loopbackPolicy(t *testing.T) Policy { t.Helper() policy, err := ParsePolicy("127.0.0.0/8") if err != nil { t.Fatal(err) } return policy } func TestProfilesSupportsDigestNormalizesAdvertisedHostsAndRejectsCredentials(t *testing.T) { digestSeen := false server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { body := make([]byte, r.ContentLength) _, _ = r.Body.Read(body) value := string(body) switch { case strings.Contains(value, "GetCapabilities"): fmt.Fprint(w, `http://unusable.invalid/onvif/media`) case !strings.HasPrefix(r.Header.Get("Authorization"), "Digest "): w.Header().Set("WWW-Authenticate", `Digest realm="camera", nonce="n", algorithm=MD5, qop="auth"`) w.WriteHeader(http.StatusUnauthorized) case strings.Contains(value, "GetProfiles"): digestSeen = strings.HasPrefix(r.Header.Get("Authorization"), "Digest ") fmt.Fprint(w, `主码流H26419201080`) default: fmt.Fprint(w, `rtsp://unusable.invalid:8554/live`) } })) defer server.Close() profiles, err := NewHTTPClient(2*time.Second, loopbackPolicy(t)).Profiles(context.Background(), server.URL+"/onvif/device", Credential{Username: "synthetic", Password: "synthetic"}) if err != nil { t.Fatal(err) } if !digestSeen || len(profiles) != 1 || !strings.Contains(profiles[0].StreamURI, "127.0.0.1:8554") { t.Fatalf("profiles=%#v digest=%v", profiles, digestSeen) } if _, _, err = loopbackPolicy(t).ValidateURL(context.Background(), "http://user:pass@127.0.0.1/onvif", "http"); err == nil { t.Fatal("credential URL accepted") } if _, _, err = loopbackPolicy(t).ValidateURL(context.Background(), "http://127.0.0.1/onvif?access_token=synthetic", "http"); err == nil { t.Fatal("credential-like query accepted") } } func TestPolicyRequiresExplicitCIDRAndRejectsOutsideTarget(t *testing.T) { if _, err := ParsePolicy(""); err == nil { t.Fatal("empty policy accepted") } policy := loopbackPolicy(t) if _, _, err := policy.ValidateURL(context.Background(), "http://192.0.2.1/onvif", "http"); err == nil { t.Fatal("outside target accepted") } } func TestDiscoveryRequiresApprovedInterface(t *testing.T) { _, err := Discover(context.Background(), "", time.Millisecond, loopbackPolicy(t)) if err != ErrDiscoveryNotConfigured { t.Fatalf("error=%v", err) } } func TestClientRejectsRedirect(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Location", "http://127.0.0.1/other") w.WriteHeader(http.StatusFound) })) defer server.Close() _, err := NewHTTPClient(time.Second, loopbackPolicy(t)).Profiles(context.Background(), server.URL+"/onvif", Credential{}) if err != ErrRedirect { t.Fatalf("error=%v", err) } }