feat(client): add rendezvous traversal coordinators (#12)
quality-gate / quality (push) Successful in 56s

This commit is contained in:
KyuubiYoru
2026-07-16 08:39:05 +02:00
parent 6d076c281a
commit b4b6072fe1
28 changed files with 2949 additions and 57 deletions
+12
View File
@@ -1054,6 +1054,7 @@
"attemptId",
"mediationHandle",
"clientPunchCapability",
"connectionTicketDigest",
"expiresAt"
],
"type": "object",
@@ -1071,6 +1072,9 @@
"clientPunchCapability": {
"type": "string"
},
"connectionTicketDigest": {
"type": "string"
},
"expiresAt": {
"type": "string",
"format": "date-time"
@@ -1146,6 +1150,8 @@
"attemptId",
"mediationHandle",
"hostPunchCapability",
"connectionTicketDigest",
"isCancelled",
"expiresAt"
],
"type": "object",
@@ -1159,6 +1165,12 @@
"hostPunchCapability": {
"type": "string"
},
"connectionTicketDigest": {
"type": "string"
},
"isCancelled": {
"type": "boolean"
},
"expiresAt": {
"type": "string",
"format": "date-time"
@@ -24,18 +24,24 @@ credentials plus opaque attempt and mediation IDs from a process-ephemeral HMAC
key, the client subject, the complete canonical request fingerprint, a fresh salt,
and a purpose/role label. Credentials are 32-byte base64url values (43 characters),
below both the 192-character Rendezvous capability ceiling and LiteNetLib's
256-character NAT token ceiling. State retains keyed credential fingerprints,
derivation inputs, and salt—not issued plaintext. All diagnostic string
representations redact credentials and derivation material.
256-character NAT token ceiling. The connection ticket uses half of that payload
for its attempt ID and half for an independently derived 128-bit authenticator, so
the SDK can correlate concurrent introductions without increasing UDP response
size. State retains keyed credential fingerprints, derivation inputs, and salt—not
issued plaintext. All diagnostic string representations redact credentials and
derivation material.
The client receives only its punch capability. A host polls its own listing with
the lease token in `X-Rendezvous-Lease-Token` and receives only host-role
capabilities through a signed, listing-bound, five-minute cursor. Replaying an
identical join request returns the same live attempt; changing the request under
the same owner/key conflicts. A client may cancel with its punch capability in
`X-Rendezvous-Client-Punch-Capability`; cancellation atomically removes the
attempt. Listing deletion, expiry, revocation, or process restart removes every
associated attempt and credential fingerprint.
`X-Rendezvous-Client-Punch-Capability`; cancellation atomically marks the attempt
and retains a bounded tombstone until its original expiry. Host polling returns
that tombstone so a coordinator can revoke any local ticket authorization, while
endpoint binding, introduction, ticket issuance, and ticket consumption all
reject the cancelled attempt. Listing deletion, expiry, revocation, or process
restart removes every associated attempt and credential fingerprint.
Endpoint binding remains role- and capability-specific. The first endpoint
observed for a role wins atomically; an exact UDP duplicate is idempotent, while
@@ -50,8 +56,14 @@ fingerprint-consumption seam for mediator tests and revocation. On the game host
the SDK's bounded `ConnectionTicketValidator` stores a process-keyed digest,
accepts an exact ticket once under a lock, rejects altered/cross-attempt/expired/
revoked/replayed tickets, and zeroes retained digests and key material on disposal.
Issue #11 carries the ticket in the authenticated introduction; issue #12 wires
authorization and consumption into the caller-owned LiteNetLib coordinator.
Issue #11 carries the fixed-size ticket in the authenticated introduction. Issue
#12 extracts its embedded attempt ID, bounds the host's local authorization window
by both the host-polled attempt expiry and the configured ticket lifetime, then
wires one-time consumption into the caller-owned coordinator. Both peers receive
a digest of the exact expected ticket over HTTP and reject any syntactically valid
but unauthenticated introduction token. Embedding the ID prevents concurrent or
late introductions from cross-binding a valid ticket while preserving the
mediator's 2.0 response-byte amplification ceiling.
## Consequences