Protocol: split client session authority
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import pathlib
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import tempfile
|
||||
@@ -24,6 +25,32 @@ def run_failure(command: list[str], directory: pathlib.Path, expected: str) -> N
|
||||
raise RuntimeError("expected failure: %s\n%s%s" % (" ".join(command), result.stdout, result.stderr))
|
||||
|
||||
|
||||
def protobuf_message_fields(name: str) -> list[tuple[str, int]]:
|
||||
result = subprocess.run(
|
||||
["protoc", "--decode=google.protobuf.FileDescriptorSet", "google/protobuf/descriptor.proto"],
|
||||
input=(ROOT / "gen/protobuf/tunnel-v1.pb").read_bytes(),
|
||||
capture_output=True,
|
||||
check=False,
|
||||
)
|
||||
if result.returncode != 0:
|
||||
raise RuntimeError(result.stderr.decode())
|
||||
lines = result.stdout.decode().splitlines()
|
||||
marker = f' name: "{name}"'
|
||||
try:
|
||||
name_index = lines.index(marker)
|
||||
start = max(index for index in range(name_index) if lines[index] == " message_type {")
|
||||
except (ValueError, StopIteration) as exc:
|
||||
raise RuntimeError(f"protobuf descriptor missing message {name}") from exc
|
||||
depth = 0
|
||||
block: list[str] = []
|
||||
for line in lines[start:]:
|
||||
depth += line.count("{") - line.count("}")
|
||||
block.append(line)
|
||||
if depth == 0:
|
||||
break
|
||||
return [(field, int(number)) for field, number in re.findall(r' field \{\n name: "([^"]+)"\n number: (\d+)', "\n".join(block))]
|
||||
|
||||
|
||||
def main() -> int:
|
||||
with tempfile.TemporaryDirectory(prefix="versevdi-generated-contracts-") as temporary:
|
||||
workspace = pathlib.Path(temporary)
|
||||
@@ -136,6 +163,52 @@ for invalid in [
|
||||
fatalError("invalid tunnel admission request was accepted")
|
||||
} catch { }
|
||||
}
|
||||
let clientAuthority = try ClientSessionAuthority(
|
||||
version: "1", sessionId: "session", gatewayId: "gateway", audience: "audience",
|
||||
reconnectSequence: 2, expiresAt: "2099-01-01T00:00:00Z", capabilities: capability
|
||||
)
|
||||
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"
|
||||
]), !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"] {
|
||||
var missing = clientAuthorityObject
|
||||
missing.removeValue(forKey: field)
|
||||
do {
|
||||
_ = try ClientSessionAuthority.decodeJSON(try JSONSerialization.data(withJSONObject: missing))
|
||||
fatalError("client authority accepted missing \(field)")
|
||||
} catch { }
|
||||
}
|
||||
for (field, value) in [
|
||||
("provider_profile", "apollo"),
|
||||
("provider_identity", "provider-1"),
|
||||
("provider_url", "https://provider.invalid"),
|
||||
("management_host", "provider.invalid"),
|
||||
("unknown", "true"),
|
||||
] {
|
||||
var injected = clientAuthorityObject
|
||||
injected[field] = value
|
||||
do {
|
||||
_ = try ClientSessionAuthority.decodeJSON(try JSONSerialization.data(withJSONObject: injected))
|
||||
fatalError("client authority accepted injected \(field)")
|
||||
} catch { }
|
||||
}
|
||||
for expiresAt in ["not-a-time", "2099-01-01T00:00:00+00:00", "2099-01-01T00:00:00.100Z"] {
|
||||
var invalidExpiry = clientAuthorityObject
|
||||
invalidExpiry["expires_at"] = expiresAt
|
||||
do {
|
||||
_ = try ClientSessionAuthority.decodeJSON(try JSONSerialization.data(withJSONObject: invalidExpiry))
|
||||
fatalError("client authority accepted invalid expiry")
|
||||
} catch { }
|
||||
}
|
||||
do {
|
||||
_ = try ClientSessionAuthority.decodeJSON(clientAuthorityJSON + Data(" {}".utf8))
|
||||
fatalError("client authority accepted trailing JSON")
|
||||
} catch { }
|
||||
do {
|
||||
_ = try AllocationPolicy(
|
||||
minimumKbps: 100, targetKbps: 50, maximumKbps: 25, tier: "standard",
|
||||
@@ -348,6 +421,16 @@ fn main() {
|
||||
"1".into(), "session".into(), "gateway".into(), "audience".into(),
|
||||
"g".repeat(43), 0, "short".into(), "s".repeat(86), capabilities.clone(),
|
||||
).is_err());
|
||||
let client_authority = ClientSessionAuthority::new(
|
||||
"1".into(), "session".into(), "gateway".into(), "audience".into(), 2,
|
||||
"2099-01-01T00:00:00Z".into(), capabilities.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(),
|
||||
).is_err());
|
||||
assert!(intersect_capability_profiles(&[capabilities.clone(), capabilities.clone()]).is_ok());
|
||||
let incompatible = CapabilityProfile::new(
|
||||
"quic-tls13".into(), "datagram-v1".into(), "encoded".into(),
|
||||
@@ -441,6 +524,21 @@ fn main() {
|
||||
)
|
||||
run(["rustc", str(rust), "-o", str(workspace / "rust-contracts")], ROOT)
|
||||
run([str(workspace / "rust-contracts")], ROOT)
|
||||
expected_protobuf_fields = [
|
||||
("version", 1),
|
||||
("session_id", 2),
|
||||
("gateway_id", 3),
|
||||
("audience", 4),
|
||||
("reconnect_sequence", 5),
|
||||
("expires_at", 6),
|
||||
("capabilities", 7),
|
||||
]
|
||||
actual_protobuf_fields = protobuf_message_fields("ClientSessionAuthority")
|
||||
if actual_protobuf_fields != expected_protobuf_fields:
|
||||
raise RuntimeError(
|
||||
f"ClientSessionAuthority protobuf fields = {actual_protobuf_fields}; "
|
||||
f"want {expected_protobuf_fields}"
|
||||
)
|
||||
rust_unknown = workspace / "unknown.rs"
|
||||
shutil.copyfile(ROOT / "gen/rust/protocol.rs", rust_unknown)
|
||||
with rust_unknown.open("a", encoding="utf-8") as output:
|
||||
|
||||
Reference in New Issue
Block a user