mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-10 16:04:04 +00:00
fix(multiplayer): align websocket assignment ids
This commit is contained in:
@@ -1591,6 +1591,8 @@ Ranked profile projection now enforces the OpenAPI tier enum, rejecting unknown
|
||||
|
||||
Assignment projections and assignment-changed events now enforce the published opaque-ID shape for match, server, and player identifiers; short or unsafe IDs fail closed.
|
||||
|
||||
The WebSocket contract and Go event hub now enforce opaque match and server IDs on assignment notifications, keeping server publication aligned with the Godot client validator.
|
||||
|
||||
Signed MatchNet claims now also require exact JSON string/integer types for every identity, protocol, expiry, slot, team, and generation field; string-number coercion is rejected before canonical signature verification.
|
||||
|
||||
Presentation progress: a shared `Game/themes/cosmic_clash_theme.tres` now gives the menu, lobby, matchmaking, and settings surfaces consistent button, input, option, and label styling. The custom-font portion of `TODO.md` remains open until a distributable font asset is selected.
|
||||
|
||||
@@ -131,7 +131,7 @@ func validateControlPlaneEvent(event ControlPlaneEvent) error {
|
||||
return errors.New("invalid proposal-changed event")
|
||||
}
|
||||
case "assignment_changed":
|
||||
if event.MatchID == "" || event.ServerID == "" {
|
||||
if !controlPlaneResourceIDRE.MatchString(event.MatchID) || !controlPlaneResourceIDRE.MatchString(event.ServerID) {
|
||||
return errors.New("invalid assignment-changed event")
|
||||
}
|
||||
case "error":
|
||||
|
||||
@@ -437,6 +437,8 @@ func TestEventHubRejectsEventsOutsideTheV1Vocabulary(t *testing.T) {
|
||||
{Event: "state_changed", State: "NOT_A_STATE", Revision: base.Revision, ResourceID: base.ResourceID, OccurredAt: base.OccurredAt, PlayerID: base.PlayerID},
|
||||
{Event: "proposal_changed", State: "LIVE", Revision: base.Revision, ResourceID: base.ResourceID, OccurredAt: base.OccurredAt, PlayerID: base.PlayerID},
|
||||
{Event: "assignment_changed", Revision: base.Revision, ResourceID: base.ResourceID, OccurredAt: base.OccurredAt, PlayerID: base.PlayerID},
|
||||
{Event: "assignment_changed", MatchID: "match-1", ServerID: "server-1", Revision: base.Revision, ResourceID: base.ResourceID, OccurredAt: base.OccurredAt, PlayerID: base.PlayerID},
|
||||
{Event: "assignment_changed", MatchID: "match_1234567890", ServerID: "server/unsafe", Revision: base.Revision, ResourceID: base.ResourceID, OccurredAt: base.OccurredAt, PlayerID: base.PlayerID},
|
||||
{Event: "error", Code: "SECRET_LEAK", Revision: base.Revision, ResourceID: base.ResourceID, OccurredAt: base.OccurredAt, PlayerID: base.PlayerID},
|
||||
}
|
||||
for _, event := range invalid {
|
||||
|
||||
@@ -9,10 +9,11 @@
|
||||
{"$ref": "#/$defs/error"}
|
||||
],
|
||||
"$defs": {
|
||||
"envelope": {"type": "object", "required": ["event", "revision", "resource_id", "occurred_at"], "properties": {"revision": {"type": "integer", "minimum": 0}, "resource_id": {"type": "string", "pattern": "^[A-Za-z0-9_-]{16,128}$"}, "occurred_at": {"type": "string", "format": "date-time"}}},
|
||||
"opaqueId": {"type": "string", "pattern": "^[A-Za-z0-9_-]{16,128}$"},
|
||||
"envelope": {"type": "object", "required": ["event", "revision", "resource_id", "occurred_at"], "properties": {"revision": {"type": "integer", "minimum": 0}, "resource_id": {"$ref": "#/$defs/opaqueId"}, "occurred_at": {"type": "string", "format": "date-time"}}},
|
||||
"stateChanged": {"allOf": [{"$ref": "#/$defs/envelope"}, {"type": "object", "properties": {"event": {"const": "state_changed"}, "state": {"type": "string", "enum": ["QUEUED", "PROPOSED", "ACCEPTED", "ALLOCATING", "PROCESS_READY", "ASSIGNMENT_READY", "ASSIGNED", "CONNECTING", "LIVE", "RESULT_PENDING", "COMPLETED", "CANCELLED", "EXPIRED", "FAILED"]}}, "required": ["event", "state"]}]},
|
||||
"proposalChanged": {"allOf": [{"$ref": "#/$defs/envelope"}, {"type": "object", "properties": {"event": {"const": "proposal_changed"}, "state": {"type": "string", "enum": ["OPEN", "ACCEPTED", "DECLINED", "EXPIRED", "CANCELLED"]}}, "required": ["event", "state"]}]},
|
||||
"assignmentChanged": {"allOf": [{"$ref": "#/$defs/envelope"}, {"type": "object", "properties": {"event": {"const": "assignment_changed"}, "match_id": {"type": "string"}, "server_id": {"type": "string"}}, "required": ["event", "match_id", "server_id"]}]},
|
||||
"assignmentChanged": {"allOf": [{"$ref": "#/$defs/envelope"}, {"type": "object", "properties": {"event": {"const": "assignment_changed"}, "match_id": {"$ref": "#/$defs/opaqueId"}, "server_id": {"$ref": "#/$defs/opaqueId"}}, "required": ["event", "match_id", "server_id"]}]},
|
||||
"error": {"allOf": [{"$ref": "#/$defs/envelope"}, {"type": "object", "properties": {"event": {"const": "error"}, "code": {"type": "string", "enum": ["REVISION_GAP", "NOT_AUTHORISED", "INVALID_STATE", "RATE_LIMITED"]}}, "required": ["event", "code"]}]}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user