mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-11 00:14:00 +00:00
fix: validate matchmaking event vocabulary
This commit is contained in:
+38
-2
@@ -70,8 +70,8 @@ func (h *eventHub) unsubscribe(subscriber *eventSubscriber) {
|
||||
}
|
||||
|
||||
func (h *eventHub) publish(event ControlPlaneEvent) error {
|
||||
if event.PlayerID == "" || event.Event == "" || event.ResourceID == "" || event.OccurredAt.IsZero() {
|
||||
return errors.New("invalid control-plane event")
|
||||
if err := validateControlPlaneEvent(event); err != nil {
|
||||
return err
|
||||
}
|
||||
payload, err := json.Marshal(event)
|
||||
if err != nil {
|
||||
@@ -96,6 +96,42 @@ func (h *eventHub) publish(event ControlPlaneEvent) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateControlPlaneEvent(event ControlPlaneEvent) error {
|
||||
if event.PlayerID == "" || event.ResourceID == "" || event.OccurredAt.IsZero() {
|
||||
return errors.New("invalid control-plane event envelope")
|
||||
}
|
||||
switch event.Event {
|
||||
case "state_changed":
|
||||
if !eventState(event.State, "QUEUED", "PROPOSED", "ACCEPTED", "ALLOCATING", "PROCESS_READY", "ASSIGNMENT_READY", "ASSIGNED", "CONNECTING", "LIVE", "RESULT_PENDING", "COMPLETED", "CANCELLED", "EXPIRED", "FAILED") {
|
||||
return errors.New("invalid state-changed event")
|
||||
}
|
||||
case "proposal_changed":
|
||||
if !eventState(event.State, "OPEN", "ACCEPTED", "DECLINED", "EXPIRED", "CANCELLED") {
|
||||
return errors.New("invalid proposal-changed event")
|
||||
}
|
||||
case "assignment_changed":
|
||||
if event.MatchID == "" || event.ServerID == "" {
|
||||
return errors.New("invalid assignment-changed event")
|
||||
}
|
||||
case "error":
|
||||
if !eventState(event.Code, "REVISION_GAP", "NOT_AUTHORISED", "INVALID_STATE", "RATE_LIMITED") {
|
||||
return errors.New("invalid error event")
|
||||
}
|
||||
default:
|
||||
return errors.New("unknown control-plane event")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func eventState(value string, allowed ...string) bool {
|
||||
for _, candidate := range allowed {
|
||||
if value == candidate {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *Service) controlPlaneEvent(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
writeError(w, http.StatusMethodNotAllowed, "method_not_allowed")
|
||||
|
||||
@@ -278,6 +278,23 @@ func TestEventHubClosesSlowSubscribersExactlyOnce(t *testing.T) {
|
||||
hub.unsubscribe(subscriber)
|
||||
}
|
||||
|
||||
func TestEventHubRejectsEventsOutsideTheV1Vocabulary(t *testing.T) {
|
||||
hub := newEventHub()
|
||||
base := ControlPlaneEvent{Revision: 1, ResourceID: "ticket-1234567890123456", OccurredAt: time.Unix(1000, 0).UTC(), PlayerID: "player-1"}
|
||||
invalid := []ControlPlaneEvent{
|
||||
{Event: "unknown", Revision: base.Revision, ResourceID: base.ResourceID, OccurredAt: base.OccurredAt, PlayerID: base.PlayerID},
|
||||
{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: "error", Code: "SECRET_LEAK", Revision: base.Revision, ResourceID: base.ResourceID, OccurredAt: base.OccurredAt, PlayerID: base.PlayerID},
|
||||
}
|
||||
for _, event := range invalid {
|
||||
if err := hub.publish(event); err == nil {
|
||||
t.Fatalf("invalid event was accepted: %+v", event)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestQueueAPIRejectsUnauthenticatedUnknownAndOversizedInput(t *testing.T) {
|
||||
service := &Service{Sessions: domain.NewSessionStore(), Queue: domain.NewQueue(), Candidate: func(string, string) (domain.Candidate, error) { return domain.Candidate{}, nil }}
|
||||
server := httptest.NewServer(service.Handler())
|
||||
|
||||
Reference in New Issue
Block a user