82 lines
3.3 KiB
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)
|
|
}
|
|
}
|