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
+11 -1
View File
@@ -32,7 +32,17 @@ def main() -> int:
expected = manifest.get("corpus_sha256")
if not expected or actual != expected:
raise ValueError(f"fixture corpus hash mismatch: {actual}")
print(f"Fixture corpus SHA256 {actual}")
json_paths = sorted(
path.relative_to(ROOT).as_posix()
for directory in (ROOT / "fixtures/valid", ROOT / "fixtures/invalid")
for path in directory.glob("*.json")
)
if json_paths != manifest.get("json_files"):
raise ValueError("JSON fixture manifest file list is stale")
json_actual = digest(json_paths)
if json_actual != manifest.get("json_corpus_sha256"):
raise ValueError(f"JSON fixture corpus hash mismatch: {json_actual}")
print(f"Fixture corpus SHA256 {actual}; JSON SHA256 {json_actual}")
return 0
+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)",
" }",
"}",
"",
+44
View File
@@ -2,6 +2,7 @@ package main
import (
"crypto/sha256"
"encoding/binary"
"encoding/hex"
"encoding/json"
"fmt"
@@ -101,6 +102,15 @@ func evaluate(version, kind, input string) string {
Profile: protocol.ManifestProfile{ID: "standard", Bounds: protocol.ManifestBounds{MinimumKbps: 1, TargetKbps: 2, MaximumKbps: 3}},
Grant: protocol.GrantReference{OpaqueValue: parts["grant"], ExpiresAt: parts["expires_at"], Audience: parts["audience"]},
CorrelationID: "correlation-1",
SelectedDescriptor: protocol.SelectedSessionDescriptor{
VideoProfile: protocol.VideoProfile{Codec: "h264", BitDepth: 8, ChromaSubsampling: "4:2:0", ColorSpace: "bt709-limited", TransferFunction: "sdr"},
AudioProfile: protocol.AudioProfile{Codec: "opus", SampleRateHz: 48000, Channels: 2, ChannelLayout: "stereo", PacketDurationMs: 5},
DisplayMode: protocol.DisplayMode{ResolutionWidth: 1920, ResolutionHeight: 1080, Fps: 60},
BitrateTargetKbps: 12000,
BitrateMaximumKbps: 20000,
Adjustment: protocol.SessionAdjustment{DisplayReason: "none", BitrateReason: "none"},
MediaTimestampBasis: "gateway-send-wall-clock-ms",
},
}
if value.Validate() == nil {
return "valid"
@@ -123,6 +133,8 @@ func evaluate(version, kind, input string) string {
value := protocol.SessionRequest{
ClientDeviceID: parts["client_device_id"], DeviceKeyID: parts["device_key_id"],
PoolID: parts["pool_id"], IdempotencyKey: parts["idempotency_key"],
VideoProfiles: []protocol.VideoProfile{{Codec: "h264", BitDepth: 8, ChromaSubsampling: "4:2:0", ColorSpace: "bt709-limited", TransferFunction: "sdr"}},
BitratePreference: protocol.BitratePreference{Mode: "auto"},
}
if value.Validate() == nil {
return "valid"
@@ -309,6 +321,13 @@ func classifyGatewayInput(encoded string) string {
if len(body) != 4 {
return "invalid:length"
}
case 8:
if len(body) != 8 {
return "invalid:length"
}
if body[0] > 15 || body[3] > 3 {
return "invalid:field"
}
default:
return "invalid:kind"
}
@@ -352,6 +371,22 @@ func classifyGatewayFeedback(encoded string) string {
if len(body) == 0 {
return "valid"
}
case 4:
if len(body) != 24 {
return "invalid:length"
}
if binary.BigEndian.Uint64(body[16:]) == 0 || allZero(body[:16]) {
return "invalid:field"
}
return "valid"
case 5:
if len(body) != 16 {
return "invalid:length"
}
if allZero(body) {
return "invalid:field"
}
return "valid"
default:
return "invalid:type"
}
@@ -386,6 +421,15 @@ func classifyGatewayFeedback(encoded string) string {
return "invalid:field"
}
func allZero(value []byte) bool {
for _, item := range value {
if item != 0 {
return false
}
}
return true
}
func validFECStatus(body []byte) bool {
if len(body) != 21 || int(body[10])<<8|int(body[11]) == 0 || int(body[14])<<8|int(body[15]) > int(body[10])<<8|int(body[11]) || int(body[16])<<8|int(body[17]) > int(body[12])<<8|int(body[13]) || body[18] > 100 || body[20] == 0 || body[19] >= body[20] {
return false
+11
View File
@@ -38,6 +38,8 @@ fn evaluate(version: &str, kind: &str, input: &str) -> &'static str {
values.get("device_key_id").cloned().unwrap_or_default(),
values.get("pool_id").cloned().unwrap_or_default(),
values.get("idempotency_key").cloned().unwrap_or_default(),
vec![VideoProfile::new("h264".into(), 8, "4:2:0".into(), "bt709-limited".into(), "sdr".into()).unwrap()],
BitratePreference::new("auto".into(), None).unwrap(),
None,
) {
Ok(_) => "valid",
@@ -184,6 +186,9 @@ fn classify_gateway_input(encoded: &str) -> &'static str {
}
7 if body.len() == 4 => "valid",
7 => "invalid:length",
8 if body.len() != 8 => "invalid:length",
8 if body[0] > 15 || body[3] > 3 => "invalid:field",
8 => "valid",
_ => "invalid:kind",
}
}
@@ -219,6 +224,12 @@ fn classify_gateway_feedback(encoded: &str) -> &'static str {
2 => "invalid:field",
3 if body.is_empty() => "valid",
3 => "invalid:length",
4 if body.len() == 24 && body[..16].iter().any(|value| *value != 0) && body[16..24].iter().any(|value| *value != 0) => "valid",
4 if body.len() != 24 => "invalid:length",
4 => "invalid:field",
5 if body.len() == 16 && body.iter().any(|value| *value != 0) => "valid",
5 if body.len() != 16 => "invalid:length",
5 => "invalid:field",
_ => "invalid:type",
};
}
+11
View File
@@ -26,6 +26,8 @@ func evaluate(_ version: String, _ kind: String, _ input: String) -> String {
guard (try? SessionRequest(
clientDeviceId: values["client_device_id"] ?? "", deviceKeyId: values["device_key_id"] ?? "",
poolId: values["pool_id"] ?? "", idempotencyKey: values["idempotency_key"] ?? "",
videoProfiles: [try! VideoProfile(codec: "h264", bitDepth: 8, chromaSubsampling: "4:2:0", colorSpace: "bt709-limited", transferFunction: "sdr")],
bitratePreference: try! BitratePreference(mode: "auto", targetKbps: nil),
requestedDisplayMode: nil
)) != nil else { return "invalid:required" }
return "valid"
@@ -136,6 +138,9 @@ func classifyGatewayInput(_ encoded: String) -> String {
let height = Int(body[6]) * 256 + Int(body[7])
return width > 0 && height > 0 && x < width && y < height ? "valid" : "invalid:field"
case 7: return body.count == 4 ? "valid" : "invalid:length"
case 8:
guard body.count == 8 else { return "invalid:length" }
return body[0] <= 15 && body[3] <= 3 ? "valid" : "invalid:field"
default: return "invalid:kind"
}
}
@@ -156,6 +161,12 @@ func classifyGatewayFeedback(_ encoded: String) -> String {
case 2:
return validFECStatus(body) ? "valid" : "invalid:field"
case 3: return body.isEmpty ? "valid" : "invalid:length"
case 4:
guard body.count == 24 else { return "invalid:length" }
return body[0...15].contains(where: { $0 != 0 }) && body[16...23].contains(where: { $0 != 0 }) ? "valid" : "invalid:field"
case 5:
guard body.count == 16 else { return "invalid:length" }
return body.contains(where: { $0 != 0 }) ? "valid" : "invalid:field"
default: return "invalid:type"
}
}
+6 -1
View File
@@ -4,12 +4,17 @@ from __future__ import annotations
import pathlib
import subprocess
import tempfile
import os
ROOT = pathlib.Path(__file__).resolve().parents[1]
def run(command: list[str]) -> None:
result = subprocess.run(command, cwd=ROOT, text=True, capture_output=True)
environment = os.environ.copy()
cache_root = pathlib.Path(tempfile.gettempdir()) / "versevdi-protocol-module-cache"
environment.setdefault("CLANG_MODULE_CACHE_PATH", str(cache_root / "clang"))
environment.setdefault("SWIFT_MODULECACHE_PATH", str(cache_root / "swift"))
result = subprocess.run(command, cwd=ROOT, env=environment, text=True, capture_output=True)
if result.returncode != 0:
raise SystemExit(result.stdout + result.stderr)
print(result.stdout.strip())
+59 -38
View File
@@ -8,13 +8,18 @@ import re
import shutil
import subprocess
import tempfile
import os
ROOT = pathlib.Path(__file__).resolve().parents[1]
def run(command: list[str], directory: pathlib.Path) -> None:
result = subprocess.run(command, cwd=directory, text=True, capture_output=True, check=False)
environment = os.environ.copy()
cache_root = pathlib.Path(tempfile.gettempdir()) / "versevdi-protocol-module-cache"
environment.setdefault("CLANG_MODULE_CACHE_PATH", str(cache_root / "clang"))
environment.setdefault("SWIFT_MODULECACHE_PATH", str(cache_root / "swift"))
result = subprocess.run(command, cwd=directory, env=environment, text=True, capture_output=True, check=False)
if result.returncode != 0:
raise RuntimeError("%s\n%s%s" % (" ".join(command), result.stdout, result.stderr))
@@ -58,21 +63,27 @@ def main() -> int:
swift.write_text(
"""import Foundation
let video = try VideoProfile(codec: "h264", bitDepth: 8, chromaSubsampling: "4:2:0", colorSpace: "bt709-limited", transferFunction: "sdr")
let hevc = try VideoProfile(codec: "hevc", bitDepth: 8, chromaSubsampling: "4:2:0", colorSpace: "bt709-limited", transferFunction: "sdr")
let audio = try AudioProfile(codec: "opus", sampleRateHz: 48000, channels: 2, channelLayout: "stereo", packetDurationMs: 5)
let display = try DisplayMode(resolutionWidth: 2560, resolutionHeight: 1440, fps: 120)
let adjustment = try SessionAdjustment(displayReason: "none", bitrateReason: "none")
let descriptor = try SelectedSessionDescriptor(videoProfile: video, audioProfile: audio, displayMode: display, bitrateTargetKbps: 40000, bitrateMaximumKbps: 50000, adjustment: adjustment, mediaTimestampBasis: "gateway-send-wall-clock-ms")
let capability = try CapabilityProfile(
transport: "quic-tls13", framing: "datagram-v1", media: "encoded",
audio: "encoded", sourceRateControl: "server", clientDecode: ["h264-opus"]
sourceRateControl: "server", videoProfiles: [video], audioProfiles: [audio]
)
guard currentWireVersion == "2", nMinus1WireVersion == "1", nMinus2WireVersion == "0" else {
fatalError("unexpected control wire compatibility declaration")
}
_ = try CapabilityProfile(
transport: "quic-tls13", framing: "datagram-v2", media: "encoded",
audio: "encoded", sourceRateControl: "server", clientDecode: ["h264-opus"]
sourceRateControl: "server", videoProfiles: [video], audioProfiles: [audio]
)
do {
_ = try CapabilityProfile(
transport: "quic-tls13", framing: "datagram-v3", media: "encoded",
audio: "encoded", sourceRateControl: "server", clientDecode: ["h264-opus"]
sourceRateControl: "server", videoProfiles: [video], audioProfiles: [audio]
)
fatalError("unregistered framing was accepted")
} catch { }
@@ -82,7 +93,7 @@ let request = try TunnelAdmissionRequest(
clientNonce: String(repeating: "n", count: 16), deviceSignature: String(repeating: "s", count: 86), capabilities: capability
)
_ = request
let transcript = "versevdi/tunnel-admission/v17:session7:gateway8:audience43:" + String(repeating: "g", count: 43) + "1:016:" + String(repeating: "n", count: 16) + "10:quic-tls1311:datagram-v17:encoded7:encoded6:server1:19:h264-opus"
let transcript = "versevdi/tunnel-admission/v17:session7:gateway8:audience43:" + String(repeating: "g", count: 43) + "1:016:" + String(repeating: "n", count: 16) + "10:quic-tls1311:datagram-v17:encoded6:server1:11:14:h2641:85:4:2:013:bt709-limited3:sdr4:opus5:480001:26:stereo1:5"
guard String(data: request.deviceAdmissionTranscript(), encoding: .utf8) == transcript else {
fatalError("unexpected device admission transcript")
}
@@ -126,18 +137,18 @@ for (name, field, serverID, principalID, deviceID, challenge, expiry) in invalid
}
let incompatible = try CapabilityProfile(
transport: "quic-tls13", framing: "datagram-v1", media: "encoded",
audio: "encoded", sourceRateControl: "server", clientDecode: ["hevc-opus"]
sourceRateControl: "server", videoProfiles: [hevc], audioProfiles: [audio]
)
let gatewayCapability = try CapabilityProfile(
transport: "quic-tls13", framing: "datagram-v1", media: "encoded",
audio: "encoded", sourceRateControl: "server", clientDecode: ["hevc-opus", "h264-opus"]
sourceRateControl: "server", videoProfiles: [hevc, video], audioProfiles: [audio]
)
do {
guard try CapabilityProfile.intersection([capability, capability]) == capability else {
fatalError("matching capability profiles did not intersect")
}
} catch { fatalError("matching capability profiles did not intersect") }
guard try CapabilityProfile.intersection([gatewayCapability, capability]).clientDecode == ["h264-opus"] else {
guard try CapabilityProfile.intersection([gatewayCapability, capability]).videoProfiles == [video] else {
fatalError("ordered registered profile intersection changed")
}
do {
@@ -165,17 +176,22 @@ for invalid in [
}
let clientAuthority = try ClientSessionAuthority(
version: "1", sessionId: "session", gatewayId: "gateway", audience: "audience",
reconnectSequence: 2, expiresAt: "2099-01-01T00:00:00Z", capabilities: capability
reconnectSequence: 2, expiresAt: "2099-01-01T00:00:00Z", capabilities: capability, selectedDescriptor: descriptor
)
let clientAuthorityJSON = try clientAuthority.encodeJSON()
let clientAuthorityObject = try JSONSerialization.jsonObject(with: clientAuthorityJSON) as! [String: Any]
guard Set(clientAuthorityObject.keys) == Set([
"version", "session_id", "gateway_id", "audience", "reconnect_sequence", "expires_at", "capabilities"
"version", "session_id", "gateway_id", "audience", "reconnect_sequence", "expires_at", "capabilities", "selected_descriptor"
]), !String(data: clientAuthorityJSON, encoding: .utf8)!.contains("provider_") else {
fatalError("client authority was not exactly provider-free")
}
_ = try ClientSessionAuthority.decodeJSON(clientAuthorityJSON)
for field in ["version", "session_id", "gateway_id", "audience", "reconnect_sequence", "expires_at", "capabilities"] {
let duplicateCapability = Data(#"{"transport":"quic-tls13","transport":"quic-tls13","framing":"datagram-v1","media":"encoded","source_rate_control":"server","video_profiles":[{"codec":"h264","bit_depth":8,"chroma_subsampling":"4:2:0","color_space":"bt709-limited","transfer_function":"sdr"}],"audio_profiles":[{"codec":"opus","sample_rate_hz":48000,"channels":2,"channel_layout":"stereo","packet_duration_ms":5}]}"#.utf8)
do {
_ = try CapabilityProfile.decodeJSON(duplicateCapability)
fatalError("capability accepted duplicate JSON keys")
} catch { }
for field in ["version", "session_id", "gateway_id", "audience", "reconnect_sequence", "expires_at", "capabilities", "selected_descriptor"] {
var missing = clientAuthorityObject
missing.removeValue(forKey: field)
do {
@@ -217,7 +233,7 @@ do {
)
fatalError("invalid allocation bounds were accepted")
} catch { }
let displayMode = try DisplayMode(resolutionWidth: 2560, resolutionHeight: 1440, fps: 120)
let displayMode = display
for invalid in [
{ try DisplayMode(resolutionWidth: 319, resolutionHeight: 1440, fps: 120) },
{ try DisplayMode(resolutionWidth: 2560, resolutionHeight: 199, fps: 120) },
@@ -230,14 +246,14 @@ for invalid in [
}
let policyFreeV2Request = try SessionRequest(
clientDeviceId: "device-1", deviceKeyId: "key-1", poolId: "pool-1",
idempotencyKey: "request-1", requestedDisplayMode: nil
idempotencyKey: "request-1", videoProfiles: [video], bitratePreference: try BitratePreference(mode: "auto", targetKbps: nil), requestedDisplayMode: nil
).encodeJSON()
guard !String(data: policyFreeV2Request, encoding: .utf8)!.contains("requested_display_mode") else {
fatalError("wire-v2 request encoded an absent display mode")
}
let displayRequest = try SessionRequest(
clientDeviceId: "device-1", deviceKeyId: "key-1", poolId: "pool-1",
idempotencyKey: "request-1", requestedDisplayMode: displayMode
idempotencyKey: "request-1", videoProfiles: [video], bitratePreference: try BitratePreference(mode: "explicit", targetKbps: 40000), requestedDisplayMode: displayMode
)
guard try SessionRequest.decodeJSON(displayRequest.encodeJSON()).requestedDisplayMode == displayMode else {
fatalError("display mode did not round-trip")
@@ -295,14 +311,14 @@ for expiresAt in ["2099-01-01T00:00:00+00:00", "2099-01-01T00:00:00.100Z"] {
} catch { }
}
let streamPolicy = try ProviderStreamPolicy(
resolutionWidth: 2560, resolutionHeight: 1440, fps: 120,
codec: "HEVC", bitrateKbps: 40000, audioEnabled: true
videoProfile: hevc, audioProfile: audio, displayMode: displayMode,
bitrateTargetKbps: 40000, bitrateMaximumKbps: 50000
)
guard streamPolicy.codec == "HEVC" else { fatalError("stream policy changed") }
guard streamPolicy.videoProfile == hevc else { fatalError("stream policy changed") }
for invalid in [
{ try ProviderStreamPolicy(resolutionWidth: 319, resolutionHeight: 1440, fps: 120, codec: "HEVC", bitrateKbps: 40000, audioEnabled: true) },
{ try ProviderStreamPolicy(resolutionWidth: 2560, resolutionHeight: 1440, fps: 241, codec: "HEVC", bitrateKbps: 40000, audioEnabled: true) },
{ try ProviderStreamPolicy(resolutionWidth: 2560, resolutionHeight: 1440, fps: 120, codec: "VP9", bitrateKbps: 40000, audioEnabled: true) },
{ try ProviderStreamPolicy(videoProfile: video, audioProfile: audio, displayMode: try DisplayMode(resolutionWidth: 319, resolutionHeight: 1440, fps: 120), bitrateTargetKbps: 40000, bitrateMaximumKbps: 50000) },
{ try ProviderStreamPolicy(videoProfile: video, audioProfile: audio, displayMode: displayMode, bitrateTargetKbps: 50001, bitrateMaximumKbps: 50000) },
{ try ProviderStreamPolicy(videoProfile: try VideoProfile(codec: "vp9", bitDepth: 8, chromaSubsampling: "4:2:0", colorSpace: "bt709-limited", transferFunction: "sdr"), audioProfile: audio, displayMode: displayMode, bitrateTargetKbps: 40000, bitrateMaximumKbps: 50000) },
] {
do {
_ = try invalid()
@@ -363,17 +379,23 @@ fn main() {
assert_eq!(CURRENT_WIRE_VERSION, "2");
assert_eq!(N_MINUS_1_WIRE_VERSION, "1");
assert_eq!(N_MINUS_2_WIRE_VERSION, "0");
let video = VideoProfile::new("h264".into(), 8, "4:2:0".into(), "bt709-limited".into(), "sdr".into()).unwrap();
let hevc = VideoProfile::new("hevc".into(), 8, "4:2:0".into(), "bt709-limited".into(), "sdr".into()).unwrap();
let audio = AudioProfile::new("opus".into(), 48000, 2, "stereo".into(), 5).unwrap();
let display = DisplayMode::new(2560, 1440, 120).unwrap();
let adjustment = SessionAdjustment::new("none".into(), "none".into()).unwrap();
let descriptor = SelectedSessionDescriptor::new(video.clone(), audio.clone(), display.clone(), 40000, 50000, adjustment, "gateway-send-wall-clock-ms".into()).unwrap();
let capabilities = CapabilityProfile::new(
"quic-tls13".into(), "datagram-v1".into(), "encoded".into(),
"encoded".into(), "server".into(), vec!["h264-opus".into()],
"server".into(), vec![video.clone()], vec![audio.clone()],
).unwrap();
assert!(CapabilityProfile::new(
"quic-tls13".into(), "datagram-v2".into(), "encoded".into(),
"encoded".into(), "server".into(), vec!["h264-opus".into()],
"server".into(), vec![video.clone()], vec![audio.clone()],
).is_ok());
assert!(CapabilityProfile::new(
"quic-tls13".into(), "datagram-v3".into(), "encoded".into(),
"encoded".into(), "server".into(), vec!["h264-opus".into()],
"server".into(), vec![video.clone()], vec![audio.clone()],
).is_err());
let request = TunnelAdmissionRequest::new(
"1".into(), "session".into(), "gateway".into(), "audience".into(),
@@ -381,7 +403,7 @@ fn main() {
).unwrap();
let transcript = "versevdi/tunnel-admission/v17:session7:gateway8:audience43:".to_string()
+ &"g".repeat(43) + "1:016:" + &"n".repeat(16)
+ "10:quic-tls1311:datagram-v17:encoded7:encoded6:server1:19:h264-opus";
+ "10:quic-tls1311:datagram-v17:encoded6:server1:11:14:h2641:85:4:2:013:bt709-limited3:sdr4:opus5:480001:26:stereo1:5";
assert_eq!(request.device_admission_transcript(), transcript.into_bytes());
let proof_server_id = vec![1u8; 16];
let proof_principal_id = vec![2u8; 16];
@@ -423,26 +445,26 @@ fn main() {
).is_err());
let client_authority = ClientSessionAuthority::new(
"1".into(), "session".into(), "gateway".into(), "audience".into(), 2,
"2099-01-01T00:00:00Z".into(), capabilities.clone(),
"2099-01-01T00:00:00Z".into(), capabilities.clone(), descriptor.clone(),
).unwrap();
assert_eq!(client_authority.sessionId(), "session");
assert_eq!(client_authority.capabilities(), &capabilities);
assert!(ClientSessionAuthority::new(
"1".into(), "session".into(), "gateway".into(), "audience".into(), 2,
"not-a-time".into(), capabilities.clone(),
"not-a-time".into(), capabilities.clone(), descriptor.clone(),
).is_err());
assert!(intersect_capability_profiles(&[capabilities.clone(), capabilities.clone()]).is_ok());
let incompatible = CapabilityProfile::new(
"quic-tls13".into(), "datagram-v1".into(), "encoded".into(),
"encoded".into(), "server".into(), vec!["hevc-opus".into()],
"server".into(), vec![hevc.clone()], vec![audio.clone()],
).unwrap();
let gateway_capability = CapabilityProfile::new(
"quic-tls13".into(), "datagram-v1".into(), "encoded".into(),
"encoded".into(), "server".into(), vec!["hevc-opus".into(), "h264-opus".into()],
"server".into(), vec![hevc.clone(), video.clone()], vec![audio.clone()],
).unwrap();
assert_eq!(
intersect_capability_profiles(&[gateway_capability, capabilities.clone()]).unwrap().clientDecode(),
&vec!["h264-opus".to_string()],
intersect_capability_profiles(&[gateway_capability, capabilities.clone()]).unwrap().videoProfiles(),
&vec![video.clone()],
);
assert!(intersect_capability_profiles(&[capabilities, incompatible]).is_err());
assert!(AllocationPolicy::new(
@@ -454,11 +476,13 @@ fn main() {
assert!(DisplayMode::new(2560, 1440, 241).is_err());
let policy_free_v2_request = SessionRequest::new(
"device-1".into(), "key-1".into(), "pool-1".into(), "request-1".into(),
vec![video.clone()], BitratePreference::new("auto".into(), None).unwrap(),
None,
).unwrap();
assert!(policy_free_v2_request.requestedDisplayMode().is_none());
let display_request = SessionRequest::new(
"device-1".into(), "key-1".into(), "pool-1".into(), "request-1".into(),
vec![video.clone()], BitratePreference::new("explicit".into(), Some(40000)).unwrap(),
Some(display_mode.clone()),
).unwrap();
assert_eq!(display_request.requestedDisplayMode(), &Some(display_mode));
@@ -486,17 +510,13 @@ fn main() {
).is_err());
}
assert!(ProviderStreamPolicy::new(
2560, 1440, 120, "HEVC".into(), 40000, true,
hevc.clone(), audio.clone(), display.clone(), 40000, 50000,
).is_ok());
assert!(DisplayMode::new(319, 1440, 120).is_err());
assert!(ProviderStreamPolicy::new(
319, 1440, 120, "HEVC".into(), 40000, true,
).is_err());
assert!(ProviderStreamPolicy::new(
2560, 1440, 241, "HEVC".into(), 40000, true,
).is_err());
assert!(ProviderStreamPolicy::new(
2560, 1440, 120, "VP9".into(), 40000, true,
video.clone(), audio.clone(), display.clone(), 50001, 50000,
).is_err());
assert!(VideoProfile::new("vp9".into(), 8, "4:2:0".into(), "bt709-limited".into(), "sdr".into()).is_err());
assert!(GatewayTelemetry::new(
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, "ready".into(),
).is_ok());
@@ -532,6 +552,7 @@ fn main() {
("reconnect_sequence", 5),
("expires_at", 6),
("capabilities", 7),
("selected_descriptor", 8),
]
actual_protobuf_fields = protobuf_message_fields("ClientSessionAuthority")
if actual_protobuf_fields != expected_protobuf_fields:
+66
View File
@@ -39,6 +39,20 @@ def main() -> int:
feature_registry = json.loads((ROOT / "registries/features.json").read_text(encoding="utf-8"))
registered_features = {entry["id"] for entry in feature_registry["features"]}
assert {"control.v1", "control.v2", "display.request.v1", "input.absolute.v1", "input.scroll.v1"}.issubset(registered_features)
assert {"video.profile.v1", "session.quality.v1", "session.stop.v1", "controller.arrival.v1"}.issubset(registered_features)
assert defs["VideoProfile"]["required"] == ["codec", "bit_depth", "chroma_subsampling", "color_space", "transfer_function"]
assert defs["AudioProfile"]["required"] == ["codec", "sample_rate_hz", "channels", "channel_layout", "packet_duration_ms"]
assert defs["CapabilityProfile"]["required"] == ["transport", "framing", "media", "source_rate_control", "video_profiles", "audio_profiles"]
assert defs["CapabilityProfile"]["properties"]["video_profiles"] == {"type": "array", "minItems": 1, "maxItems": 12, "uniqueItems": True, "items": {"$ref": "#/$defs/VideoProfile"}}
assert defs["CapabilityProfile"]["properties"]["audio_profiles"] == {"type": "array", "minItems": 1, "maxItems": 1, "uniqueItems": True, "items": {"$ref": "#/$defs/AudioProfile"}}
assert defs["SessionRequest"]["required"][-2:] == ["video_profiles", "bitrate_preference"]
assert defs["ReconnectRequest"]["required"][-1] == "display_relaunch_confirmed"
assert defs["AssignedDesktop"]["required"][-1] == "quality_limits"
assert defs["EntitledPool"]["required"][-1] == "quality_limits"
for owner in ("SessionAuthority", "ClientSessionAuthority"):
assert defs[owner]["required"][-1] == "selected_descriptor"
assert defs["ConnectionManifest"]["required"][-1] == "selected_descriptor"
display_mode = defs["DisplayMode"]
assert display_mode["required"] == ["resolution_width", "resolution_height", "fps"]
@@ -113,6 +127,17 @@ def main() -> int:
assert "native_identity" not in native_missing_fixture
tunnel_credential_fixture = json.loads((ROOT / "fixtures/valid/native-tunnel-credential.json").read_text(encoding="utf-8"))
assert set(tunnel_credential_fixture) == set(tunnel_credential["required"])
valid_fixture_contracts = {
"fixtures/valid/session-request.json": "SessionRequest",
"fixtures/valid/selected-session-descriptor.json": "SelectedSessionDescriptor",
"fixtures/valid/session-quality-limits.json": "SessionQualityLimits",
}
for relative, definition in valid_fixture_contracts.items():
fixture = json.loads((ROOT / relative).read_text(encoding="utf-8"))
assert set(fixture) == set(defs[definition]["required"]), (relative, definition)
assert set(json.loads((ROOT / "fixtures/invalid/capability-rc5-opaque.json").read_text())) & {"audio", "client_decode"} == {"audio", "client_decode"}
assert "video_profiles" not in json.loads((ROOT / "fixtures/invalid/session-request-rc5.json").read_text())
assert set(json.loads((ROOT / "fixtures/invalid/provider-stream-policy-rc5.json").read_text())) == {"resolution_width", "resolution_height", "fps", "codec", "bitrate_kbps", "audio_enabled"}
expected_header = "id\tversion\tkind\tinput\texpected"
ids = set()
@@ -139,10 +164,49 @@ def main() -> int:
fixture_hash.update((ROOT / relative).read_bytes())
fixture_hash.update(b"\0")
assert fixture_manifest["corpus_sha256"] == fixture_hash.hexdigest()
json_fixture_paths = sorted(
path.relative_to(ROOT).as_posix()
for directory in (ROOT / "fixtures/valid", ROOT / "fixtures/invalid")
for path in directory.glob("*.json")
)
assert fixture_manifest["json_files"] == json_fixture_paths
json_fixture_hash = hashlib.sha256()
for relative in json_fixture_paths:
json_fixture_hash.update(relative.encode("utf-8"))
json_fixture_hash.update(b"\0")
json_fixture_hash.update((ROOT / relative).read_bytes())
json_fixture_hash.update(b"\0")
assert fixture_manifest["json_corpus_sha256"] == json_fixture_hash.hexdigest()
openapi = (ROOT / "openapi/control-v1.yaml").read_text(encoding="utf-8")
assert "openapi: 3.1.0" in openapi
assert "/api/v1/auth/refresh:" in openapi and "/api/v1/resources:" in openapi and "/api/v1/events:" in openapi
for route in (
"/api/v1/session-quality-limits:",
"/api/v1/session-quality-limits/assignments/{assignment_id}:",
"/api/v1/session-quality-limits/pools/{pool_id}:",
"/api/v1/admin/entitlements/{entitlement_id}/display-limit-override:",
"/api/v1/broker/sessions/{session_id}/quality-changes:",
"/api/v1/broker/sessions/{session_id}/quality-changes/{operation_id}:",
"/api/v1/broker/sessions/{session_id}/stop-operations:",
"/api/v1/broker/sessions/{session_id}/stop-operations/{operation_id}:",
"/api/v1/gateway/quality-work:",
"/api/v1/gateway/quality-ack:",
"/api/v1/gateway/stop-work:",
"/api/v1/gateway/stop-ack:",
):
assert route in openapi, route
for operation_id in (
"getSessionQualityLimits", "getAssignmentSessionQualityLimits", "getPoolSessionQualityLimits",
"createSessionQualityChange", "getSessionQualityChange", "createSessionStopOperation", "getSessionStopOperation",
):
operation = openapi.split(f" operationId: {operation_id}\n", 1)[1].split(" responses:\n", 1)[0]
assert "nativeBearer: []" in operation and "browserSession" not in operation, operation_id
for operation_id in (
"acquireGatewayQualityWork", "acknowledgeGatewayQualityWork", "acquireGatewayStopWork", "acknowledgeGatewayStopWork",
):
operation = openapi.split(f" operationId: {operation_id}\n", 1)[1].split(" responses:\n", 1)[0]
assert "gatewayMutualTLS: []" in operation and "nativeBearer" not in operation and "browserSession" not in operation, operation_id
assert "provider_url" not in openapi and "vm_address" not in openapi
session_endpoint = openapi.split(" /api/v1/auth/session:", 1)[1].split("\n /api/", 1)[0]
assert "$defs/BrowserAuthenticatedSession" in session_endpoint
@@ -172,6 +236,8 @@ def main() -> int:
browserCsrfCookie: []
browserCsrfHeader: []
"""
admin_override = openapi.split(" operationId: updateEntitlementDisplayLimitOverride\n", 1)[1].split(" responses:\n", 1)[0]
assert browser_requirement.removeprefix(" ") in admin_override
for operation_id in (
"issueReauthenticationGrant", "logoutSession", "registerDevice", "proveDevice", "revokeDevice",
"requestBrokerSession", "allocateBrokerSession", "reconnectBrokerSession", "cancelBrokerSession",
+12
View File
@@ -44,6 +44,10 @@ def classify_input(raw: bytes) -> str:
return "valid" if width and height and x < width and y < height else "invalid:field"
if kind == 7:
return "valid" if len(body) == 4 else "invalid:length"
if kind == 8:
if len(body) != 8:
return "invalid:length"
return "valid" if body[0] <= 15 and body[3] <= 3 else "invalid:field"
return "invalid:kind"
@@ -68,6 +72,14 @@ def classify_feedback(raw: bytes) -> str:
return "valid" if valid_fec_status(body) else "invalid:field"
if kind == 3:
return "valid" if not body else "invalid:length"
if kind == 4:
if len(body) != 24:
return "invalid:length"
return "valid" if any(body[:16]) and int.from_bytes(body[16:24], "big") > 0 else "invalid:field"
if kind == 5:
if len(body) != 16:
return "invalid:length"
return "valid" if any(body) else "invalid:field"
return "invalid:type"
if kind in (1, 2, 3):
return "invalid:direction"