feat(protocol): define gateway control envelopes
This commit is contained in:
+310
-18
@@ -12,7 +12,7 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
const SchemaSHA256 = "792abfb9cfe70e79911d499d76c009ab848713278bc240b88576df520580e480"
|
||||
const SchemaSHA256 = "e35414af52d7a097dea05567fdab11f842a42e529fb6cbedd281c48dbf930b17"
|
||||
const ProtocolVersion = "1.0.0"
|
||||
const CurrentWireVersion = "1"
|
||||
const NMinus1WireVersion = "0"
|
||||
@@ -86,6 +86,13 @@ type ChannelFrame struct {
|
||||
Payload string `json:"payload"`
|
||||
}
|
||||
|
||||
type ClipboardPolicy struct {
|
||||
ClientToProviderEnabled bool `json:"client_to_provider_enabled"`
|
||||
ProviderToClientEnabled bool `json:"provider_to_client_enabled"`
|
||||
MaxTextBytes int64 `json:"max_text_bytes"`
|
||||
MaxUpdatesPerMinute int64 `json:"max_updates_per_minute"`
|
||||
}
|
||||
|
||||
type ClipboardText struct {
|
||||
Text string `json:"text"`
|
||||
Encoding string `json:"encoding"`
|
||||
@@ -158,6 +165,22 @@ type EventResume struct {
|
||||
LastSequence int64 `json:"last_sequence"`
|
||||
}
|
||||
|
||||
type GatewayClipboardAudit struct {
|
||||
Version string `json:"version"`
|
||||
SessionID string `json:"session_id"`
|
||||
Direction string `json:"direction"`
|
||||
Outcome string `json:"outcome"`
|
||||
TextBytes int64 `json:"text_bytes"`
|
||||
Reason string `json:"reason"`
|
||||
}
|
||||
|
||||
type GatewayClipboardText struct {
|
||||
Direction string `json:"direction"`
|
||||
Text string `json:"text"`
|
||||
Encoding string `json:"encoding"`
|
||||
LoopToken string `json:"loop_token"`
|
||||
}
|
||||
|
||||
type GatewayDrain struct {
|
||||
Version string `json:"version"`
|
||||
GatewayID string `json:"gateway_id"`
|
||||
@@ -241,23 +264,25 @@ type PageInfo struct {
|
||||
}
|
||||
|
||||
type ProviderSessionWork struct {
|
||||
Version string `json:"version"`
|
||||
SessionID string `json:"session_id"`
|
||||
GatewayID string `json:"gateway_id"`
|
||||
ReconnectSequence int64 `json:"reconnect_sequence"`
|
||||
ExpiresAt string `json:"expires_at"`
|
||||
ProviderProfile string `json:"provider_profile"`
|
||||
ProviderIdentity string `json:"provider_identity"`
|
||||
PolicyVersionID string `json:"policy_version_id"`
|
||||
ApplicationID string `json:"application_id"`
|
||||
ClientID string `json:"client_id"`
|
||||
ManagementHost string `json:"management_host"`
|
||||
ManagementPort int64 `json:"management_port"`
|
||||
StreamHost string `json:"stream_host"`
|
||||
StreamPort int64 `json:"stream_port"`
|
||||
ClientCertificatePem string `json:"client_certificate_pem"`
|
||||
ClientPrivateKeyPem string `json:"client_private_key_pem"`
|
||||
ServerCertificatePem string `json:"server_certificate_pem"`
|
||||
Version string `json:"version"`
|
||||
SessionID string `json:"session_id"`
|
||||
GatewayID string `json:"gateway_id"`
|
||||
ReconnectSequence int64 `json:"reconnect_sequence"`
|
||||
ExpiresAt string `json:"expires_at"`
|
||||
ProviderProfile string `json:"provider_profile"`
|
||||
ProviderIdentity string `json:"provider_identity"`
|
||||
PolicyVersionID string `json:"policy_version_id"`
|
||||
ApplicationID string `json:"application_id"`
|
||||
ClientID string `json:"client_id"`
|
||||
ManagementHost string `json:"management_host"`
|
||||
ManagementPort int64 `json:"management_port"`
|
||||
StreamHost string `json:"stream_host"`
|
||||
StreamPort int64 `json:"stream_port"`
|
||||
ClientCertificatePem string `json:"client_certificate_pem"`
|
||||
ClientPrivateKeyPem string `json:"client_private_key_pem"`
|
||||
ServerCertificatePem string `json:"server_certificate_pem"`
|
||||
ClipboardPolicy ClipboardPolicy `json:"clipboard_policy"`
|
||||
ProviderApplicationTerminationAllowed bool `json:"provider_application_termination_allowed"`
|
||||
}
|
||||
|
||||
type ProviderState struct {
|
||||
@@ -1013,6 +1038,78 @@ func EncodeChannelFrame(value ChannelFrame) ([]byte, error) {
|
||||
return json.Marshal(value)
|
||||
}
|
||||
|
||||
func (v ClipboardPolicy) Validate() error {
|
||||
var violations []FieldViolation
|
||||
if v.MaxTextBytes == 0 {
|
||||
violations = append(violations, FieldViolation{Field: "max_text_bytes", Code: "required"})
|
||||
}
|
||||
if v.MaxTextBytes != 0 && v.MaxTextBytes < 1 {
|
||||
violations = append(violations, FieldViolation{Field: "max_text_bytes", Code: "minimum"})
|
||||
}
|
||||
if v.MaxTextBytes > 65536 {
|
||||
violations = append(violations, FieldViolation{Field: "max_text_bytes", Code: "maximum"})
|
||||
}
|
||||
if v.MaxUpdatesPerMinute == 0 {
|
||||
violations = append(violations, FieldViolation{Field: "max_updates_per_minute", Code: "required"})
|
||||
}
|
||||
if v.MaxUpdatesPerMinute != 0 && v.MaxUpdatesPerMinute < 1 {
|
||||
violations = append(violations, FieldViolation{Field: "max_updates_per_minute", Code: "minimum"})
|
||||
}
|
||||
if v.MaxUpdatesPerMinute > 120 {
|
||||
violations = append(violations, FieldViolation{Field: "max_updates_per_minute", Code: "maximum"})
|
||||
}
|
||||
if len(violations) > 0 {
|
||||
return ValidationError{Violations: violations}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DecodeClipboardPolicy(data []byte) (ClipboardPolicy, error) {
|
||||
var value ClipboardPolicy
|
||||
if len(data) > 1024*1024 {
|
||||
return value, errors.New("protocol payload exceeds limit")
|
||||
}
|
||||
var fields map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &fields); err != nil {
|
||||
return value, err
|
||||
}
|
||||
if raw, ok := fields["client_to_provider_enabled"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) {
|
||||
return value, ValidationError{Violations: []FieldViolation{{Field: "client_to_provider_enabled", Code: "required"}}}
|
||||
}
|
||||
if raw, ok := fields["max_text_bytes"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) {
|
||||
return value, ValidationError{Violations: []FieldViolation{{Field: "max_text_bytes", Code: "required"}}}
|
||||
}
|
||||
if raw, ok := fields["max_updates_per_minute"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) {
|
||||
return value, ValidationError{Violations: []FieldViolation{{Field: "max_updates_per_minute", Code: "required"}}}
|
||||
}
|
||||
if raw, ok := fields["provider_to_client_enabled"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) {
|
||||
return value, ValidationError{Violations: []FieldViolation{{Field: "provider_to_client_enabled", Code: "required"}}}
|
||||
}
|
||||
decoder := json.NewDecoder(bytes.NewReader(data))
|
||||
decoder.DisallowUnknownFields()
|
||||
if err := decoder.Decode(&value); err != nil {
|
||||
return value, err
|
||||
}
|
||||
var trailing any
|
||||
if err := decoder.Decode(&trailing); err != io.EOF {
|
||||
if err == nil {
|
||||
return value, errors.New("trailing JSON value")
|
||||
}
|
||||
return value, err
|
||||
}
|
||||
if err := value.Validate(); err != nil {
|
||||
return value, err
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func EncodeClipboardPolicy(value ClipboardPolicy) ([]byte, error) {
|
||||
if err := value.Validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(value)
|
||||
}
|
||||
|
||||
func (v ClipboardText) Validate() error {
|
||||
var violations []FieldViolation
|
||||
if v.Text == "" {
|
||||
@@ -1934,6 +2031,189 @@ func EncodeFieldViolation(value FieldViolation) ([]byte, error) {
|
||||
return json.Marshal(value)
|
||||
}
|
||||
|
||||
func (v GatewayClipboardAudit) Validate() error {
|
||||
var violations []FieldViolation
|
||||
if v.Version == "" {
|
||||
violations = append(violations, FieldViolation{Field: "version", Code: "required"})
|
||||
}
|
||||
if v.Version != "1" && v.Version != "" {
|
||||
violations = append(violations, FieldViolation{Field: "version", Code: "invalid_value"})
|
||||
}
|
||||
if v.SessionID == "" {
|
||||
violations = append(violations, FieldViolation{Field: "session_id", Code: "required"})
|
||||
}
|
||||
if len(v.SessionID) < 1 && v.SessionID != "" {
|
||||
violations = append(violations, FieldViolation{Field: "session_id", Code: "min_length"})
|
||||
}
|
||||
if len(v.SessionID) > 128 {
|
||||
violations = append(violations, FieldViolation{Field: "session_id", Code: "max_length"})
|
||||
}
|
||||
if v.Direction == "" {
|
||||
violations = append(violations, FieldViolation{Field: "direction", Code: "required"})
|
||||
}
|
||||
if v.Direction != "" && !(v.Direction == "client_to_provider" || v.Direction == "provider_to_client") {
|
||||
violations = append(violations, FieldViolation{Field: "direction", Code: "invalid_value"})
|
||||
}
|
||||
if v.Outcome == "" {
|
||||
violations = append(violations, FieldViolation{Field: "outcome", Code: "required"})
|
||||
}
|
||||
if v.Outcome != "" && !(v.Outcome == "forwarded" || v.Outcome == "suppressed" || v.Outcome == "rejected") {
|
||||
violations = append(violations, FieldViolation{Field: "outcome", Code: "invalid_value"})
|
||||
}
|
||||
if v.TextBytes != 0 && v.TextBytes < 0 {
|
||||
violations = append(violations, FieldViolation{Field: "text_bytes", Code: "minimum"})
|
||||
}
|
||||
if v.TextBytes > 65536 {
|
||||
violations = append(violations, FieldViolation{Field: "text_bytes", Code: "maximum"})
|
||||
}
|
||||
if v.Reason == "" {
|
||||
violations = append(violations, FieldViolation{Field: "reason", Code: "required"})
|
||||
}
|
||||
if v.Reason != "" && !(v.Reason == "forwarded" || v.Reason == "loop" || v.Reason == "policy" || v.Reason == "rate" || v.Reason == "provider" || v.Reason == "malformed") {
|
||||
violations = append(violations, FieldViolation{Field: "reason", Code: "invalid_value"})
|
||||
}
|
||||
if len(violations) > 0 {
|
||||
return ValidationError{Violations: violations}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DecodeGatewayClipboardAudit(data []byte) (GatewayClipboardAudit, error) {
|
||||
var value GatewayClipboardAudit
|
||||
if len(data) > 1024*1024 {
|
||||
return value, errors.New("protocol payload exceeds limit")
|
||||
}
|
||||
var fields map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &fields); err != nil {
|
||||
return value, err
|
||||
}
|
||||
if raw, ok := fields["direction"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) {
|
||||
return value, ValidationError{Violations: []FieldViolation{{Field: "direction", Code: "required"}}}
|
||||
}
|
||||
if raw, ok := fields["outcome"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) {
|
||||
return value, ValidationError{Violations: []FieldViolation{{Field: "outcome", Code: "required"}}}
|
||||
}
|
||||
if raw, ok := fields["reason"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) {
|
||||
return value, ValidationError{Violations: []FieldViolation{{Field: "reason", Code: "required"}}}
|
||||
}
|
||||
if raw, ok := fields["session_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) {
|
||||
return value, ValidationError{Violations: []FieldViolation{{Field: "session_id", Code: "required"}}}
|
||||
}
|
||||
if raw, ok := fields["text_bytes"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) {
|
||||
return value, ValidationError{Violations: []FieldViolation{{Field: "text_bytes", Code: "required"}}}
|
||||
}
|
||||
if raw, ok := fields["version"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) {
|
||||
return value, ValidationError{Violations: []FieldViolation{{Field: "version", Code: "required"}}}
|
||||
}
|
||||
decoder := json.NewDecoder(bytes.NewReader(data))
|
||||
decoder.DisallowUnknownFields()
|
||||
if err := decoder.Decode(&value); err != nil {
|
||||
return value, err
|
||||
}
|
||||
var trailing any
|
||||
if err := decoder.Decode(&trailing); err != io.EOF {
|
||||
if err == nil {
|
||||
return value, errors.New("trailing JSON value")
|
||||
}
|
||||
return value, err
|
||||
}
|
||||
if err := value.Validate(); err != nil {
|
||||
return value, err
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func EncodeGatewayClipboardAudit(value GatewayClipboardAudit) ([]byte, error) {
|
||||
if err := value.Validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(value)
|
||||
}
|
||||
|
||||
func (v GatewayClipboardText) Validate() error {
|
||||
var violations []FieldViolation
|
||||
if v.Direction == "" {
|
||||
violations = append(violations, FieldViolation{Field: "direction", Code: "required"})
|
||||
}
|
||||
if v.Direction != "" && !(v.Direction == "client_to_provider" || v.Direction == "provider_to_client") {
|
||||
violations = append(violations, FieldViolation{Field: "direction", Code: "invalid_value"})
|
||||
}
|
||||
if v.Text == "" {
|
||||
violations = append(violations, FieldViolation{Field: "text", Code: "required"})
|
||||
}
|
||||
if len(v.Text) > 65536 {
|
||||
violations = append(violations, FieldViolation{Field: "text", Code: "max_length"})
|
||||
}
|
||||
if v.Encoding == "" {
|
||||
violations = append(violations, FieldViolation{Field: "encoding", Code: "required"})
|
||||
}
|
||||
if v.Encoding != "utf-8" && v.Encoding != "" {
|
||||
violations = append(violations, FieldViolation{Field: "encoding", Code: "invalid_value"})
|
||||
}
|
||||
if v.LoopToken == "" {
|
||||
violations = append(violations, FieldViolation{Field: "loop_token", Code: "required"})
|
||||
}
|
||||
if len(v.LoopToken) < 16 && v.LoopToken != "" {
|
||||
violations = append(violations, FieldViolation{Field: "loop_token", Code: "min_length"})
|
||||
}
|
||||
if len(v.LoopToken) > 128 {
|
||||
violations = append(violations, FieldViolation{Field: "loop_token", Code: "max_length"})
|
||||
}
|
||||
if len(violations) > 0 {
|
||||
return ValidationError{Violations: violations}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DecodeGatewayClipboardText(data []byte) (GatewayClipboardText, error) {
|
||||
var value GatewayClipboardText
|
||||
if len(data) > 1024*1024 {
|
||||
return value, errors.New("protocol payload exceeds limit")
|
||||
}
|
||||
var fields map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &fields); err != nil {
|
||||
return value, err
|
||||
}
|
||||
if raw, ok := fields["direction"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) {
|
||||
return value, ValidationError{Violations: []FieldViolation{{Field: "direction", Code: "required"}}}
|
||||
}
|
||||
if raw, ok := fields["encoding"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) {
|
||||
return value, ValidationError{Violations: []FieldViolation{{Field: "encoding", Code: "required"}}}
|
||||
}
|
||||
if raw, ok := fields["loop_token"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) {
|
||||
return value, ValidationError{Violations: []FieldViolation{{Field: "loop_token", Code: "required"}}}
|
||||
}
|
||||
if raw, ok := fields["text"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) {
|
||||
return value, ValidationError{Violations: []FieldViolation{{Field: "text", Code: "required"}}}
|
||||
}
|
||||
if raw, ok := fields["text"]; ok && len(raw) > 65536 {
|
||||
return value, ValidationError{Violations: []FieldViolation{{Field: "text", 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 EncodeGatewayClipboardText(value GatewayClipboardText) ([]byte, error) {
|
||||
if err := value.Validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(value)
|
||||
}
|
||||
|
||||
func (v GatewayDrain) Validate() error {
|
||||
var violations []FieldViolation
|
||||
if v.Version == "" {
|
||||
@@ -3082,6 +3362,12 @@ func (v ProviderSessionWork) Validate() error {
|
||||
if len(v.ServerCertificatePem) > 32768 {
|
||||
violations = append(violations, FieldViolation{Field: "server_certificate_pem", Code: "max_length"})
|
||||
}
|
||||
if reflect.DeepEqual(v.ClipboardPolicy, ClipboardPolicy{}) {
|
||||
violations = append(violations, FieldViolation{Field: "clipboard_policy", Code: "required"})
|
||||
}
|
||||
if err := v.ClipboardPolicy.Validate(); err != nil {
|
||||
violations = append(violations, FieldViolation{Field: "clipboard_policy", Code: "invalid_object"})
|
||||
}
|
||||
if len(violations) > 0 {
|
||||
return ValidationError{Violations: violations}
|
||||
}
|
||||
@@ -3109,6 +3395,9 @@ func DecodeProviderSessionWork(data []byte) (ProviderSessionWork, error) {
|
||||
if raw, ok := fields["client_private_key_pem"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) {
|
||||
return value, ValidationError{Violations: []FieldViolation{{Field: "client_private_key_pem", Code: "required"}}}
|
||||
}
|
||||
if raw, ok := fields["clipboard_policy"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) {
|
||||
return value, ValidationError{Violations: []FieldViolation{{Field: "clipboard_policy", Code: "required"}}}
|
||||
}
|
||||
if raw, ok := fields["expires_at"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) {
|
||||
return value, ValidationError{Violations: []FieldViolation{{Field: "expires_at", Code: "required"}}}
|
||||
}
|
||||
@@ -3124,6 +3413,9 @@ func DecodeProviderSessionWork(data []byte) (ProviderSessionWork, error) {
|
||||
if raw, ok := fields["policy_version_id"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) {
|
||||
return value, ValidationError{Violations: []FieldViolation{{Field: "policy_version_id", Code: "required"}}}
|
||||
}
|
||||
if raw, ok := fields["provider_application_termination_allowed"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) {
|
||||
return value, ValidationError{Violations: []FieldViolation{{Field: "provider_application_termination_allowed", Code: "required"}}}
|
||||
}
|
||||
if raw, ok := fields["provider_identity"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) {
|
||||
return value, ValidationError{Violations: []FieldViolation{{Field: "provider_identity", Code: "required"}}}
|
||||
}
|
||||
|
||||
+1
-1
@@ -14,5 +14,5 @@
|
||||
},
|
||||
"generator_sha256": "e9c6ee1541585fcb00dcc5e94a5a6d93dbe3a719a5c545f31e5eda268f2638ab",
|
||||
"protocol_version": "1.0.0",
|
||||
"schema_sha256": "792abfb9cfe70e79911d499d76c009ab848713278bc240b88576df520580e480"
|
||||
"schema_sha256": "e35414af52d7a097dea05567fdab11f842a42e529fb6cbedd281c48dbf930b17"
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
+100
-3
@@ -1,6 +1,6 @@
|
||||
// Code generated by tools/generate.py; DO NOT EDIT.
|
||||
#![allow(non_snake_case)]
|
||||
pub const SCHEMA_SHA256: &str = "792abfb9cfe70e79911d499d76c009ab848713278bc240b88576df520580e480";
|
||||
pub const SCHEMA_SHA256: &str = "e35414af52d7a097dea05567fdab11f842a42e529fb6cbedd281c48dbf930b17";
|
||||
pub const CURRENT_WIRE_VERSION: &str = "1";
|
||||
pub const N_MINUS_1_WIRE_VERSION: &str = "0";
|
||||
pub const N_MINUS_2_WIRE_VERSION: &str = "-1";
|
||||
@@ -272,6 +272,33 @@ impl ChannelFrame {
|
||||
pub fn payload(&self) -> &String { &self.payload }
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ClipboardPolicy {
|
||||
clientToProviderEnabled: bool,
|
||||
providerToClientEnabled: bool,
|
||||
maxTextBytes: i64,
|
||||
maxUpdatesPerMinute: i64,
|
||||
}
|
||||
|
||||
impl ClipboardPolicy {
|
||||
pub fn new(clientToProviderEnabled: bool, providerToClientEnabled: bool, maxTextBytes: i64, maxUpdatesPerMinute: i64) -> Result<Self, ValidationError> {
|
||||
let value = Self { clientToProviderEnabled, providerToClientEnabled, maxTextBytes, maxUpdatesPerMinute };
|
||||
value.validate()?;
|
||||
Ok(value)
|
||||
}
|
||||
pub fn validate(&self) -> Result<(), ValidationError> {
|
||||
if self.maxTextBytes < 1 { return Err(ValidationError::new("max_text_bytes", "minimum")); }
|
||||
if self.maxTextBytes > 65536 { return Err(ValidationError::new("max_text_bytes", "maximum")); }
|
||||
if self.maxUpdatesPerMinute < 1 { return Err(ValidationError::new("max_updates_per_minute", "minimum")); }
|
||||
if self.maxUpdatesPerMinute > 120 { return Err(ValidationError::new("max_updates_per_minute", "maximum")); }
|
||||
Ok(())
|
||||
}
|
||||
pub fn clientToProviderEnabled(&self) -> &bool { &self.clientToProviderEnabled }
|
||||
pub fn providerToClientEnabled(&self) -> &bool { &self.providerToClientEnabled }
|
||||
pub fn maxTextBytes(&self) -> &i64 { &self.maxTextBytes }
|
||||
pub fn maxUpdatesPerMinute(&self) -> &i64 { &self.maxUpdatesPerMinute }
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ClipboardText {
|
||||
text: String,
|
||||
@@ -612,6 +639,71 @@ impl FieldViolation {
|
||||
pub fn code(&self) -> &String { &self.code }
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct GatewayClipboardAudit {
|
||||
version: String,
|
||||
sessionId: String,
|
||||
direction: String,
|
||||
outcome: String,
|
||||
textBytes: i64,
|
||||
reason: String,
|
||||
}
|
||||
|
||||
impl GatewayClipboardAudit {
|
||||
pub fn new(version: String, sessionId: String, direction: String, outcome: String, textBytes: i64, reason: String) -> Result<Self, ValidationError> {
|
||||
let value = Self { version, sessionId, direction, outcome, textBytes, reason };
|
||||
value.validate()?;
|
||||
Ok(value)
|
||||
}
|
||||
pub fn validate(&self) -> Result<(), ValidationError> {
|
||||
if self.version != "1" { return Err(ValidationError::new("version", "invalid_value")); }
|
||||
if self.sessionId.is_empty() { return Err(ValidationError::new("session_id", "required")); }
|
||||
if !self.sessionId.is_empty() && self.sessionId.len() < 1 { return Err(ValidationError::new("session_id", "min_length")); }
|
||||
if self.sessionId.len() > 128 { return Err(ValidationError::new("session_id", "max_length")); }
|
||||
if self.direction != "client_to_provider" && self.direction != "provider_to_client" { return Err(ValidationError::new("direction", "invalid_value")); }
|
||||
if self.outcome != "forwarded" && self.outcome != "suppressed" && self.outcome != "rejected" { return Err(ValidationError::new("outcome", "invalid_value")); }
|
||||
if self.textBytes < 0 { return Err(ValidationError::new("text_bytes", "minimum")); }
|
||||
if self.textBytes > 65536 { return Err(ValidationError::new("text_bytes", "maximum")); }
|
||||
if self.reason != "forwarded" && self.reason != "loop" && self.reason != "policy" && self.reason != "rate" && self.reason != "provider" && self.reason != "malformed" { return Err(ValidationError::new("reason", "invalid_value")); }
|
||||
Ok(())
|
||||
}
|
||||
pub fn version(&self) -> &String { &self.version }
|
||||
pub fn sessionId(&self) -> &String { &self.sessionId }
|
||||
pub fn direction(&self) -> &String { &self.direction }
|
||||
pub fn outcome(&self) -> &String { &self.outcome }
|
||||
pub fn textBytes(&self) -> &i64 { &self.textBytes }
|
||||
pub fn reason(&self) -> &String { &self.reason }
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct GatewayClipboardText {
|
||||
direction: String,
|
||||
text: String,
|
||||
encoding: String,
|
||||
loopToken: String,
|
||||
}
|
||||
|
||||
impl GatewayClipboardText {
|
||||
pub fn new(direction: String, text: String, encoding: String, loopToken: String) -> Result<Self, ValidationError> {
|
||||
let value = Self { direction, text, encoding, loopToken };
|
||||
value.validate()?;
|
||||
Ok(value)
|
||||
}
|
||||
pub fn validate(&self) -> Result<(), ValidationError> {
|
||||
if self.direction != "client_to_provider" && self.direction != "provider_to_client" { return Err(ValidationError::new("direction", "invalid_value")); }
|
||||
if self.text.len() > 65536 { return Err(ValidationError::new("text", "max_length")); }
|
||||
if self.encoding != "utf-8" { return Err(ValidationError::new("encoding", "invalid_value")); }
|
||||
if self.loopToken.is_empty() { return Err(ValidationError::new("loop_token", "required")); }
|
||||
if !self.loopToken.is_empty() && self.loopToken.len() < 16 { return Err(ValidationError::new("loop_token", "min_length")); }
|
||||
if self.loopToken.len() > 128 { return Err(ValidationError::new("loop_token", "max_length")); }
|
||||
Ok(())
|
||||
}
|
||||
pub fn direction(&self) -> &String { &self.direction }
|
||||
pub fn text(&self) -> &String { &self.text }
|
||||
pub fn encoding(&self) -> &String { &self.encoding }
|
||||
pub fn loopToken(&self) -> &String { &self.loopToken }
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct GatewayDrain {
|
||||
version: String,
|
||||
@@ -1001,11 +1093,13 @@ pub struct ProviderSessionWork {
|
||||
clientCertificatePem: String,
|
||||
clientPrivateKeyPem: String,
|
||||
serverCertificatePem: String,
|
||||
clipboardPolicy: ClipboardPolicy,
|
||||
providerApplicationTerminationAllowed: bool,
|
||||
}
|
||||
|
||||
impl ProviderSessionWork {
|
||||
pub fn new(version: String, sessionId: String, gatewayId: String, reconnectSequence: i64, expiresAt: String, providerProfile: String, providerIdentity: String, policyVersionId: String, applicationId: String, clientId: String, managementHost: String, managementPort: i64, streamHost: String, streamPort: i64, clientCertificatePem: String, clientPrivateKeyPem: String, serverCertificatePem: String) -> Result<Self, ValidationError> {
|
||||
let value = Self { version, sessionId, gatewayId, reconnectSequence, expiresAt, providerProfile, providerIdentity, policyVersionId, applicationId, clientId, managementHost, managementPort, streamHost, streamPort, clientCertificatePem, clientPrivateKeyPem, serverCertificatePem };
|
||||
pub fn new(version: String, sessionId: String, gatewayId: String, reconnectSequence: i64, expiresAt: String, providerProfile: String, providerIdentity: String, policyVersionId: String, applicationId: String, clientId: String, managementHost: String, managementPort: i64, streamHost: String, streamPort: i64, clientCertificatePem: String, clientPrivateKeyPem: String, serverCertificatePem: String, clipboardPolicy: ClipboardPolicy, providerApplicationTerminationAllowed: bool) -> Result<Self, ValidationError> {
|
||||
let value = Self { version, sessionId, gatewayId, reconnectSequence, expiresAt, providerProfile, providerIdentity, policyVersionId, applicationId, clientId, managementHost, managementPort, streamHost, streamPort, clientCertificatePem, clientPrivateKeyPem, serverCertificatePem, clipboardPolicy, providerApplicationTerminationAllowed };
|
||||
value.validate()?;
|
||||
Ok(value)
|
||||
}
|
||||
@@ -1051,6 +1145,7 @@ impl ProviderSessionWork {
|
||||
if self.serverCertificatePem.is_empty() { return Err(ValidationError::new("server_certificate_pem", "required")); }
|
||||
if !self.serverCertificatePem.is_empty() && self.serverCertificatePem.len() < 1 { return Err(ValidationError::new("server_certificate_pem", "min_length")); }
|
||||
if self.serverCertificatePem.len() > 32768 { return Err(ValidationError::new("server_certificate_pem", "max_length")); }
|
||||
self.clipboardPolicy.validate().map_err(|_| ValidationError::new("clipboard_policy", "invalid_object"))?;
|
||||
Ok(())
|
||||
}
|
||||
pub fn version(&self) -> &String { &self.version }
|
||||
@@ -1070,6 +1165,8 @@ impl ProviderSessionWork {
|
||||
pub fn clientCertificatePem(&self) -> &String { &self.clientCertificatePem }
|
||||
pub fn clientPrivateKeyPem(&self) -> &String { &self.clientPrivateKeyPem }
|
||||
pub fn serverCertificatePem(&self) -> &String { &self.serverCertificatePem }
|
||||
pub fn clipboardPolicy(&self) -> &ClipboardPolicy { &self.clipboardPolicy }
|
||||
pub fn providerApplicationTerminationAllowed(&self) -> &bool { &self.providerApplicationTerminationAllowed }
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
|
||||
+137
-3
@@ -1,7 +1,7 @@
|
||||
// Code generated by tools/generate.py; DO NOT EDIT.
|
||||
import Foundation
|
||||
public typealias JSONObject = [String: String]
|
||||
public let schemaSHA256 = "792abfb9cfe70e79911d499d76c009ab848713278bc240b88576df520580e480"
|
||||
public let schemaSHA256 = "e35414af52d7a097dea05567fdab11f842a42e529fb6cbedd281c48dbf930b17"
|
||||
public let currentWireVersion = "1"
|
||||
public let nMinus1WireVersion = "0"
|
||||
public let nMinus2WireVersion = "-1"
|
||||
@@ -350,6 +350,44 @@ public struct ChannelFrame: Codable, Equatable {
|
||||
public func encodeJSON() throws -> Data { try validate(); return try JSONEncoder().encode(self) }
|
||||
}
|
||||
|
||||
public struct ClipboardPolicy: Codable, Equatable {
|
||||
public let clientToProviderEnabled: Bool
|
||||
public let providerToClientEnabled: Bool
|
||||
public let maxTextBytes: Int64
|
||||
public let maxUpdatesPerMinute: Int64
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case clientToProviderEnabled = "client_to_provider_enabled"
|
||||
case providerToClientEnabled = "provider_to_client_enabled"
|
||||
case maxTextBytes = "max_text_bytes"
|
||||
case maxUpdatesPerMinute = "max_updates_per_minute"
|
||||
}
|
||||
|
||||
public init(clientToProviderEnabled: Bool, providerToClientEnabled: Bool, maxTextBytes: Int64, maxUpdatesPerMinute: Int64) throws {
|
||||
self.clientToProviderEnabled = clientToProviderEnabled
|
||||
self.providerToClientEnabled = providerToClientEnabled
|
||||
self.maxTextBytes = maxTextBytes
|
||||
self.maxUpdatesPerMinute = maxUpdatesPerMinute
|
||||
try validate()
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let all = try decoder.container(keyedBy: AnyCodingKey.self)
|
||||
for key in all.allKeys where CodingKeys(stringValue: key.stringValue) == nil { throw ContractValidationError(field: key.stringValue, code: "unknown_field") }
|
||||
let c = try decoder.container(keyedBy: CodingKeys.self)
|
||||
try self.init(clientToProviderEnabled: try c.decode(Bool.self, forKey: .clientToProviderEnabled), providerToClientEnabled: try c.decode(Bool.self, forKey: .providerToClientEnabled), maxTextBytes: try c.decode(Int64.self, forKey: .maxTextBytes), maxUpdatesPerMinute: try c.decode(Int64.self, forKey: .maxUpdatesPerMinute))
|
||||
}
|
||||
|
||||
public func validate() throws {
|
||||
if self.maxTextBytes < 1 { throw ContractValidationError(field: "max_text_bytes", code: "minimum") }
|
||||
if self.maxTextBytes > 65536 { throw ContractValidationError(field: "max_text_bytes", code: "maximum") }
|
||||
if self.maxUpdatesPerMinute < 1 { throw ContractValidationError(field: "max_updates_per_minute", code: "minimum") }
|
||||
if self.maxUpdatesPerMinute > 120 { throw ContractValidationError(field: "max_updates_per_minute", code: "maximum") }
|
||||
}
|
||||
|
||||
public static func decodeJSON(_ data: Data) throws -> Self { try JSONDecoder().decode(Self.self, from: data) }
|
||||
public func encodeJSON() throws -> Data { try validate(); return try JSONEncoder().encode(self) }
|
||||
}
|
||||
|
||||
public struct ClipboardText: Codable, Equatable {
|
||||
public let text: String
|
||||
public let encoding: String
|
||||
@@ -809,6 +847,95 @@ public struct FieldViolation: Codable, Equatable {
|
||||
public func encodeJSON() throws -> Data { try validate(); return try JSONEncoder().encode(self) }
|
||||
}
|
||||
|
||||
public struct GatewayClipboardAudit: Codable, Equatable {
|
||||
public let version: String
|
||||
public let sessionId: String
|
||||
public let direction: String
|
||||
public let outcome: String
|
||||
public let textBytes: Int64
|
||||
public let reason: String
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case version = "version"
|
||||
case sessionId = "session_id"
|
||||
case direction = "direction"
|
||||
case outcome = "outcome"
|
||||
case textBytes = "text_bytes"
|
||||
case reason = "reason"
|
||||
}
|
||||
|
||||
public init(version: String, sessionId: String, direction: String, outcome: String, textBytes: Int64, reason: String) throws {
|
||||
self.version = version
|
||||
self.sessionId = sessionId
|
||||
self.direction = direction
|
||||
self.outcome = outcome
|
||||
self.textBytes = textBytes
|
||||
self.reason = reason
|
||||
try validate()
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let all = try decoder.container(keyedBy: AnyCodingKey.self)
|
||||
for key in all.allKeys where CodingKeys(stringValue: key.stringValue) == nil { throw ContractValidationError(field: key.stringValue, code: "unknown_field") }
|
||||
let c = try decoder.container(keyedBy: CodingKeys.self)
|
||||
try self.init(version: try c.decode(String.self, forKey: .version), sessionId: try c.decode(String.self, forKey: .sessionId), direction: try c.decode(String.self, forKey: .direction), outcome: try c.decode(String.self, forKey: .outcome), textBytes: try c.decode(Int64.self, forKey: .textBytes), reason: try c.decode(String.self, forKey: .reason))
|
||||
}
|
||||
|
||||
public func validate() throws {
|
||||
if self.version != "1" { throw ContractValidationError(field: "version", code: "invalid_value") }
|
||||
if self.sessionId.isEmpty { throw ContractValidationError(field: "session_id", code: "required") }
|
||||
if !self.sessionId.isEmpty && self.sessionId.utf8.count < 1 { throw ContractValidationError(field: "session_id", code: "min_length") }
|
||||
if self.sessionId.utf8.count > 128 { throw ContractValidationError(field: "session_id", code: "max_length") }
|
||||
if !["client_to_provider", "provider_to_client"].contains(self.direction) { throw ContractValidationError(field: "direction", code: "invalid_value") }
|
||||
if !["forwarded", "suppressed", "rejected"].contains(self.outcome) { throw ContractValidationError(field: "outcome", code: "invalid_value") }
|
||||
if self.textBytes < 0 { throw ContractValidationError(field: "text_bytes", code: "minimum") }
|
||||
if self.textBytes > 65536 { throw ContractValidationError(field: "text_bytes", code: "maximum") }
|
||||
if !["forwarded", "loop", "policy", "rate", "provider", "malformed"].contains(self.reason) { throw ContractValidationError(field: "reason", code: "invalid_value") }
|
||||
}
|
||||
|
||||
public static func decodeJSON(_ data: Data) throws -> Self { try JSONDecoder().decode(Self.self, from: data) }
|
||||
public func encodeJSON() throws -> Data { try validate(); return try JSONEncoder().encode(self) }
|
||||
}
|
||||
|
||||
public struct GatewayClipboardText: Codable, Equatable {
|
||||
public let direction: String
|
||||
public let text: String
|
||||
public let encoding: String
|
||||
public let loopToken: String
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case direction = "direction"
|
||||
case text = "text"
|
||||
case encoding = "encoding"
|
||||
case loopToken = "loop_token"
|
||||
}
|
||||
|
||||
public init(direction: String, text: String, encoding: String, loopToken: String) throws {
|
||||
self.direction = direction
|
||||
self.text = text
|
||||
self.encoding = encoding
|
||||
self.loopToken = loopToken
|
||||
try validate()
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let all = try decoder.container(keyedBy: AnyCodingKey.self)
|
||||
for key in all.allKeys where CodingKeys(stringValue: key.stringValue) == nil { throw ContractValidationError(field: key.stringValue, code: "unknown_field") }
|
||||
let c = try decoder.container(keyedBy: CodingKeys.self)
|
||||
try self.init(direction: try c.decode(String.self, forKey: .direction), text: try c.decode(String.self, forKey: .text), encoding: try c.decode(String.self, forKey: .encoding), loopToken: try c.decode(String.self, forKey: .loopToken))
|
||||
}
|
||||
|
||||
public func validate() throws {
|
||||
if !["client_to_provider", "provider_to_client"].contains(self.direction) { throw ContractValidationError(field: "direction", code: "invalid_value") }
|
||||
if self.text.utf8.count > 65536 { throw ContractValidationError(field: "text", code: "max_length") }
|
||||
if self.encoding != "utf-8" { throw ContractValidationError(field: "encoding", code: "invalid_value") }
|
||||
if self.loopToken.isEmpty { throw ContractValidationError(field: "loop_token", code: "required") }
|
||||
if !self.loopToken.isEmpty && self.loopToken.utf8.count < 16 { throw ContractValidationError(field: "loop_token", code: "min_length") }
|
||||
if self.loopToken.utf8.count > 128 { throw ContractValidationError(field: "loop_token", code: "max_length") }
|
||||
}
|
||||
|
||||
public static func decodeJSON(_ data: Data) throws -> Self { try JSONDecoder().decode(Self.self, from: data) }
|
||||
public func encodeJSON() throws -> Data { try validate(); return try JSONEncoder().encode(self) }
|
||||
}
|
||||
|
||||
public struct GatewayDrain: Codable, Equatable {
|
||||
public let version: String
|
||||
public let gatewayId: String
|
||||
@@ -1328,6 +1455,8 @@ public struct ProviderSessionWork: Codable, Equatable {
|
||||
public let clientCertificatePem: String
|
||||
public let clientPrivateKeyPem: String
|
||||
public let serverCertificatePem: String
|
||||
public let clipboardPolicy: ClipboardPolicy
|
||||
public let providerApplicationTerminationAllowed: Bool
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case version = "version"
|
||||
case sessionId = "session_id"
|
||||
@@ -1346,9 +1475,11 @@ public struct ProviderSessionWork: Codable, Equatable {
|
||||
case clientCertificatePem = "client_certificate_pem"
|
||||
case clientPrivateKeyPem = "client_private_key_pem"
|
||||
case serverCertificatePem = "server_certificate_pem"
|
||||
case clipboardPolicy = "clipboard_policy"
|
||||
case providerApplicationTerminationAllowed = "provider_application_termination_allowed"
|
||||
}
|
||||
|
||||
public init(version: String, sessionId: String, gatewayId: String, reconnectSequence: Int64, expiresAt: String, providerProfile: String, providerIdentity: String, policyVersionId: String, applicationId: String, clientId: String, managementHost: String, managementPort: Int64, streamHost: String, streamPort: Int64, clientCertificatePem: String, clientPrivateKeyPem: String, serverCertificatePem: String) throws {
|
||||
public init(version: String, sessionId: String, gatewayId: String, reconnectSequence: Int64, expiresAt: String, providerProfile: String, providerIdentity: String, policyVersionId: String, applicationId: String, clientId: String, managementHost: String, managementPort: Int64, streamHost: String, streamPort: Int64, clientCertificatePem: String, clientPrivateKeyPem: String, serverCertificatePem: String, clipboardPolicy: ClipboardPolicy, providerApplicationTerminationAllowed: Bool) throws {
|
||||
self.version = version
|
||||
self.sessionId = sessionId
|
||||
self.gatewayId = gatewayId
|
||||
@@ -1366,6 +1497,8 @@ public struct ProviderSessionWork: Codable, Equatable {
|
||||
self.clientCertificatePem = clientCertificatePem
|
||||
self.clientPrivateKeyPem = clientPrivateKeyPem
|
||||
self.serverCertificatePem = serverCertificatePem
|
||||
self.clipboardPolicy = clipboardPolicy
|
||||
self.providerApplicationTerminationAllowed = providerApplicationTerminationAllowed
|
||||
try validate()
|
||||
}
|
||||
|
||||
@@ -1373,7 +1506,7 @@ public struct ProviderSessionWork: Codable, Equatable {
|
||||
let all = try decoder.container(keyedBy: AnyCodingKey.self)
|
||||
for key in all.allKeys where CodingKeys(stringValue: key.stringValue) == nil { throw ContractValidationError(field: key.stringValue, code: "unknown_field") }
|
||||
let c = try decoder.container(keyedBy: CodingKeys.self)
|
||||
try self.init(version: try c.decode(String.self, forKey: .version), sessionId: try c.decode(String.self, forKey: .sessionId), gatewayId: try c.decode(String.self, forKey: .gatewayId), reconnectSequence: try c.decode(Int64.self, forKey: .reconnectSequence), expiresAt: try c.decode(String.self, forKey: .expiresAt), providerProfile: try c.decode(String.self, forKey: .providerProfile), providerIdentity: try c.decode(String.self, forKey: .providerIdentity), policyVersionId: try c.decode(String.self, forKey: .policyVersionId), applicationId: try c.decode(String.self, forKey: .applicationId), clientId: try c.decode(String.self, forKey: .clientId), managementHost: try c.decode(String.self, forKey: .managementHost), managementPort: try c.decode(Int64.self, forKey: .managementPort), streamHost: try c.decode(String.self, forKey: .streamHost), streamPort: try c.decode(Int64.self, forKey: .streamPort), clientCertificatePem: try c.decode(String.self, forKey: .clientCertificatePem), clientPrivateKeyPem: try c.decode(String.self, forKey: .clientPrivateKeyPem), serverCertificatePem: try c.decode(String.self, forKey: .serverCertificatePem))
|
||||
try self.init(version: try c.decode(String.self, forKey: .version), sessionId: try c.decode(String.self, forKey: .sessionId), gatewayId: try c.decode(String.self, forKey: .gatewayId), reconnectSequence: try c.decode(Int64.self, forKey: .reconnectSequence), expiresAt: try c.decode(String.self, forKey: .expiresAt), providerProfile: try c.decode(String.self, forKey: .providerProfile), providerIdentity: try c.decode(String.self, forKey: .providerIdentity), policyVersionId: try c.decode(String.self, forKey: .policyVersionId), applicationId: try c.decode(String.self, forKey: .applicationId), clientId: try c.decode(String.self, forKey: .clientId), managementHost: try c.decode(String.self, forKey: .managementHost), managementPort: try c.decode(Int64.self, forKey: .managementPort), streamHost: try c.decode(String.self, forKey: .streamHost), streamPort: try c.decode(Int64.self, forKey: .streamPort), clientCertificatePem: try c.decode(String.self, forKey: .clientCertificatePem), clientPrivateKeyPem: try c.decode(String.self, forKey: .clientPrivateKeyPem), serverCertificatePem: try c.decode(String.self, forKey: .serverCertificatePem), clipboardPolicy: try c.decode(ClipboardPolicy.self, forKey: .clipboardPolicy), providerApplicationTerminationAllowed: try c.decode(Bool.self, forKey: .providerApplicationTerminationAllowed))
|
||||
}
|
||||
|
||||
public func validate() throws {
|
||||
@@ -1419,6 +1552,7 @@ public struct ProviderSessionWork: Codable, Equatable {
|
||||
if self.serverCertificatePem.isEmpty { throw ContractValidationError(field: "server_certificate_pem", code: "required") }
|
||||
if !self.serverCertificatePem.isEmpty && self.serverCertificatePem.utf8.count < 1 { throw ContractValidationError(field: "server_certificate_pem", code: "min_length") }
|
||||
if self.serverCertificatePem.utf8.count > 32768 { throw ContractValidationError(field: "server_certificate_pem", code: "max_length") }
|
||||
try self.clipboardPolicy.validate()
|
||||
}
|
||||
|
||||
public static func decodeJSON(_ data: Data) throws -> Self { try JSONDecoder().decode(Self.self, from: data) }
|
||||
|
||||
Reference in New Issue
Block a user