Files
yovision/Sense/server/app/sense/onvif/client_test.go

82 lines
3.3 KiB
Go

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, `<Envelope><Body><GetCapabilitiesResponse><Capabilities><Media><XAddr>http://unusable.invalid/onvif/media</XAddr></Media></Capabilities></GetCapabilitiesResponse></Body></Envelope>`)
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, `<Envelope><Body><GetProfilesResponse><Profiles token="main"><Name>主码流</Name><VideoEncoderConfiguration><Encoding>H264</Encoding><Resolution><Width>1920</Width><Height>1080</Height></Resolution></VideoEncoderConfiguration></Profiles></GetProfilesResponse></Body></Envelope>`)
default:
fmt.Fprint(w, `<Envelope><Body><GetStreamUriResponse><MediaUri><Uri>rtsp://unusable.invalid:8554/live</Uri></MediaUri></GetStreamUriResponse></Body></Envelope>`)
}
}))
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)
}
}