115 lines
7.1 KiB
Go
115 lines
7.1 KiB
Go
package protocol_test
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
protocol "git.sechmachine.io.vn/sechmachine/VerseVDI-Protocol/gen/go/protocol"
|
|
)
|
|
|
|
func TestManifestRejectsForbiddenAndUnknownFields(t *testing.T) {
|
|
valid := `{"version":"1","purpose":"launch","session_id":"session-1","reconnect_sequence":0,"gateway":{"id":"gateway-1","addresses":["gateway.control.test:443"],"public_identity":"gateway-1"},"tunnel":{"versions":["verse-gateway-v1/1"],"features":["control.v1"]},"profile":{"id":"standard","bounds":{"minimum_kbps":1,"target_kbps":2,"maximum_kbps":3}},"grant":{"opaque_value":"opaque-one-time-grant-value-with-at-least-43-bytes","expires_at":"2099-01-01T00:00:00Z","audience":"versevdi-gateway"},"correlation_id":"correlation-1"}`
|
|
manifest, err := protocol.DecodeConnectionManifest([]byte(valid))
|
|
if err != nil || manifest.Gateway.ID != "gateway-1" {
|
|
t.Fatalf("valid manifest = %+v, err = %v", manifest, err)
|
|
}
|
|
for _, field := range []string{"provider_url", "vm_address", "password"} {
|
|
payload := strings.Replace(valid, `"correlation_id":"correlation-1"`, `"correlation_id":"correlation-1","`+field+`":"forbidden"`, 1)
|
|
if _, err := protocol.DecodeConnectionManifest([]byte(payload)); err == nil {
|
|
t.Fatalf("DecodeConnectionManifest accepted forbidden field %q", field)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestPageInfoRejectsOutOfBoundsLimit(t *testing.T) {
|
|
if _, err := protocol.DecodePageInfo([]byte(`{"limit":101,"next_cursor":""}`)); err == nil {
|
|
t.Fatal("DecodePageInfo accepted limit above the contract maximum")
|
|
}
|
|
}
|
|
|
|
func TestGeneratedDecodersRejectMissingRequiredFieldsAndTrailingValues(t *testing.T) {
|
|
if _, err := protocol.DecodeErrorEnvelope([]byte(`{"status":false,"error":"safe","code":"invalid_request","message":"safe","resolution":"retry","violations":[]} {}`)); err == nil {
|
|
t.Fatal("DecodeErrorEnvelope accepted a trailing JSON value")
|
|
}
|
|
if _, err := protocol.DecodeErrorEnvelope([]byte(`{"error":"safe","code":"invalid_request","message":"safe","resolution":"retry","request_id":"req-1","violations":[]}`)); err == nil {
|
|
t.Fatal("DecodeErrorEnvelope accepted a missing required boolean")
|
|
}
|
|
}
|
|
|
|
func TestGatewayContractsRejectUnknownVersionsAndFields(t *testing.T) {
|
|
registration := `{"version":"1","gateway_id":"gateway-1","instance_identity":"instance-1","certificate_identity":"cert-1","public_identity":"public-1","address":"gateway.test:443","provider_identity":"apollo-provider-1","protocol_min_version":1,"protocol_max_version":1,"connection_capacity":8,"bandwidth_capacity_kbps":100000,"features":["datagram.media"],"capabilities":{"transport":"quic","framing":"datagram-v1","media":"encoded","audio":"encoded","source_rate_control":"server","client_decode":"h264-opus"}}`
|
|
if _, err := protocol.DecodeGatewayRegistration([]byte(registration)); err != nil {
|
|
t.Fatalf("valid gateway registration rejected: %v", err)
|
|
}
|
|
for _, invalid := range []string{
|
|
strings.Replace(registration, `"version":"1"`, `"version":"2"`, 1),
|
|
strings.Replace(registration, `"version":"1"`, `"version":"0"`, 1),
|
|
strings.Replace(registration, `"features":["datagram.media"]`, `"features":["datagram.media"],"provider_url":"https://provider.invalid"`, 1),
|
|
} {
|
|
if _, err := protocol.DecodeGatewayRegistration([]byte(invalid)); err == nil {
|
|
t.Fatalf("invalid gateway registration accepted: %s", invalid)
|
|
}
|
|
}
|
|
if _, err := protocol.DecodeGatewayRegistration([]byte("{")); err == nil {
|
|
t.Fatal("DecodeGatewayRegistration accepted malformed JSON")
|
|
}
|
|
}
|
|
|
|
func TestGatewayRegistrationRejectsInvertedProtocolBounds(t *testing.T) {
|
|
registration := `{"version":"1","gateway_id":"gateway-1","instance_identity":"instance-1","certificate_identity":"cert-1","public_identity":"public-1","address":"gateway.test:443","provider_identity":"apollo-provider-1","protocol_min_version":2,"protocol_max_version":1,"connection_capacity":8,"bandwidth_capacity_kbps":100000,"features":["datagram.media"],"capabilities":{"transport":"quic","framing":"datagram-v1","media":"encoded","audio":"encoded","source_rate_control":"server","client_decode":"h264-opus"}}`
|
|
if _, err := protocol.DecodeGatewayRegistration([]byte(registration)); err == nil {
|
|
t.Fatal("DecodeGatewayRegistration accepted inverted protocol bounds")
|
|
}
|
|
}
|
|
|
|
func TestCapabilityIntersectionRejectsNoOverlap(t *testing.T) {
|
|
first := protocol.CapabilityProfile{Transport: "quic-tls13", Framing: "datagram-v1", Media: "encoded", Audio: "encoded", SourceRateControl: "server", ClientDecode: "h264-opus"}
|
|
if got, err := protocol.IntersectCapabilityProfiles(first, first); err != nil || got != first {
|
|
t.Fatalf("IntersectCapabilityProfiles matching profiles = %+v, %v", got, err)
|
|
}
|
|
second := first
|
|
second.ClientDecode = "hevc-opus"
|
|
if _, err := protocol.IntersectCapabilityProfiles(first, second); err == nil {
|
|
t.Fatal("IntersectCapabilityProfiles accepted profiles without a common codec profile")
|
|
}
|
|
}
|
|
|
|
func TestTunnelAdmissionRequiresDeviceSignature(t *testing.T) {
|
|
request := protocol.TunnelAdmissionRequest{
|
|
Version: "1", SessionID: "session-1", GatewayID: "gateway-1", Audience: "versevdi-gateway",
|
|
Grant: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_", ReconnectSequence: 0,
|
|
ClientNonce: "0123456789abcdef", Capabilities: protocol.CapabilityProfile{
|
|
Transport: "quic-tls13", Framing: "datagram-v1", Media: "encoded", Audio: "encoded",
|
|
SourceRateControl: "server", ClientDecode: "h264-opus",
|
|
},
|
|
}
|
|
if _, err := protocol.EncodeTunnelAdmissionRequest(request); err == nil {
|
|
t.Fatal("EncodeTunnelAdmissionRequest accepted an unsigned device admission")
|
|
}
|
|
}
|
|
|
|
func TestTunnelAdmissionTranscriptIsDomainSeparatedAndLengthDelimited(t *testing.T) {
|
|
request := protocol.TunnelAdmissionRequest{
|
|
Version: "1", SessionID: "session", GatewayID: "gateway", Audience: "audience",
|
|
Grant: strings.Repeat("g", 43), ReconnectSequence: 0, ClientNonce: strings.Repeat("n", 16),
|
|
DeviceSignature: strings.Repeat("s", 86), Capabilities: protocol.CapabilityProfile{
|
|
Transport: "quic-tls13", Framing: "datagram-v1", Media: "encoded", Audio: "encoded",
|
|
SourceRateControl: "server", ClientDecode: "h264-opus",
|
|
},
|
|
}
|
|
want := "versevdi/tunnel-admission/v17:session7:gateway8:audience43:" + strings.Repeat("g", 43) + "1:016:" + strings.Repeat("n", 16) + "10:quic-tls1311:datagram-v17:encoded7:encoded6:server9:h264-opus"
|
|
if got := string(request.DeviceAdmissionTranscript()); got != want {
|
|
t.Fatalf("DeviceAdmissionTranscript() = %q, want %q", got, want)
|
|
}
|
|
}
|
|
|
|
func TestSessionAuthorityRejectsProviderRoute(t *testing.T) {
|
|
valid := `{"version":"1","session_id":"session-1","gateway_id":"gateway-1","audience":"versevdi-gateway","reconnect_sequence":0,"expires_at":"2099-01-01T00:00:00Z","capabilities":{"transport":"quic","framing":"datagram-v1","media":"encoded","audio":"encoded","source_rate_control":"server","client_decode":"h264-opus"},"provider_profile":"apollo","provider_identity":"provider-1"}`
|
|
if _, err := protocol.DecodeSessionAuthority([]byte(valid)); err != nil {
|
|
t.Fatalf("valid session authority rejected: %v", err)
|
|
}
|
|
if _, err := protocol.DecodeSessionAuthority([]byte(strings.Replace(valid, `"provider_identity":"provider-1"`, `"provider_identity":"provider-1","rtsp_url":"rtsp://provider.invalid"`, 1))); err == nil {
|
|
t.Fatal("session authority accepted a provider route")
|
|
}
|
|
}
|