feat(protocol): freeze M4 native session RC6 contract

This commit is contained in:
sechmachine
2026-08-13 07:18:03 +07:00
parent 4693102b3c
commit 8eacc4fda9
35 changed files with 5334 additions and 473 deletions
+168 -33
View File
@@ -139,11 +139,15 @@ def go_validation(definition: dict[str, Any]) -> list[str]:
)
if prop.get("format") == "base64url":
lines.append(f"\tif v.{field} != \"\" {{ if _, err := base64.RawURLEncoding.Strict().DecodeString(v.{field}); err != nil {{ violations = append(violations, FieldViolation{{Field: \"{prop_name}\", Code: \"invalid_format\"}}) }} }}")
if prop.get("format") == "uuid":
lines.append(f"\tif v.{field} != \"\" && !validCanonicalUUID(v.{field}) {{ violations = append(violations, FieldViolation{{Field: \"{prop_name}\", Code: \"invalid_uuid\"}}) }}")
if prop.get("type") == "integer":
value = f"*v.{field}" if prop.get("x-optional-pointer") else f"v.{field}"
guard = f"v.{field} != nil && " if prop.get("x-optional-pointer") else ""
if "minimum" in prop:
lines.append(f"\tif v.{field} != 0 && v.{field} < {prop['minimum']} {{ violations = append(violations, FieldViolation{{Field: \"{prop_name}\", Code: \"minimum\"}}) }}")
lines.append(f"\tif {guard}{value} != 0 && {value} < {prop['minimum']} {{ violations = append(violations, FieldViolation{{Field: \"{prop_name}\", Code: \"minimum\"}}) }}")
if "maximum" in prop:
lines.append(f"\tif v.{field} > {prop['maximum']} {{ violations = append(violations, FieldViolation{{Field: \"{prop_name}\", Code: \"maximum\"}}) }}")
lines.append(f"\tif {guard}{value} > {prop['maximum']} {{ violations = append(violations, FieldViolation{{Field: \"{prop_name}\", Code: \"maximum\"}}) }}")
if prop.get("type") == "array":
if "minItems" in prop:
lines.append(f"\tif len(v.{field}) < {prop['minItems']} {{ violations = append(violations, FieldViolation{{Field: \"{prop_name}\", Code: \"min_items\"}}) }}")
@@ -159,8 +163,8 @@ def go_validation(definition: dict[str, Any]) -> list[str]:
if "enum" in items:
allowed = " || ".join(f'item == "{value}"' for value in items["enum"])
lines.append(f"\tfor _, item := range v.{field} {{ if !({allowed}) {{ violations = append(violations, FieldViolation{{Field: \"{prop_name}\", Code: \"invalid_item\"}}) }} }}")
if prop.get("uniqueItems") and items.get("type") == "string":
lines.append(f"\tfor index, item := range v.{field} {{ for prior := 0; prior < index; prior++ {{ if item == v.{field}[prior] {{ violations = append(violations, FieldViolation{{Field: \"{prop_name}\", Code: \"duplicate_item\"}}) }} }} }}")
if prop.get("uniqueItems"):
lines.append(f"\tfor index, item := range v.{field} {{ for prior := 0; prior < index; prior++ {{ if reflect.DeepEqual(item, v.{field}[prior]) {{ violations = append(violations, FieldViolation{{Field: \"{prop_name}\", Code: \"duplicate_item\"}}) }} }} }}")
item_ref = ref_name(items)
if item_ref:
lines.append(f"\tfor index := range v.{field} {{ if err := v.{field}[index].Validate(); err != nil {{ violations = append(violations, FieldViolation{{Field: fmt.Sprintf(\"{prop_name}[%d]\", index), Code: \"invalid_item\"}}) }} }}")
@@ -173,6 +177,12 @@ def go_validation(definition: dict[str, Any]) -> list[str]:
lines.append(f"\t{validation}")
if name in {"AllocationPolicy", "ManifestBounds"}:
lines.append("\tif v.MinimumKbps > v.TargetKbps || v.TargetKbps > v.MaximumKbps { violations = append(violations, FieldViolation{Field: \"bounds\", Code: \"invalid_order\"}) }")
if name == "SessionQualityLimits":
lines.append("\tif v.BitrateMinimumKbps > v.BitrateTargetKbps || v.BitrateTargetKbps > v.BitrateMaximumKbps { violations = append(violations, FieldViolation{Field: \"bitrate_bounds\", Code: \"invalid_order\"}) }")
if name in {"SelectedSessionDescriptor", "ProviderStreamPolicy"}:
lines.append("\tif v.BitrateTargetKbps > v.BitrateMaximumKbps { violations = append(violations, FieldViolation{Field: \"bitrate_bounds\", Code: \"invalid_order\"}) }")
if name == "BitratePreference":
lines.append("\tif v.Mode == \"auto\" && v.TargetKbps != nil || v.Mode == \"explicit\" && v.TargetKbps == nil { violations = append(violations, FieldViolation{Field: \"target_kbps\", Code: \"invalid_tagged_value\"}) }")
if name == "GatewayRegistration":
lines.append("\tif v.ProtocolMinVersion > v.ProtocolMaxVersion { violations = append(violations, FieldViolation{Field: \"protocol_version\", Code: \"invalid_order\"}) }")
if name == "ChannelFrame":
@@ -214,6 +224,30 @@ def generate_go(defs: dict[str, dict[str, Any]], schema_hash: str, version: str,
"",
"func (e ValidationError) Error() string { return \"protocol validation failed\" }",
"",
"func validCanonicalUUID(value string) bool {",
"\tif len(value) != 36 || value[8] != '-' || value[13] != '-' || value[18] != '-' || value[23] != '-' { return false }",
"\tfor index, char := range []byte(value) { if index == 8 || index == 13 || index == 18 || index == 23 { continue }; if !((char >= '0' && char <= '9') || (char >= 'a' && char <= 'f')) { return false } }",
"\treturn value != \"00000000-0000-0000-0000-000000000000\"",
"}",
"",
"func rejectDuplicateJSONKeys(data []byte) error {",
"\tdecoder := json.NewDecoder(bytes.NewReader(data))",
"\tvar scan func(json.Token) error",
"\tscan = func(token json.Token) error {",
"\t\tdelim, ok := token.(json.Delim); if !ok { return nil }",
"\t\tswitch delim {",
"\t\tcase '{':",
"\t\t\tseen := map[string]struct{}{}",
"\t\t\tfor decoder.More() { keyToken, err := decoder.Token(); if err != nil { return err }; key, ok := keyToken.(string); if !ok { return errors.New(\"invalid JSON object key\") }; if _, exists := seen[key]; exists { return errors.New(\"duplicate JSON object key\") }; seen[key] = struct{}{}; value, err := decoder.Token(); if err != nil { return err }; if err := scan(value); err != nil { return err } }",
"\t\t\t_, err := decoder.Token(); return err",
"\t\tcase '[':",
"\t\t\tfor decoder.More() { value, err := decoder.Token(); if err != nil { return err }; if err := scan(value); err != nil { return err } }; _, err := decoder.Token(); return err",
"\t\t}",
"\t\treturn nil",
"\t}",
"\ttoken, err := decoder.Token(); if err != nil { return err }; return scan(token)",
"}",
"",
]
for name in sorted(defs):
if name == "FieldViolation":
@@ -224,7 +258,9 @@ def generate_go(defs: dict[str, dict[str, Any]], schema_hash: str, version: str,
for prop_name, prop in definition.get("properties", {}).items():
tag = prop_name + (",omitempty" if prop_name not in required else "")
typ = prop_type(prop, "go")
if prop_name not in required and ref_name(prop):
if prop.get("x-optional-pointer"):
typ = "*" + typ
elif prop_name not in required and ref_name(prop):
typ = "*" + typ
out.append(f"\t{go_field(prop_name)} {typ} `json:\"{tag}\"`")
out.extend(["}", ""])
@@ -239,6 +275,7 @@ def generate_go(defs: dict[str, dict[str, Any]], schema_hash: str, version: str,
out.append(f"func Decode{name}(data []byte) ({name}, error) {{")
out.append(f"\tvar value {name}")
out.append("\tif len(data) > 1024*1024 { return value, errors.New(\"protocol payload exceeds limit\") }")
out.append("\tif err := rejectDuplicateJSONKeys(data); err != nil { return value, err }")
out.append("\tvar fields map[string]json.RawMessage")
out.append("\tif err := json.Unmarshal(data, &fields); err != nil { return value, err }")
required_fields = sorted(defs[name].get("required", []))
@@ -295,23 +332,29 @@ def generate_go(defs: dict[str, dict[str, Any]], schema_hash: str, version: str,
"\tif len(profiles) == 0 { return CapabilityProfile{}, ErrNoCapabilityOverlap }",
"\tselected := profiles[0]",
"\tif err := selected.Validate(); err != nil { return CapabilityProfile{}, ErrNoCapabilityOverlap }",
"\tcommon := append([]string(nil), selected.ClientDecode...)",
"\tcommonVideo := append([]VideoProfile(nil), selected.VideoProfiles...)",
"\tcommonAudio := append([]AudioProfile(nil), selected.AudioProfiles...)",
"\tfor _, profile := range profiles[1:] {",
"\t\tif err := profile.Validate(); err != nil || profile.Transport != selected.Transport || profile.Framing != selected.Framing || profile.Media != selected.Media || profile.Audio != selected.Audio || profile.SourceRateControl != selected.SourceRateControl { return CapabilityProfile{}, ErrNoCapabilityOverlap }",
"\t\tnext := common[:0]",
"\t\tfor _, candidate := range common { for _, offered := range profile.ClientDecode { if candidate == offered { next = append(next, candidate); break } } }",
"\t\tcommon = next",
"\t\tif len(common) == 0 { return CapabilityProfile{}, ErrNoCapabilityOverlap }",
"\t\tif err := profile.Validate(); err != nil || profile.Transport != selected.Transport || profile.Framing != selected.Framing || profile.Media != selected.Media || profile.SourceRateControl != selected.SourceRateControl { return CapabilityProfile{}, ErrNoCapabilityOverlap }",
"\t\tnextVideo := commonVideo[:0]",
"\t\tfor _, candidate := range commonVideo { for _, offered := range profile.VideoProfiles { if candidate == offered { nextVideo = append(nextVideo, candidate); break } } }",
"\t\tcommonVideo = nextVideo",
"\t\tnextAudio := commonAudio[:0]",
"\t\tfor _, candidate := range commonAudio { for _, offered := range profile.AudioProfiles { if candidate == offered { nextAudio = append(nextAudio, candidate); break } } }",
"\t\tcommonAudio = nextAudio",
"\t\tif len(commonVideo) == 0 || len(commonAudio) == 0 { return CapabilityProfile{}, ErrNoCapabilityOverlap }",
"\t}",
"\tselected.ClientDecode = common",
"\tselected.VideoProfiles = commonVideo",
"\tselected.AudioProfiles = commonAudio",
"\treturn selected, nil",
"}",
"",
])
out.extend([
"func (v TunnelAdmissionRequest) DeviceAdmissionTranscript() []byte {",
"\tfields := []string{v.SessionID, v.GatewayID, v.Audience, v.Grant, fmt.Sprintf(\"%d\", v.ReconnectSequence), v.ClientNonce, v.Capabilities.Transport, v.Capabilities.Framing, v.Capabilities.Media, v.Capabilities.Audio, v.Capabilities.SourceRateControl, fmt.Sprintf(\"%d\", len(v.Capabilities.ClientDecode))}",
"\tfields = append(fields, v.Capabilities.ClientDecode...)",
"\tfields := []string{v.SessionID, v.GatewayID, v.Audience, v.Grant, fmt.Sprintf(\"%d\", v.ReconnectSequence), v.ClientNonce, v.Capabilities.Transport, v.Capabilities.Framing, v.Capabilities.Media, v.Capabilities.SourceRateControl, fmt.Sprintf(\"%d\", len(v.Capabilities.VideoProfiles)), fmt.Sprintf(\"%d\", len(v.Capabilities.AudioProfiles))}",
"\tfor _, profile := range v.Capabilities.VideoProfiles { fields = append(fields, profile.Codec, fmt.Sprintf(\"%d\", profile.BitDepth), profile.ChromaSubsampling, profile.ColorSpace, profile.TransferFunction) }",
"\tfor _, profile := range v.Capabilities.AudioProfiles { fields = append(fields, profile.Codec, fmt.Sprintf(\"%d\", profile.SampleRateHz), fmt.Sprintf(\"%d\", profile.Channels), profile.ChannelLayout, fmt.Sprintf(\"%d\", profile.PacketDurationMs)) }",
"\tvar transcript strings.Builder",
"\ttranscript.WriteString(\"versevdi/tunnel-admission/v1\")",
"\tfor _, field := range fields { fmt.Fprintf(&transcript, \"%d:%s\", len(field), field) }",
@@ -386,11 +429,14 @@ def rust_validation(definition: dict[str, Any]) -> list[str]:
lines.append(f" {prefix}if !valid_rfc3339_utc({value}.as_str()) {{ return Err(ValidationError::new(\"{prop_name}\", \"invalid_time\")); }}")
if prop.get("format") == "base64url":
lines.append(f" {prefix}if !valid_base64_url({value}.as_str()) {{ return Err(ValidationError::new(\"{prop_name}\", \"invalid_format\")); }}")
if prop.get("format") == "uuid":
lines.append(f" {prefix}if !valid_canonical_uuid({value}.as_str()) {{ return Err(ValidationError::new(\"{prop_name}\", \"invalid_uuid\")); }}")
if prop.get("type") == "integer":
numeric = f"*{value}" if prop_name not in required else value
if "minimum" in prop:
lines.append(f" {prefix}if {value} < {prop['minimum']} {{ return Err(ValidationError::new(\"{prop_name}\", \"minimum\")); }}")
lines.append(f" {prefix}if {numeric} < {prop['minimum']} {{ return Err(ValidationError::new(\"{prop_name}\", \"minimum\")); }}")
if "maximum" in prop:
lines.append(f" {prefix}if {value} > {prop['maximum']} {{ return Err(ValidationError::new(\"{prop_name}\", \"maximum\")); }}")
lines.append(f" {prefix}if {numeric} > {prop['maximum']} {{ return Err(ValidationError::new(\"{prop_name}\", \"maximum\")); }}")
if prop.get("type") == "array":
if "minItems" in prop:
lines.append(f" {prefix}if {value}.len() < {prop['minItems']} {{ return Err(ValidationError::new(\"{prop_name}\", \"min_items\")); }}")
@@ -406,7 +452,7 @@ def rust_validation(definition: dict[str, Any]) -> list[str]:
if "enum" in items:
allowed = " && ".join(f'item != \"{item}\"' for item in items["enum"])
lines.append(f" {prefix}for item in {value}.iter() {{ if {allowed} {{ return Err(ValidationError::new(\"{prop_name}\", \"invalid_item\")); }} }}")
if prop.get("uniqueItems") and items.get("type") == "string":
if prop.get("uniqueItems"):
lines.append(f" {prefix}for (index, item) in {value}.iter().enumerate() {{ if {value}[..index].contains(item) {{ return Err(ValidationError::new(\"{prop_name}\", \"duplicate_item\")); }} }}")
item_ref = ref_name(items)
if item_ref:
@@ -419,6 +465,12 @@ def rust_validation(definition: dict[str, Any]) -> list[str]:
name = definition["name"]
if name in {"AllocationPolicy", "ManifestBounds"}:
lines.append(" if self.minimumKbps > self.targetKbps || self.targetKbps > self.maximumKbps { return Err(ValidationError::new(\"bounds\", \"invalid_order\")); }")
if name == "SessionQualityLimits":
lines.append(" if self.bitrateMinimumKbps > self.bitrateTargetKbps || self.bitrateTargetKbps > self.bitrateMaximumKbps { return Err(ValidationError::new(\"bitrate_bounds\", \"invalid_order\")); }")
if name in {"SelectedSessionDescriptor", "ProviderStreamPolicy"}:
lines.append(" if self.bitrateTargetKbps > self.bitrateMaximumKbps { return Err(ValidationError::new(\"bitrate_bounds\", \"invalid_order\")); }")
if name == "BitratePreference":
lines.append(" if self.mode == \"auto\" && self.targetKbps.is_some() || self.mode == \"explicit\" && self.targetKbps.is_none() { return Err(ValidationError::new(\"target_kbps\", \"invalid_tagged_value\")); }")
if name == "GatewayRegistration":
lines.append(" if self.protocolMinVersion > self.protocolMaxVersion { return Err(ValidationError::new(\"protocol_version\", \"invalid_order\")); }")
if name == "ChannelFrame":
@@ -473,6 +525,10 @@ def generate_rust(defs: dict[str, dict[str, Any]], schema_hash: str, compatibili
" let fraction = &bytes[20..bytes.len() - 1];",
" bytes[19] == b'.' && !fraction.is_empty() && fraction.len() <= 9 && fraction.iter().all(u8::is_ascii_digit) && *fraction.last().unwrap() != b'0'",
"}",
"fn valid_canonical_uuid(value: &str) -> bool {",
" let bytes = value.as_bytes();",
" bytes.len() == 36 && [8, 13, 18, 23].iter().all(|index| bytes[*index] == b'-') && bytes.iter().enumerate().all(|(index, byte)| [8, 13, 18, 23].contains(&index) || byte.is_ascii_digit() || (b'a'..=b'f').contains(byte)) && value != \"00000000-0000-0000-0000-000000000000\"",
"}",
"",
]
for name in sorted(defs):
@@ -515,9 +571,12 @@ def generate_rust(defs: dict[str, dict[str, Any]], schema_hash: str, compatibili
out.extend([
" pub fn device_admission_transcript(&self) -> Vec<u8> {",
" let reconnect_sequence = self.reconnectSequence.to_string();",
" let client_decode_count = self.capabilities.clientDecode.len().to_string();",
" let mut fields = vec![self.sessionId.as_str(), self.gatewayId.as_str(), self.audience.as_str(), self.grant.as_str(), reconnect_sequence.as_str(), self.clientNonce.as_str(), self.capabilities.transport.as_str(), self.capabilities.framing.as_str(), self.capabilities.media.as_str(), self.capabilities.audio.as_str(), self.capabilities.sourceRateControl.as_str(), client_decode_count.as_str()];",
" fields.extend(self.capabilities.clientDecode.iter().map(String::as_str));",
" let video_count = self.capabilities.videoProfiles.len().to_string();",
" let audio_count = self.capabilities.audioProfiles.len().to_string();",
" let mut owned = vec![self.sessionId.clone(), self.gatewayId.clone(), self.audience.clone(), self.grant.clone(), reconnect_sequence, self.clientNonce.clone(), self.capabilities.transport.clone(), self.capabilities.framing.clone(), self.capabilities.media.clone(), self.capabilities.sourceRateControl.clone(), video_count, audio_count];",
" for profile in &self.capabilities.videoProfiles { owned.extend([profile.codec.clone(), profile.bitDepth.to_string(), profile.chromaSubsampling.clone(), profile.colorSpace.clone(), profile.transferFunction.clone()]); }",
" for profile in &self.capabilities.audioProfiles { owned.extend([profile.codec.clone(), profile.sampleRateHz.to_string(), profile.channels.to_string(), profile.channelLayout.clone(), profile.packetDurationMs.to_string()]); }",
" let fields: Vec<&str> = owned.iter().map(String::as_str).collect();",
" let mut transcript = String::from(\"versevdi/tunnel-admission/v1\");",
" for field in fields { transcript.push_str(&format!(\"{}:{}\", field.as_bytes().len(), field)); }",
" transcript.into_bytes()",
@@ -545,9 +604,10 @@ def generate_rust(defs: dict[str, dict[str, Any]], schema_hash: str, compatibili
" selected.validate().map_err(|_| ValidationError::new(\"capabilities\", \"no_overlap\"))?;",
" for profile in &profiles[1..] {",
" profile.validate().map_err(|_| ValidationError::new(\"capabilities\", \"no_overlap\"))?;",
" if profile.transport != selected.transport || profile.framing != selected.framing || profile.media != selected.media || profile.audio != selected.audio || profile.sourceRateControl != selected.sourceRateControl { return Err(ValidationError::new(\"capabilities\", \"no_overlap\")); }",
" selected.clientDecode.retain(|candidate| profile.clientDecode.contains(candidate));",
" if selected.clientDecode.is_empty() { return Err(ValidationError::new(\"capabilities\", \"no_overlap\")); }",
" if profile.transport != selected.transport || profile.framing != selected.framing || profile.media != selected.media || profile.sourceRateControl != selected.sourceRateControl { return Err(ValidationError::new(\"capabilities\", \"no_overlap\")); }",
" selected.videoProfiles.retain(|candidate| profile.videoProfiles.contains(candidate));",
" selected.audioProfiles.retain(|candidate| profile.audioProfiles.contains(candidate));",
" if selected.videoProfiles.is_empty() || selected.audioProfiles.is_empty() { return Err(ValidationError::new(\"capabilities\", \"no_overlap\")); }",
" }",
" Ok(selected)",
"}",
@@ -586,6 +646,8 @@ def swift_validation(definition: dict[str, Any]) -> list[str]:
lines.append(f" {prefix}if !validRFC3339UTC({value}) {{ throw ContractValidationError(field: \"{prop_name}\", code: \"invalid_time\") }}")
if prop.get("format") == "base64url":
lines.append(f" {prefix}if !validBase64URL({value}) {{ throw ContractValidationError(field: \"{prop_name}\", code: \"invalid_format\") }}")
if prop.get("format") == "uuid":
lines.append(f" {prefix}if !validCanonicalUUID({value}) {{ throw ContractValidationError(field: \"{prop_name}\", code: \"invalid_uuid\") }}")
if prop.get("type") == "integer":
if "minimum" in prop:
lines.append(f" {prefix}if {value} < {prop['minimum']} {{ throw ContractValidationError(field: \"{prop_name}\", code: \"minimum\") }}")
@@ -606,8 +668,8 @@ def swift_validation(definition: dict[str, Any]) -> list[str]:
if "enum" in items:
allowed = ", ".join(f'\"{item}\"' for item in items["enum"])
lines.append(f" {prefix}for item in {value} where ![{allowed}].contains(item) {{ throw ContractValidationError(field: \"{prop_name}\", code: \"invalid_item\") }}")
if prop.get("uniqueItems") and items.get("type") == "string":
lines.append(f" {prefix}if Set({value}).count != {value}.count {{ throw ContractValidationError(field: \"{prop_name}\", code: \"duplicate_item\") }}")
if prop.get("uniqueItems"):
lines.append(f" {prefix}for (index, item) in {value}.enumerated() where {value}[..<index].contains(item) {{ throw ContractValidationError(field: \"{prop_name}\", code: \"duplicate_item\") }}")
item_ref = ref_name(items)
if item_ref:
lines.append(f" {prefix}for item in {value} {{ try item.validate() }}")
@@ -619,6 +681,12 @@ def swift_validation(definition: dict[str, Any]) -> list[str]:
name = definition["name"]
if name in {"AllocationPolicy", "ManifestBounds"}:
lines.append(" if minimumKbps > targetKbps || targetKbps > maximumKbps { throw ContractValidationError(field: \"bounds\", code: \"invalid_order\") }")
if name == "SessionQualityLimits":
lines.append(" if bitrateMinimumKbps > bitrateTargetKbps || bitrateTargetKbps > bitrateMaximumKbps { throw ContractValidationError(field: \"bitrate_bounds\", code: \"invalid_order\") }")
if name in {"SelectedSessionDescriptor", "ProviderStreamPolicy"}:
lines.append(" if bitrateTargetKbps > bitrateMaximumKbps { throw ContractValidationError(field: \"bitrate_bounds\", code: \"invalid_order\") }")
if name == "BitratePreference":
lines.append(" if mode == \"auto\" && targetKbps != nil || mode == \"explicit\" && targetKbps == nil { throw ContractValidationError(field: \"target_kbps\", code: \"invalid_tagged_value\") }")
if name == "GatewayRegistration":
lines.append(" if protocolMinVersion > protocolMaxVersion { throw ContractValidationError(field: \"protocol_version\", code: \"invalid_order\") }")
if name == "ChannelFrame":
@@ -637,6 +705,65 @@ def generate_swift(defs: dict[str, dict[str, Any]], schema_hash: str, compatibil
f'public let nMinus2WireVersion = "{compatibility["n_minus_2"]}"',
"public struct ContractValidationError: Error, Equatable { public let field: String; public let code: String }",
"private struct AnyCodingKey: CodingKey { let stringValue: String; let intValue: Int?; init?(stringValue: String) { self.stringValue = stringValue; self.intValue = nil }; init?(intValue: Int) { self.stringValue = String(intValue); self.intValue = intValue } }",
"private func rejectDuplicateJSONKeys(_ data: Data) throws {",
" var index = 0",
" func skipWhitespace() { while index < data.count && [9, 10, 13, 32].contains(data[index]) { index += 1 } }",
" func parseString() throws -> String {",
" guard index < data.count, data[index] == 34 else { throw ContractValidationError(field: \"json\", code: \"invalid_json\") }",
" let start = index",
" index += 1",
" while index < data.count {",
" if data[index] == 92 { index += 2; continue }",
" if data[index] == 34 { index += 1; return try JSONDecoder().decode(String.self, from: data[start..<index]) }",
" index += 1",
" }",
" throw ContractValidationError(field: \"json\", code: \"invalid_json\")",
" }",
" func parseValue() throws {",
" skipWhitespace()",
" guard index < data.count else { throw ContractValidationError(field: \"json\", code: \"invalid_json\") }",
" if data[index] == 123 {",
" index += 1",
" var keys = Set<String>()",
" skipWhitespace()",
" if index < data.count, data[index] == 125 { index += 1; return }",
" while true {",
" skipWhitespace()",
" let key = try parseString()",
" guard keys.insert(key).inserted else { throw ContractValidationError(field: key, code: \"duplicate_field\") }",
" skipWhitespace()",
" guard index < data.count, data[index] == 58 else { throw ContractValidationError(field: \"json\", code: \"invalid_json\") }",
" index += 1",
" try parseValue()",
" skipWhitespace()",
" guard index < data.count else { throw ContractValidationError(field: \"json\", code: \"invalid_json\") }",
" if data[index] == 125 { index += 1; return }",
" guard data[index] == 44 else { throw ContractValidationError(field: \"json\", code: \"invalid_json\") }",
" index += 1",
" }",
" }",
" if data[index] == 91 {",
" index += 1",
" skipWhitespace()",
" if index < data.count, data[index] == 93 { index += 1; return }",
" while true {",
" try parseValue()",
" skipWhitespace()",
" guard index < data.count else { throw ContractValidationError(field: \"json\", code: \"invalid_json\") }",
" if data[index] == 93 { index += 1; return }",
" guard data[index] == 44 else { throw ContractValidationError(field: \"json\", code: \"invalid_json\") }",
" index += 1",
" }",
" }",
" if data[index] == 34 { _ = try parseString(); return }",
" let start = index",
" while index < data.count && ![9, 10, 13, 32, 44, 93, 125].contains(data[index]) { index += 1 }",
" guard index > start else { throw ContractValidationError(field: \"json\", code: \"invalid_json\") }",
" }",
" try parseValue()",
" skipWhitespace()",
" guard index == data.count else { throw ContractValidationError(field: \"json\", code: \"trailing_json\") }",
"}",
"private func validBase64URL(_ value: String) -> Bool {",
" guard !value.isEmpty, value.utf8.allSatisfy({ byte in",
" (byte >= 65 && byte <= 90) || (byte >= 97 && byte <= 122) || (byte >= 48 && byte <= 57) || byte == 45 || byte == 95",
@@ -663,6 +790,11 @@ def generate_swift(defs: dict[str, dict[str, Any]], schema_hash: str, compatibil
" let fraction = bytes[20..<(bytes.count - 1)]",
" return bytes[19] == 46 && !fraction.isEmpty && fraction.count <= 9 && fraction.allSatisfy { $0 >= 48 && $0 <= 57 } && fraction.last != 48",
"}",
"private func validCanonicalUUID(_ value: String) -> Bool {",
" let bytes = Array(value.utf8)",
" guard bytes.count == 36, bytes[8] == 45, bytes[13] == 45, bytes[18] == 45, bytes[23] == 45, value != \"00000000-0000-0000-0000-000000000000\" else { return false }",
" return bytes.enumerated().allSatisfy { index, byte in [8, 13, 18, 23].contains(index) || (byte >= 48 && byte <= 57) || (byte >= 97 && byte <= 102) }",
"}",
"",
]
for name in sorted(defs):
@@ -704,7 +836,7 @@ def generate_swift(defs: dict[str, dict[str, Any]], schema_hash: str, compatibil
out.append(f" try self.init({', '.join(decoded)})")
out.extend([" }", "", " public func validate() throws {"])
out.extend(swift_validation(definition))
out.extend([" }", "", " 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) }", "}", ""])
out.extend([" }", "", " public static func decodeJSON(_ data: Data) throws -> Self { try rejectDuplicateJSONKeys(data); return try JSONDecoder().decode(Self.self, from: data) }", " public func encodeJSON() throws -> Data { try validate(); return try JSONEncoder().encode(self) }", "}", ""])
out.extend([
"public func deviceRegistrationProofTranscript(serverID: Data, principalID: Data, deviceID: Data, challenge: Data, expiryUnixMilliseconds: Int64) throws -> Data {",
" for (field, value, length) in [(\"server_id\", serverID, 16), (\"principal_id\", principalID, 16), (\"device_id\", deviceID, 16), (\"challenge\", challenge, 32)] {",
@@ -723,8 +855,9 @@ def generate_swift(defs: dict[str, dict[str, Any]], schema_hash: str, compatibil
"",
"public extension TunnelAdmissionRequest {",
" func deviceAdmissionTranscript() -> Data {",
" var fields = [sessionId, gatewayId, audience, grant, String(reconnectSequence), clientNonce, capabilities.transport, capabilities.framing, capabilities.media, capabilities.audio, capabilities.sourceRateControl, String(capabilities.clientDecode.count)]",
" fields.append(contentsOf: capabilities.clientDecode)",
" var fields = [sessionId, gatewayId, audience, grant, String(reconnectSequence), clientNonce, capabilities.transport, capabilities.framing, capabilities.media, capabilities.sourceRateControl, String(capabilities.videoProfiles.count), String(capabilities.audioProfiles.count)]",
" for profile in capabilities.videoProfiles { fields.append(contentsOf: [profile.codec, String(profile.bitDepth), profile.chromaSubsampling, profile.colorSpace, profile.transferFunction]) }",
" for profile in capabilities.audioProfiles { fields.append(contentsOf: [profile.codec, String(profile.sampleRateHz), String(profile.channels), profile.channelLayout, String(profile.packetDurationMs)]) }",
" var transcript = \"versevdi/tunnel-admission/v1\"",
" for field in fields { transcript += \"\\(field.utf8.count):\\(field)\" }",
" return Data(transcript.utf8)",
@@ -735,14 +868,16 @@ def generate_swift(defs: dict[str, dict[str, Any]], schema_hash: str, compatibil
" static func intersection(_ profiles: [CapabilityProfile]) throws -> CapabilityProfile {",
" guard let selected = profiles.first else { throw ContractValidationError(field: \"capabilities\", code: \"no_overlap\") }",
" try selected.validate()",
" var common = selected.clientDecode",
" var commonVideo = selected.videoProfiles",
" var commonAudio = selected.audioProfiles",
" for profile in profiles.dropFirst() {",
" try profile.validate()",
" if profile.transport != selected.transport || profile.framing != selected.framing || profile.media != selected.media || profile.audio != selected.audio || profile.sourceRateControl != selected.sourceRateControl { throw ContractValidationError(field: \"capabilities\", code: \"no_overlap\") }",
" common = common.filter { profile.clientDecode.contains($0) }",
" if common.isEmpty { throw ContractValidationError(field: \"capabilities\", code: \"no_overlap\") }",
" if profile.transport != selected.transport || profile.framing != selected.framing || profile.media != selected.media || profile.sourceRateControl != selected.sourceRateControl { throw ContractValidationError(field: \"capabilities\", code: \"no_overlap\") }",
" commonVideo = commonVideo.filter { profile.videoProfiles.contains($0) }",
" commonAudio = commonAudio.filter { profile.audioProfiles.contains($0) }",
" if commonVideo.isEmpty || commonAudio.isEmpty { throw ContractValidationError(field: \"capabilities\", code: \"no_overlap\") }",
" }",
" return try CapabilityProfile(transport: selected.transport, framing: selected.framing, media: selected.media, audio: selected.audio, sourceRateControl: selected.sourceRateControl, clientDecode: common)",
" return try CapabilityProfile(transport: selected.transport, framing: selected.framing, media: selected.media, sourceRateControl: selected.sourceRateControl, videoProfiles: commonVideo, audioProfiles: commonAudio)",
" }",
"}",
"",