// Code generated by tools/generate.py; DO NOT EDIT. package protocol import ( "bytes" "encoding/base64" "encoding/binary" "encoding/json" "errors" "fmt" "io" "reflect" "strings" "time" ) const SchemaSHA256 = "b9e72838b2ae02b3a47e7e2dfa03620b8580f2c98668e6eaf551ea8fb642d297" const ProtocolVersion = "1.0.0" const CurrentWireVersion = "2" const NMinus1WireVersion = "1" const NMinus2WireVersion = "0" type FieldViolation struct { Field string `json:"field"` Code string `json:"code"` } type ValidationError struct { Violations []FieldViolation } func (e ValidationError) Error() string { return "protocol validation failed" } func validCanonicalUUID(value string) bool { if len(value) != 36 || value[8] != '-' || value[13] != '-' || value[18] != '-' || value[23] != '-' { return false } for index, char := range []byte(value) { if index == 8 || index == 13 || index == 18 || index == 23 { continue } if !((char >= '0' && char <= '9') || (char >= 'a' && char <= 'f')) { return false } } return value != "00000000-0000-0000-0000-000000000000" } func rejectDuplicateJSONKeys(data []byte) error { decoder := json.NewDecoder(bytes.NewReader(data)) var scan func(json.Token) error scan = func(token json.Token) error { delim, ok := token.(json.Delim) if !ok { return nil } switch delim { case '{': seen := map[string]struct{}{} for decoder.More() { keyToken, err := decoder.Token() if err != nil { return err } key, ok := keyToken.(string) if !ok { return errors.New("invalid JSON object key") } if _, exists := seen[key]; exists { return errors.New("duplicate JSON object key") } seen[key] = struct{}{} value, err := decoder.Token() if err != nil { return err } if err := scan(value); err != nil { return err } } _, err := decoder.Token() return err case '[': for decoder.More() { value, err := decoder.Token() if err != nil { return err } if err := scan(value); err != nil { return err } } _, err := decoder.Token() return err } return nil } token, err := decoder.Token() if err != nil { return err } return scan(token) } type AllocationPolicy struct { MinimumKbps int64 `json:"minimum_kbps"` TargetKbps int64 `json:"target_kbps"` MaximumKbps int64 `json:"maximum_kbps"` Tier string `json:"tier"` Audience string `json:"audience"` Protocol string `json:"protocol"` ProtocolVersion int64 `json:"protocol_version"` GrantTTLSeconds int64 `json:"grant_ttl_seconds"` ReservationLeaseSeconds int64 `json:"reservation_lease_seconds"` } type AssignedDesktop struct { AssignmentID string `json:"assignment_id"` PoolID string `json:"pool_id"` Name string `json:"name"` Availability string `json:"availability"` QualityLimits SessionQualityLimits `json:"quality_limits"` } type AudioProfile struct { Codec string `json:"codec"` SampleRateHz int64 `json:"sample_rate_hz"` Channels int64 `json:"channels"` ChannelLayout string `json:"channel_layout"` PacketDurationMs int64 `json:"packet_duration_ms"` } type BitratePreference struct { Mode string `json:"mode"` TargetKbps *int64 `json:"target_kbps,omitempty"` } type BrokerSession struct { ID string `json:"id"` PrincipalID string `json:"principal_id"` PoolID string `json:"pool_id"` AssignmentID string `json:"assignment_id,omitempty"` State string `json:"state"` PolicySnapshot AllocationPolicy `json:"policy_snapshot"` ReconnectDeadline string `json:"reconnect_deadline,omitempty"` Outcome string `json:"outcome,omitempty"` FailureCode string `json:"failure_code,omitempty"` CleanupState string `json:"cleanup_state"` IdempotencyKey string `json:"idempotency_key"` CorrelationID string `json:"correlation_id"` RequestedAt string `json:"requested_at"` EndedAt string `json:"ended_at,omitempty"` Version int64 `json:"version"` RequestedDisplayMode *DisplayMode `json:"requested_display_mode,omitempty"` EffectiveDisplayMode *DisplayMode `json:"effective_display_mode,omitempty"` RequestedVideoProfiles []VideoProfile `json:"requested_video_profiles"` RequestedBitratePreference BitratePreference `json:"requested_bitrate_preference"` SelectedDescriptor *SelectedSessionDescriptor `json:"selected_descriptor,omitempty"` } type BrowserAuthenticatedSession struct { Username string `json:"username"` Provider string `json:"provider"` Roles []string `json:"roles"` Role string `json:"role"` } type CapabilityProfile struct { Transport string `json:"transport"` Framing string `json:"framing"` Media string `json:"media"` SourceRateControl string `json:"source_rate_control"` VideoProfiles []VideoProfile `json:"video_profiles"` AudioProfiles []AudioProfile `json:"audio_profiles"` } type ChannelFrame struct { Version string `json:"version"` FlowID string `json:"flow_id"` Sequence int64 `json:"sequence"` Flags int64 `json:"flags"` FragmentIndex int64 `json:"fragment_index"` FragmentCount int64 `json:"fragment_count"` TimestampMs int64 `json:"timestamp_ms"` Payload string `json:"payload"` } type ClientSessionAuthority struct { Version string `json:"version"` SessionID string `json:"session_id"` GatewayID string `json:"gateway_id"` Audience string `json:"audience"` ReconnectSequence int64 `json:"reconnect_sequence"` ExpiresAt string `json:"expires_at"` Capabilities CapabilityProfile `json:"capabilities"` SelectedDescriptor SelectedSessionDescriptor `json:"selected_descriptor"` } type ClipboardPolicy struct { ClientToProviderEnabled bool `json:"client_to_provider_enabled"` ProviderToClientEnabled bool `json:"provider_to_client_enabled"` MaxTextBytes int64 `json:"max_text_bytes"` MaxUpdatesPerMinute int64 `json:"max_updates_per_minute"` } type ClipboardText struct { Text string `json:"text"` Encoding string `json:"encoding"` } type ConnectionManifest struct { Version string `json:"version"` Purpose string `json:"purpose"` SessionID string `json:"session_id"` ReconnectSequence int64 `json:"reconnect_sequence"` Gateway ManifestGateway `json:"gateway"` Tunnel ManifestTunnel `json:"tunnel"` Profile ManifestProfile `json:"profile"` Grant GrantReference `json:"grant"` CorrelationID string `json:"correlation_id"` SelectedDescriptor SelectedSessionDescriptor `json:"selected_descriptor"` } type DeviceChallenge struct { DeviceID string `json:"device_id"` ServerID string `json:"server_id"` PrincipalID string `json:"principal_id"` Challenge string `json:"challenge"` ExpiresAt string `json:"expires_at"` Algorithm string `json:"algorithm"` SignatureFormat string `json:"signature_format"` } type DeviceProofRequest struct { Challenge string `json:"challenge"` Signature string `json:"signature"` } type DeviceRegistrationRequest struct { Name string `json:"name"` Platform string `json:"platform"` DeviceSubject string `json:"device_subject"` Algorithm string `json:"algorithm"` PublicKey string `json:"public_key"` } type DisplayLimitOverrideRequest struct { AllowDisplayLimitOverride bool `json:"allow_display_limit_override"` ExpectedVersion int64 `json:"expected_version"` } type DisplayMode struct { ResolutionWidth int64 `json:"resolution_width"` ResolutionHeight int64 `json:"resolution_height"` Fps int64 `json:"fps"` } type EntitledPool struct { PoolID string `json:"pool_id"` Name string `json:"name"` AssignmentState string `json:"assignment_state"` QualityLimits SessionQualityLimits `json:"quality_limits"` } type ErrorEnvelope struct { Status bool `json:"status"` Error string `json:"error"` Code string `json:"code"` Message string `json:"message"` Resolution string `json:"resolution"` RequestID string `json:"request_id"` Violations []FieldViolation `json:"violations"` } type EventEnvelope struct { EventID string `json:"event_id"` Sequence int64 `json:"sequence"` Type string `json:"type"` Version int64 `json:"version"` Resource ResourceLink `json:"resource"` OccurredAt string `json:"occurred_at"` CorrelationID string `json:"correlation_id"` Payload map[string]any `json:"payload"` } type EventResume struct { Cursor string `json:"cursor"` LastSequence int64 `json:"last_sequence"` } type GatewayClipboardAudit struct { Version string `json:"version"` SessionID string `json:"session_id"` Direction string `json:"direction"` Outcome string `json:"outcome"` TextBytes int64 `json:"text_bytes"` Reason string `json:"reason"` } type GatewayClipboardText struct { Direction string `json:"direction"` Text string `json:"text"` Encoding string `json:"encoding"` LoopToken string `json:"loop_token"` } type GatewayDrain struct { Version string `json:"version"` GatewayID string `json:"gateway_id"` Sequence int64 `json:"sequence"` Reason string `json:"reason"` Deadline string `json:"deadline"` } type GatewayHeartbeat struct { Version string `json:"version"` GatewayID string `json:"gateway_id"` Sequence int64 `json:"sequence"` ObservedAt string `json:"observed_at"` ActiveConnections int64 `json:"active_connections"` EgressKbps int64 `json:"egress_kbps"` State string `json:"state"` Telemetry GatewayTelemetry `json:"telemetry"` } type GatewayQualityAck struct { Version string `json:"version"` SessionID string `json:"session_id"` GatewayID string `json:"gateway_id"` ReconnectSequence int64 `json:"reconnect_sequence"` OperationID string `json:"operation_id"` Revision int64 `json:"revision"` LeaseGeneration int64 `json:"lease_generation"` Outcome string `json:"outcome"` CurrentAppliedRevision *int64 `json:"current_applied_revision,omitempty"` FailureCode string `json:"failure_code,omitempty"` } type GatewayQualityWork struct { Version string `json:"version"` SessionID string `json:"session_id"` GatewayID string `json:"gateway_id"` ReconnectSequence int64 `json:"reconnect_sequence"` OperationID string `json:"operation_id"` Revision int64 `json:"revision"` LeaseGeneration int64 `json:"lease_generation"` LeaseExpiresAt string `json:"lease_expires_at"` SelectedDescriptor SelectedSessionDescriptor `json:"selected_descriptor"` CurrentAppliedRevision *int64 `json:"current_applied_revision,omitempty"` } type GatewayQualityWorkRequest struct { Version string `json:"version"` SessionID string `json:"session_id"` GatewayID string `json:"gateway_id"` ReconnectSequence int64 `json:"reconnect_sequence"` Acquisition string `json:"acquisition"` OperationID string `json:"operation_id,omitempty"` Revision *int64 `json:"revision,omitempty"` LeaseGeneration *int64 `json:"lease_generation,omitempty"` CurrentAppliedRevision *int64 `json:"current_applied_revision,omitempty"` } type GatewayRegistration struct { Version string `json:"version"` GatewayID string `json:"gateway_id"` InstanceIdentity string `json:"instance_identity"` CertificateIdentity string `json:"certificate_identity"` PublicIdentity string `json:"public_identity"` Address string `json:"address"` ProviderIdentity string `json:"provider_identity"` ProtocolMinVersion int64 `json:"protocol_min_version"` ProtocolMaxVersion int64 `json:"protocol_max_version"` ConnectionCapacity int64 `json:"connection_capacity"` BandwidthCapacityKbps int64 `json:"bandwidth_capacity_kbps"` Features []string `json:"features"` Capabilities CapabilityProfile `json:"capabilities"` } type GatewayStopAck struct { Version string `json:"version"` SessionID string `json:"session_id"` GatewayID string `json:"gateway_id"` ReconnectSequence int64 `json:"reconnect_sequence"` OperationID string `json:"operation_id"` Outcome string `json:"outcome"` FailureCode string `json:"failure_code,omitempty"` } type GatewayStopWork struct { Version string `json:"version"` SessionID string `json:"session_id"` GatewayID string `json:"gateway_id"` ReconnectSequence int64 `json:"reconnect_sequence"` OperationID string `json:"operation_id"` Attempt int64 `json:"attempt"` } type GatewayStopWorkRequest struct { Version string `json:"version"` SessionID string `json:"session_id"` GatewayID string `json:"gateway_id"` ReconnectSequence int64 `json:"reconnect_sequence"` Acquisition string `json:"acquisition"` OperationID string `json:"operation_id,omitempty"` } type GatewayTelemetry struct { AdmittedSessions int64 `json:"admitted_sessions"` AdmissionRejects int64 `json:"admission_rejects"` Reconnects int64 `json:"reconnects"` DrainTransitions int64 `json:"drain_transitions"` MediaDrops int64 `json:"media_drops"` MediaPackets int64 `json:"media_packets"` MediaBytes int64 `json:"media_bytes"` QueueDelayMicros int64 `json:"queue_delay_micros"` ProcessingDelayMicros int64 `json:"processing_delay_micros"` ProcessingSamples int64 `json:"processing_samples"` PacingDelayMicros int64 `json:"pacing_delay_micros"` ProviderErrors int64 `json:"provider_errors"` InputRejected int64 `json:"input_rejected"` ControlRttMicros int64 `json:"control_rtt_micros"` ControlJitterMicros int64 `json:"control_jitter_micros"` ControlLossPpm int64 `json:"control_loss_ppm"` PendingReliable int64 `json:"pending_reliable"` ProviderState string `json:"provider_state"` } type GrantReference struct { OpaqueValue string `json:"opaque_value"` ExpiresAt string `json:"expires_at"` Audience string `json:"audience"` } type LoginRequest struct { Provider string `json:"provider,omitempty"` Username string `json:"username"` Password string `json:"password"` } type ManifestBounds struct { MinimumKbps int64 `json:"minimum_kbps"` TargetKbps int64 `json:"target_kbps"` MaximumKbps int64 `json:"maximum_kbps"` } type ManifestGateway struct { ID string `json:"id"` Addresses []string `json:"addresses"` PublicIdentity string `json:"public_identity"` } type ManifestProfile struct { ID string `json:"id"` Bounds ManifestBounds `json:"bounds"` DisplayMode *DisplayMode `json:"display_mode,omitempty"` } type ManifestTunnel struct { Versions []string `json:"versions"` Features []string `json:"features"` } type NativeAuthenticatedSession struct { Username string `json:"username"` Provider string `json:"provider"` Roles []string `json:"roles"` Role string `json:"role"` NativeIdentity NativeSessionIdentity `json:"native_identity"` } type NativeCredential struct { DeviceID string `json:"device_id,omitempty"` FamilyID string `json:"family_id"` AccessToken string `json:"access_token"` RefreshToken string `json:"refresh_token"` ExpiresAt string `json:"expires_at"` RefreshExpiresAt string `json:"refresh_expires_at,omitempty"` } type NativeSessionIdentity struct { ClientDeviceID string `json:"client_device_id"` DeviceKeyID string `json:"device_key_id"` } type NativeTunnelCredential struct { ClientDeviceID string `json:"client_device_id"` DeviceKeyID string `json:"device_key_id"` CertificateChainPem string `json:"certificate_chain_pem"` TrustBundlePem string `json:"trust_bundle_pem"` ExpiresAt string `json:"expires_at"` } type PageInfo struct { Limit int64 `json:"limit"` NextCursor string `json:"next_cursor"` } type ProviderSessionWork struct { Version string `json:"version"` SessionID string `json:"session_id"` GatewayID string `json:"gateway_id"` ReconnectSequence int64 `json:"reconnect_sequence"` ExpiresAt string `json:"expires_at"` ProviderProfile string `json:"provider_profile"` ProviderIdentity string `json:"provider_identity"` PolicyVersionID string `json:"policy_version_id"` StreamPolicy ProviderStreamPolicy `json:"stream_policy"` ApplicationID string `json:"application_id"` ClientID string `json:"client_id"` ManagementHost string `json:"management_host"` ManagementPort int64 `json:"management_port"` StreamHost string `json:"stream_host"` StreamPort int64 `json:"stream_port"` ClientCertificatePem string `json:"client_certificate_pem"` ClientPrivateKeyPem string `json:"client_private_key_pem"` ServerCertificatePem string `json:"server_certificate_pem"` ClipboardPolicy ClipboardPolicy `json:"clipboard_policy"` ProviderApplicationTerminationAllowed bool `json:"provider_application_termination_allowed"` } type ProviderState struct { Version string `json:"version"` SessionID string `json:"session_id"` State string `json:"state"` CleanupPending bool `json:"cleanup_pending"` Channels []string `json:"channels"` } type ProviderStreamPolicy struct { VideoProfile VideoProfile `json:"video_profile"` AudioProfile AudioProfile `json:"audio_profile"` DisplayMode DisplayMode `json:"display_mode"` BitrateTargetKbps int64 `json:"bitrate_target_kbps"` BitrateMaximumKbps int64 `json:"bitrate_maximum_kbps"` } type QualityChangeOperation struct { OperationID string `json:"operation_id"` SessionID string `json:"session_id"` Revision int64 `json:"revision"` State string `json:"state"` RequestedBitratePreference BitratePreference `json:"requested_bitrate_preference"` EffectiveBitrateKbps int64 `json:"effective_bitrate_kbps"` GoverningPolicyVersion string `json:"governing_policy_version"` SessionVersion int64 `json:"session_version"` CreatedAt string `json:"created_at"` DeadlineAt string `json:"deadline_at"` UpdatedAt string `json:"updated_at"` FailureCode string `json:"failure_code,omitempty"` } type QualityChangeRequest struct { BitratePreference BitratePreference `json:"bitrate_preference"` ExpectedSessionVersion int64 `json:"expected_session_version"` ExpectedPolicyVersion string `json:"expected_policy_version"` } type ReauthGrant struct { Token string `json:"token"` Purpose string `json:"purpose"` ExpiresAt string `json:"expires_at"` } type ReauthRequest struct { Password string `json:"password"` Purpose string `json:"purpose"` } type ReconnectRequest struct { ClientDeviceID string `json:"client_device_id"` DeviceKeyID string `json:"device_key_id"` ExpectedVersion int64 `json:"expected_version"` DisplayRelaunchConfirmed bool `json:"display_relaunch_confirmed"` } type RefreshRequest struct { FamilyID string `json:"family_id"` RefreshToken string `json:"refresh_token"` } type Resource struct { ID string `json:"id"` Kind string `json:"kind"` Name string `json:"name"` State string `json:"state"` AssignmentState string `json:"assignment_state,omitempty"` Version int64 `json:"version"` Links []ResourceLink `json:"links"` } type ResourceLink struct { Type string `json:"type"` ID string `json:"id"` Version int64 `json:"version"` } type ResourceList struct { AssignedDesktops []AssignedDesktop `json:"assigned_desktops"` EntitledPools []EntitledPool `json:"entitled_pools"` Page PageInfo `json:"page"` } type SelectedSessionDescriptor struct { VideoProfile VideoProfile `json:"video_profile"` AudioProfile AudioProfile `json:"audio_profile"` DisplayMode DisplayMode `json:"display_mode"` BitrateTargetKbps int64 `json:"bitrate_target_kbps"` BitrateMaximumKbps int64 `json:"bitrate_maximum_kbps"` Adjustment SessionAdjustment `json:"adjustment"` MediaTimestampBasis string `json:"media_timestamp_basis"` } type SessionAdjustment struct { DisplayReason string `json:"display_reason"` BitrateReason string `json:"bitrate_reason"` } type SessionAuthority struct { Version string `json:"version"` SessionID string `json:"session_id"` GatewayID string `json:"gateway_id"` Audience string `json:"audience"` ReconnectSequence int64 `json:"reconnect_sequence"` ExpiresAt string `json:"expires_at"` Capabilities CapabilityProfile `json:"capabilities"` ProviderProfile string `json:"provider_profile"` ProviderIdentity string `json:"provider_identity"` SelectedDescriptor SelectedSessionDescriptor `json:"selected_descriptor"` } type SessionQualityLimits struct { PolicyVersionID string `json:"policy_version_id"` PolicyDisplayLimit DisplayMode `json:"policy_display_limit"` SelectableDisplayMaximum DisplayMode `json:"selectable_display_maximum"` DisplayLimitOverride bool `json:"display_limit_override"` BitrateMinimumKbps int64 `json:"bitrate_minimum_kbps"` BitrateTargetKbps int64 `json:"bitrate_target_kbps"` BitrateMaximumKbps int64 `json:"bitrate_maximum_kbps"` } type SessionRequest struct { ClientDeviceID string `json:"client_device_id"` DeviceKeyID string `json:"device_key_id"` PoolID string `json:"pool_id"` IdempotencyKey string `json:"idempotency_key"` VideoProfiles []VideoProfile `json:"video_profiles"` BitratePreference BitratePreference `json:"bitrate_preference"` RequestedDisplayMode *DisplayMode `json:"requested_display_mode,omitempty"` } type StableError struct { Version string `json:"version"` Code string `json:"code"` Message string `json:"message"` Retryable bool `json:"retryable"` } type StopOperation struct { OperationID string `json:"operation_id"` SessionID string `json:"session_id"` State string `json:"state"` SessionVersion int64 `json:"session_version"` CreatedAt string `json:"created_at"` DeadlineAt string `json:"deadline_at"` UpdatedAt string `json:"updated_at"` FailureCode string `json:"failure_code,omitempty"` } type TunnelAdmissionRequest struct { Version string `json:"version"` SessionID string `json:"session_id"` GatewayID string `json:"gateway_id"` Audience string `json:"audience"` Grant string `json:"grant"` ReconnectSequence int64 `json:"reconnect_sequence"` ClientNonce string `json:"client_nonce"` DeviceSignature string `json:"device_signature"` Capabilities CapabilityProfile `json:"capabilities"` } type VersionNegotiation struct { SupportedVersions []string `json:"supported_versions"` Features []string `json:"features"` } type VideoProfile struct { Codec string `json:"codec"` BitDepth int64 `json:"bit_depth"` ChromaSubsampling string `json:"chroma_subsampling"` ColorSpace string `json:"color_space"` TransferFunction string `json:"transfer_function"` } func (v AllocationPolicy) Validate() error { var violations []FieldViolation if v.MinimumKbps == 0 { violations = append(violations, FieldViolation{Field: "minimum_kbps", Code: "required"}) } if v.MinimumKbps != 0 && v.MinimumKbps < 1 { violations = append(violations, FieldViolation{Field: "minimum_kbps", Code: "minimum"}) } if v.MinimumKbps > 100000000 { violations = append(violations, FieldViolation{Field: "minimum_kbps", Code: "maximum"}) } if v.TargetKbps == 0 { violations = append(violations, FieldViolation{Field: "target_kbps", Code: "required"}) } if v.TargetKbps != 0 && v.TargetKbps < 1 { violations = append(violations, FieldViolation{Field: "target_kbps", Code: "minimum"}) } if v.TargetKbps > 100000000 { violations = append(violations, FieldViolation{Field: "target_kbps", Code: "maximum"}) } if v.MaximumKbps == 0 { violations = append(violations, FieldViolation{Field: "maximum_kbps", Code: "required"}) } if v.MaximumKbps != 0 && v.MaximumKbps < 1 { violations = append(violations, FieldViolation{Field: "maximum_kbps", Code: "minimum"}) } if v.MaximumKbps > 100000000 { violations = append(violations, FieldViolation{Field: "maximum_kbps", Code: "maximum"}) } if v.Tier == "" { violations = append(violations, FieldViolation{Field: "tier", Code: "required"}) } if v.Tier != "" && !(v.Tier == "standard" || v.Tier == "priority" || v.Tier == "premium") { violations = append(violations, FieldViolation{Field: "tier", Code: "invalid_value"}) } if v.Audience == "" { violations = append(violations, FieldViolation{Field: "audience", Code: "required"}) } if len(v.Audience) < 1 && v.Audience != "" { violations = append(violations, FieldViolation{Field: "audience", Code: "min_length"}) } if len(v.Audience) > 256 { violations = append(violations, FieldViolation{Field: "audience", Code: "max_length"}) } if v.Protocol == "" { violations = append(violations, FieldViolation{Field: "protocol", Code: "required"}) } if len(v.Protocol) < 1 && v.Protocol != "" { violations = append(violations, FieldViolation{Field: "protocol", Code: "min_length"}) } if len(v.Protocol) > 64 { violations = append(violations, FieldViolation{Field: "protocol", Code: "max_length"}) } if v.ProtocolVersion == 0 { violations = append(violations, FieldViolation{Field: "protocol_version", Code: "required"}) } if v.ProtocolVersion != 0 && v.ProtocolVersion < 1 { violations = append(violations, FieldViolation{Field: "protocol_version", Code: "minimum"}) } if v.ProtocolVersion > 100 { violations = append(violations, FieldViolation{Field: "protocol_version", Code: "maximum"}) } if v.GrantTTLSeconds == 0 { violations = append(violations, FieldViolation{Field: "grant_ttl_seconds", Code: "required"}) } if v.GrantTTLSeconds != 0 && v.GrantTTLSeconds < 5 { violations = append(violations, FieldViolation{Field: "grant_ttl_seconds", Code: "minimum"}) } if v.GrantTTLSeconds > 300 { violations = append(violations, FieldViolation{Field: "grant_ttl_seconds", Code: "maximum"}) } if v.ReservationLeaseSeconds == 0 { violations = append(violations, FieldViolation{Field: "reservation_lease_seconds", Code: "required"}) } if v.ReservationLeaseSeconds != 0 && v.ReservationLeaseSeconds < 5 { violations = append(violations, FieldViolation{Field: "reservation_lease_seconds", Code: "minimum"}) } if v.ReservationLeaseSeconds > 3600 { violations = append(violations, FieldViolation{Field: "reservation_lease_seconds", Code: "maximum"}) } if v.MinimumKbps > v.TargetKbps || v.TargetKbps > v.MaximumKbps { violations = append(violations, FieldViolation{Field: "bounds", Code: "invalid_order"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeAllocationPolicy(data []byte) (AllocationPolicy, error) { var value AllocationPolicy if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["audience"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "audience", Code: "required"}}} } if raw, ok := fields["grant_ttl_seconds"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "grant_ttl_seconds", Code: "required"}}} } if raw, ok := fields["maximum_kbps"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "maximum_kbps", Code: "required"}}} } if raw, ok := fields["minimum_kbps"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "minimum_kbps", Code: "required"}}} } if raw, ok := fields["protocol"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "protocol", Code: "required"}}} } if raw, ok := fields["protocol_version"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "protocol_version", Code: "required"}}} } if raw, ok := fields["reservation_lease_seconds"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "reservation_lease_seconds", Code: "required"}}} } if raw, ok := fields["target_kbps"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "target_kbps", Code: "required"}}} } if raw, ok := fields["tier"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "tier", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeAllocationPolicy(value AllocationPolicy) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v AssignedDesktop) Validate() error { var violations []FieldViolation if v.AssignmentID == "" { violations = append(violations, FieldViolation{Field: "assignment_id", Code: "required"}) } if len(v.AssignmentID) < 1 && v.AssignmentID != "" { violations = append(violations, FieldViolation{Field: "assignment_id", Code: "min_length"}) } if len(v.AssignmentID) > 128 { violations = append(violations, FieldViolation{Field: "assignment_id", Code: "max_length"}) } if v.PoolID == "" { violations = append(violations, FieldViolation{Field: "pool_id", Code: "required"}) } if len(v.PoolID) < 1 && v.PoolID != "" { violations = append(violations, FieldViolation{Field: "pool_id", Code: "min_length"}) } if len(v.PoolID) > 128 { violations = append(violations, FieldViolation{Field: "pool_id", Code: "max_length"}) } if v.Name == "" { violations = append(violations, FieldViolation{Field: "name", Code: "required"}) } if len(v.Name) < 1 && v.Name != "" { violations = append(violations, FieldViolation{Field: "name", Code: "min_length"}) } if len(v.Name) > 256 { violations = append(violations, FieldViolation{Field: "name", Code: "max_length"}) } if v.Availability == "" { violations = append(violations, FieldViolation{Field: "availability", Code: "required"}) } if len(v.Availability) < 1 && v.Availability != "" { violations = append(violations, FieldViolation{Field: "availability", Code: "min_length"}) } if len(v.Availability) > 64 { violations = append(violations, FieldViolation{Field: "availability", Code: "max_length"}) } if reflect.DeepEqual(v.QualityLimits, SessionQualityLimits{}) { violations = append(violations, FieldViolation{Field: "quality_limits", Code: "required"}) } if err := v.QualityLimits.Validate(); err != nil { violations = append(violations, FieldViolation{Field: "quality_limits", Code: "invalid_object"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeAssignedDesktop(data []byte) (AssignedDesktop, error) { var value AssignedDesktop if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["assignment_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "assignment_id", Code: "required"}}} } if raw, ok := fields["availability"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "availability", Code: "required"}}} } if raw, ok := fields["name"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "name", Code: "required"}}} } if raw, ok := fields["pool_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "pool_id", Code: "required"}}} } if raw, ok := fields["quality_limits"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "quality_limits", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeAssignedDesktop(value AssignedDesktop) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v AudioProfile) Validate() error { var violations []FieldViolation if v.Codec == "" { violations = append(violations, FieldViolation{Field: "codec", Code: "required"}) } if v.Codec != "opus" && v.Codec != "" { violations = append(violations, FieldViolation{Field: "codec", Code: "invalid_value"}) } if v.SampleRateHz == 0 { violations = append(violations, FieldViolation{Field: "sample_rate_hz", Code: "required"}) } if v.SampleRateHz != 0 && v.SampleRateHz < 48000 { violations = append(violations, FieldViolation{Field: "sample_rate_hz", Code: "minimum"}) } if v.SampleRateHz > 48000 { violations = append(violations, FieldViolation{Field: "sample_rate_hz", Code: "maximum"}) } if v.Channels == 0 { violations = append(violations, FieldViolation{Field: "channels", Code: "required"}) } if v.Channels != 0 && v.Channels < 2 { violations = append(violations, FieldViolation{Field: "channels", Code: "minimum"}) } if v.Channels > 2 { violations = append(violations, FieldViolation{Field: "channels", Code: "maximum"}) } if v.ChannelLayout == "" { violations = append(violations, FieldViolation{Field: "channel_layout", Code: "required"}) } if v.ChannelLayout != "stereo" && v.ChannelLayout != "" { violations = append(violations, FieldViolation{Field: "channel_layout", Code: "invalid_value"}) } if v.PacketDurationMs == 0 { violations = append(violations, FieldViolation{Field: "packet_duration_ms", Code: "required"}) } if v.PacketDurationMs != 0 && v.PacketDurationMs < 5 { violations = append(violations, FieldViolation{Field: "packet_duration_ms", Code: "minimum"}) } if v.PacketDurationMs > 5 { violations = append(violations, FieldViolation{Field: "packet_duration_ms", Code: "maximum"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeAudioProfile(data []byte) (AudioProfile, error) { var value AudioProfile if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["channel_layout"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "channel_layout", Code: "required"}}} } if raw, ok := fields["channels"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "channels", Code: "required"}}} } if raw, ok := fields["codec"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "codec", Code: "required"}}} } if raw, ok := fields["packet_duration_ms"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "packet_duration_ms", Code: "required"}}} } if raw, ok := fields["sample_rate_hz"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "sample_rate_hz", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeAudioProfile(value AudioProfile) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v BitratePreference) Validate() error { var violations []FieldViolation if v.Mode == "" { violations = append(violations, FieldViolation{Field: "mode", Code: "required"}) } if v.Mode != "" && !(v.Mode == "auto" || v.Mode == "explicit") { violations = append(violations, FieldViolation{Field: "mode", Code: "invalid_value"}) } if v.TargetKbps != nil && *v.TargetKbps != 0 && *v.TargetKbps < 100 { violations = append(violations, FieldViolation{Field: "target_kbps", Code: "minimum"}) } if v.TargetKbps != nil && *v.TargetKbps > 1000000 { violations = append(violations, FieldViolation{Field: "target_kbps", Code: "maximum"}) } if v.Mode == "auto" && v.TargetKbps != nil || v.Mode == "explicit" && v.TargetKbps == nil { violations = append(violations, FieldViolation{Field: "target_kbps", Code: "invalid_tagged_value"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeBitratePreference(data []byte) (BitratePreference, error) { var value BitratePreference if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["mode"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "mode", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeBitratePreference(value BitratePreference) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v BrokerSession) Validate() error { var violations []FieldViolation if v.ID == "" { violations = append(violations, FieldViolation{Field: "id", Code: "required"}) } if len(v.ID) < 1 && v.ID != "" { violations = append(violations, FieldViolation{Field: "id", Code: "min_length"}) } if len(v.ID) > 128 { violations = append(violations, FieldViolation{Field: "id", Code: "max_length"}) } if v.PrincipalID == "" { violations = append(violations, FieldViolation{Field: "principal_id", Code: "required"}) } if len(v.PrincipalID) < 1 && v.PrincipalID != "" { violations = append(violations, FieldViolation{Field: "principal_id", Code: "min_length"}) } if len(v.PrincipalID) > 128 { violations = append(violations, FieldViolation{Field: "principal_id", Code: "max_length"}) } if v.PoolID == "" { violations = append(violations, FieldViolation{Field: "pool_id", Code: "required"}) } if len(v.PoolID) < 1 && v.PoolID != "" { violations = append(violations, FieldViolation{Field: "pool_id", Code: "min_length"}) } if len(v.PoolID) > 128 { violations = append(violations, FieldViolation{Field: "pool_id", Code: "max_length"}) } if len(v.AssignmentID) > 128 { violations = append(violations, FieldViolation{Field: "assignment_id", Code: "max_length"}) } if v.State == "" { violations = append(violations, FieldViolation{Field: "state", Code: "required"}) } if len(v.State) < 1 && v.State != "" { violations = append(violations, FieldViolation{Field: "state", Code: "min_length"}) } if len(v.State) > 64 { violations = append(violations, FieldViolation{Field: "state", Code: "max_length"}) } if reflect.DeepEqual(v.PolicySnapshot, AllocationPolicy{}) { violations = append(violations, FieldViolation{Field: "policy_snapshot", Code: "required"}) } if err := v.PolicySnapshot.Validate(); err != nil { violations = append(violations, FieldViolation{Field: "policy_snapshot", Code: "invalid_object"}) } if len(v.ReconnectDeadline) > 64 { violations = append(violations, FieldViolation{Field: "reconnect_deadline", Code: "max_length"}) } if v.ReconnectDeadline != "" { if parsed, err := time.Parse(time.RFC3339Nano, v.ReconnectDeadline); err != nil || parsed.UTC().Format(time.RFC3339Nano) != v.ReconnectDeadline { violations = append(violations, FieldViolation{Field: "reconnect_deadline", Code: "invalid_time"}) } } if len(v.Outcome) > 64 { violations = append(violations, FieldViolation{Field: "outcome", Code: "max_length"}) } if len(v.FailureCode) > 128 { violations = append(violations, FieldViolation{Field: "failure_code", Code: "max_length"}) } if v.CleanupState == "" { violations = append(violations, FieldViolation{Field: "cleanup_state", Code: "required"}) } if len(v.CleanupState) < 1 && v.CleanupState != "" { violations = append(violations, FieldViolation{Field: "cleanup_state", Code: "min_length"}) } if len(v.CleanupState) > 64 { violations = append(violations, FieldViolation{Field: "cleanup_state", Code: "max_length"}) } if v.IdempotencyKey == "" { violations = append(violations, FieldViolation{Field: "idempotency_key", Code: "required"}) } if len(v.IdempotencyKey) < 1 && v.IdempotencyKey != "" { violations = append(violations, FieldViolation{Field: "idempotency_key", Code: "min_length"}) } if len(v.IdempotencyKey) > 256 { violations = append(violations, FieldViolation{Field: "idempotency_key", Code: "max_length"}) } if v.CorrelationID == "" { violations = append(violations, FieldViolation{Field: "correlation_id", Code: "required"}) } if len(v.CorrelationID) < 1 && v.CorrelationID != "" { violations = append(violations, FieldViolation{Field: "correlation_id", Code: "min_length"}) } if len(v.CorrelationID) > 128 { violations = append(violations, FieldViolation{Field: "correlation_id", Code: "max_length"}) } if v.RequestedAt == "" { violations = append(violations, FieldViolation{Field: "requested_at", Code: "required"}) } if len(v.RequestedAt) > 64 { violations = append(violations, FieldViolation{Field: "requested_at", Code: "max_length"}) } if v.RequestedAt != "" { if parsed, err := time.Parse(time.RFC3339Nano, v.RequestedAt); err != nil || parsed.UTC().Format(time.RFC3339Nano) != v.RequestedAt { violations = append(violations, FieldViolation{Field: "requested_at", Code: "invalid_time"}) } } if len(v.EndedAt) > 64 { violations = append(violations, FieldViolation{Field: "ended_at", Code: "max_length"}) } if v.EndedAt != "" { if parsed, err := time.Parse(time.RFC3339Nano, v.EndedAt); err != nil || parsed.UTC().Format(time.RFC3339Nano) != v.EndedAt { violations = append(violations, FieldViolation{Field: "ended_at", Code: "invalid_time"}) } } if v.Version == 0 { violations = append(violations, FieldViolation{Field: "version", Code: "required"}) } if v.Version != 0 && v.Version < 1 { violations = append(violations, FieldViolation{Field: "version", Code: "minimum"}) } if v.RequestedDisplayMode != nil { if err := v.RequestedDisplayMode.Validate(); err != nil { violations = append(violations, FieldViolation{Field: "requested_display_mode", Code: "invalid_object"}) } } if v.EffectiveDisplayMode != nil { if err := v.EffectiveDisplayMode.Validate(); err != nil { violations = append(violations, FieldViolation{Field: "effective_display_mode", Code: "invalid_object"}) } } if v.RequestedVideoProfiles == nil { violations = append(violations, FieldViolation{Field: "requested_video_profiles", Code: "required"}) } if len(v.RequestedVideoProfiles) < 1 { violations = append(violations, FieldViolation{Field: "requested_video_profiles", Code: "min_items"}) } if len(v.RequestedVideoProfiles) > 12 { violations = append(violations, FieldViolation{Field: "requested_video_profiles", Code: "max_items"}) } for index, item := range v.RequestedVideoProfiles { for prior := 0; prior < index; prior++ { if reflect.DeepEqual(item, v.RequestedVideoProfiles[prior]) { violations = append(violations, FieldViolation{Field: "requested_video_profiles", Code: "duplicate_item"}) } } } for index := range v.RequestedVideoProfiles { if err := v.RequestedVideoProfiles[index].Validate(); err != nil { violations = append(violations, FieldViolation{Field: fmt.Sprintf("requested_video_profiles[%d]", index), Code: "invalid_item"}) } } if reflect.DeepEqual(v.RequestedBitratePreference, BitratePreference{}) { violations = append(violations, FieldViolation{Field: "requested_bitrate_preference", Code: "required"}) } if err := v.RequestedBitratePreference.Validate(); err != nil { violations = append(violations, FieldViolation{Field: "requested_bitrate_preference", Code: "invalid_object"}) } if v.SelectedDescriptor != nil { if err := v.SelectedDescriptor.Validate(); err != nil { violations = append(violations, FieldViolation{Field: "selected_descriptor", Code: "invalid_object"}) } } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeBrokerSession(data []byte) (BrokerSession, error) { var value BrokerSession if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["cleanup_state"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "cleanup_state", Code: "required"}}} } if raw, ok := fields["correlation_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "correlation_id", Code: "required"}}} } if raw, ok := fields["id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "id", Code: "required"}}} } if raw, ok := fields["idempotency_key"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "idempotency_key", Code: "required"}}} } if raw, ok := fields["policy_snapshot"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "policy_snapshot", Code: "required"}}} } if raw, ok := fields["pool_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "pool_id", Code: "required"}}} } if raw, ok := fields["principal_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "principal_id", Code: "required"}}} } if raw, ok := fields["requested_at"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "requested_at", Code: "required"}}} } if raw, ok := fields["requested_bitrate_preference"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "requested_bitrate_preference", Code: "required"}}} } if raw, ok := fields["requested_video_profiles"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "requested_video_profiles", Code: "required"}}} } if raw, ok := fields["state"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "state", Code: "required"}}} } if raw, ok := fields["version"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "version", Code: "required"}}} } if raw, ok := fields["requested_display_mode"]; ok && bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "requested_display_mode", Code: "invalid_object"}}} } if raw, ok := fields["effective_display_mode"]; ok && bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "effective_display_mode", Code: "invalid_object"}}} } if raw, ok := fields["selected_descriptor"]; ok && bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "selected_descriptor", Code: "invalid_object"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeBrokerSession(value BrokerSession) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v BrowserAuthenticatedSession) Validate() error { var violations []FieldViolation if v.Username == "" { violations = append(violations, FieldViolation{Field: "username", Code: "required"}) } if len(v.Username) < 1 && v.Username != "" { violations = append(violations, FieldViolation{Field: "username", Code: "min_length"}) } if len(v.Username) > 256 { violations = append(violations, FieldViolation{Field: "username", Code: "max_length"}) } if v.Provider == "" { violations = append(violations, FieldViolation{Field: "provider", Code: "required"}) } if len(v.Provider) < 1 && v.Provider != "" { violations = append(violations, FieldViolation{Field: "provider", Code: "min_length"}) } if len(v.Provider) > 64 { violations = append(violations, FieldViolation{Field: "provider", Code: "max_length"}) } if v.Roles == nil { violations = append(violations, FieldViolation{Field: "roles", Code: "required"}) } if len(v.Roles) > 16 { violations = append(violations, FieldViolation{Field: "roles", Code: "max_items"}) } for _, item := range v.Roles { if len(item) < 1 { violations = append(violations, FieldViolation{Field: "roles", Code: "min_item_length"}) } } for _, item := range v.Roles { if len(item) > 64 { violations = append(violations, FieldViolation{Field: "roles", Code: "max_item_length"}) } } for _, item := range v.Roles { if len(item) > 64 { violations = append(violations, FieldViolation{Field: "roles", Code: "max_item_bytes"}) } } if v.Role == "" { violations = append(violations, FieldViolation{Field: "role", Code: "required"}) } if v.Role != "" && !(v.Role == "user" || v.Role == "admin") { violations = append(violations, FieldViolation{Field: "role", Code: "invalid_value"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeBrowserAuthenticatedSession(data []byte) (BrowserAuthenticatedSession, error) { var value BrowserAuthenticatedSession if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["provider"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "provider", Code: "required"}}} } if raw, ok := fields["role"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "role", Code: "required"}}} } if raw, ok := fields["roles"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "roles", Code: "required"}}} } if raw, ok := fields["username"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "username", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeBrowserAuthenticatedSession(value BrowserAuthenticatedSession) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v CapabilityProfile) Validate() error { var violations []FieldViolation if v.Transport == "" { violations = append(violations, FieldViolation{Field: "transport", Code: "required"}) } if len(v.Transport) < 1 && v.Transport != "" { violations = append(violations, FieldViolation{Field: "transport", Code: "min_length"}) } if len(v.Transport) > 64 { violations = append(violations, FieldViolation{Field: "transport", Code: "max_length"}) } if v.Framing == "" { violations = append(violations, FieldViolation{Field: "framing", Code: "required"}) } if v.Framing != "" && !(v.Framing == "datagram-v1" || v.Framing == "datagram-v2") { violations = append(violations, FieldViolation{Field: "framing", Code: "invalid_value"}) } if v.Media == "" { violations = append(violations, FieldViolation{Field: "media", Code: "required"}) } if len(v.Media) < 1 && v.Media != "" { violations = append(violations, FieldViolation{Field: "media", Code: "min_length"}) } if len(v.Media) > 64 { violations = append(violations, FieldViolation{Field: "media", Code: "max_length"}) } if v.SourceRateControl == "" { violations = append(violations, FieldViolation{Field: "source_rate_control", Code: "required"}) } if len(v.SourceRateControl) < 1 && v.SourceRateControl != "" { violations = append(violations, FieldViolation{Field: "source_rate_control", Code: "min_length"}) } if len(v.SourceRateControl) > 64 { violations = append(violations, FieldViolation{Field: "source_rate_control", Code: "max_length"}) } if v.VideoProfiles == nil { violations = append(violations, FieldViolation{Field: "video_profiles", Code: "required"}) } if len(v.VideoProfiles) < 1 { violations = append(violations, FieldViolation{Field: "video_profiles", Code: "min_items"}) } if len(v.VideoProfiles) > 12 { violations = append(violations, FieldViolation{Field: "video_profiles", Code: "max_items"}) } for index, item := range v.VideoProfiles { for prior := 0; prior < index; prior++ { if reflect.DeepEqual(item, v.VideoProfiles[prior]) { violations = append(violations, FieldViolation{Field: "video_profiles", Code: "duplicate_item"}) } } } for index := range v.VideoProfiles { if err := v.VideoProfiles[index].Validate(); err != nil { violations = append(violations, FieldViolation{Field: fmt.Sprintf("video_profiles[%d]", index), Code: "invalid_item"}) } } if v.AudioProfiles == nil { violations = append(violations, FieldViolation{Field: "audio_profiles", Code: "required"}) } if len(v.AudioProfiles) < 1 { violations = append(violations, FieldViolation{Field: "audio_profiles", Code: "min_items"}) } if len(v.AudioProfiles) > 1 { violations = append(violations, FieldViolation{Field: "audio_profiles", Code: "max_items"}) } for index, item := range v.AudioProfiles { for prior := 0; prior < index; prior++ { if reflect.DeepEqual(item, v.AudioProfiles[prior]) { violations = append(violations, FieldViolation{Field: "audio_profiles", Code: "duplicate_item"}) } } } for index := range v.AudioProfiles { if err := v.AudioProfiles[index].Validate(); err != nil { violations = append(violations, FieldViolation{Field: fmt.Sprintf("audio_profiles[%d]", index), Code: "invalid_item"}) } } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeCapabilityProfile(data []byte) (CapabilityProfile, error) { var value CapabilityProfile if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["audio_profiles"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "audio_profiles", Code: "required"}}} } if raw, ok := fields["framing"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "framing", Code: "required"}}} } if raw, ok := fields["media"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "media", Code: "required"}}} } if raw, ok := fields["source_rate_control"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "source_rate_control", Code: "required"}}} } if raw, ok := fields["transport"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "transport", Code: "required"}}} } if raw, ok := fields["video_profiles"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "video_profiles", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeCapabilityProfile(value CapabilityProfile) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v ChannelFrame) Validate() error { var violations []FieldViolation if v.Version == "" { violations = append(violations, FieldViolation{Field: "version", Code: "required"}) } if v.Version != "1" && v.Version != "" { violations = append(violations, FieldViolation{Field: "version", Code: "invalid_value"}) } if v.FlowID == "" { violations = append(violations, FieldViolation{Field: "flow_id", Code: "required"}) } if len(v.FlowID) < 1 && v.FlowID != "" { violations = append(violations, FieldViolation{Field: "flow_id", Code: "min_length"}) } if len(v.FlowID) > 64 { violations = append(violations, FieldViolation{Field: "flow_id", Code: "max_length"}) } if v.Sequence != 0 && v.Sequence < 0 { violations = append(violations, FieldViolation{Field: "sequence", Code: "minimum"}) } if v.Flags != 0 && v.Flags < 0 { violations = append(violations, FieldViolation{Field: "flags", Code: "minimum"}) } if v.Flags > 255 { violations = append(violations, FieldViolation{Field: "flags", Code: "maximum"}) } if v.FragmentIndex != 0 && v.FragmentIndex < 0 { violations = append(violations, FieldViolation{Field: "fragment_index", Code: "minimum"}) } if v.FragmentIndex > 15 { violations = append(violations, FieldViolation{Field: "fragment_index", Code: "maximum"}) } if v.FragmentCount == 0 { violations = append(violations, FieldViolation{Field: "fragment_count", Code: "required"}) } if v.FragmentCount != 0 && v.FragmentCount < 1 { violations = append(violations, FieldViolation{Field: "fragment_count", Code: "minimum"}) } if v.FragmentCount > 16 { violations = append(violations, FieldViolation{Field: "fragment_count", Code: "maximum"}) } if v.TimestampMs != 0 && v.TimestampMs < 0 { violations = append(violations, FieldViolation{Field: "timestamp_ms", Code: "minimum"}) } if v.Payload == "" { violations = append(violations, FieldViolation{Field: "payload", Code: "required"}) } if len(v.Payload) > 87384 { violations = append(violations, FieldViolation{Field: "payload", Code: "max_length"}) } if len(v.Payload) > 65536 { violations = append(violations, FieldViolation{Field: "payload", Code: "max_bytes"}) } if v.FragmentIndex >= v.FragmentCount { violations = append(violations, FieldViolation{Field: "fragment_index", Code: "invalid_order"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeChannelFrame(data []byte) (ChannelFrame, error) { var value ChannelFrame if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["flags"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "flags", Code: "required"}}} } if raw, ok := fields["flow_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "flow_id", Code: "required"}}} } if raw, ok := fields["fragment_count"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "fragment_count", Code: "required"}}} } if raw, ok := fields["fragment_index"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "fragment_index", Code: "required"}}} } if raw, ok := fields["payload"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "payload", Code: "required"}}} } if raw, ok := fields["sequence"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "sequence", Code: "required"}}} } if raw, ok := fields["timestamp_ms"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "timestamp_ms", Code: "required"}}} } if raw, ok := fields["version"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "version", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeChannelFrame(value ChannelFrame) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v ClientSessionAuthority) Validate() error { var violations []FieldViolation if v.Version == "" { violations = append(violations, FieldViolation{Field: "version", Code: "required"}) } if v.Version != "1" && v.Version != "" { violations = append(violations, FieldViolation{Field: "version", Code: "invalid_value"}) } if v.SessionID == "" { violations = append(violations, FieldViolation{Field: "session_id", Code: "required"}) } if len(v.SessionID) < 1 && v.SessionID != "" { violations = append(violations, FieldViolation{Field: "session_id", Code: "min_length"}) } if len(v.SessionID) > 128 { violations = append(violations, FieldViolation{Field: "session_id", Code: "max_length"}) } if v.GatewayID == "" { violations = append(violations, FieldViolation{Field: "gateway_id", Code: "required"}) } if len(v.GatewayID) < 1 && v.GatewayID != "" { violations = append(violations, FieldViolation{Field: "gateway_id", Code: "min_length"}) } if len(v.GatewayID) > 128 { violations = append(violations, FieldViolation{Field: "gateway_id", Code: "max_length"}) } if v.Audience == "" { violations = append(violations, FieldViolation{Field: "audience", Code: "required"}) } if len(v.Audience) < 1 && v.Audience != "" { violations = append(violations, FieldViolation{Field: "audience", Code: "min_length"}) } if len(v.Audience) > 256 { violations = append(violations, FieldViolation{Field: "audience", Code: "max_length"}) } if v.ReconnectSequence != 0 && v.ReconnectSequence < 0 { violations = append(violations, FieldViolation{Field: "reconnect_sequence", Code: "minimum"}) } if v.ExpiresAt == "" { violations = append(violations, FieldViolation{Field: "expires_at", Code: "required"}) } if len(v.ExpiresAt) > 64 { violations = append(violations, FieldViolation{Field: "expires_at", Code: "max_length"}) } if v.ExpiresAt != "" { if parsed, err := time.Parse(time.RFC3339Nano, v.ExpiresAt); err != nil || parsed.UTC().Format(time.RFC3339Nano) != v.ExpiresAt { violations = append(violations, FieldViolation{Field: "expires_at", Code: "invalid_time"}) } } if reflect.DeepEqual(v.Capabilities, CapabilityProfile{}) { violations = append(violations, FieldViolation{Field: "capabilities", Code: "required"}) } if err := v.Capabilities.Validate(); err != nil { violations = append(violations, FieldViolation{Field: "capabilities", Code: "invalid_object"}) } if reflect.DeepEqual(v.SelectedDescriptor, SelectedSessionDescriptor{}) { violations = append(violations, FieldViolation{Field: "selected_descriptor", Code: "required"}) } if err := v.SelectedDescriptor.Validate(); err != nil { violations = append(violations, FieldViolation{Field: "selected_descriptor", Code: "invalid_object"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeClientSessionAuthority(data []byte) (ClientSessionAuthority, error) { var value ClientSessionAuthority if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["audience"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "audience", Code: "required"}}} } if raw, ok := fields["capabilities"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "capabilities", Code: "required"}}} } if raw, ok := fields["expires_at"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "expires_at", Code: "required"}}} } if raw, ok := fields["gateway_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "gateway_id", Code: "required"}}} } if raw, ok := fields["reconnect_sequence"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "reconnect_sequence", Code: "required"}}} } if raw, ok := fields["selected_descriptor"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "selected_descriptor", Code: "required"}}} } if raw, ok := fields["session_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "session_id", Code: "required"}}} } if raw, ok := fields["version"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "version", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeClientSessionAuthority(value ClientSessionAuthority) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v ClipboardPolicy) Validate() error { var violations []FieldViolation if v.MaxTextBytes == 0 { violations = append(violations, FieldViolation{Field: "max_text_bytes", Code: "required"}) } if v.MaxTextBytes != 0 && v.MaxTextBytes < 1 { violations = append(violations, FieldViolation{Field: "max_text_bytes", Code: "minimum"}) } if v.MaxTextBytes > 65536 { violations = append(violations, FieldViolation{Field: "max_text_bytes", Code: "maximum"}) } if v.MaxUpdatesPerMinute == 0 { violations = append(violations, FieldViolation{Field: "max_updates_per_minute", Code: "required"}) } if v.MaxUpdatesPerMinute != 0 && v.MaxUpdatesPerMinute < 1 { violations = append(violations, FieldViolation{Field: "max_updates_per_minute", Code: "minimum"}) } if v.MaxUpdatesPerMinute > 120 { violations = append(violations, FieldViolation{Field: "max_updates_per_minute", Code: "maximum"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeClipboardPolicy(data []byte) (ClipboardPolicy, error) { var value ClipboardPolicy if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["client_to_provider_enabled"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "client_to_provider_enabled", Code: "required"}}} } if raw, ok := fields["max_text_bytes"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "max_text_bytes", Code: "required"}}} } if raw, ok := fields["max_updates_per_minute"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "max_updates_per_minute", Code: "required"}}} } if raw, ok := fields["provider_to_client_enabled"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "provider_to_client_enabled", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeClipboardPolicy(value ClipboardPolicy) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v ClipboardText) Validate() error { var violations []FieldViolation if v.Text == "" { violations = append(violations, FieldViolation{Field: "text", Code: "required"}) } if len(v.Text) > 65536 { violations = append(violations, FieldViolation{Field: "text", Code: "max_length"}) } if v.Encoding == "" { violations = append(violations, FieldViolation{Field: "encoding", Code: "required"}) } if v.Encoding != "utf-8" && v.Encoding != "" { violations = append(violations, FieldViolation{Field: "encoding", Code: "invalid_value"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeClipboardText(data []byte) (ClipboardText, error) { var value ClipboardText if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["encoding"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "encoding", Code: "required"}}} } if raw, ok := fields["text"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "text", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeClipboardText(value ClipboardText) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v ConnectionManifest) Validate() error { var violations []FieldViolation if v.Version == "" { violations = append(violations, FieldViolation{Field: "version", Code: "required"}) } if v.Version != "1" && v.Version != "" { violations = append(violations, FieldViolation{Field: "version", Code: "invalid_value"}) } if v.Purpose == "" { violations = append(violations, FieldViolation{Field: "purpose", Code: "required"}) } if v.Purpose != "" && !(v.Purpose == "launch" || v.Purpose == "reconnect") { violations = append(violations, FieldViolation{Field: "purpose", Code: "invalid_value"}) } if v.SessionID == "" { violations = append(violations, FieldViolation{Field: "session_id", Code: "required"}) } if len(v.SessionID) < 1 && v.SessionID != "" { violations = append(violations, FieldViolation{Field: "session_id", Code: "min_length"}) } if len(v.SessionID) > 128 { violations = append(violations, FieldViolation{Field: "session_id", Code: "max_length"}) } if v.ReconnectSequence != 0 && v.ReconnectSequence < 0 { violations = append(violations, FieldViolation{Field: "reconnect_sequence", Code: "minimum"}) } if reflect.DeepEqual(v.Gateway, ManifestGateway{}) { violations = append(violations, FieldViolation{Field: "gateway", Code: "required"}) } if err := v.Gateway.Validate(); err != nil { violations = append(violations, FieldViolation{Field: "gateway", Code: "invalid_object"}) } if reflect.DeepEqual(v.Tunnel, ManifestTunnel{}) { violations = append(violations, FieldViolation{Field: "tunnel", Code: "required"}) } if err := v.Tunnel.Validate(); err != nil { violations = append(violations, FieldViolation{Field: "tunnel", Code: "invalid_object"}) } if reflect.DeepEqual(v.Profile, ManifestProfile{}) { violations = append(violations, FieldViolation{Field: "profile", Code: "required"}) } if err := v.Profile.Validate(); err != nil { violations = append(violations, FieldViolation{Field: "profile", Code: "invalid_object"}) } if reflect.DeepEqual(v.Grant, GrantReference{}) { violations = append(violations, FieldViolation{Field: "grant", Code: "required"}) } if err := v.Grant.Validate(); err != nil { violations = append(violations, FieldViolation{Field: "grant", Code: "invalid_object"}) } if v.CorrelationID == "" { violations = append(violations, FieldViolation{Field: "correlation_id", Code: "required"}) } if len(v.CorrelationID) < 1 && v.CorrelationID != "" { violations = append(violations, FieldViolation{Field: "correlation_id", Code: "min_length"}) } if len(v.CorrelationID) > 128 { violations = append(violations, FieldViolation{Field: "correlation_id", Code: "max_length"}) } if reflect.DeepEqual(v.SelectedDescriptor, SelectedSessionDescriptor{}) { violations = append(violations, FieldViolation{Field: "selected_descriptor", Code: "required"}) } if err := v.SelectedDescriptor.Validate(); err != nil { violations = append(violations, FieldViolation{Field: "selected_descriptor", Code: "invalid_object"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeConnectionManifest(data []byte) (ConnectionManifest, error) { var value ConnectionManifest if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["correlation_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "correlation_id", Code: "required"}}} } if raw, ok := fields["gateway"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "gateway", Code: "required"}}} } if raw, ok := fields["grant"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "grant", Code: "required"}}} } if raw, ok := fields["profile"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "profile", Code: "required"}}} } if raw, ok := fields["purpose"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "purpose", Code: "required"}}} } if raw, ok := fields["reconnect_sequence"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "reconnect_sequence", Code: "required"}}} } if raw, ok := fields["selected_descriptor"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "selected_descriptor", Code: "required"}}} } if raw, ok := fields["session_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "session_id", Code: "required"}}} } if raw, ok := fields["tunnel"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "tunnel", Code: "required"}}} } if raw, ok := fields["version"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "version", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeConnectionManifest(value ConnectionManifest) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v DeviceChallenge) Validate() error { var violations []FieldViolation if v.DeviceID == "" { violations = append(violations, FieldViolation{Field: "device_id", Code: "required"}) } if len(v.DeviceID) < 1 && v.DeviceID != "" { violations = append(violations, FieldViolation{Field: "device_id", Code: "min_length"}) } if len(v.DeviceID) > 128 { violations = append(violations, FieldViolation{Field: "device_id", Code: "max_length"}) } if v.ServerID == "" { violations = append(violations, FieldViolation{Field: "server_id", Code: "required"}) } if len(v.ServerID) < 1 && v.ServerID != "" { violations = append(violations, FieldViolation{Field: "server_id", Code: "min_length"}) } if len(v.ServerID) > 128 { violations = append(violations, FieldViolation{Field: "server_id", Code: "max_length"}) } if v.PrincipalID == "" { violations = append(violations, FieldViolation{Field: "principal_id", Code: "required"}) } if len(v.PrincipalID) < 1 && v.PrincipalID != "" { violations = append(violations, FieldViolation{Field: "principal_id", Code: "min_length"}) } if len(v.PrincipalID) > 128 { violations = append(violations, FieldViolation{Field: "principal_id", Code: "max_length"}) } if v.Challenge == "" { violations = append(violations, FieldViolation{Field: "challenge", Code: "required"}) } if len(v.Challenge) < 1 && v.Challenge != "" { violations = append(violations, FieldViolation{Field: "challenge", Code: "min_length"}) } if len(v.Challenge) > 256 { violations = append(violations, FieldViolation{Field: "challenge", Code: "max_length"}) } if v.ExpiresAt == "" { violations = append(violations, FieldViolation{Field: "expires_at", Code: "required"}) } if len(v.ExpiresAt) > 64 { violations = append(violations, FieldViolation{Field: "expires_at", Code: "max_length"}) } if v.ExpiresAt != "" { if parsed, err := time.Parse(time.RFC3339Nano, v.ExpiresAt); err != nil || parsed.UTC().Format(time.RFC3339Nano) != v.ExpiresAt { violations = append(violations, FieldViolation{Field: "expires_at", Code: "invalid_time"}) } } if v.Algorithm == "" { violations = append(violations, FieldViolation{Field: "algorithm", Code: "required"}) } if v.Algorithm != "ed25519" && v.Algorithm != "" { violations = append(violations, FieldViolation{Field: "algorithm", Code: "invalid_value"}) } if v.SignatureFormat == "" { violations = append(violations, FieldViolation{Field: "signature_format", Code: "required"}) } if v.SignatureFormat != "ed25519-domain-separated-v1" && v.SignatureFormat != "" { violations = append(violations, FieldViolation{Field: "signature_format", Code: "invalid_value"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeDeviceChallenge(data []byte) (DeviceChallenge, error) { var value DeviceChallenge if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["algorithm"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "algorithm", Code: "required"}}} } if raw, ok := fields["challenge"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "challenge", Code: "required"}}} } if raw, ok := fields["device_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "device_id", Code: "required"}}} } if raw, ok := fields["expires_at"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "expires_at", Code: "required"}}} } if raw, ok := fields["principal_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "principal_id", Code: "required"}}} } if raw, ok := fields["server_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "server_id", Code: "required"}}} } if raw, ok := fields["signature_format"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "signature_format", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeDeviceChallenge(value DeviceChallenge) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v DeviceProofRequest) Validate() error { var violations []FieldViolation if v.Challenge == "" { violations = append(violations, FieldViolation{Field: "challenge", Code: "required"}) } if len(v.Challenge) < 1 && v.Challenge != "" { violations = append(violations, FieldViolation{Field: "challenge", Code: "min_length"}) } if len(v.Challenge) > 256 { violations = append(violations, FieldViolation{Field: "challenge", Code: "max_length"}) } if v.Signature == "" { violations = append(violations, FieldViolation{Field: "signature", Code: "required"}) } if len(v.Signature) < 1 && v.Signature != "" { violations = append(violations, FieldViolation{Field: "signature", Code: "min_length"}) } if len(v.Signature) > 256 { violations = append(violations, FieldViolation{Field: "signature", Code: "max_length"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeDeviceProofRequest(data []byte) (DeviceProofRequest, error) { var value DeviceProofRequest if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["challenge"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "challenge", Code: "required"}}} } if raw, ok := fields["signature"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "signature", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeDeviceProofRequest(value DeviceProofRequest) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v DeviceRegistrationRequest) Validate() error { var violations []FieldViolation if v.Name == "" { violations = append(violations, FieldViolation{Field: "name", Code: "required"}) } if len(v.Name) < 1 && v.Name != "" { violations = append(violations, FieldViolation{Field: "name", Code: "min_length"}) } if len(v.Name) > 128 { violations = append(violations, FieldViolation{Field: "name", Code: "max_length"}) } if v.Platform == "" { violations = append(violations, FieldViolation{Field: "platform", Code: "required"}) } if len(v.Platform) < 1 && v.Platform != "" { violations = append(violations, FieldViolation{Field: "platform", Code: "min_length"}) } if len(v.Platform) > 64 { violations = append(violations, FieldViolation{Field: "platform", Code: "max_length"}) } if v.DeviceSubject == "" { violations = append(violations, FieldViolation{Field: "device_subject", Code: "required"}) } if len(v.DeviceSubject) < 1 && v.DeviceSubject != "" { violations = append(violations, FieldViolation{Field: "device_subject", Code: "min_length"}) } if len(v.DeviceSubject) > 256 { violations = append(violations, FieldViolation{Field: "device_subject", Code: "max_length"}) } if v.Algorithm == "" { violations = append(violations, FieldViolation{Field: "algorithm", Code: "required"}) } if v.Algorithm != "ed25519" && v.Algorithm != "" { violations = append(violations, FieldViolation{Field: "algorithm", Code: "invalid_value"}) } if v.PublicKey == "" { violations = append(violations, FieldViolation{Field: "public_key", Code: "required"}) } if len(v.PublicKey) < 1 && v.PublicKey != "" { violations = append(violations, FieldViolation{Field: "public_key", Code: "min_length"}) } if len(v.PublicKey) > 256 { violations = append(violations, FieldViolation{Field: "public_key", Code: "max_length"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeDeviceRegistrationRequest(data []byte) (DeviceRegistrationRequest, error) { var value DeviceRegistrationRequest if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["algorithm"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "algorithm", Code: "required"}}} } if raw, ok := fields["device_subject"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "device_subject", Code: "required"}}} } if raw, ok := fields["name"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "name", Code: "required"}}} } if raw, ok := fields["platform"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "platform", Code: "required"}}} } if raw, ok := fields["public_key"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "public_key", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeDeviceRegistrationRequest(value DeviceRegistrationRequest) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v DisplayLimitOverrideRequest) Validate() error { var violations []FieldViolation if v.ExpectedVersion == 0 { violations = append(violations, FieldViolation{Field: "expected_version", Code: "required"}) } if v.ExpectedVersion != 0 && v.ExpectedVersion < 1 { violations = append(violations, FieldViolation{Field: "expected_version", Code: "minimum"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeDisplayLimitOverrideRequest(data []byte) (DisplayLimitOverrideRequest, error) { var value DisplayLimitOverrideRequest if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["allow_display_limit_override"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "allow_display_limit_override", Code: "required"}}} } if raw, ok := fields["expected_version"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "expected_version", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeDisplayLimitOverrideRequest(value DisplayLimitOverrideRequest) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v DisplayMode) Validate() error { var violations []FieldViolation if v.ResolutionWidth == 0 { violations = append(violations, FieldViolation{Field: "resolution_width", Code: "required"}) } if v.ResolutionWidth != 0 && v.ResolutionWidth < 320 { violations = append(violations, FieldViolation{Field: "resolution_width", Code: "minimum"}) } if v.ResolutionWidth > 16384 { violations = append(violations, FieldViolation{Field: "resolution_width", Code: "maximum"}) } if v.ResolutionHeight == 0 { violations = append(violations, FieldViolation{Field: "resolution_height", Code: "required"}) } if v.ResolutionHeight != 0 && v.ResolutionHeight < 200 { violations = append(violations, FieldViolation{Field: "resolution_height", Code: "minimum"}) } if v.ResolutionHeight > 8640 { violations = append(violations, FieldViolation{Field: "resolution_height", Code: "maximum"}) } if v.Fps == 0 { violations = append(violations, FieldViolation{Field: "fps", Code: "required"}) } if v.Fps != 0 && v.Fps < 1 { violations = append(violations, FieldViolation{Field: "fps", Code: "minimum"}) } if v.Fps > 240 { violations = append(violations, FieldViolation{Field: "fps", Code: "maximum"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeDisplayMode(data []byte) (DisplayMode, error) { var value DisplayMode if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["fps"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "fps", Code: "required"}}} } if raw, ok := fields["resolution_height"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "resolution_height", Code: "required"}}} } if raw, ok := fields["resolution_width"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "resolution_width", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeDisplayMode(value DisplayMode) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v EntitledPool) Validate() error { var violations []FieldViolation if v.PoolID == "" { violations = append(violations, FieldViolation{Field: "pool_id", Code: "required"}) } if len(v.PoolID) < 1 && v.PoolID != "" { violations = append(violations, FieldViolation{Field: "pool_id", Code: "min_length"}) } if len(v.PoolID) > 128 { violations = append(violations, FieldViolation{Field: "pool_id", Code: "max_length"}) } if v.Name == "" { violations = append(violations, FieldViolation{Field: "name", Code: "required"}) } if len(v.Name) < 1 && v.Name != "" { violations = append(violations, FieldViolation{Field: "name", Code: "min_length"}) } if len(v.Name) > 256 { violations = append(violations, FieldViolation{Field: "name", Code: "max_length"}) } if v.AssignmentState == "" { violations = append(violations, FieldViolation{Field: "assignment_state", Code: "required"}) } if len(v.AssignmentState) < 1 && v.AssignmentState != "" { violations = append(violations, FieldViolation{Field: "assignment_state", Code: "min_length"}) } if len(v.AssignmentState) > 64 { violations = append(violations, FieldViolation{Field: "assignment_state", Code: "max_length"}) } if reflect.DeepEqual(v.QualityLimits, SessionQualityLimits{}) { violations = append(violations, FieldViolation{Field: "quality_limits", Code: "required"}) } if err := v.QualityLimits.Validate(); err != nil { violations = append(violations, FieldViolation{Field: "quality_limits", Code: "invalid_object"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeEntitledPool(data []byte) (EntitledPool, error) { var value EntitledPool if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["assignment_state"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "assignment_state", Code: "required"}}} } if raw, ok := fields["name"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "name", Code: "required"}}} } if raw, ok := fields["pool_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "pool_id", Code: "required"}}} } if raw, ok := fields["quality_limits"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "quality_limits", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeEntitledPool(value EntitledPool) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v ErrorEnvelope) Validate() error { var violations []FieldViolation if v.Error == "" { violations = append(violations, FieldViolation{Field: "error", Code: "required"}) } if len(v.Error) < 1 && v.Error != "" { violations = append(violations, FieldViolation{Field: "error", Code: "min_length"}) } if len(v.Error) > 512 { violations = append(violations, FieldViolation{Field: "error", Code: "max_length"}) } if v.Code == "" { violations = append(violations, FieldViolation{Field: "code", Code: "required"}) } if len(v.Code) < 1 && v.Code != "" { violations = append(violations, FieldViolation{Field: "code", Code: "min_length"}) } if len(v.Code) > 128 { violations = append(violations, FieldViolation{Field: "code", Code: "max_length"}) } if v.Message == "" { violations = append(violations, FieldViolation{Field: "message", Code: "required"}) } if len(v.Message) < 1 && v.Message != "" { violations = append(violations, FieldViolation{Field: "message", Code: "min_length"}) } if len(v.Message) > 512 { violations = append(violations, FieldViolation{Field: "message", Code: "max_length"}) } if v.Resolution == "" { violations = append(violations, FieldViolation{Field: "resolution", Code: "required"}) } if len(v.Resolution) < 1 && v.Resolution != "" { violations = append(violations, FieldViolation{Field: "resolution", Code: "min_length"}) } if len(v.Resolution) > 128 { violations = append(violations, FieldViolation{Field: "resolution", Code: "max_length"}) } if v.RequestID == "" { violations = append(violations, FieldViolation{Field: "request_id", Code: "required"}) } if len(v.RequestID) < 1 && v.RequestID != "" { violations = append(violations, FieldViolation{Field: "request_id", Code: "min_length"}) } if len(v.RequestID) > 128 { violations = append(violations, FieldViolation{Field: "request_id", Code: "max_length"}) } if v.Violations == nil { violations = append(violations, FieldViolation{Field: "violations", Code: "required"}) } if len(v.Violations) > 16 { violations = append(violations, FieldViolation{Field: "violations", Code: "max_items"}) } for index := range v.Violations { if err := v.Violations[index].Validate(); err != nil { violations = append(violations, FieldViolation{Field: fmt.Sprintf("violations[%d]", index), Code: "invalid_item"}) } } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeErrorEnvelope(data []byte) (ErrorEnvelope, error) { var value ErrorEnvelope if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["code"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "code", Code: "required"}}} } if raw, ok := fields["error"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "error", Code: "required"}}} } if raw, ok := fields["message"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "message", Code: "required"}}} } if raw, ok := fields["request_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "request_id", Code: "required"}}} } if raw, ok := fields["resolution"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "resolution", Code: "required"}}} } if raw, ok := fields["status"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "status", Code: "required"}}} } if raw, ok := fields["violations"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "violations", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeErrorEnvelope(value ErrorEnvelope) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v EventEnvelope) Validate() error { var violations []FieldViolation if v.EventID == "" { violations = append(violations, FieldViolation{Field: "event_id", Code: "required"}) } if len(v.EventID) < 1 && v.EventID != "" { violations = append(violations, FieldViolation{Field: "event_id", Code: "min_length"}) } if len(v.EventID) > 128 { violations = append(violations, FieldViolation{Field: "event_id", Code: "max_length"}) } if v.Sequence == 0 { violations = append(violations, FieldViolation{Field: "sequence", Code: "required"}) } if v.Sequence != 0 && v.Sequence < 1 { violations = append(violations, FieldViolation{Field: "sequence", Code: "minimum"}) } if v.Type == "" { violations = append(violations, FieldViolation{Field: "type", Code: "required"}) } if len(v.Type) < 1 && v.Type != "" { violations = append(violations, FieldViolation{Field: "type", Code: "min_length"}) } if len(v.Type) > 128 { violations = append(violations, FieldViolation{Field: "type", Code: "max_length"}) } if v.Version == 0 { violations = append(violations, FieldViolation{Field: "version", Code: "required"}) } if v.Version != 0 && v.Version < 1 { violations = append(violations, FieldViolation{Field: "version", Code: "minimum"}) } if reflect.DeepEqual(v.Resource, ResourceLink{}) { violations = append(violations, FieldViolation{Field: "resource", Code: "required"}) } if err := v.Resource.Validate(); err != nil { violations = append(violations, FieldViolation{Field: "resource", Code: "invalid_object"}) } if v.OccurredAt == "" { violations = append(violations, FieldViolation{Field: "occurred_at", Code: "required"}) } if len(v.OccurredAt) > 64 { violations = append(violations, FieldViolation{Field: "occurred_at", Code: "max_length"}) } if v.OccurredAt != "" { if parsed, err := time.Parse(time.RFC3339Nano, v.OccurredAt); err != nil || parsed.UTC().Format(time.RFC3339Nano) != v.OccurredAt { violations = append(violations, FieldViolation{Field: "occurred_at", Code: "invalid_time"}) } } if v.CorrelationID == "" { violations = append(violations, FieldViolation{Field: "correlation_id", Code: "required"}) } if len(v.CorrelationID) < 1 && v.CorrelationID != "" { violations = append(violations, FieldViolation{Field: "correlation_id", Code: "min_length"}) } if len(v.CorrelationID) > 128 { violations = append(violations, FieldViolation{Field: "correlation_id", Code: "max_length"}) } if v.Payload == nil { violations = append(violations, FieldViolation{Field: "payload", Code: "required"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeEventEnvelope(data []byte) (EventEnvelope, error) { var value EventEnvelope if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["correlation_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "correlation_id", Code: "required"}}} } if raw, ok := fields["event_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "event_id", Code: "required"}}} } if raw, ok := fields["occurred_at"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "occurred_at", Code: "required"}}} } if raw, ok := fields["payload"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "payload", Code: "required"}}} } if raw, ok := fields["resource"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "resource", Code: "required"}}} } if raw, ok := fields["sequence"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "sequence", Code: "required"}}} } if raw, ok := fields["type"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "type", Code: "required"}}} } if raw, ok := fields["version"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "version", Code: "required"}}} } if raw, ok := fields["payload"]; ok && len(raw) > 16384 { return value, ValidationError{Violations: []FieldViolation{{Field: "payload", Code: "max_bytes"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeEventEnvelope(value EventEnvelope) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v EventResume) Validate() error { var violations []FieldViolation if v.Cursor == "" { violations = append(violations, FieldViolation{Field: "cursor", Code: "required"}) } if len(v.Cursor) > 512 { violations = append(violations, FieldViolation{Field: "cursor", Code: "max_length"}) } if v.LastSequence != 0 && v.LastSequence < 0 { violations = append(violations, FieldViolation{Field: "last_sequence", Code: "minimum"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeEventResume(data []byte) (EventResume, error) { var value EventResume if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["cursor"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "cursor", Code: "required"}}} } if raw, ok := fields["last_sequence"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "last_sequence", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeEventResume(value EventResume) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v FieldViolation) Validate() error { var violations []FieldViolation if v.Field == "" { violations = append(violations, FieldViolation{Field: "field", Code: "required"}) } if len(v.Field) < 1 && v.Field != "" { violations = append(violations, FieldViolation{Field: "field", Code: "min_length"}) } if len(v.Field) > 128 { violations = append(violations, FieldViolation{Field: "field", Code: "max_length"}) } if v.Code == "" { violations = append(violations, FieldViolation{Field: "code", Code: "required"}) } if len(v.Code) < 1 && v.Code != "" { violations = append(violations, FieldViolation{Field: "code", Code: "min_length"}) } if len(v.Code) > 64 { violations = append(violations, FieldViolation{Field: "code", Code: "max_length"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeFieldViolation(data []byte) (FieldViolation, error) { var value FieldViolation if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["code"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "code", Code: "required"}}} } if raw, ok := fields["field"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "field", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeFieldViolation(value FieldViolation) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v GatewayClipboardAudit) Validate() error { var violations []FieldViolation if v.Version == "" { violations = append(violations, FieldViolation{Field: "version", Code: "required"}) } if v.Version != "1" && v.Version != "" { violations = append(violations, FieldViolation{Field: "version", Code: "invalid_value"}) } if v.SessionID == "" { violations = append(violations, FieldViolation{Field: "session_id", Code: "required"}) } if len(v.SessionID) < 1 && v.SessionID != "" { violations = append(violations, FieldViolation{Field: "session_id", Code: "min_length"}) } if len(v.SessionID) > 128 { violations = append(violations, FieldViolation{Field: "session_id", Code: "max_length"}) } if v.Direction == "" { violations = append(violations, FieldViolation{Field: "direction", Code: "required"}) } if v.Direction != "" && !(v.Direction == "client_to_provider" || v.Direction == "provider_to_client") { violations = append(violations, FieldViolation{Field: "direction", Code: "invalid_value"}) } if v.Outcome == "" { violations = append(violations, FieldViolation{Field: "outcome", Code: "required"}) } if v.Outcome != "" && !(v.Outcome == "forwarded" || v.Outcome == "suppressed" || v.Outcome == "rejected") { violations = append(violations, FieldViolation{Field: "outcome", Code: "invalid_value"}) } if v.TextBytes != 0 && v.TextBytes < 0 { violations = append(violations, FieldViolation{Field: "text_bytes", Code: "minimum"}) } if v.TextBytes > 65536 { violations = append(violations, FieldViolation{Field: "text_bytes", Code: "maximum"}) } if v.Reason == "" { violations = append(violations, FieldViolation{Field: "reason", Code: "required"}) } if v.Reason != "" && !(v.Reason == "forwarded" || v.Reason == "loop" || v.Reason == "policy" || v.Reason == "rate" || v.Reason == "provider" || v.Reason == "malformed") { violations = append(violations, FieldViolation{Field: "reason", Code: "invalid_value"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeGatewayClipboardAudit(data []byte) (GatewayClipboardAudit, error) { var value GatewayClipboardAudit if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["direction"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "direction", Code: "required"}}} } if raw, ok := fields["outcome"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "outcome", Code: "required"}}} } if raw, ok := fields["reason"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "reason", Code: "required"}}} } if raw, ok := fields["session_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "session_id", Code: "required"}}} } if raw, ok := fields["text_bytes"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "text_bytes", Code: "required"}}} } if raw, ok := fields["version"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "version", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeGatewayClipboardAudit(value GatewayClipboardAudit) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v GatewayClipboardText) Validate() error { var violations []FieldViolation if v.Direction == "" { violations = append(violations, FieldViolation{Field: "direction", Code: "required"}) } if v.Direction != "" && !(v.Direction == "client_to_provider" || v.Direction == "provider_to_client") { violations = append(violations, FieldViolation{Field: "direction", Code: "invalid_value"}) } if v.Text == "" { violations = append(violations, FieldViolation{Field: "text", Code: "required"}) } if len(v.Text) > 65536 { violations = append(violations, FieldViolation{Field: "text", Code: "max_length"}) } if len(v.Text) > 65536 { violations = append(violations, FieldViolation{Field: "text", Code: "max_bytes"}) } if v.Encoding == "" { violations = append(violations, FieldViolation{Field: "encoding", Code: "required"}) } if v.Encoding != "utf-8" && v.Encoding != "" { violations = append(violations, FieldViolation{Field: "encoding", Code: "invalid_value"}) } if v.LoopToken == "" { violations = append(violations, FieldViolation{Field: "loop_token", Code: "required"}) } if len(v.LoopToken) < 16 && v.LoopToken != "" { violations = append(violations, FieldViolation{Field: "loop_token", Code: "min_length"}) } if len(v.LoopToken) > 128 { violations = append(violations, FieldViolation{Field: "loop_token", Code: "max_length"}) } if v.LoopToken != "" { if _, err := base64.RawURLEncoding.Strict().DecodeString(v.LoopToken); err != nil { violations = append(violations, FieldViolation{Field: "loop_token", Code: "invalid_format"}) } } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeGatewayClipboardText(data []byte) (GatewayClipboardText, error) { var value GatewayClipboardText if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["direction"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "direction", Code: "required"}}} } if raw, ok := fields["encoding"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "encoding", Code: "required"}}} } if raw, ok := fields["loop_token"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "loop_token", Code: "required"}}} } if raw, ok := fields["text"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "text", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeGatewayClipboardText(value GatewayClipboardText) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v GatewayDrain) Validate() error { var violations []FieldViolation if v.Version == "" { violations = append(violations, FieldViolation{Field: "version", Code: "required"}) } if v.Version != "1" && v.Version != "" { violations = append(violations, FieldViolation{Field: "version", Code: "invalid_value"}) } if v.GatewayID == "" { violations = append(violations, FieldViolation{Field: "gateway_id", Code: "required"}) } if len(v.GatewayID) < 1 && v.GatewayID != "" { violations = append(violations, FieldViolation{Field: "gateway_id", Code: "min_length"}) } if len(v.GatewayID) > 128 { violations = append(violations, FieldViolation{Field: "gateway_id", Code: "max_length"}) } if v.Sequence == 0 { violations = append(violations, FieldViolation{Field: "sequence", Code: "required"}) } if v.Sequence != 0 && v.Sequence < 1 { violations = append(violations, FieldViolation{Field: "sequence", Code: "minimum"}) } if v.Reason == "" { violations = append(violations, FieldViolation{Field: "reason", Code: "required"}) } if len(v.Reason) < 1 && v.Reason != "" { violations = append(violations, FieldViolation{Field: "reason", Code: "min_length"}) } if len(v.Reason) > 256 { violations = append(violations, FieldViolation{Field: "reason", Code: "max_length"}) } if v.Deadline == "" { violations = append(violations, FieldViolation{Field: "deadline", Code: "required"}) } if len(v.Deadline) > 64 { violations = append(violations, FieldViolation{Field: "deadline", Code: "max_length"}) } if v.Deadline != "" { if parsed, err := time.Parse(time.RFC3339Nano, v.Deadline); err != nil || parsed.UTC().Format(time.RFC3339Nano) != v.Deadline { violations = append(violations, FieldViolation{Field: "deadline", Code: "invalid_time"}) } } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeGatewayDrain(data []byte) (GatewayDrain, error) { var value GatewayDrain if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["deadline"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "deadline", Code: "required"}}} } if raw, ok := fields["gateway_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "gateway_id", Code: "required"}}} } if raw, ok := fields["reason"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "reason", Code: "required"}}} } if raw, ok := fields["sequence"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "sequence", Code: "required"}}} } if raw, ok := fields["version"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "version", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeGatewayDrain(value GatewayDrain) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v GatewayHeartbeat) Validate() error { var violations []FieldViolation if v.Version == "" { violations = append(violations, FieldViolation{Field: "version", Code: "required"}) } if v.Version != "1" && v.Version != "" { violations = append(violations, FieldViolation{Field: "version", Code: "invalid_value"}) } if v.GatewayID == "" { violations = append(violations, FieldViolation{Field: "gateway_id", Code: "required"}) } if len(v.GatewayID) < 1 && v.GatewayID != "" { violations = append(violations, FieldViolation{Field: "gateway_id", Code: "min_length"}) } if len(v.GatewayID) > 128 { violations = append(violations, FieldViolation{Field: "gateway_id", Code: "max_length"}) } if v.Sequence == 0 { violations = append(violations, FieldViolation{Field: "sequence", Code: "required"}) } if v.Sequence != 0 && v.Sequence < 1 { violations = append(violations, FieldViolation{Field: "sequence", Code: "minimum"}) } if v.ObservedAt == "" { violations = append(violations, FieldViolation{Field: "observed_at", Code: "required"}) } if len(v.ObservedAt) > 64 { violations = append(violations, FieldViolation{Field: "observed_at", Code: "max_length"}) } if v.ObservedAt != "" { if parsed, err := time.Parse(time.RFC3339Nano, v.ObservedAt); err != nil || parsed.UTC().Format(time.RFC3339Nano) != v.ObservedAt { violations = append(violations, FieldViolation{Field: "observed_at", Code: "invalid_time"}) } } if v.ActiveConnections != 0 && v.ActiveConnections < 0 { violations = append(violations, FieldViolation{Field: "active_connections", Code: "minimum"}) } if v.ActiveConnections > 1000000 { violations = append(violations, FieldViolation{Field: "active_connections", Code: "maximum"}) } if v.EgressKbps != 0 && v.EgressKbps < 0 { violations = append(violations, FieldViolation{Field: "egress_kbps", Code: "minimum"}) } if v.EgressKbps > 1000000000 { violations = append(violations, FieldViolation{Field: "egress_kbps", Code: "maximum"}) } if v.State == "" { violations = append(violations, FieldViolation{Field: "state", Code: "required"}) } if v.State != "" && !(v.State == "ready" || v.State == "draining" || v.State == "offline") { violations = append(violations, FieldViolation{Field: "state", Code: "invalid_value"}) } if reflect.DeepEqual(v.Telemetry, GatewayTelemetry{}) { violations = append(violations, FieldViolation{Field: "telemetry", Code: "required"}) } if err := v.Telemetry.Validate(); err != nil { violations = append(violations, FieldViolation{Field: "telemetry", Code: "invalid_object"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeGatewayHeartbeat(data []byte) (GatewayHeartbeat, error) { var value GatewayHeartbeat if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["active_connections"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "active_connections", Code: "required"}}} } if raw, ok := fields["egress_kbps"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "egress_kbps", Code: "required"}}} } if raw, ok := fields["gateway_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "gateway_id", Code: "required"}}} } if raw, ok := fields["observed_at"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "observed_at", Code: "required"}}} } if raw, ok := fields["sequence"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "sequence", Code: "required"}}} } if raw, ok := fields["state"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "state", Code: "required"}}} } if raw, ok := fields["telemetry"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "telemetry", Code: "required"}}} } if raw, ok := fields["version"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "version", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeGatewayHeartbeat(value GatewayHeartbeat) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v GatewayQualityAck) Validate() error { var violations []FieldViolation if v.Version == "" { violations = append(violations, FieldViolation{Field: "version", Code: "required"}) } if v.Version != "1" && v.Version != "" { violations = append(violations, FieldViolation{Field: "version", Code: "invalid_value"}) } if v.SessionID == "" { violations = append(violations, FieldViolation{Field: "session_id", Code: "required"}) } if len(v.SessionID) < 1 && v.SessionID != "" { violations = append(violations, FieldViolation{Field: "session_id", Code: "min_length"}) } if len(v.SessionID) > 128 { violations = append(violations, FieldViolation{Field: "session_id", Code: "max_length"}) } if v.GatewayID == "" { violations = append(violations, FieldViolation{Field: "gateway_id", Code: "required"}) } if len(v.GatewayID) < 1 && v.GatewayID != "" { violations = append(violations, FieldViolation{Field: "gateway_id", Code: "min_length"}) } if len(v.GatewayID) > 128 { violations = append(violations, FieldViolation{Field: "gateway_id", Code: "max_length"}) } if v.ReconnectSequence != 0 && v.ReconnectSequence < 0 { violations = append(violations, FieldViolation{Field: "reconnect_sequence", Code: "minimum"}) } if v.OperationID == "" { violations = append(violations, FieldViolation{Field: "operation_id", Code: "required"}) } if len(v.OperationID) < 36 && v.OperationID != "" { violations = append(violations, FieldViolation{Field: "operation_id", Code: "min_length"}) } if len(v.OperationID) > 36 { violations = append(violations, FieldViolation{Field: "operation_id", Code: "max_length"}) } if v.OperationID != "" && !validCanonicalUUID(v.OperationID) { violations = append(violations, FieldViolation{Field: "operation_id", Code: "invalid_uuid"}) } if v.Revision == 0 { violations = append(violations, FieldViolation{Field: "revision", Code: "required"}) } if v.Revision != 0 && v.Revision < 1 { violations = append(violations, FieldViolation{Field: "revision", Code: "minimum"}) } if v.LeaseGeneration == 0 { violations = append(violations, FieldViolation{Field: "lease_generation", Code: "required"}) } if v.LeaseGeneration != 0 && v.LeaseGeneration < 1 { violations = append(violations, FieldViolation{Field: "lease_generation", Code: "minimum"}) } if v.Outcome == "" { violations = append(violations, FieldViolation{Field: "outcome", Code: "required"}) } if v.Outcome != "" && !(v.Outcome == "applied" || v.Outcome == "proven_prior" || v.Outcome == "unknown") { violations = append(violations, FieldViolation{Field: "outcome", Code: "invalid_value"}) } if v.CurrentAppliedRevision != nil && *v.CurrentAppliedRevision != 0 && *v.CurrentAppliedRevision < 0 { violations = append(violations, FieldViolation{Field: "current_applied_revision", Code: "minimum"}) } if len(v.FailureCode) < 1 && v.FailureCode != "" { violations = append(violations, FieldViolation{Field: "failure_code", Code: "min_length"}) } if len(v.FailureCode) > 128 { violations = append(violations, FieldViolation{Field: "failure_code", Code: "max_length"}) } if v.Outcome == "applied" && (v.CurrentAppliedRevision == nil || *v.CurrentAppliedRevision != v.Revision) { violations = append(violations, FieldViolation{Field: "current_applied_revision", Code: "invalid_tagged_value"}) } if v.Outcome == "proven_prior" && (v.CurrentAppliedRevision == nil || *v.CurrentAppliedRevision >= v.Revision) { violations = append(violations, FieldViolation{Field: "current_applied_revision", Code: "invalid_tagged_value"}) } if v.Outcome == "unknown" && v.CurrentAppliedRevision != nil { violations = append(violations, FieldViolation{Field: "current_applied_revision", Code: "invalid_tagged_value"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeGatewayQualityAck(data []byte) (GatewayQualityAck, error) { var value GatewayQualityAck if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["gateway_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "gateway_id", Code: "required"}}} } if raw, ok := fields["lease_generation"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "lease_generation", Code: "required"}}} } if raw, ok := fields["operation_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "operation_id", Code: "required"}}} } if raw, ok := fields["outcome"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "outcome", Code: "required"}}} } if raw, ok := fields["reconnect_sequence"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "reconnect_sequence", Code: "required"}}} } if raw, ok := fields["revision"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "revision", Code: "required"}}} } if raw, ok := fields["session_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "session_id", Code: "required"}}} } if raw, ok := fields["version"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "version", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeGatewayQualityAck(value GatewayQualityAck) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v GatewayQualityWork) Validate() error { var violations []FieldViolation if v.Version == "" { violations = append(violations, FieldViolation{Field: "version", Code: "required"}) } if v.Version != "1" && v.Version != "" { violations = append(violations, FieldViolation{Field: "version", Code: "invalid_value"}) } if v.SessionID == "" { violations = append(violations, FieldViolation{Field: "session_id", Code: "required"}) } if len(v.SessionID) < 1 && v.SessionID != "" { violations = append(violations, FieldViolation{Field: "session_id", Code: "min_length"}) } if len(v.SessionID) > 128 { violations = append(violations, FieldViolation{Field: "session_id", Code: "max_length"}) } if v.GatewayID == "" { violations = append(violations, FieldViolation{Field: "gateway_id", Code: "required"}) } if len(v.GatewayID) < 1 && v.GatewayID != "" { violations = append(violations, FieldViolation{Field: "gateway_id", Code: "min_length"}) } if len(v.GatewayID) > 128 { violations = append(violations, FieldViolation{Field: "gateway_id", Code: "max_length"}) } if v.ReconnectSequence != 0 && v.ReconnectSequence < 0 { violations = append(violations, FieldViolation{Field: "reconnect_sequence", Code: "minimum"}) } if v.OperationID == "" { violations = append(violations, FieldViolation{Field: "operation_id", Code: "required"}) } if len(v.OperationID) < 36 && v.OperationID != "" { violations = append(violations, FieldViolation{Field: "operation_id", Code: "min_length"}) } if len(v.OperationID) > 36 { violations = append(violations, FieldViolation{Field: "operation_id", Code: "max_length"}) } if v.OperationID != "" && !validCanonicalUUID(v.OperationID) { violations = append(violations, FieldViolation{Field: "operation_id", Code: "invalid_uuid"}) } if v.Revision == 0 { violations = append(violations, FieldViolation{Field: "revision", Code: "required"}) } if v.Revision != 0 && v.Revision < 1 { violations = append(violations, FieldViolation{Field: "revision", Code: "minimum"}) } if v.LeaseGeneration == 0 { violations = append(violations, FieldViolation{Field: "lease_generation", Code: "required"}) } if v.LeaseGeneration != 0 && v.LeaseGeneration < 1 { violations = append(violations, FieldViolation{Field: "lease_generation", Code: "minimum"}) } if v.LeaseExpiresAt == "" { violations = append(violations, FieldViolation{Field: "lease_expires_at", Code: "required"}) } if len(v.LeaseExpiresAt) > 64 { violations = append(violations, FieldViolation{Field: "lease_expires_at", Code: "max_length"}) } if v.LeaseExpiresAt != "" { if parsed, err := time.Parse(time.RFC3339Nano, v.LeaseExpiresAt); err != nil || parsed.UTC().Format(time.RFC3339Nano) != v.LeaseExpiresAt { violations = append(violations, FieldViolation{Field: "lease_expires_at", Code: "invalid_time"}) } } if reflect.DeepEqual(v.SelectedDescriptor, SelectedSessionDescriptor{}) { violations = append(violations, FieldViolation{Field: "selected_descriptor", Code: "required"}) } if err := v.SelectedDescriptor.Validate(); err != nil { violations = append(violations, FieldViolation{Field: "selected_descriptor", Code: "invalid_object"}) } if v.CurrentAppliedRevision != nil && *v.CurrentAppliedRevision != 0 && *v.CurrentAppliedRevision < 0 { violations = append(violations, FieldViolation{Field: "current_applied_revision", Code: "minimum"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeGatewayQualityWork(data []byte) (GatewayQualityWork, error) { var value GatewayQualityWork if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["gateway_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "gateway_id", Code: "required"}}} } if raw, ok := fields["lease_expires_at"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "lease_expires_at", Code: "required"}}} } if raw, ok := fields["lease_generation"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "lease_generation", Code: "required"}}} } if raw, ok := fields["operation_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "operation_id", Code: "required"}}} } if raw, ok := fields["reconnect_sequence"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "reconnect_sequence", Code: "required"}}} } if raw, ok := fields["revision"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "revision", Code: "required"}}} } if raw, ok := fields["selected_descriptor"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "selected_descriptor", Code: "required"}}} } if raw, ok := fields["session_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "session_id", Code: "required"}}} } if raw, ok := fields["version"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "version", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeGatewayQualityWork(value GatewayQualityWork) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v GatewayQualityWorkRequest) Validate() error { var violations []FieldViolation if v.Version == "" { violations = append(violations, FieldViolation{Field: "version", Code: "required"}) } if v.Version != "1" && v.Version != "" { violations = append(violations, FieldViolation{Field: "version", Code: "invalid_value"}) } if v.SessionID == "" { violations = append(violations, FieldViolation{Field: "session_id", Code: "required"}) } if len(v.SessionID) < 1 && v.SessionID != "" { violations = append(violations, FieldViolation{Field: "session_id", Code: "min_length"}) } if len(v.SessionID) > 128 { violations = append(violations, FieldViolation{Field: "session_id", Code: "max_length"}) } if v.GatewayID == "" { violations = append(violations, FieldViolation{Field: "gateway_id", Code: "required"}) } if len(v.GatewayID) < 1 && v.GatewayID != "" { violations = append(violations, FieldViolation{Field: "gateway_id", Code: "min_length"}) } if len(v.GatewayID) > 128 { violations = append(violations, FieldViolation{Field: "gateway_id", Code: "max_length"}) } if v.ReconnectSequence != 0 && v.ReconnectSequence < 0 { violations = append(violations, FieldViolation{Field: "reconnect_sequence", Code: "minimum"}) } if v.Acquisition == "" { violations = append(violations, FieldViolation{Field: "acquisition", Code: "required"}) } if v.Acquisition != "" && !(v.Acquisition == "poll" || v.Acquisition == "prompt" || v.Acquisition == "observation") { violations = append(violations, FieldViolation{Field: "acquisition", Code: "invalid_value"}) } if len(v.OperationID) < 36 && v.OperationID != "" { violations = append(violations, FieldViolation{Field: "operation_id", Code: "min_length"}) } if len(v.OperationID) > 36 { violations = append(violations, FieldViolation{Field: "operation_id", Code: "max_length"}) } if v.OperationID != "" && !validCanonicalUUID(v.OperationID) { violations = append(violations, FieldViolation{Field: "operation_id", Code: "invalid_uuid"}) } if v.Revision != nil && *v.Revision != 0 && *v.Revision < 1 { violations = append(violations, FieldViolation{Field: "revision", Code: "minimum"}) } if v.LeaseGeneration != nil && *v.LeaseGeneration != 0 && *v.LeaseGeneration < 1 { violations = append(violations, FieldViolation{Field: "lease_generation", Code: "minimum"}) } if v.CurrentAppliedRevision != nil && *v.CurrentAppliedRevision != 0 && *v.CurrentAppliedRevision < 0 { violations = append(violations, FieldViolation{Field: "current_applied_revision", Code: "minimum"}) } if v.Acquisition == "poll" && (v.OperationID != "" || v.Revision != nil || v.LeaseGeneration != nil || v.CurrentAppliedRevision != nil) { violations = append(violations, FieldViolation{Field: "acquisition", Code: "invalid_tagged_value"}) } if v.Acquisition == "prompt" && (v.OperationID == "" || v.Revision == nil || v.LeaseGeneration != nil || v.CurrentAppliedRevision != nil) { violations = append(violations, FieldViolation{Field: "acquisition", Code: "invalid_tagged_value"}) } if v.Acquisition == "observation" && (v.OperationID == "" || v.Revision == nil || v.LeaseGeneration == nil || v.CurrentAppliedRevision == nil) { violations = append(violations, FieldViolation{Field: "acquisition", Code: "invalid_tagged_value"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeGatewayQualityWorkRequest(data []byte) (GatewayQualityWorkRequest, error) { var value GatewayQualityWorkRequest if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["acquisition"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "acquisition", Code: "required"}}} } if raw, ok := fields["gateway_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "gateway_id", Code: "required"}}} } if raw, ok := fields["reconnect_sequence"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "reconnect_sequence", Code: "required"}}} } if raw, ok := fields["session_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "session_id", Code: "required"}}} } if raw, ok := fields["version"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "version", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeGatewayQualityWorkRequest(value GatewayQualityWorkRequest) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v GatewayRegistration) Validate() error { var violations []FieldViolation if v.Version == "" { violations = append(violations, FieldViolation{Field: "version", Code: "required"}) } if v.Version != "1" && v.Version != "" { violations = append(violations, FieldViolation{Field: "version", Code: "invalid_value"}) } if v.GatewayID == "" { violations = append(violations, FieldViolation{Field: "gateway_id", Code: "required"}) } if len(v.GatewayID) < 1 && v.GatewayID != "" { violations = append(violations, FieldViolation{Field: "gateway_id", Code: "min_length"}) } if len(v.GatewayID) > 128 { violations = append(violations, FieldViolation{Field: "gateway_id", Code: "max_length"}) } if v.InstanceIdentity == "" { violations = append(violations, FieldViolation{Field: "instance_identity", Code: "required"}) } if len(v.InstanceIdentity) < 1 && v.InstanceIdentity != "" { violations = append(violations, FieldViolation{Field: "instance_identity", Code: "min_length"}) } if len(v.InstanceIdentity) > 512 { violations = append(violations, FieldViolation{Field: "instance_identity", Code: "max_length"}) } if v.CertificateIdentity == "" { violations = append(violations, FieldViolation{Field: "certificate_identity", Code: "required"}) } if len(v.CertificateIdentity) < 1 && v.CertificateIdentity != "" { violations = append(violations, FieldViolation{Field: "certificate_identity", Code: "min_length"}) } if len(v.CertificateIdentity) > 512 { violations = append(violations, FieldViolation{Field: "certificate_identity", Code: "max_length"}) } if v.PublicIdentity == "" { violations = append(violations, FieldViolation{Field: "public_identity", Code: "required"}) } if len(v.PublicIdentity) < 1 && v.PublicIdentity != "" { violations = append(violations, FieldViolation{Field: "public_identity", Code: "min_length"}) } if len(v.PublicIdentity) > 256 { violations = append(violations, FieldViolation{Field: "public_identity", Code: "max_length"}) } if v.Address == "" { violations = append(violations, FieldViolation{Field: "address", Code: "required"}) } if len(v.Address) < 1 && v.Address != "" { violations = append(violations, FieldViolation{Field: "address", Code: "min_length"}) } if len(v.Address) > 256 { violations = append(violations, FieldViolation{Field: "address", Code: "max_length"}) } if v.ProviderIdentity == "" { violations = append(violations, FieldViolation{Field: "provider_identity", Code: "required"}) } if len(v.ProviderIdentity) < 1 && v.ProviderIdentity != "" { violations = append(violations, FieldViolation{Field: "provider_identity", Code: "min_length"}) } if len(v.ProviderIdentity) > 256 { violations = append(violations, FieldViolation{Field: "provider_identity", Code: "max_length"}) } if v.ProtocolMinVersion == 0 { violations = append(violations, FieldViolation{Field: "protocol_min_version", Code: "required"}) } if v.ProtocolMinVersion != 0 && v.ProtocolMinVersion < 1 { violations = append(violations, FieldViolation{Field: "protocol_min_version", Code: "minimum"}) } if v.ProtocolMinVersion > 100 { violations = append(violations, FieldViolation{Field: "protocol_min_version", Code: "maximum"}) } if v.ProtocolMaxVersion == 0 { violations = append(violations, FieldViolation{Field: "protocol_max_version", Code: "required"}) } if v.ProtocolMaxVersion != 0 && v.ProtocolMaxVersion < 1 { violations = append(violations, FieldViolation{Field: "protocol_max_version", Code: "minimum"}) } if v.ProtocolMaxVersion > 100 { violations = append(violations, FieldViolation{Field: "protocol_max_version", Code: "maximum"}) } if v.ConnectionCapacity == 0 { violations = append(violations, FieldViolation{Field: "connection_capacity", Code: "required"}) } if v.ConnectionCapacity != 0 && v.ConnectionCapacity < 1 { violations = append(violations, FieldViolation{Field: "connection_capacity", Code: "minimum"}) } if v.ConnectionCapacity > 1000000 { violations = append(violations, FieldViolation{Field: "connection_capacity", Code: "maximum"}) } if v.BandwidthCapacityKbps == 0 { violations = append(violations, FieldViolation{Field: "bandwidth_capacity_kbps", Code: "required"}) } if v.BandwidthCapacityKbps != 0 && v.BandwidthCapacityKbps < 1 { violations = append(violations, FieldViolation{Field: "bandwidth_capacity_kbps", Code: "minimum"}) } if v.BandwidthCapacityKbps > 1000000000 { violations = append(violations, FieldViolation{Field: "bandwidth_capacity_kbps", Code: "maximum"}) } if v.Features == nil { violations = append(violations, FieldViolation{Field: "features", Code: "required"}) } if len(v.Features) > 64 { violations = append(violations, FieldViolation{Field: "features", Code: "max_items"}) } for _, item := range v.Features { if len(item) < 1 { violations = append(violations, FieldViolation{Field: "features", Code: "min_item_length"}) } } for _, item := range v.Features { if len(item) > 64 { violations = append(violations, FieldViolation{Field: "features", Code: "max_item_length"}) } } if reflect.DeepEqual(v.Capabilities, CapabilityProfile{}) { violations = append(violations, FieldViolation{Field: "capabilities", Code: "required"}) } if err := v.Capabilities.Validate(); err != nil { violations = append(violations, FieldViolation{Field: "capabilities", Code: "invalid_object"}) } if v.ProtocolMinVersion > v.ProtocolMaxVersion { violations = append(violations, FieldViolation{Field: "protocol_version", Code: "invalid_order"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeGatewayRegistration(data []byte) (GatewayRegistration, error) { var value GatewayRegistration if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["address"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "address", Code: "required"}}} } if raw, ok := fields["bandwidth_capacity_kbps"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "bandwidth_capacity_kbps", Code: "required"}}} } if raw, ok := fields["capabilities"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "capabilities", Code: "required"}}} } if raw, ok := fields["certificate_identity"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "certificate_identity", Code: "required"}}} } if raw, ok := fields["connection_capacity"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "connection_capacity", Code: "required"}}} } if raw, ok := fields["features"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "features", Code: "required"}}} } if raw, ok := fields["gateway_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "gateway_id", Code: "required"}}} } if raw, ok := fields["instance_identity"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "instance_identity", Code: "required"}}} } if raw, ok := fields["protocol_max_version"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "protocol_max_version", Code: "required"}}} } if raw, ok := fields["protocol_min_version"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "protocol_min_version", Code: "required"}}} } if raw, ok := fields["provider_identity"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "provider_identity", Code: "required"}}} } if raw, ok := fields["public_identity"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "public_identity", Code: "required"}}} } if raw, ok := fields["version"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "version", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeGatewayRegistration(value GatewayRegistration) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v GatewayStopAck) Validate() error { var violations []FieldViolation if v.Version == "" { violations = append(violations, FieldViolation{Field: "version", Code: "required"}) } if v.Version != "1" && v.Version != "" { violations = append(violations, FieldViolation{Field: "version", Code: "invalid_value"}) } if v.SessionID == "" { violations = append(violations, FieldViolation{Field: "session_id", Code: "required"}) } if len(v.SessionID) < 1 && v.SessionID != "" { violations = append(violations, FieldViolation{Field: "session_id", Code: "min_length"}) } if len(v.SessionID) > 128 { violations = append(violations, FieldViolation{Field: "session_id", Code: "max_length"}) } if v.GatewayID == "" { violations = append(violations, FieldViolation{Field: "gateway_id", Code: "required"}) } if len(v.GatewayID) < 1 && v.GatewayID != "" { violations = append(violations, FieldViolation{Field: "gateway_id", Code: "min_length"}) } if len(v.GatewayID) > 128 { violations = append(violations, FieldViolation{Field: "gateway_id", Code: "max_length"}) } if v.ReconnectSequence != 0 && v.ReconnectSequence < 0 { violations = append(violations, FieldViolation{Field: "reconnect_sequence", Code: "minimum"}) } if v.OperationID == "" { violations = append(violations, FieldViolation{Field: "operation_id", Code: "required"}) } if len(v.OperationID) < 36 && v.OperationID != "" { violations = append(violations, FieldViolation{Field: "operation_id", Code: "min_length"}) } if len(v.OperationID) > 36 { violations = append(violations, FieldViolation{Field: "operation_id", Code: "max_length"}) } if v.OperationID != "" && !validCanonicalUUID(v.OperationID) { violations = append(violations, FieldViolation{Field: "operation_id", Code: "invalid_uuid"}) } if v.Outcome == "" { violations = append(violations, FieldViolation{Field: "outcome", Code: "required"}) } if v.Outcome != "" && !(v.Outcome == "applied" || v.Outcome == "failed" || v.Outcome == "termination_unconfirmed") { violations = append(violations, FieldViolation{Field: "outcome", Code: "invalid_value"}) } if len(v.FailureCode) < 1 && v.FailureCode != "" { violations = append(violations, FieldViolation{Field: "failure_code", Code: "min_length"}) } if len(v.FailureCode) > 128 { violations = append(violations, FieldViolation{Field: "failure_code", Code: "max_length"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeGatewayStopAck(data []byte) (GatewayStopAck, error) { var value GatewayStopAck if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["gateway_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "gateway_id", Code: "required"}}} } if raw, ok := fields["operation_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "operation_id", Code: "required"}}} } if raw, ok := fields["outcome"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "outcome", Code: "required"}}} } if raw, ok := fields["reconnect_sequence"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "reconnect_sequence", Code: "required"}}} } if raw, ok := fields["session_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "session_id", Code: "required"}}} } if raw, ok := fields["version"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "version", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeGatewayStopAck(value GatewayStopAck) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v GatewayStopWork) Validate() error { var violations []FieldViolation if v.Version == "" { violations = append(violations, FieldViolation{Field: "version", Code: "required"}) } if v.Version != "1" && v.Version != "" { violations = append(violations, FieldViolation{Field: "version", Code: "invalid_value"}) } if v.SessionID == "" { violations = append(violations, FieldViolation{Field: "session_id", Code: "required"}) } if len(v.SessionID) < 1 && v.SessionID != "" { violations = append(violations, FieldViolation{Field: "session_id", Code: "min_length"}) } if len(v.SessionID) > 128 { violations = append(violations, FieldViolation{Field: "session_id", Code: "max_length"}) } if v.GatewayID == "" { violations = append(violations, FieldViolation{Field: "gateway_id", Code: "required"}) } if len(v.GatewayID) < 1 && v.GatewayID != "" { violations = append(violations, FieldViolation{Field: "gateway_id", Code: "min_length"}) } if len(v.GatewayID) > 128 { violations = append(violations, FieldViolation{Field: "gateway_id", Code: "max_length"}) } if v.ReconnectSequence != 0 && v.ReconnectSequence < 0 { violations = append(violations, FieldViolation{Field: "reconnect_sequence", Code: "minimum"}) } if v.OperationID == "" { violations = append(violations, FieldViolation{Field: "operation_id", Code: "required"}) } if len(v.OperationID) < 36 && v.OperationID != "" { violations = append(violations, FieldViolation{Field: "operation_id", Code: "min_length"}) } if len(v.OperationID) > 36 { violations = append(violations, FieldViolation{Field: "operation_id", Code: "max_length"}) } if v.OperationID != "" && !validCanonicalUUID(v.OperationID) { violations = append(violations, FieldViolation{Field: "operation_id", Code: "invalid_uuid"}) } if v.Attempt == 0 { violations = append(violations, FieldViolation{Field: "attempt", Code: "required"}) } if v.Attempt != 0 && v.Attempt < 1 { violations = append(violations, FieldViolation{Field: "attempt", Code: "minimum"}) } if v.Attempt > 1 { violations = append(violations, FieldViolation{Field: "attempt", Code: "maximum"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeGatewayStopWork(data []byte) (GatewayStopWork, error) { var value GatewayStopWork if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["attempt"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "attempt", Code: "required"}}} } if raw, ok := fields["gateway_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "gateway_id", Code: "required"}}} } if raw, ok := fields["operation_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "operation_id", Code: "required"}}} } if raw, ok := fields["reconnect_sequence"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "reconnect_sequence", Code: "required"}}} } if raw, ok := fields["session_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "session_id", Code: "required"}}} } if raw, ok := fields["version"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "version", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeGatewayStopWork(value GatewayStopWork) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v GatewayStopWorkRequest) Validate() error { var violations []FieldViolation if v.Version == "" { violations = append(violations, FieldViolation{Field: "version", Code: "required"}) } if v.Version != "1" && v.Version != "" { violations = append(violations, FieldViolation{Field: "version", Code: "invalid_value"}) } if v.SessionID == "" { violations = append(violations, FieldViolation{Field: "session_id", Code: "required"}) } if len(v.SessionID) < 1 && v.SessionID != "" { violations = append(violations, FieldViolation{Field: "session_id", Code: "min_length"}) } if len(v.SessionID) > 128 { violations = append(violations, FieldViolation{Field: "session_id", Code: "max_length"}) } if v.GatewayID == "" { violations = append(violations, FieldViolation{Field: "gateway_id", Code: "required"}) } if len(v.GatewayID) < 1 && v.GatewayID != "" { violations = append(violations, FieldViolation{Field: "gateway_id", Code: "min_length"}) } if len(v.GatewayID) > 128 { violations = append(violations, FieldViolation{Field: "gateway_id", Code: "max_length"}) } if v.ReconnectSequence != 0 && v.ReconnectSequence < 0 { violations = append(violations, FieldViolation{Field: "reconnect_sequence", Code: "minimum"}) } if v.Acquisition == "" { violations = append(violations, FieldViolation{Field: "acquisition", Code: "required"}) } if v.Acquisition != "" && !(v.Acquisition == "poll" || v.Acquisition == "prompt") { violations = append(violations, FieldViolation{Field: "acquisition", Code: "invalid_value"}) } if len(v.OperationID) < 36 && v.OperationID != "" { violations = append(violations, FieldViolation{Field: "operation_id", Code: "min_length"}) } if len(v.OperationID) > 36 { violations = append(violations, FieldViolation{Field: "operation_id", Code: "max_length"}) } if v.OperationID != "" && !validCanonicalUUID(v.OperationID) { violations = append(violations, FieldViolation{Field: "operation_id", Code: "invalid_uuid"}) } if v.Acquisition == "poll" && v.OperationID != "" || v.Acquisition == "prompt" && v.OperationID == "" { violations = append(violations, FieldViolation{Field: "acquisition", Code: "invalid_tagged_value"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeGatewayStopWorkRequest(data []byte) (GatewayStopWorkRequest, error) { var value GatewayStopWorkRequest if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["acquisition"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "acquisition", Code: "required"}}} } if raw, ok := fields["gateway_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "gateway_id", Code: "required"}}} } if raw, ok := fields["reconnect_sequence"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "reconnect_sequence", Code: "required"}}} } if raw, ok := fields["session_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "session_id", Code: "required"}}} } if raw, ok := fields["version"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "version", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeGatewayStopWorkRequest(value GatewayStopWorkRequest) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v GatewayTelemetry) Validate() error { var violations []FieldViolation if v.AdmittedSessions != 0 && v.AdmittedSessions < 0 { violations = append(violations, FieldViolation{Field: "admitted_sessions", Code: "minimum"}) } if v.AdmittedSessions > 9223372036854775807 { violations = append(violations, FieldViolation{Field: "admitted_sessions", Code: "maximum"}) } if v.AdmissionRejects != 0 && v.AdmissionRejects < 0 { violations = append(violations, FieldViolation{Field: "admission_rejects", Code: "minimum"}) } if v.AdmissionRejects > 9223372036854775807 { violations = append(violations, FieldViolation{Field: "admission_rejects", Code: "maximum"}) } if v.Reconnects != 0 && v.Reconnects < 0 { violations = append(violations, FieldViolation{Field: "reconnects", Code: "minimum"}) } if v.Reconnects > 9223372036854775807 { violations = append(violations, FieldViolation{Field: "reconnects", Code: "maximum"}) } if v.DrainTransitions != 0 && v.DrainTransitions < 0 { violations = append(violations, FieldViolation{Field: "drain_transitions", Code: "minimum"}) } if v.DrainTransitions > 9223372036854775807 { violations = append(violations, FieldViolation{Field: "drain_transitions", Code: "maximum"}) } if v.MediaDrops != 0 && v.MediaDrops < 0 { violations = append(violations, FieldViolation{Field: "media_drops", Code: "minimum"}) } if v.MediaDrops > 9223372036854775807 { violations = append(violations, FieldViolation{Field: "media_drops", Code: "maximum"}) } if v.MediaPackets != 0 && v.MediaPackets < 0 { violations = append(violations, FieldViolation{Field: "media_packets", Code: "minimum"}) } if v.MediaPackets > 9223372036854775807 { violations = append(violations, FieldViolation{Field: "media_packets", Code: "maximum"}) } if v.MediaBytes != 0 && v.MediaBytes < 0 { violations = append(violations, FieldViolation{Field: "media_bytes", Code: "minimum"}) } if v.MediaBytes > 9223372036854775807 { violations = append(violations, FieldViolation{Field: "media_bytes", Code: "maximum"}) } if v.QueueDelayMicros != 0 && v.QueueDelayMicros < 0 { violations = append(violations, FieldViolation{Field: "queue_delay_micros", Code: "minimum"}) } if v.QueueDelayMicros > 9223372036854775807 { violations = append(violations, FieldViolation{Field: "queue_delay_micros", Code: "maximum"}) } if v.ProcessingDelayMicros != 0 && v.ProcessingDelayMicros < 0 { violations = append(violations, FieldViolation{Field: "processing_delay_micros", Code: "minimum"}) } if v.ProcessingDelayMicros > 9223372036854775807 { violations = append(violations, FieldViolation{Field: "processing_delay_micros", Code: "maximum"}) } if v.ProcessingSamples != 0 && v.ProcessingSamples < 0 { violations = append(violations, FieldViolation{Field: "processing_samples", Code: "minimum"}) } if v.ProcessingSamples > 9223372036854775807 { violations = append(violations, FieldViolation{Field: "processing_samples", Code: "maximum"}) } if v.PacingDelayMicros != 0 && v.PacingDelayMicros < 0 { violations = append(violations, FieldViolation{Field: "pacing_delay_micros", Code: "minimum"}) } if v.PacingDelayMicros > 9223372036854775807 { violations = append(violations, FieldViolation{Field: "pacing_delay_micros", Code: "maximum"}) } if v.ProviderErrors != 0 && v.ProviderErrors < 0 { violations = append(violations, FieldViolation{Field: "provider_errors", Code: "minimum"}) } if v.ProviderErrors > 9223372036854775807 { violations = append(violations, FieldViolation{Field: "provider_errors", Code: "maximum"}) } if v.InputRejected != 0 && v.InputRejected < 0 { violations = append(violations, FieldViolation{Field: "input_rejected", Code: "minimum"}) } if v.InputRejected > 9223372036854775807 { violations = append(violations, FieldViolation{Field: "input_rejected", Code: "maximum"}) } if v.ControlRttMicros != 0 && v.ControlRttMicros < 0 { violations = append(violations, FieldViolation{Field: "control_rtt_micros", Code: "minimum"}) } if v.ControlRttMicros > 9223372036854775807 { violations = append(violations, FieldViolation{Field: "control_rtt_micros", Code: "maximum"}) } if v.ControlJitterMicros != 0 && v.ControlJitterMicros < 0 { violations = append(violations, FieldViolation{Field: "control_jitter_micros", Code: "minimum"}) } if v.ControlJitterMicros > 9223372036854775807 { violations = append(violations, FieldViolation{Field: "control_jitter_micros", Code: "maximum"}) } if v.ControlLossPpm != 0 && v.ControlLossPpm < 0 { violations = append(violations, FieldViolation{Field: "control_loss_ppm", Code: "minimum"}) } if v.ControlLossPpm > 1000000 { violations = append(violations, FieldViolation{Field: "control_loss_ppm", Code: "maximum"}) } if v.PendingReliable != 0 && v.PendingReliable < 0 { violations = append(violations, FieldViolation{Field: "pending_reliable", Code: "minimum"}) } if v.PendingReliable > 9223372036854775807 { violations = append(violations, FieldViolation{Field: "pending_reliable", Code: "maximum"}) } if v.ProviderState == "" { violations = append(violations, FieldViolation{Field: "provider_state", Code: "required"}) } if v.ProviderState != "" && !(v.ProviderState == "unknown" || v.ProviderState == "starting" || v.ProviderState == "ready" || v.ProviderState == "disconnected" || v.ProviderState == "terminating" || v.ProviderState == "terminated" || v.ProviderState == "cleanup_pending" || v.ProviderState == "failed") { violations = append(violations, FieldViolation{Field: "provider_state", Code: "invalid_value"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeGatewayTelemetry(data []byte) (GatewayTelemetry, error) { var value GatewayTelemetry if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["admission_rejects"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "admission_rejects", Code: "required"}}} } if raw, ok := fields["admitted_sessions"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "admitted_sessions", Code: "required"}}} } if raw, ok := fields["control_jitter_micros"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "control_jitter_micros", Code: "required"}}} } if raw, ok := fields["control_loss_ppm"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "control_loss_ppm", Code: "required"}}} } if raw, ok := fields["control_rtt_micros"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "control_rtt_micros", Code: "required"}}} } if raw, ok := fields["drain_transitions"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "drain_transitions", Code: "required"}}} } if raw, ok := fields["input_rejected"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "input_rejected", Code: "required"}}} } if raw, ok := fields["media_bytes"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "media_bytes", Code: "required"}}} } if raw, ok := fields["media_drops"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "media_drops", Code: "required"}}} } if raw, ok := fields["media_packets"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "media_packets", Code: "required"}}} } if raw, ok := fields["pacing_delay_micros"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "pacing_delay_micros", Code: "required"}}} } if raw, ok := fields["pending_reliable"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "pending_reliable", Code: "required"}}} } if raw, ok := fields["processing_delay_micros"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "processing_delay_micros", Code: "required"}}} } if raw, ok := fields["processing_samples"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "processing_samples", Code: "required"}}} } if raw, ok := fields["provider_errors"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "provider_errors", Code: "required"}}} } if raw, ok := fields["provider_state"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "provider_state", Code: "required"}}} } if raw, ok := fields["queue_delay_micros"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "queue_delay_micros", Code: "required"}}} } if raw, ok := fields["reconnects"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "reconnects", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeGatewayTelemetry(value GatewayTelemetry) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v GrantReference) Validate() error { var violations []FieldViolation if v.OpaqueValue == "" { violations = append(violations, FieldViolation{Field: "opaque_value", Code: "required"}) } if len(v.OpaqueValue) < 43 && v.OpaqueValue != "" { violations = append(violations, FieldViolation{Field: "opaque_value", Code: "min_length"}) } if len(v.OpaqueValue) > 256 { violations = append(violations, FieldViolation{Field: "opaque_value", Code: "max_length"}) } if v.ExpiresAt == "" { violations = append(violations, FieldViolation{Field: "expires_at", Code: "required"}) } if len(v.ExpiresAt) > 64 { violations = append(violations, FieldViolation{Field: "expires_at", Code: "max_length"}) } if v.ExpiresAt != "" { if parsed, err := time.Parse(time.RFC3339Nano, v.ExpiresAt); err != nil || parsed.UTC().Format(time.RFC3339Nano) != v.ExpiresAt { violations = append(violations, FieldViolation{Field: "expires_at", Code: "invalid_time"}) } } if v.Audience == "" { violations = append(violations, FieldViolation{Field: "audience", Code: "required"}) } if len(v.Audience) < 1 && v.Audience != "" { violations = append(violations, FieldViolation{Field: "audience", Code: "min_length"}) } if len(v.Audience) > 128 { violations = append(violations, FieldViolation{Field: "audience", Code: "max_length"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeGrantReference(data []byte) (GrantReference, error) { var value GrantReference if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["audience"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "audience", Code: "required"}}} } if raw, ok := fields["expires_at"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "expires_at", Code: "required"}}} } if raw, ok := fields["opaque_value"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "opaque_value", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeGrantReference(value GrantReference) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v LoginRequest) Validate() error { var violations []FieldViolation if v.Provider != "" && !(v.Provider == "ldap" || v.Provider == "local") { violations = append(violations, FieldViolation{Field: "provider", Code: "invalid_value"}) } if v.Username == "" { violations = append(violations, FieldViolation{Field: "username", Code: "required"}) } if len(v.Username) < 1 && v.Username != "" { violations = append(violations, FieldViolation{Field: "username", Code: "min_length"}) } if len(v.Username) > 256 { violations = append(violations, FieldViolation{Field: "username", Code: "max_length"}) } if v.Password == "" { violations = append(violations, FieldViolation{Field: "password", Code: "required"}) } if len(v.Password) < 1 && v.Password != "" { violations = append(violations, FieldViolation{Field: "password", Code: "min_length"}) } if len(v.Password) > 1024 { violations = append(violations, FieldViolation{Field: "password", Code: "max_length"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeLoginRequest(data []byte) (LoginRequest, error) { var value LoginRequest if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["password"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "password", Code: "required"}}} } if raw, ok := fields["username"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "username", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeLoginRequest(value LoginRequest) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v ManifestBounds) Validate() error { var violations []FieldViolation if v.MinimumKbps == 0 { violations = append(violations, FieldViolation{Field: "minimum_kbps", Code: "required"}) } if v.MinimumKbps != 0 && v.MinimumKbps < 1 { violations = append(violations, FieldViolation{Field: "minimum_kbps", Code: "minimum"}) } if v.MinimumKbps > 100000000 { violations = append(violations, FieldViolation{Field: "minimum_kbps", Code: "maximum"}) } if v.TargetKbps == 0 { violations = append(violations, FieldViolation{Field: "target_kbps", Code: "required"}) } if v.TargetKbps != 0 && v.TargetKbps < 1 { violations = append(violations, FieldViolation{Field: "target_kbps", Code: "minimum"}) } if v.TargetKbps > 100000000 { violations = append(violations, FieldViolation{Field: "target_kbps", Code: "maximum"}) } if v.MaximumKbps == 0 { violations = append(violations, FieldViolation{Field: "maximum_kbps", Code: "required"}) } if v.MaximumKbps != 0 && v.MaximumKbps < 1 { violations = append(violations, FieldViolation{Field: "maximum_kbps", Code: "minimum"}) } if v.MaximumKbps > 100000000 { violations = append(violations, FieldViolation{Field: "maximum_kbps", Code: "maximum"}) } if v.MinimumKbps > v.TargetKbps || v.TargetKbps > v.MaximumKbps { violations = append(violations, FieldViolation{Field: "bounds", Code: "invalid_order"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeManifestBounds(data []byte) (ManifestBounds, error) { var value ManifestBounds if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["maximum_kbps"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "maximum_kbps", Code: "required"}}} } if raw, ok := fields["minimum_kbps"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "minimum_kbps", Code: "required"}}} } if raw, ok := fields["target_kbps"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "target_kbps", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeManifestBounds(value ManifestBounds) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v ManifestGateway) Validate() error { var violations []FieldViolation if v.ID == "" { violations = append(violations, FieldViolation{Field: "id", Code: "required"}) } if len(v.ID) < 1 && v.ID != "" { violations = append(violations, FieldViolation{Field: "id", Code: "min_length"}) } if len(v.ID) > 128 { violations = append(violations, FieldViolation{Field: "id", Code: "max_length"}) } if v.Addresses == nil { violations = append(violations, FieldViolation{Field: "addresses", Code: "required"}) } if len(v.Addresses) < 1 { violations = append(violations, FieldViolation{Field: "addresses", Code: "min_items"}) } if len(v.Addresses) > 4 { violations = append(violations, FieldViolation{Field: "addresses", Code: "max_items"}) } for _, item := range v.Addresses { if len(item) < 1 { violations = append(violations, FieldViolation{Field: "addresses", Code: "min_item_length"}) } } for _, item := range v.Addresses { if len(item) > 256 { violations = append(violations, FieldViolation{Field: "addresses", Code: "max_item_length"}) } } if v.PublicIdentity == "" { violations = append(violations, FieldViolation{Field: "public_identity", Code: "required"}) } if len(v.PublicIdentity) < 1 && v.PublicIdentity != "" { violations = append(violations, FieldViolation{Field: "public_identity", Code: "min_length"}) } if len(v.PublicIdentity) > 256 { violations = append(violations, FieldViolation{Field: "public_identity", Code: "max_length"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeManifestGateway(data []byte) (ManifestGateway, error) { var value ManifestGateway if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["addresses"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "addresses", Code: "required"}}} } if raw, ok := fields["id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "id", Code: "required"}}} } if raw, ok := fields["public_identity"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "public_identity", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeManifestGateway(value ManifestGateway) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v ManifestProfile) Validate() error { var violations []FieldViolation if v.ID == "" { violations = append(violations, FieldViolation{Field: "id", Code: "required"}) } if len(v.ID) < 1 && v.ID != "" { violations = append(violations, FieldViolation{Field: "id", Code: "min_length"}) } if len(v.ID) > 128 { violations = append(violations, FieldViolation{Field: "id", Code: "max_length"}) } if reflect.DeepEqual(v.Bounds, ManifestBounds{}) { violations = append(violations, FieldViolation{Field: "bounds", Code: "required"}) } if err := v.Bounds.Validate(); err != nil { violations = append(violations, FieldViolation{Field: "bounds", Code: "invalid_object"}) } if v.DisplayMode != nil { if err := v.DisplayMode.Validate(); err != nil { violations = append(violations, FieldViolation{Field: "display_mode", Code: "invalid_object"}) } } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeManifestProfile(data []byte) (ManifestProfile, error) { var value ManifestProfile if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["bounds"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "bounds", Code: "required"}}} } if raw, ok := fields["id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "id", Code: "required"}}} } if raw, ok := fields["display_mode"]; ok && bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "display_mode", Code: "invalid_object"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeManifestProfile(value ManifestProfile) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v ManifestTunnel) Validate() error { var violations []FieldViolation if v.Versions == nil { violations = append(violations, FieldViolation{Field: "versions", Code: "required"}) } if len(v.Versions) < 1 { violations = append(violations, FieldViolation{Field: "versions", Code: "min_items"}) } if len(v.Versions) > 4 { violations = append(violations, FieldViolation{Field: "versions", Code: "max_items"}) } for _, item := range v.Versions { if len(item) < 1 { violations = append(violations, FieldViolation{Field: "versions", Code: "min_item_length"}) } } for _, item := range v.Versions { if len(item) > 64 { violations = append(violations, FieldViolation{Field: "versions", Code: "max_item_length"}) } } if v.Features == nil { violations = append(violations, FieldViolation{Field: "features", Code: "required"}) } if len(v.Features) > 32 { violations = append(violations, FieldViolation{Field: "features", Code: "max_items"}) } for _, item := range v.Features { if len(item) < 1 { violations = append(violations, FieldViolation{Field: "features", Code: "min_item_length"}) } } for _, item := range v.Features { if len(item) > 64 { violations = append(violations, FieldViolation{Field: "features", Code: "max_item_length"}) } } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeManifestTunnel(data []byte) (ManifestTunnel, error) { var value ManifestTunnel if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["features"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "features", Code: "required"}}} } if raw, ok := fields["versions"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "versions", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeManifestTunnel(value ManifestTunnel) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v NativeAuthenticatedSession) Validate() error { var violations []FieldViolation if v.Username == "" { violations = append(violations, FieldViolation{Field: "username", Code: "required"}) } if len(v.Username) < 1 && v.Username != "" { violations = append(violations, FieldViolation{Field: "username", Code: "min_length"}) } if len(v.Username) > 256 { violations = append(violations, FieldViolation{Field: "username", Code: "max_length"}) } if v.Provider == "" { violations = append(violations, FieldViolation{Field: "provider", Code: "required"}) } if len(v.Provider) < 1 && v.Provider != "" { violations = append(violations, FieldViolation{Field: "provider", Code: "min_length"}) } if len(v.Provider) > 64 { violations = append(violations, FieldViolation{Field: "provider", Code: "max_length"}) } if v.Roles == nil { violations = append(violations, FieldViolation{Field: "roles", Code: "required"}) } if len(v.Roles) > 16 { violations = append(violations, FieldViolation{Field: "roles", Code: "max_items"}) } for _, item := range v.Roles { if len(item) < 1 { violations = append(violations, FieldViolation{Field: "roles", Code: "min_item_length"}) } } for _, item := range v.Roles { if len(item) > 64 { violations = append(violations, FieldViolation{Field: "roles", Code: "max_item_length"}) } } for _, item := range v.Roles { if len(item) > 64 { violations = append(violations, FieldViolation{Field: "roles", Code: "max_item_bytes"}) } } if v.Role == "" { violations = append(violations, FieldViolation{Field: "role", Code: "required"}) } if v.Role != "" && !(v.Role == "user" || v.Role == "admin") { violations = append(violations, FieldViolation{Field: "role", Code: "invalid_value"}) } if reflect.DeepEqual(v.NativeIdentity, NativeSessionIdentity{}) { violations = append(violations, FieldViolation{Field: "native_identity", Code: "required"}) } if err := v.NativeIdentity.Validate(); err != nil { violations = append(violations, FieldViolation{Field: "native_identity", Code: "invalid_object"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeNativeAuthenticatedSession(data []byte) (NativeAuthenticatedSession, error) { var value NativeAuthenticatedSession if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["native_identity"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "native_identity", Code: "required"}}} } if raw, ok := fields["provider"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "provider", Code: "required"}}} } if raw, ok := fields["role"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "role", Code: "required"}}} } if raw, ok := fields["roles"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "roles", Code: "required"}}} } if raw, ok := fields["username"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "username", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeNativeAuthenticatedSession(value NativeAuthenticatedSession) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v NativeCredential) Validate() error { var violations []FieldViolation if len(v.DeviceID) > 128 { violations = append(violations, FieldViolation{Field: "device_id", Code: "max_length"}) } if v.FamilyID == "" { violations = append(violations, FieldViolation{Field: "family_id", Code: "required"}) } if len(v.FamilyID) < 1 && v.FamilyID != "" { violations = append(violations, FieldViolation{Field: "family_id", Code: "min_length"}) } if len(v.FamilyID) > 128 { violations = append(violations, FieldViolation{Field: "family_id", Code: "max_length"}) } if v.AccessToken == "" { violations = append(violations, FieldViolation{Field: "access_token", Code: "required"}) } if len(v.AccessToken) < 1 && v.AccessToken != "" { violations = append(violations, FieldViolation{Field: "access_token", Code: "min_length"}) } if len(v.AccessToken) > 256 { violations = append(violations, FieldViolation{Field: "access_token", Code: "max_length"}) } if v.RefreshToken == "" { violations = append(violations, FieldViolation{Field: "refresh_token", Code: "required"}) } if len(v.RefreshToken) < 1 && v.RefreshToken != "" { violations = append(violations, FieldViolation{Field: "refresh_token", Code: "min_length"}) } if len(v.RefreshToken) > 256 { violations = append(violations, FieldViolation{Field: "refresh_token", Code: "max_length"}) } if v.ExpiresAt == "" { violations = append(violations, FieldViolation{Field: "expires_at", Code: "required"}) } if len(v.ExpiresAt) > 64 { violations = append(violations, FieldViolation{Field: "expires_at", Code: "max_length"}) } if v.ExpiresAt != "" { if parsed, err := time.Parse(time.RFC3339Nano, v.ExpiresAt); err != nil || parsed.UTC().Format(time.RFC3339Nano) != v.ExpiresAt { violations = append(violations, FieldViolation{Field: "expires_at", Code: "invalid_time"}) } } if len(v.RefreshExpiresAt) > 64 { violations = append(violations, FieldViolation{Field: "refresh_expires_at", Code: "max_length"}) } if v.RefreshExpiresAt != "" { if parsed, err := time.Parse(time.RFC3339Nano, v.RefreshExpiresAt); err != nil || parsed.UTC().Format(time.RFC3339Nano) != v.RefreshExpiresAt { violations = append(violations, FieldViolation{Field: "refresh_expires_at", Code: "invalid_time"}) } } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeNativeCredential(data []byte) (NativeCredential, error) { var value NativeCredential if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["access_token"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "access_token", Code: "required"}}} } if raw, ok := fields["expires_at"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "expires_at", Code: "required"}}} } if raw, ok := fields["family_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "family_id", Code: "required"}}} } if raw, ok := fields["refresh_token"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "refresh_token", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeNativeCredential(value NativeCredential) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v NativeSessionIdentity) Validate() error { var violations []FieldViolation if v.ClientDeviceID == "" { violations = append(violations, FieldViolation{Field: "client_device_id", Code: "required"}) } if len(v.ClientDeviceID) < 1 && v.ClientDeviceID != "" { violations = append(violations, FieldViolation{Field: "client_device_id", Code: "min_length"}) } if len(v.ClientDeviceID) > 128 { violations = append(violations, FieldViolation{Field: "client_device_id", Code: "max_length"}) } if v.DeviceKeyID == "" { violations = append(violations, FieldViolation{Field: "device_key_id", Code: "required"}) } if len(v.DeviceKeyID) < 1 && v.DeviceKeyID != "" { violations = append(violations, FieldViolation{Field: "device_key_id", Code: "min_length"}) } if len(v.DeviceKeyID) > 128 { violations = append(violations, FieldViolation{Field: "device_key_id", Code: "max_length"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeNativeSessionIdentity(data []byte) (NativeSessionIdentity, error) { var value NativeSessionIdentity if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["client_device_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "client_device_id", Code: "required"}}} } if raw, ok := fields["device_key_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "device_key_id", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeNativeSessionIdentity(value NativeSessionIdentity) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v NativeTunnelCredential) Validate() error { var violations []FieldViolation if v.ClientDeviceID == "" { violations = append(violations, FieldViolation{Field: "client_device_id", Code: "required"}) } if len(v.ClientDeviceID) < 1 && v.ClientDeviceID != "" { violations = append(violations, FieldViolation{Field: "client_device_id", Code: "min_length"}) } if len(v.ClientDeviceID) > 128 { violations = append(violations, FieldViolation{Field: "client_device_id", Code: "max_length"}) } if v.DeviceKeyID == "" { violations = append(violations, FieldViolation{Field: "device_key_id", Code: "required"}) } if len(v.DeviceKeyID) < 1 && v.DeviceKeyID != "" { violations = append(violations, FieldViolation{Field: "device_key_id", Code: "min_length"}) } if len(v.DeviceKeyID) > 128 { violations = append(violations, FieldViolation{Field: "device_key_id", Code: "max_length"}) } if v.CertificateChainPem == "" { violations = append(violations, FieldViolation{Field: "certificate_chain_pem", Code: "required"}) } if len(v.CertificateChainPem) < 1 && v.CertificateChainPem != "" { violations = append(violations, FieldViolation{Field: "certificate_chain_pem", Code: "min_length"}) } if len(v.CertificateChainPem) > 65536 { violations = append(violations, FieldViolation{Field: "certificate_chain_pem", Code: "max_length"}) } if v.TrustBundlePem == "" { violations = append(violations, FieldViolation{Field: "trust_bundle_pem", Code: "required"}) } if len(v.TrustBundlePem) < 1 && v.TrustBundlePem != "" { violations = append(violations, FieldViolation{Field: "trust_bundle_pem", Code: "min_length"}) } if len(v.TrustBundlePem) > 65536 { violations = append(violations, FieldViolation{Field: "trust_bundle_pem", Code: "max_length"}) } if v.ExpiresAt == "" { violations = append(violations, FieldViolation{Field: "expires_at", Code: "required"}) } if len(v.ExpiresAt) > 64 { violations = append(violations, FieldViolation{Field: "expires_at", Code: "max_length"}) } if v.ExpiresAt != "" { if parsed, err := time.Parse(time.RFC3339Nano, v.ExpiresAt); err != nil || parsed.UTC().Format(time.RFC3339Nano) != v.ExpiresAt { violations = append(violations, FieldViolation{Field: "expires_at", Code: "invalid_time"}) } } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeNativeTunnelCredential(data []byte) (NativeTunnelCredential, error) { var value NativeTunnelCredential if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["certificate_chain_pem"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "certificate_chain_pem", Code: "required"}}} } if raw, ok := fields["client_device_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "client_device_id", Code: "required"}}} } if raw, ok := fields["device_key_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "device_key_id", Code: "required"}}} } if raw, ok := fields["expires_at"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "expires_at", Code: "required"}}} } if raw, ok := fields["trust_bundle_pem"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "trust_bundle_pem", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeNativeTunnelCredential(value NativeTunnelCredential) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v PageInfo) Validate() error { var violations []FieldViolation if v.Limit == 0 { violations = append(violations, FieldViolation{Field: "limit", Code: "required"}) } if v.Limit != 0 && v.Limit < 1 { violations = append(violations, FieldViolation{Field: "limit", Code: "minimum"}) } if v.Limit > 100 { violations = append(violations, FieldViolation{Field: "limit", Code: "maximum"}) } if v.NextCursor == "" { violations = append(violations, FieldViolation{Field: "next_cursor", Code: "required"}) } if len(v.NextCursor) > 512 { violations = append(violations, FieldViolation{Field: "next_cursor", Code: "max_length"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodePageInfo(data []byte) (PageInfo, error) { var value PageInfo if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["limit"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "limit", Code: "required"}}} } if raw, ok := fields["next_cursor"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "next_cursor", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodePageInfo(value PageInfo) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v ProviderSessionWork) Validate() error { var violations []FieldViolation if v.Version == "" { violations = append(violations, FieldViolation{Field: "version", Code: "required"}) } if v.Version != "1" && v.Version != "" { violations = append(violations, FieldViolation{Field: "version", Code: "invalid_value"}) } if v.SessionID == "" { violations = append(violations, FieldViolation{Field: "session_id", Code: "required"}) } if len(v.SessionID) < 1 && v.SessionID != "" { violations = append(violations, FieldViolation{Field: "session_id", Code: "min_length"}) } if len(v.SessionID) > 128 { violations = append(violations, FieldViolation{Field: "session_id", Code: "max_length"}) } if v.GatewayID == "" { violations = append(violations, FieldViolation{Field: "gateway_id", Code: "required"}) } if len(v.GatewayID) < 1 && v.GatewayID != "" { violations = append(violations, FieldViolation{Field: "gateway_id", Code: "min_length"}) } if len(v.GatewayID) > 128 { violations = append(violations, FieldViolation{Field: "gateway_id", Code: "max_length"}) } if v.ReconnectSequence != 0 && v.ReconnectSequence < 0 { violations = append(violations, FieldViolation{Field: "reconnect_sequence", Code: "minimum"}) } if v.ExpiresAt == "" { violations = append(violations, FieldViolation{Field: "expires_at", Code: "required"}) } if len(v.ExpiresAt) > 64 { violations = append(violations, FieldViolation{Field: "expires_at", Code: "max_length"}) } if v.ExpiresAt != "" { if parsed, err := time.Parse(time.RFC3339Nano, v.ExpiresAt); err != nil || parsed.UTC().Format(time.RFC3339Nano) != v.ExpiresAt { violations = append(violations, FieldViolation{Field: "expires_at", Code: "invalid_time"}) } } if v.ProviderProfile == "" { violations = append(violations, FieldViolation{Field: "provider_profile", Code: "required"}) } if v.ProviderProfile != "apollo" && v.ProviderProfile != "" { violations = append(violations, FieldViolation{Field: "provider_profile", Code: "invalid_value"}) } if v.ProviderIdentity == "" { violations = append(violations, FieldViolation{Field: "provider_identity", Code: "required"}) } if len(v.ProviderIdentity) < 1 && v.ProviderIdentity != "" { violations = append(violations, FieldViolation{Field: "provider_identity", Code: "min_length"}) } if len(v.ProviderIdentity) > 256 { violations = append(violations, FieldViolation{Field: "provider_identity", Code: "max_length"}) } if v.PolicyVersionID == "" { violations = append(violations, FieldViolation{Field: "policy_version_id", Code: "required"}) } if len(v.PolicyVersionID) < 1 && v.PolicyVersionID != "" { violations = append(violations, FieldViolation{Field: "policy_version_id", Code: "min_length"}) } if len(v.PolicyVersionID) > 128 { violations = append(violations, FieldViolation{Field: "policy_version_id", Code: "max_length"}) } if reflect.DeepEqual(v.StreamPolicy, ProviderStreamPolicy{}) { violations = append(violations, FieldViolation{Field: "stream_policy", Code: "required"}) } if err := v.StreamPolicy.Validate(); err != nil { violations = append(violations, FieldViolation{Field: "stream_policy", Code: "invalid_object"}) } if v.ApplicationID == "" { violations = append(violations, FieldViolation{Field: "application_id", Code: "required"}) } if len(v.ApplicationID) < 1 && v.ApplicationID != "" { violations = append(violations, FieldViolation{Field: "application_id", Code: "min_length"}) } if len(v.ApplicationID) > 128 { violations = append(violations, FieldViolation{Field: "application_id", Code: "max_length"}) } if v.ClientID == "" { violations = append(violations, FieldViolation{Field: "client_id", Code: "required"}) } if len(v.ClientID) < 1 && v.ClientID != "" { violations = append(violations, FieldViolation{Field: "client_id", Code: "min_length"}) } if len(v.ClientID) > 128 { violations = append(violations, FieldViolation{Field: "client_id", Code: "max_length"}) } if v.ManagementHost == "" { violations = append(violations, FieldViolation{Field: "management_host", Code: "required"}) } if len(v.ManagementHost) < 1 && v.ManagementHost != "" { violations = append(violations, FieldViolation{Field: "management_host", Code: "min_length"}) } if len(v.ManagementHost) > 256 { violations = append(violations, FieldViolation{Field: "management_host", Code: "max_length"}) } if v.ManagementPort == 0 { violations = append(violations, FieldViolation{Field: "management_port", Code: "required"}) } if v.ManagementPort != 0 && v.ManagementPort < 1 { violations = append(violations, FieldViolation{Field: "management_port", Code: "minimum"}) } if v.ManagementPort > 65535 { violations = append(violations, FieldViolation{Field: "management_port", Code: "maximum"}) } if v.StreamHost == "" { violations = append(violations, FieldViolation{Field: "stream_host", Code: "required"}) } if len(v.StreamHost) < 1 && v.StreamHost != "" { violations = append(violations, FieldViolation{Field: "stream_host", Code: "min_length"}) } if len(v.StreamHost) > 256 { violations = append(violations, FieldViolation{Field: "stream_host", Code: "max_length"}) } if v.StreamPort == 0 { violations = append(violations, FieldViolation{Field: "stream_port", Code: "required"}) } if v.StreamPort != 0 && v.StreamPort < 1 { violations = append(violations, FieldViolation{Field: "stream_port", Code: "minimum"}) } if v.StreamPort > 65535 { violations = append(violations, FieldViolation{Field: "stream_port", Code: "maximum"}) } if v.ClientCertificatePem == "" { violations = append(violations, FieldViolation{Field: "client_certificate_pem", Code: "required"}) } if len(v.ClientCertificatePem) < 1 && v.ClientCertificatePem != "" { violations = append(violations, FieldViolation{Field: "client_certificate_pem", Code: "min_length"}) } if len(v.ClientCertificatePem) > 32768 { violations = append(violations, FieldViolation{Field: "client_certificate_pem", Code: "max_length"}) } if v.ClientPrivateKeyPem == "" { violations = append(violations, FieldViolation{Field: "client_private_key_pem", Code: "required"}) } if len(v.ClientPrivateKeyPem) < 1 && v.ClientPrivateKeyPem != "" { violations = append(violations, FieldViolation{Field: "client_private_key_pem", Code: "min_length"}) } if len(v.ClientPrivateKeyPem) > 32768 { violations = append(violations, FieldViolation{Field: "client_private_key_pem", Code: "max_length"}) } if v.ServerCertificatePem == "" { violations = append(violations, FieldViolation{Field: "server_certificate_pem", Code: "required"}) } if len(v.ServerCertificatePem) < 1 && v.ServerCertificatePem != "" { violations = append(violations, FieldViolation{Field: "server_certificate_pem", Code: "min_length"}) } if len(v.ServerCertificatePem) > 32768 { violations = append(violations, FieldViolation{Field: "server_certificate_pem", Code: "max_length"}) } if reflect.DeepEqual(v.ClipboardPolicy, ClipboardPolicy{}) { violations = append(violations, FieldViolation{Field: "clipboard_policy", Code: "required"}) } if err := v.ClipboardPolicy.Validate(); err != nil { violations = append(violations, FieldViolation{Field: "clipboard_policy", Code: "invalid_object"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeProviderSessionWork(data []byte) (ProviderSessionWork, error) { var value ProviderSessionWork if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["application_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "application_id", Code: "required"}}} } if raw, ok := fields["client_certificate_pem"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "client_certificate_pem", Code: "required"}}} } if raw, ok := fields["client_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "client_id", Code: "required"}}} } if raw, ok := fields["client_private_key_pem"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "client_private_key_pem", Code: "required"}}} } if raw, ok := fields["clipboard_policy"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "clipboard_policy", Code: "required"}}} } if raw, ok := fields["expires_at"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "expires_at", Code: "required"}}} } if raw, ok := fields["gateway_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "gateway_id", Code: "required"}}} } if raw, ok := fields["management_host"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "management_host", Code: "required"}}} } if raw, ok := fields["management_port"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "management_port", Code: "required"}}} } if raw, ok := fields["policy_version_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "policy_version_id", Code: "required"}}} } if raw, ok := fields["provider_application_termination_allowed"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "provider_application_termination_allowed", Code: "required"}}} } if raw, ok := fields["provider_identity"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "provider_identity", Code: "required"}}} } if raw, ok := fields["provider_profile"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "provider_profile", Code: "required"}}} } if raw, ok := fields["reconnect_sequence"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "reconnect_sequence", Code: "required"}}} } if raw, ok := fields["server_certificate_pem"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "server_certificate_pem", Code: "required"}}} } if raw, ok := fields["session_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "session_id", Code: "required"}}} } if raw, ok := fields["stream_host"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "stream_host", Code: "required"}}} } if raw, ok := fields["stream_policy"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "stream_policy", Code: "required"}}} } if raw, ok := fields["stream_port"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "stream_port", Code: "required"}}} } if raw, ok := fields["version"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "version", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeProviderSessionWork(value ProviderSessionWork) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v ProviderState) Validate() error { var violations []FieldViolation if v.Version == "" { violations = append(violations, FieldViolation{Field: "version", Code: "required"}) } if v.Version != "1" && v.Version != "" { violations = append(violations, FieldViolation{Field: "version", Code: "invalid_value"}) } if v.SessionID == "" { violations = append(violations, FieldViolation{Field: "session_id", Code: "required"}) } if len(v.SessionID) < 1 && v.SessionID != "" { violations = append(violations, FieldViolation{Field: "session_id", Code: "min_length"}) } if len(v.SessionID) > 128 { violations = append(violations, FieldViolation{Field: "session_id", Code: "max_length"}) } if v.State == "" { violations = append(violations, FieldViolation{Field: "state", Code: "required"}) } if v.State != "" && !(v.State == "starting" || v.State == "ready" || v.State == "disconnected" || v.State == "terminating" || v.State == "terminated" || v.State == "cleanup_pending" || v.State == "failed") { violations = append(violations, FieldViolation{Field: "state", Code: "invalid_value"}) } if v.Channels == nil { violations = append(violations, FieldViolation{Field: "channels", Code: "required"}) } if len(v.Channels) > 8 { violations = append(violations, FieldViolation{Field: "channels", Code: "max_items"}) } for _, item := range v.Channels { if len(item) < 1 { violations = append(violations, FieldViolation{Field: "channels", Code: "min_item_length"}) } } for _, item := range v.Channels { if len(item) > 64 { violations = append(violations, FieldViolation{Field: "channels", Code: "max_item_length"}) } } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeProviderState(data []byte) (ProviderState, error) { var value ProviderState if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["channels"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "channels", Code: "required"}}} } if raw, ok := fields["cleanup_pending"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "cleanup_pending", Code: "required"}}} } if raw, ok := fields["session_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "session_id", Code: "required"}}} } if raw, ok := fields["state"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "state", Code: "required"}}} } if raw, ok := fields["version"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "version", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeProviderState(value ProviderState) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v ProviderStreamPolicy) Validate() error { var violations []FieldViolation if reflect.DeepEqual(v.VideoProfile, VideoProfile{}) { violations = append(violations, FieldViolation{Field: "video_profile", Code: "required"}) } if err := v.VideoProfile.Validate(); err != nil { violations = append(violations, FieldViolation{Field: "video_profile", Code: "invalid_object"}) } if reflect.DeepEqual(v.AudioProfile, AudioProfile{}) { violations = append(violations, FieldViolation{Field: "audio_profile", Code: "required"}) } if err := v.AudioProfile.Validate(); err != nil { violations = append(violations, FieldViolation{Field: "audio_profile", Code: "invalid_object"}) } if reflect.DeepEqual(v.DisplayMode, DisplayMode{}) { violations = append(violations, FieldViolation{Field: "display_mode", Code: "required"}) } if err := v.DisplayMode.Validate(); err != nil { violations = append(violations, FieldViolation{Field: "display_mode", Code: "invalid_object"}) } if v.BitrateTargetKbps == 0 { violations = append(violations, FieldViolation{Field: "bitrate_target_kbps", Code: "required"}) } if v.BitrateTargetKbps != 0 && v.BitrateTargetKbps < 100 { violations = append(violations, FieldViolation{Field: "bitrate_target_kbps", Code: "minimum"}) } if v.BitrateTargetKbps > 1000000 { violations = append(violations, FieldViolation{Field: "bitrate_target_kbps", Code: "maximum"}) } if v.BitrateMaximumKbps == 0 { violations = append(violations, FieldViolation{Field: "bitrate_maximum_kbps", Code: "required"}) } if v.BitrateMaximumKbps != 0 && v.BitrateMaximumKbps < 100 { violations = append(violations, FieldViolation{Field: "bitrate_maximum_kbps", Code: "minimum"}) } if v.BitrateMaximumKbps > 1000000 { violations = append(violations, FieldViolation{Field: "bitrate_maximum_kbps", Code: "maximum"}) } if v.BitrateTargetKbps > v.BitrateMaximumKbps { violations = append(violations, FieldViolation{Field: "bitrate_bounds", Code: "invalid_order"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeProviderStreamPolicy(data []byte) (ProviderStreamPolicy, error) { var value ProviderStreamPolicy if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["audio_profile"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "audio_profile", Code: "required"}}} } if raw, ok := fields["bitrate_maximum_kbps"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "bitrate_maximum_kbps", Code: "required"}}} } if raw, ok := fields["bitrate_target_kbps"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "bitrate_target_kbps", Code: "required"}}} } if raw, ok := fields["display_mode"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "display_mode", Code: "required"}}} } if raw, ok := fields["video_profile"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "video_profile", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeProviderStreamPolicy(value ProviderStreamPolicy) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v QualityChangeOperation) Validate() error { var violations []FieldViolation if v.OperationID == "" { violations = append(violations, FieldViolation{Field: "operation_id", Code: "required"}) } if len(v.OperationID) < 36 && v.OperationID != "" { violations = append(violations, FieldViolation{Field: "operation_id", Code: "min_length"}) } if len(v.OperationID) > 36 { violations = append(violations, FieldViolation{Field: "operation_id", Code: "max_length"}) } if v.OperationID != "" && !validCanonicalUUID(v.OperationID) { violations = append(violations, FieldViolation{Field: "operation_id", Code: "invalid_uuid"}) } if v.SessionID == "" { violations = append(violations, FieldViolation{Field: "session_id", Code: "required"}) } if len(v.SessionID) < 1 && v.SessionID != "" { violations = append(violations, FieldViolation{Field: "session_id", Code: "min_length"}) } if len(v.SessionID) > 128 { violations = append(violations, FieldViolation{Field: "session_id", Code: "max_length"}) } if v.Revision == 0 { violations = append(violations, FieldViolation{Field: "revision", Code: "required"}) } if v.Revision != 0 && v.Revision < 1 { violations = append(violations, FieldViolation{Field: "revision", Code: "minimum"}) } if v.State == "" { violations = append(violations, FieldViolation{Field: "state", Code: "required"}) } if v.State != "" && !(v.State == "pending" || v.State == "applying" || v.State == "applied" || v.State == "failed" || v.State == "timed_out") { violations = append(violations, FieldViolation{Field: "state", Code: "invalid_value"}) } if reflect.DeepEqual(v.RequestedBitratePreference, BitratePreference{}) { violations = append(violations, FieldViolation{Field: "requested_bitrate_preference", Code: "required"}) } if err := v.RequestedBitratePreference.Validate(); err != nil { violations = append(violations, FieldViolation{Field: "requested_bitrate_preference", Code: "invalid_object"}) } if v.EffectiveBitrateKbps == 0 { violations = append(violations, FieldViolation{Field: "effective_bitrate_kbps", Code: "required"}) } if v.EffectiveBitrateKbps != 0 && v.EffectiveBitrateKbps < 100 { violations = append(violations, FieldViolation{Field: "effective_bitrate_kbps", Code: "minimum"}) } if v.EffectiveBitrateKbps > 1000000 { violations = append(violations, FieldViolation{Field: "effective_bitrate_kbps", Code: "maximum"}) } if v.GoverningPolicyVersion == "" { violations = append(violations, FieldViolation{Field: "governing_policy_version", Code: "required"}) } if len(v.GoverningPolicyVersion) < 1 && v.GoverningPolicyVersion != "" { violations = append(violations, FieldViolation{Field: "governing_policy_version", Code: "min_length"}) } if len(v.GoverningPolicyVersion) > 128 { violations = append(violations, FieldViolation{Field: "governing_policy_version", Code: "max_length"}) } if v.SessionVersion == 0 { violations = append(violations, FieldViolation{Field: "session_version", Code: "required"}) } if v.SessionVersion != 0 && v.SessionVersion < 1 { violations = append(violations, FieldViolation{Field: "session_version", Code: "minimum"}) } if v.CreatedAt == "" { violations = append(violations, FieldViolation{Field: "created_at", Code: "required"}) } if len(v.CreatedAt) > 64 { violations = append(violations, FieldViolation{Field: "created_at", Code: "max_length"}) } if v.CreatedAt != "" { if parsed, err := time.Parse(time.RFC3339Nano, v.CreatedAt); err != nil || parsed.UTC().Format(time.RFC3339Nano) != v.CreatedAt { violations = append(violations, FieldViolation{Field: "created_at", Code: "invalid_time"}) } } if v.DeadlineAt == "" { violations = append(violations, FieldViolation{Field: "deadline_at", Code: "required"}) } if len(v.DeadlineAt) > 64 { violations = append(violations, FieldViolation{Field: "deadline_at", Code: "max_length"}) } if v.DeadlineAt != "" { if parsed, err := time.Parse(time.RFC3339Nano, v.DeadlineAt); err != nil || parsed.UTC().Format(time.RFC3339Nano) != v.DeadlineAt { violations = append(violations, FieldViolation{Field: "deadline_at", Code: "invalid_time"}) } } if v.UpdatedAt == "" { violations = append(violations, FieldViolation{Field: "updated_at", Code: "required"}) } if len(v.UpdatedAt) > 64 { violations = append(violations, FieldViolation{Field: "updated_at", Code: "max_length"}) } if v.UpdatedAt != "" { if parsed, err := time.Parse(time.RFC3339Nano, v.UpdatedAt); err != nil || parsed.UTC().Format(time.RFC3339Nano) != v.UpdatedAt { violations = append(violations, FieldViolation{Field: "updated_at", Code: "invalid_time"}) } } if len(v.FailureCode) < 1 && v.FailureCode != "" { violations = append(violations, FieldViolation{Field: "failure_code", Code: "min_length"}) } if len(v.FailureCode) > 128 { violations = append(violations, FieldViolation{Field: "failure_code", Code: "max_length"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeQualityChangeOperation(data []byte) (QualityChangeOperation, error) { var value QualityChangeOperation if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["created_at"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "created_at", Code: "required"}}} } if raw, ok := fields["deadline_at"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "deadline_at", Code: "required"}}} } if raw, ok := fields["effective_bitrate_kbps"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "effective_bitrate_kbps", Code: "required"}}} } if raw, ok := fields["governing_policy_version"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "governing_policy_version", Code: "required"}}} } if raw, ok := fields["operation_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "operation_id", Code: "required"}}} } if raw, ok := fields["requested_bitrate_preference"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "requested_bitrate_preference", Code: "required"}}} } if raw, ok := fields["revision"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "revision", Code: "required"}}} } if raw, ok := fields["session_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "session_id", Code: "required"}}} } if raw, ok := fields["session_version"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "session_version", Code: "required"}}} } if raw, ok := fields["state"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "state", Code: "required"}}} } if raw, ok := fields["updated_at"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "updated_at", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeQualityChangeOperation(value QualityChangeOperation) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v QualityChangeRequest) Validate() error { var violations []FieldViolation if reflect.DeepEqual(v.BitratePreference, BitratePreference{}) { violations = append(violations, FieldViolation{Field: "bitrate_preference", Code: "required"}) } if err := v.BitratePreference.Validate(); err != nil { violations = append(violations, FieldViolation{Field: "bitrate_preference", Code: "invalid_object"}) } if v.ExpectedSessionVersion == 0 { violations = append(violations, FieldViolation{Field: "expected_session_version", Code: "required"}) } if v.ExpectedSessionVersion != 0 && v.ExpectedSessionVersion < 1 { violations = append(violations, FieldViolation{Field: "expected_session_version", Code: "minimum"}) } if v.ExpectedPolicyVersion == "" { violations = append(violations, FieldViolation{Field: "expected_policy_version", Code: "required"}) } if len(v.ExpectedPolicyVersion) < 1 && v.ExpectedPolicyVersion != "" { violations = append(violations, FieldViolation{Field: "expected_policy_version", Code: "min_length"}) } if len(v.ExpectedPolicyVersion) > 128 { violations = append(violations, FieldViolation{Field: "expected_policy_version", Code: "max_length"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeQualityChangeRequest(data []byte) (QualityChangeRequest, error) { var value QualityChangeRequest if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["bitrate_preference"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "bitrate_preference", Code: "required"}}} } if raw, ok := fields["expected_policy_version"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "expected_policy_version", Code: "required"}}} } if raw, ok := fields["expected_session_version"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "expected_session_version", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeQualityChangeRequest(value QualityChangeRequest) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v ReauthGrant) Validate() error { var violations []FieldViolation if v.Token == "" { violations = append(violations, FieldViolation{Field: "token", Code: "required"}) } if len(v.Token) < 1 && v.Token != "" { violations = append(violations, FieldViolation{Field: "token", Code: "min_length"}) } if len(v.Token) > 256 { violations = append(violations, FieldViolation{Field: "token", Code: "max_length"}) } if v.Purpose == "" { violations = append(violations, FieldViolation{Field: "purpose", Code: "required"}) } if len(v.Purpose) < 1 && v.Purpose != "" { violations = append(violations, FieldViolation{Field: "purpose", Code: "min_length"}) } if len(v.Purpose) > 64 { violations = append(violations, FieldViolation{Field: "purpose", Code: "max_length"}) } if v.ExpiresAt == "" { violations = append(violations, FieldViolation{Field: "expires_at", Code: "required"}) } if len(v.ExpiresAt) > 64 { violations = append(violations, FieldViolation{Field: "expires_at", Code: "max_length"}) } if v.ExpiresAt != "" { if parsed, err := time.Parse(time.RFC3339Nano, v.ExpiresAt); err != nil || parsed.UTC().Format(time.RFC3339Nano) != v.ExpiresAt { violations = append(violations, FieldViolation{Field: "expires_at", Code: "invalid_time"}) } } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeReauthGrant(data []byte) (ReauthGrant, error) { var value ReauthGrant if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["expires_at"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "expires_at", Code: "required"}}} } if raw, ok := fields["purpose"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "purpose", Code: "required"}}} } if raw, ok := fields["token"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "token", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeReauthGrant(value ReauthGrant) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v ReauthRequest) Validate() error { var violations []FieldViolation if v.Password == "" { violations = append(violations, FieldViolation{Field: "password", Code: "required"}) } if len(v.Password) < 1 && v.Password != "" { violations = append(violations, FieldViolation{Field: "password", Code: "min_length"}) } if len(v.Password) > 1024 { violations = append(violations, FieldViolation{Field: "password", Code: "max_length"}) } if v.Purpose == "" { violations = append(violations, FieldViolation{Field: "purpose", Code: "required"}) } if v.Purpose != "" && !(v.Purpose == "identity_change" || v.Purpose == "key_change" || v.Purpose == "backup_enable" || v.Purpose == "external_database_tls_disabled" || v.Purpose == "assignment_change") { violations = append(violations, FieldViolation{Field: "purpose", Code: "invalid_value"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeReauthRequest(data []byte) (ReauthRequest, error) { var value ReauthRequest if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["password"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "password", Code: "required"}}} } if raw, ok := fields["purpose"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "purpose", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeReauthRequest(value ReauthRequest) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v ReconnectRequest) Validate() error { var violations []FieldViolation if v.ClientDeviceID == "" { violations = append(violations, FieldViolation{Field: "client_device_id", Code: "required"}) } if len(v.ClientDeviceID) < 1 && v.ClientDeviceID != "" { violations = append(violations, FieldViolation{Field: "client_device_id", Code: "min_length"}) } if len(v.ClientDeviceID) > 128 { violations = append(violations, FieldViolation{Field: "client_device_id", Code: "max_length"}) } if v.DeviceKeyID == "" { violations = append(violations, FieldViolation{Field: "device_key_id", Code: "required"}) } if len(v.DeviceKeyID) < 1 && v.DeviceKeyID != "" { violations = append(violations, FieldViolation{Field: "device_key_id", Code: "min_length"}) } if len(v.DeviceKeyID) > 128 { violations = append(violations, FieldViolation{Field: "device_key_id", Code: "max_length"}) } if v.ExpectedVersion == 0 { violations = append(violations, FieldViolation{Field: "expected_version", Code: "required"}) } if v.ExpectedVersion != 0 && v.ExpectedVersion < 1 { violations = append(violations, FieldViolation{Field: "expected_version", Code: "minimum"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeReconnectRequest(data []byte) (ReconnectRequest, error) { var value ReconnectRequest if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["client_device_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "client_device_id", Code: "required"}}} } if raw, ok := fields["device_key_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "device_key_id", Code: "required"}}} } if raw, ok := fields["display_relaunch_confirmed"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "display_relaunch_confirmed", Code: "required"}}} } if raw, ok := fields["expected_version"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "expected_version", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeReconnectRequest(value ReconnectRequest) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v RefreshRequest) Validate() error { var violations []FieldViolation if v.FamilyID == "" { violations = append(violations, FieldViolation{Field: "family_id", Code: "required"}) } if len(v.FamilyID) < 1 && v.FamilyID != "" { violations = append(violations, FieldViolation{Field: "family_id", Code: "min_length"}) } if len(v.FamilyID) > 128 { violations = append(violations, FieldViolation{Field: "family_id", Code: "max_length"}) } if v.RefreshToken == "" { violations = append(violations, FieldViolation{Field: "refresh_token", Code: "required"}) } if len(v.RefreshToken) < 1 && v.RefreshToken != "" { violations = append(violations, FieldViolation{Field: "refresh_token", Code: "min_length"}) } if len(v.RefreshToken) > 256 { violations = append(violations, FieldViolation{Field: "refresh_token", Code: "max_length"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeRefreshRequest(data []byte) (RefreshRequest, error) { var value RefreshRequest if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["family_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "family_id", Code: "required"}}} } if raw, ok := fields["refresh_token"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "refresh_token", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeRefreshRequest(value RefreshRequest) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v Resource) Validate() error { var violations []FieldViolation if v.ID == "" { violations = append(violations, FieldViolation{Field: "id", Code: "required"}) } if len(v.ID) < 1 && v.ID != "" { violations = append(violations, FieldViolation{Field: "id", Code: "min_length"}) } if len(v.ID) > 128 { violations = append(violations, FieldViolation{Field: "id", Code: "max_length"}) } if v.Kind == "" { violations = append(violations, FieldViolation{Field: "kind", Code: "required"}) } if len(v.Kind) < 1 && v.Kind != "" { violations = append(violations, FieldViolation{Field: "kind", Code: "min_length"}) } if len(v.Kind) > 64 { violations = append(violations, FieldViolation{Field: "kind", Code: "max_length"}) } if v.Name == "" { violations = append(violations, FieldViolation{Field: "name", Code: "required"}) } if len(v.Name) < 1 && v.Name != "" { violations = append(violations, FieldViolation{Field: "name", Code: "min_length"}) } if len(v.Name) > 256 { violations = append(violations, FieldViolation{Field: "name", Code: "max_length"}) } if v.State == "" { violations = append(violations, FieldViolation{Field: "state", Code: "required"}) } if len(v.State) < 1 && v.State != "" { violations = append(violations, FieldViolation{Field: "state", Code: "min_length"}) } if len(v.State) > 64 { violations = append(violations, FieldViolation{Field: "state", Code: "max_length"}) } if len(v.AssignmentState) > 64 { violations = append(violations, FieldViolation{Field: "assignment_state", Code: "max_length"}) } if v.Version == 0 { violations = append(violations, FieldViolation{Field: "version", Code: "required"}) } if v.Version != 0 && v.Version < 1 { violations = append(violations, FieldViolation{Field: "version", Code: "minimum"}) } if v.Links == nil { violations = append(violations, FieldViolation{Field: "links", Code: "required"}) } if len(v.Links) > 16 { violations = append(violations, FieldViolation{Field: "links", Code: "max_items"}) } for index := range v.Links { if err := v.Links[index].Validate(); err != nil { violations = append(violations, FieldViolation{Field: fmt.Sprintf("links[%d]", index), Code: "invalid_item"}) } } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeResource(data []byte) (Resource, error) { var value Resource if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "id", Code: "required"}}} } if raw, ok := fields["kind"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "kind", Code: "required"}}} } if raw, ok := fields["links"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "links", Code: "required"}}} } if raw, ok := fields["name"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "name", Code: "required"}}} } if raw, ok := fields["state"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "state", Code: "required"}}} } if raw, ok := fields["version"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "version", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeResource(value Resource) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v ResourceLink) Validate() error { var violations []FieldViolation if v.Type == "" { violations = append(violations, FieldViolation{Field: "type", Code: "required"}) } if len(v.Type) < 1 && v.Type != "" { violations = append(violations, FieldViolation{Field: "type", Code: "min_length"}) } if len(v.Type) > 64 { violations = append(violations, FieldViolation{Field: "type", Code: "max_length"}) } if v.ID == "" { violations = append(violations, FieldViolation{Field: "id", Code: "required"}) } if len(v.ID) < 1 && v.ID != "" { violations = append(violations, FieldViolation{Field: "id", Code: "min_length"}) } if len(v.ID) > 128 { violations = append(violations, FieldViolation{Field: "id", Code: "max_length"}) } if v.Version == 0 { violations = append(violations, FieldViolation{Field: "version", Code: "required"}) } if v.Version != 0 && v.Version < 1 { violations = append(violations, FieldViolation{Field: "version", Code: "minimum"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeResourceLink(data []byte) (ResourceLink, error) { var value ResourceLink if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "id", Code: "required"}}} } if raw, ok := fields["type"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "type", Code: "required"}}} } if raw, ok := fields["version"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "version", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeResourceLink(value ResourceLink) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v ResourceList) Validate() error { var violations []FieldViolation if v.AssignedDesktops == nil { violations = append(violations, FieldViolation{Field: "assigned_desktops", Code: "required"}) } if len(v.AssignedDesktops) > 100 { violations = append(violations, FieldViolation{Field: "assigned_desktops", Code: "max_items"}) } for index := range v.AssignedDesktops { if err := v.AssignedDesktops[index].Validate(); err != nil { violations = append(violations, FieldViolation{Field: fmt.Sprintf("assigned_desktops[%d]", index), Code: "invalid_item"}) } } if v.EntitledPools == nil { violations = append(violations, FieldViolation{Field: "entitled_pools", Code: "required"}) } if len(v.EntitledPools) > 100 { violations = append(violations, FieldViolation{Field: "entitled_pools", Code: "max_items"}) } for index := range v.EntitledPools { if err := v.EntitledPools[index].Validate(); err != nil { violations = append(violations, FieldViolation{Field: fmt.Sprintf("entitled_pools[%d]", index), Code: "invalid_item"}) } } if reflect.DeepEqual(v.Page, PageInfo{}) { violations = append(violations, FieldViolation{Field: "page", Code: "required"}) } if err := v.Page.Validate(); err != nil { violations = append(violations, FieldViolation{Field: "page", Code: "invalid_object"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeResourceList(data []byte) (ResourceList, error) { var value ResourceList if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["assigned_desktops"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "assigned_desktops", Code: "required"}}} } if raw, ok := fields["entitled_pools"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "entitled_pools", Code: "required"}}} } if raw, ok := fields["page"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "page", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeResourceList(value ResourceList) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v SelectedSessionDescriptor) Validate() error { var violations []FieldViolation if reflect.DeepEqual(v.VideoProfile, VideoProfile{}) { violations = append(violations, FieldViolation{Field: "video_profile", Code: "required"}) } if err := v.VideoProfile.Validate(); err != nil { violations = append(violations, FieldViolation{Field: "video_profile", Code: "invalid_object"}) } if reflect.DeepEqual(v.AudioProfile, AudioProfile{}) { violations = append(violations, FieldViolation{Field: "audio_profile", Code: "required"}) } if err := v.AudioProfile.Validate(); err != nil { violations = append(violations, FieldViolation{Field: "audio_profile", Code: "invalid_object"}) } if reflect.DeepEqual(v.DisplayMode, DisplayMode{}) { violations = append(violations, FieldViolation{Field: "display_mode", Code: "required"}) } if err := v.DisplayMode.Validate(); err != nil { violations = append(violations, FieldViolation{Field: "display_mode", Code: "invalid_object"}) } if v.BitrateTargetKbps == 0 { violations = append(violations, FieldViolation{Field: "bitrate_target_kbps", Code: "required"}) } if v.BitrateTargetKbps != 0 && v.BitrateTargetKbps < 100 { violations = append(violations, FieldViolation{Field: "bitrate_target_kbps", Code: "minimum"}) } if v.BitrateTargetKbps > 1000000 { violations = append(violations, FieldViolation{Field: "bitrate_target_kbps", Code: "maximum"}) } if v.BitrateMaximumKbps == 0 { violations = append(violations, FieldViolation{Field: "bitrate_maximum_kbps", Code: "required"}) } if v.BitrateMaximumKbps != 0 && v.BitrateMaximumKbps < 100 { violations = append(violations, FieldViolation{Field: "bitrate_maximum_kbps", Code: "minimum"}) } if v.BitrateMaximumKbps > 1000000 { violations = append(violations, FieldViolation{Field: "bitrate_maximum_kbps", Code: "maximum"}) } if reflect.DeepEqual(v.Adjustment, SessionAdjustment{}) { violations = append(violations, FieldViolation{Field: "adjustment", Code: "required"}) } if err := v.Adjustment.Validate(); err != nil { violations = append(violations, FieldViolation{Field: "adjustment", Code: "invalid_object"}) } if v.MediaTimestampBasis == "" { violations = append(violations, FieldViolation{Field: "media_timestamp_basis", Code: "required"}) } if v.MediaTimestampBasis != "gateway-send-wall-clock-ms" && v.MediaTimestampBasis != "" { violations = append(violations, FieldViolation{Field: "media_timestamp_basis", Code: "invalid_value"}) } if v.BitrateTargetKbps > v.BitrateMaximumKbps { violations = append(violations, FieldViolation{Field: "bitrate_bounds", Code: "invalid_order"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeSelectedSessionDescriptor(data []byte) (SelectedSessionDescriptor, error) { var value SelectedSessionDescriptor if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["adjustment"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "adjustment", Code: "required"}}} } if raw, ok := fields["audio_profile"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "audio_profile", Code: "required"}}} } if raw, ok := fields["bitrate_maximum_kbps"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "bitrate_maximum_kbps", Code: "required"}}} } if raw, ok := fields["bitrate_target_kbps"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "bitrate_target_kbps", Code: "required"}}} } if raw, ok := fields["display_mode"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "display_mode", Code: "required"}}} } if raw, ok := fields["media_timestamp_basis"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "media_timestamp_basis", Code: "required"}}} } if raw, ok := fields["video_profile"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "video_profile", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeSelectedSessionDescriptor(value SelectedSessionDescriptor) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v SessionAdjustment) Validate() error { var violations []FieldViolation if v.DisplayReason == "" { violations = append(violations, FieldViolation{Field: "display_reason", Code: "required"}) } if v.DisplayReason != "" && !(v.DisplayReason == "none" || v.DisplayReason == "policy_clamp" || v.DisplayReason == "direct_entitlement_override") { violations = append(violations, FieldViolation{Field: "display_reason", Code: "invalid_value"}) } if v.BitrateReason == "" { violations = append(violations, FieldViolation{Field: "bitrate_reason", Code: "required"}) } if v.BitrateReason != "" && !(v.BitrateReason == "none" || v.BitrateReason == "policy_default" || v.BitrateReason == "session_ceiling_clamp" || v.BitrateReason == "aggregate_capacity_clamp") { violations = append(violations, FieldViolation{Field: "bitrate_reason", Code: "invalid_value"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeSessionAdjustment(data []byte) (SessionAdjustment, error) { var value SessionAdjustment if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["bitrate_reason"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "bitrate_reason", Code: "required"}}} } if raw, ok := fields["display_reason"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "display_reason", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeSessionAdjustment(value SessionAdjustment) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v SessionAuthority) Validate() error { var violations []FieldViolation if v.Version == "" { violations = append(violations, FieldViolation{Field: "version", Code: "required"}) } if v.Version != "1" && v.Version != "" { violations = append(violations, FieldViolation{Field: "version", Code: "invalid_value"}) } if v.SessionID == "" { violations = append(violations, FieldViolation{Field: "session_id", Code: "required"}) } if len(v.SessionID) < 1 && v.SessionID != "" { violations = append(violations, FieldViolation{Field: "session_id", Code: "min_length"}) } if len(v.SessionID) > 128 { violations = append(violations, FieldViolation{Field: "session_id", Code: "max_length"}) } if v.GatewayID == "" { violations = append(violations, FieldViolation{Field: "gateway_id", Code: "required"}) } if len(v.GatewayID) < 1 && v.GatewayID != "" { violations = append(violations, FieldViolation{Field: "gateway_id", Code: "min_length"}) } if len(v.GatewayID) > 128 { violations = append(violations, FieldViolation{Field: "gateway_id", Code: "max_length"}) } if v.Audience == "" { violations = append(violations, FieldViolation{Field: "audience", Code: "required"}) } if len(v.Audience) < 1 && v.Audience != "" { violations = append(violations, FieldViolation{Field: "audience", Code: "min_length"}) } if len(v.Audience) > 256 { violations = append(violations, FieldViolation{Field: "audience", Code: "max_length"}) } if v.ReconnectSequence != 0 && v.ReconnectSequence < 0 { violations = append(violations, FieldViolation{Field: "reconnect_sequence", Code: "minimum"}) } if v.ExpiresAt == "" { violations = append(violations, FieldViolation{Field: "expires_at", Code: "required"}) } if len(v.ExpiresAt) > 64 { violations = append(violations, FieldViolation{Field: "expires_at", Code: "max_length"}) } if v.ExpiresAt != "" { if parsed, err := time.Parse(time.RFC3339Nano, v.ExpiresAt); err != nil || parsed.UTC().Format(time.RFC3339Nano) != v.ExpiresAt { violations = append(violations, FieldViolation{Field: "expires_at", Code: "invalid_time"}) } } if reflect.DeepEqual(v.Capabilities, CapabilityProfile{}) { violations = append(violations, FieldViolation{Field: "capabilities", Code: "required"}) } if err := v.Capabilities.Validate(); err != nil { violations = append(violations, FieldViolation{Field: "capabilities", Code: "invalid_object"}) } if v.ProviderProfile == "" { violations = append(violations, FieldViolation{Field: "provider_profile", Code: "required"}) } if v.ProviderProfile != "" && !(v.ProviderProfile == "apollo") { violations = append(violations, FieldViolation{Field: "provider_profile", Code: "invalid_value"}) } if v.ProviderIdentity == "" { violations = append(violations, FieldViolation{Field: "provider_identity", Code: "required"}) } if len(v.ProviderIdentity) < 1 && v.ProviderIdentity != "" { violations = append(violations, FieldViolation{Field: "provider_identity", Code: "min_length"}) } if len(v.ProviderIdentity) > 256 { violations = append(violations, FieldViolation{Field: "provider_identity", Code: "max_length"}) } if reflect.DeepEqual(v.SelectedDescriptor, SelectedSessionDescriptor{}) { violations = append(violations, FieldViolation{Field: "selected_descriptor", Code: "required"}) } if err := v.SelectedDescriptor.Validate(); err != nil { violations = append(violations, FieldViolation{Field: "selected_descriptor", Code: "invalid_object"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeSessionAuthority(data []byte) (SessionAuthority, error) { var value SessionAuthority if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["audience"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "audience", Code: "required"}}} } if raw, ok := fields["capabilities"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "capabilities", Code: "required"}}} } if raw, ok := fields["expires_at"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "expires_at", Code: "required"}}} } if raw, ok := fields["gateway_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "gateway_id", Code: "required"}}} } if raw, ok := fields["provider_identity"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "provider_identity", Code: "required"}}} } if raw, ok := fields["provider_profile"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "provider_profile", Code: "required"}}} } if raw, ok := fields["reconnect_sequence"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "reconnect_sequence", Code: "required"}}} } if raw, ok := fields["selected_descriptor"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "selected_descriptor", Code: "required"}}} } if raw, ok := fields["session_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "session_id", Code: "required"}}} } if raw, ok := fields["version"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "version", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeSessionAuthority(value SessionAuthority) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v SessionQualityLimits) Validate() error { var violations []FieldViolation if v.PolicyVersionID == "" { violations = append(violations, FieldViolation{Field: "policy_version_id", Code: "required"}) } if len(v.PolicyVersionID) < 1 && v.PolicyVersionID != "" { violations = append(violations, FieldViolation{Field: "policy_version_id", Code: "min_length"}) } if len(v.PolicyVersionID) > 128 { violations = append(violations, FieldViolation{Field: "policy_version_id", Code: "max_length"}) } if reflect.DeepEqual(v.PolicyDisplayLimit, DisplayMode{}) { violations = append(violations, FieldViolation{Field: "policy_display_limit", Code: "required"}) } if err := v.PolicyDisplayLimit.Validate(); err != nil { violations = append(violations, FieldViolation{Field: "policy_display_limit", Code: "invalid_object"}) } if reflect.DeepEqual(v.SelectableDisplayMaximum, DisplayMode{}) { violations = append(violations, FieldViolation{Field: "selectable_display_maximum", Code: "required"}) } if err := v.SelectableDisplayMaximum.Validate(); err != nil { violations = append(violations, FieldViolation{Field: "selectable_display_maximum", Code: "invalid_object"}) } if v.BitrateMinimumKbps == 0 { violations = append(violations, FieldViolation{Field: "bitrate_minimum_kbps", Code: "required"}) } if v.BitrateMinimumKbps != 0 && v.BitrateMinimumKbps < 100 { violations = append(violations, FieldViolation{Field: "bitrate_minimum_kbps", Code: "minimum"}) } if v.BitrateMinimumKbps > 1000000 { violations = append(violations, FieldViolation{Field: "bitrate_minimum_kbps", Code: "maximum"}) } if v.BitrateTargetKbps == 0 { violations = append(violations, FieldViolation{Field: "bitrate_target_kbps", Code: "required"}) } if v.BitrateTargetKbps != 0 && v.BitrateTargetKbps < 100 { violations = append(violations, FieldViolation{Field: "bitrate_target_kbps", Code: "minimum"}) } if v.BitrateTargetKbps > 1000000 { violations = append(violations, FieldViolation{Field: "bitrate_target_kbps", Code: "maximum"}) } if v.BitrateMaximumKbps == 0 { violations = append(violations, FieldViolation{Field: "bitrate_maximum_kbps", Code: "required"}) } if v.BitrateMaximumKbps != 0 && v.BitrateMaximumKbps < 100 { violations = append(violations, FieldViolation{Field: "bitrate_maximum_kbps", Code: "minimum"}) } if v.BitrateMaximumKbps > 1000000 { violations = append(violations, FieldViolation{Field: "bitrate_maximum_kbps", Code: "maximum"}) } if v.BitrateMinimumKbps > v.BitrateTargetKbps || v.BitrateTargetKbps > v.BitrateMaximumKbps { violations = append(violations, FieldViolation{Field: "bitrate_bounds", Code: "invalid_order"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeSessionQualityLimits(data []byte) (SessionQualityLimits, error) { var value SessionQualityLimits if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["bitrate_maximum_kbps"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "bitrate_maximum_kbps", Code: "required"}}} } if raw, ok := fields["bitrate_minimum_kbps"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "bitrate_minimum_kbps", Code: "required"}}} } if raw, ok := fields["bitrate_target_kbps"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "bitrate_target_kbps", Code: "required"}}} } if raw, ok := fields["display_limit_override"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "display_limit_override", Code: "required"}}} } if raw, ok := fields["policy_display_limit"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "policy_display_limit", Code: "required"}}} } if raw, ok := fields["policy_version_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "policy_version_id", Code: "required"}}} } if raw, ok := fields["selectable_display_maximum"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "selectable_display_maximum", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeSessionQualityLimits(value SessionQualityLimits) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v SessionRequest) Validate() error { var violations []FieldViolation if v.ClientDeviceID == "" { violations = append(violations, FieldViolation{Field: "client_device_id", Code: "required"}) } if len(v.ClientDeviceID) < 1 && v.ClientDeviceID != "" { violations = append(violations, FieldViolation{Field: "client_device_id", Code: "min_length"}) } if len(v.ClientDeviceID) > 128 { violations = append(violations, FieldViolation{Field: "client_device_id", Code: "max_length"}) } if v.DeviceKeyID == "" { violations = append(violations, FieldViolation{Field: "device_key_id", Code: "required"}) } if len(v.DeviceKeyID) < 1 && v.DeviceKeyID != "" { violations = append(violations, FieldViolation{Field: "device_key_id", Code: "min_length"}) } if len(v.DeviceKeyID) > 128 { violations = append(violations, FieldViolation{Field: "device_key_id", Code: "max_length"}) } if v.PoolID == "" { violations = append(violations, FieldViolation{Field: "pool_id", Code: "required"}) } if len(v.PoolID) < 1 && v.PoolID != "" { violations = append(violations, FieldViolation{Field: "pool_id", Code: "min_length"}) } if len(v.PoolID) > 128 { violations = append(violations, FieldViolation{Field: "pool_id", Code: "max_length"}) } if v.IdempotencyKey == "" { violations = append(violations, FieldViolation{Field: "idempotency_key", Code: "required"}) } if len(v.IdempotencyKey) < 1 && v.IdempotencyKey != "" { violations = append(violations, FieldViolation{Field: "idempotency_key", Code: "min_length"}) } if len(v.IdempotencyKey) > 256 { violations = append(violations, FieldViolation{Field: "idempotency_key", Code: "max_length"}) } if v.VideoProfiles == nil { violations = append(violations, FieldViolation{Field: "video_profiles", Code: "required"}) } if len(v.VideoProfiles) < 1 { violations = append(violations, FieldViolation{Field: "video_profiles", Code: "min_items"}) } if len(v.VideoProfiles) > 12 { violations = append(violations, FieldViolation{Field: "video_profiles", Code: "max_items"}) } for index, item := range v.VideoProfiles { for prior := 0; prior < index; prior++ { if reflect.DeepEqual(item, v.VideoProfiles[prior]) { violations = append(violations, FieldViolation{Field: "video_profiles", Code: "duplicate_item"}) } } } for index := range v.VideoProfiles { if err := v.VideoProfiles[index].Validate(); err != nil { violations = append(violations, FieldViolation{Field: fmt.Sprintf("video_profiles[%d]", index), Code: "invalid_item"}) } } if reflect.DeepEqual(v.BitratePreference, BitratePreference{}) { violations = append(violations, FieldViolation{Field: "bitrate_preference", Code: "required"}) } if err := v.BitratePreference.Validate(); err != nil { violations = append(violations, FieldViolation{Field: "bitrate_preference", Code: "invalid_object"}) } if v.RequestedDisplayMode != nil { if err := v.RequestedDisplayMode.Validate(); err != nil { violations = append(violations, FieldViolation{Field: "requested_display_mode", Code: "invalid_object"}) } } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeSessionRequest(data []byte) (SessionRequest, error) { var value SessionRequest if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["bitrate_preference"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "bitrate_preference", Code: "required"}}} } if raw, ok := fields["client_device_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "client_device_id", Code: "required"}}} } if raw, ok := fields["device_key_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "device_key_id", Code: "required"}}} } if raw, ok := fields["idempotency_key"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "idempotency_key", Code: "required"}}} } if raw, ok := fields["pool_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "pool_id", Code: "required"}}} } if raw, ok := fields["video_profiles"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "video_profiles", Code: "required"}}} } if raw, ok := fields["requested_display_mode"]; ok && bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "requested_display_mode", Code: "invalid_object"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeSessionRequest(value SessionRequest) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v StableError) Validate() error { var violations []FieldViolation if v.Version == "" { violations = append(violations, FieldViolation{Field: "version", Code: "required"}) } if v.Version != "1" && v.Version != "" { violations = append(violations, FieldViolation{Field: "version", Code: "invalid_value"}) } if v.Code == "" { violations = append(violations, FieldViolation{Field: "code", Code: "required"}) } if len(v.Code) < 1 && v.Code != "" { violations = append(violations, FieldViolation{Field: "code", Code: "min_length"}) } if len(v.Code) > 128 { violations = append(violations, FieldViolation{Field: "code", Code: "max_length"}) } if v.Message == "" { violations = append(violations, FieldViolation{Field: "message", Code: "required"}) } if len(v.Message) < 1 && v.Message != "" { violations = append(violations, FieldViolation{Field: "message", Code: "min_length"}) } if len(v.Message) > 512 { violations = append(violations, FieldViolation{Field: "message", Code: "max_length"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeStableError(data []byte) (StableError, error) { var value StableError if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["code"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "code", Code: "required"}}} } if raw, ok := fields["message"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "message", Code: "required"}}} } if raw, ok := fields["retryable"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "retryable", Code: "required"}}} } if raw, ok := fields["version"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "version", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeStableError(value StableError) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v StopOperation) Validate() error { var violations []FieldViolation if v.OperationID == "" { violations = append(violations, FieldViolation{Field: "operation_id", Code: "required"}) } if len(v.OperationID) < 36 && v.OperationID != "" { violations = append(violations, FieldViolation{Field: "operation_id", Code: "min_length"}) } if len(v.OperationID) > 36 { violations = append(violations, FieldViolation{Field: "operation_id", Code: "max_length"}) } if v.OperationID != "" && !validCanonicalUUID(v.OperationID) { violations = append(violations, FieldViolation{Field: "operation_id", Code: "invalid_uuid"}) } if v.SessionID == "" { violations = append(violations, FieldViolation{Field: "session_id", Code: "required"}) } if len(v.SessionID) < 1 && v.SessionID != "" { violations = append(violations, FieldViolation{Field: "session_id", Code: "min_length"}) } if len(v.SessionID) > 128 { violations = append(violations, FieldViolation{Field: "session_id", Code: "max_length"}) } if v.State == "" { violations = append(violations, FieldViolation{Field: "state", Code: "required"}) } if v.State != "" && !(v.State == "pending" || v.State == "attempting" || v.State == "applied" || v.State == "failed" || v.State == "termination_unconfirmed") { violations = append(violations, FieldViolation{Field: "state", Code: "invalid_value"}) } if v.SessionVersion == 0 { violations = append(violations, FieldViolation{Field: "session_version", Code: "required"}) } if v.SessionVersion != 0 && v.SessionVersion < 1 { violations = append(violations, FieldViolation{Field: "session_version", Code: "minimum"}) } if v.CreatedAt == "" { violations = append(violations, FieldViolation{Field: "created_at", Code: "required"}) } if len(v.CreatedAt) > 64 { violations = append(violations, FieldViolation{Field: "created_at", Code: "max_length"}) } if v.CreatedAt != "" { if parsed, err := time.Parse(time.RFC3339Nano, v.CreatedAt); err != nil || parsed.UTC().Format(time.RFC3339Nano) != v.CreatedAt { violations = append(violations, FieldViolation{Field: "created_at", Code: "invalid_time"}) } } if v.DeadlineAt == "" { violations = append(violations, FieldViolation{Field: "deadline_at", Code: "required"}) } if len(v.DeadlineAt) > 64 { violations = append(violations, FieldViolation{Field: "deadline_at", Code: "max_length"}) } if v.DeadlineAt != "" { if parsed, err := time.Parse(time.RFC3339Nano, v.DeadlineAt); err != nil || parsed.UTC().Format(time.RFC3339Nano) != v.DeadlineAt { violations = append(violations, FieldViolation{Field: "deadline_at", Code: "invalid_time"}) } } if v.UpdatedAt == "" { violations = append(violations, FieldViolation{Field: "updated_at", Code: "required"}) } if len(v.UpdatedAt) > 64 { violations = append(violations, FieldViolation{Field: "updated_at", Code: "max_length"}) } if v.UpdatedAt != "" { if parsed, err := time.Parse(time.RFC3339Nano, v.UpdatedAt); err != nil || parsed.UTC().Format(time.RFC3339Nano) != v.UpdatedAt { violations = append(violations, FieldViolation{Field: "updated_at", Code: "invalid_time"}) } } if len(v.FailureCode) < 1 && v.FailureCode != "" { violations = append(violations, FieldViolation{Field: "failure_code", Code: "min_length"}) } if len(v.FailureCode) > 128 { violations = append(violations, FieldViolation{Field: "failure_code", Code: "max_length"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeStopOperation(data []byte) (StopOperation, error) { var value StopOperation if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["created_at"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "created_at", Code: "required"}}} } if raw, ok := fields["deadline_at"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "deadline_at", Code: "required"}}} } if raw, ok := fields["operation_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "operation_id", Code: "required"}}} } if raw, ok := fields["session_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "session_id", Code: "required"}}} } if raw, ok := fields["session_version"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "session_version", Code: "required"}}} } if raw, ok := fields["state"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "state", Code: "required"}}} } if raw, ok := fields["updated_at"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "updated_at", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeStopOperation(value StopOperation) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v TunnelAdmissionRequest) Validate() error { var violations []FieldViolation if v.Version == "" { violations = append(violations, FieldViolation{Field: "version", Code: "required"}) } if v.Version != "1" && v.Version != "" { violations = append(violations, FieldViolation{Field: "version", Code: "invalid_value"}) } if v.SessionID == "" { violations = append(violations, FieldViolation{Field: "session_id", Code: "required"}) } if len(v.SessionID) < 1 && v.SessionID != "" { violations = append(violations, FieldViolation{Field: "session_id", Code: "min_length"}) } if len(v.SessionID) > 128 { violations = append(violations, FieldViolation{Field: "session_id", Code: "max_length"}) } if v.GatewayID == "" { violations = append(violations, FieldViolation{Field: "gateway_id", Code: "required"}) } if len(v.GatewayID) < 1 && v.GatewayID != "" { violations = append(violations, FieldViolation{Field: "gateway_id", Code: "min_length"}) } if len(v.GatewayID) > 128 { violations = append(violations, FieldViolation{Field: "gateway_id", Code: "max_length"}) } if v.Audience == "" { violations = append(violations, FieldViolation{Field: "audience", Code: "required"}) } if len(v.Audience) < 1 && v.Audience != "" { violations = append(violations, FieldViolation{Field: "audience", Code: "min_length"}) } if len(v.Audience) > 256 { violations = append(violations, FieldViolation{Field: "audience", Code: "max_length"}) } if v.Grant == "" { violations = append(violations, FieldViolation{Field: "grant", Code: "required"}) } if len(v.Grant) < 43 && v.Grant != "" { violations = append(violations, FieldViolation{Field: "grant", Code: "min_length"}) } if len(v.Grant) > 256 { violations = append(violations, FieldViolation{Field: "grant", Code: "max_length"}) } if v.ReconnectSequence != 0 && v.ReconnectSequence < 0 { violations = append(violations, FieldViolation{Field: "reconnect_sequence", Code: "minimum"}) } if v.ClientNonce == "" { violations = append(violations, FieldViolation{Field: "client_nonce", Code: "required"}) } if len(v.ClientNonce) < 16 && v.ClientNonce != "" { violations = append(violations, FieldViolation{Field: "client_nonce", Code: "min_length"}) } if len(v.ClientNonce) > 128 { violations = append(violations, FieldViolation{Field: "client_nonce", Code: "max_length"}) } if v.DeviceSignature == "" { violations = append(violations, FieldViolation{Field: "device_signature", Code: "required"}) } if len(v.DeviceSignature) < 86 && v.DeviceSignature != "" { violations = append(violations, FieldViolation{Field: "device_signature", Code: "min_length"}) } if len(v.DeviceSignature) > 86 { violations = append(violations, FieldViolation{Field: "device_signature", Code: "max_length"}) } if reflect.DeepEqual(v.Capabilities, CapabilityProfile{}) { violations = append(violations, FieldViolation{Field: "capabilities", Code: "required"}) } if err := v.Capabilities.Validate(); err != nil { violations = append(violations, FieldViolation{Field: "capabilities", Code: "invalid_object"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeTunnelAdmissionRequest(data []byte) (TunnelAdmissionRequest, error) { var value TunnelAdmissionRequest if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["audience"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "audience", Code: "required"}}} } if raw, ok := fields["capabilities"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "capabilities", Code: "required"}}} } if raw, ok := fields["client_nonce"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "client_nonce", Code: "required"}}} } if raw, ok := fields["device_signature"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "device_signature", Code: "required"}}} } if raw, ok := fields["gateway_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "gateway_id", Code: "required"}}} } if raw, ok := fields["grant"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "grant", Code: "required"}}} } if raw, ok := fields["reconnect_sequence"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "reconnect_sequence", Code: "required"}}} } if raw, ok := fields["session_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "session_id", Code: "required"}}} } if raw, ok := fields["version"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "version", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeTunnelAdmissionRequest(value TunnelAdmissionRequest) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v VersionNegotiation) Validate() error { var violations []FieldViolation if v.SupportedVersions == nil { violations = append(violations, FieldViolation{Field: "supported_versions", Code: "required"}) } if len(v.SupportedVersions) < 1 { violations = append(violations, FieldViolation{Field: "supported_versions", Code: "min_items"}) } if len(v.SupportedVersions) > 3 { violations = append(violations, FieldViolation{Field: "supported_versions", Code: "max_items"}) } for _, item := range v.SupportedVersions { if len(item) > 16 { violations = append(violations, FieldViolation{Field: "supported_versions", Code: "max_item_length"}) } } if v.Features == nil { violations = append(violations, FieldViolation{Field: "features", Code: "required"}) } if len(v.Features) > 64 { violations = append(violations, FieldViolation{Field: "features", Code: "max_items"}) } for _, item := range v.Features { if len(item) > 64 { violations = append(violations, FieldViolation{Field: "features", Code: "max_item_length"}) } } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeVersionNegotiation(data []byte) (VersionNegotiation, error) { var value VersionNegotiation if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["features"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "features", Code: "required"}}} } if raw, ok := fields["supported_versions"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "supported_versions", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeVersionNegotiation(value VersionNegotiation) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func (v VideoProfile) Validate() error { var violations []FieldViolation if v.Codec == "" { violations = append(violations, FieldViolation{Field: "codec", Code: "required"}) } if v.Codec != "" && !(v.Codec == "h264" || v.Codec == "hevc" || v.Codec == "av1") { violations = append(violations, FieldViolation{Field: "codec", Code: "invalid_value"}) } if v.BitDepth == 0 { violations = append(violations, FieldViolation{Field: "bit_depth", Code: "required"}) } if v.BitDepth != 0 && v.BitDepth < 8 { violations = append(violations, FieldViolation{Field: "bit_depth", Code: "minimum"}) } if v.BitDepth > 8 { violations = append(violations, FieldViolation{Field: "bit_depth", Code: "maximum"}) } if v.ChromaSubsampling == "" { violations = append(violations, FieldViolation{Field: "chroma_subsampling", Code: "required"}) } if v.ChromaSubsampling != "4:2:0" && v.ChromaSubsampling != "" { violations = append(violations, FieldViolation{Field: "chroma_subsampling", Code: "invalid_value"}) } if v.ColorSpace == "" { violations = append(violations, FieldViolation{Field: "color_space", Code: "required"}) } if v.ColorSpace != "bt709-limited" && v.ColorSpace != "" { violations = append(violations, FieldViolation{Field: "color_space", Code: "invalid_value"}) } if v.TransferFunction == "" { violations = append(violations, FieldViolation{Field: "transfer_function", Code: "required"}) } if v.TransferFunction != "sdr" && v.TransferFunction != "" { violations = append(violations, FieldViolation{Field: "transfer_function", Code: "invalid_value"}) } if len(violations) > 0 { return ValidationError{Violations: violations} } return nil } func DecodeVideoProfile(data []byte) (VideoProfile, error) { var value VideoProfile if len(data) > 1024*1024 { return value, errors.New("protocol payload exceeds limit") } if err := rejectDuplicateJSONKeys(data); err != nil { return value, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["bit_depth"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "bit_depth", Code: "required"}}} } if raw, ok := fields["chroma_subsampling"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "chroma_subsampling", Code: "required"}}} } if raw, ok := fields["codec"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "codec", Code: "required"}}} } if raw, ok := fields["color_space"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "color_space", Code: "required"}}} } if raw, ok := fields["transfer_function"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "transfer_function", Code: "required"}}} } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&value); err != nil { return value, err } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { return value, errors.New("trailing JSON value") } return value, err } if err := value.Validate(); err != nil { return value, err } return value, nil } func EncodeVideoProfile(value VideoProfile) ([]byte, error) { if err := value.Validate(); err != nil { return nil, err } return json.Marshal(value) } func DeviceRegistrationProofTranscript(serverID, principalID, deviceID, challenge []byte, expiryUnixMilliseconds int64) ([]byte, error) { for _, value := range []struct { field string bytes []byte length int }{{"server_id", serverID, 16}, {"principal_id", principalID, 16}, {"device_id", deviceID, 16}, {"challenge", challenge, 32}} { if len(value.bytes) != value.length { return nil, ValidationError{Violations: []FieldViolation{{Field: value.field, Code: "invalid_length"}}} } } if expiryUnixMilliseconds < 0 { return nil, ValidationError{Violations: []FieldViolation{{Field: "expiry_unix_milliseconds", Code: "minimum"}}} } transcript := make([]byte, 0, 112) transcript = append(transcript, "versevdi-device-proof-v1"...) transcript = append(transcript, serverID...) transcript = append(transcript, principalID...) transcript = append(transcript, deviceID...) transcript = append(transcript, challenge...) var expiry [8]byte binary.BigEndian.PutUint64(expiry[:], uint64(expiryUnixMilliseconds)) return append(transcript, expiry[:]...), nil } var ErrNoCapabilityOverlap = errors.New("no capability overlap") func IntersectCapabilityProfiles(profiles ...CapabilityProfile) (CapabilityProfile, error) { if len(profiles) == 0 { return CapabilityProfile{}, ErrNoCapabilityOverlap } selected := profiles[0] if err := selected.Validate(); err != nil { return CapabilityProfile{}, ErrNoCapabilityOverlap } commonVideo := append([]VideoProfile(nil), selected.VideoProfiles...) commonAudio := append([]AudioProfile(nil), selected.AudioProfiles...) for _, profile := range profiles[1:] { if err := profile.Validate(); err != nil || profile.Transport != selected.Transport || profile.Framing != selected.Framing || profile.Media != selected.Media || profile.SourceRateControl != selected.SourceRateControl { return CapabilityProfile{}, ErrNoCapabilityOverlap } nextVideo := commonVideo[:0] for _, candidate := range commonVideo { for _, offered := range profile.VideoProfiles { if candidate == offered { nextVideo = append(nextVideo, candidate) break } } } commonVideo = nextVideo nextAudio := commonAudio[:0] for _, candidate := range commonAudio { for _, offered := range profile.AudioProfiles { if candidate == offered { nextAudio = append(nextAudio, candidate) break } } } commonAudio = nextAudio if len(commonVideo) == 0 || len(commonAudio) == 0 { return CapabilityProfile{}, ErrNoCapabilityOverlap } } selected.VideoProfiles = commonVideo selected.AudioProfiles = commonAudio return selected, nil } func (v TunnelAdmissionRequest) DeviceAdmissionTranscript() []byte { fields := []string{v.SessionID, v.GatewayID, v.Audience, v.Grant, fmt.Sprintf("%d", v.ReconnectSequence), v.ClientNonce, v.Capabilities.Transport, v.Capabilities.Framing, v.Capabilities.Media, v.Capabilities.SourceRateControl, fmt.Sprintf("%d", len(v.Capabilities.VideoProfiles)), fmt.Sprintf("%d", len(v.Capabilities.AudioProfiles))} for _, profile := range v.Capabilities.VideoProfiles { fields = append(fields, profile.Codec, fmt.Sprintf("%d", profile.BitDepth), profile.ChromaSubsampling, profile.ColorSpace, profile.TransferFunction) } for _, profile := range v.Capabilities.AudioProfiles { fields = append(fields, profile.Codec, fmt.Sprintf("%d", profile.SampleRateHz), fmt.Sprintf("%d", profile.Channels), profile.ChannelLayout, fmt.Sprintf("%d", profile.PacketDurationMs)) } var transcript strings.Builder transcript.WriteString("versevdi/tunnel-admission/v1") for _, field := range fields { fmt.Fprintf(&transcript, "%d:%s", len(field), field) } return []byte(transcript.String()) }