// Code generated by tools/generate.py; DO NOT EDIT. package protocol import ( "bytes" "encoding/json" "errors" "fmt" "io" "reflect" "time" ) const SchemaSHA256 = "b8a69785112bb94d45f47c2250ca59d0bde47e3667b8ad89c9b0e2c4cfb25aec" const ProtocolVersion = "1.0.0" const CurrentWireVersion = "1" const NMinus1WireVersion = "0" const NMinus2WireVersion = "-1" 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" } 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"` } 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"` } type CapabilityProfile struct { Transport string `json:"transport"` Framing string `json:"framing"` Media string `json:"media"` Audio string `json:"audio"` SourceRateControl string `json:"source_rate_control"` ClientDecode string `json:"client_decode"` } 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 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"` } 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 EntitledPool struct { PoolID string `json:"pool_id"` Name string `json:"name"` AssignmentState string `json:"assignment_state"` } 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 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"` } 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 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"` } type ManifestTunnel struct { Versions []string `json:"versions"` Features []string `json:"features"` } 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 PageInfo struct { Limit int64 `json:"limit"` NextCursor string `json:"next_cursor"` } 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 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"` } 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 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"` } 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"` PolicySnapshot AllocationPolicy `json:"policy_snapshot"` } type StableError struct { Version string `json:"version"` Code string `json:"code"` Message string `json:"message"` Retryable bool `json:"retryable"` } 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"` Capabilities CapabilityProfile `json:"capabilities"` } type VersionNegotiation struct { SupportedVersions []string `json:"supported_versions"` Features []string `json:"features"` } 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") } 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 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") } 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"}}} } 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 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 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") } 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["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 EncodeBrokerSession(value BrokerSession) ([]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 len(v.Framing) < 1 && v.Framing != "" { violations = append(violations, FieldViolation{Field: "framing", Code: "min_length"}) } if len(v.Framing) > 64 { violations = append(violations, FieldViolation{Field: "framing", Code: "max_length"}) } 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.Audio == "" { violations = append(violations, FieldViolation{Field: "audio", Code: "required"}) } if len(v.Audio) < 1 && v.Audio != "" { violations = append(violations, FieldViolation{Field: "audio", Code: "min_length"}) } if len(v.Audio) > 64 { violations = append(violations, FieldViolation{Field: "audio", 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.ClientDecode == "" { violations = append(violations, FieldViolation{Field: "client_decode", Code: "required"}) } if len(v.ClientDecode) < 1 && v.ClientDecode != "" { violations = append(violations, FieldViolation{Field: "client_decode", Code: "min_length"}) } if len(v.ClientDecode) > 64 { violations = append(violations, FieldViolation{Field: "client_decode", Code: "max_length"}) } 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") } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { return value, err } if raw, ok := fields["audio"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "audio", Code: "required"}}} } if raw, ok := fields["client_decode"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) { return value, ValidationError{Violations: []FieldViolation{{Field: "client_decode", 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"}}} } 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 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") } 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"}}} } if raw, ok := fields["payload"]; ok && len(raw) > 65536 { 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 EncodeChannelFrame(value ChannelFrame) ([]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") } 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 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") } 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["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") } 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") } 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") } 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 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 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") } 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"}}} } 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") } 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") } 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") } 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") } 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 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") } 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 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") } 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["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 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"}) } 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") } 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 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") } 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") } 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") } 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"}) } 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") } 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 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") } 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"}}} } 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"}) } 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"}) } 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") } 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 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") } 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 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") } 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 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"}) } 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") } 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 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") } 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") } 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") } 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["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") } 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") } 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") } 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") } 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 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 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") } 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["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 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 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(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") } 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["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"}}} } 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") } 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 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 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") } 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["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"}) } 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"}) } 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") } 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) } 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 } for _, profile := range profiles[1:] { if err := profile.Validate(); err != nil || profile != selected { return CapabilityProfile{}, ErrNoCapabilityOverlap } } return selected, nil }