fix(multiplayer): fence roster topology at persistence

This commit is contained in:
Josh Creek
2026-09-01 16:20:01 +01:00
parent 80d6ee8cf5
commit a439a1059b
3 changed files with 23 additions and 1 deletions
+11 -1
View File
@@ -149,11 +149,21 @@ func SaveVerifiedAssignmentRoster(ctx context.Context, db *sql.DB, assignment do
}
digest := domain.ManifestDigest(assignment.Manifest)
rows := make([]DurableAssignment, 0, len(roster))
seenPlayers := make(map[string]struct{}, len(roster))
seenSlots := make(map[int]struct{}, len(roster))
for _, signed := range roster {
auth := signed.Authorisation
if err := validateSignedRosterEntry(assignment, signed, verify); err != nil {
return err
}
if _, exists := seenPlayers[auth.PlayerID]; exists {
return fmt.Errorf("invalid signed assignment roster: duplicate player")
}
if _, exists := seenSlots[auth.Slot]; exists {
return fmt.Errorf("invalid signed assignment roster: duplicate slot")
}
seenPlayers[auth.PlayerID] = struct{}{}
seenSlots[auth.Slot] = struct{}{}
envelope, err := json.Marshal(signed)
if err != nil {
return fmt.Errorf("encode signed assignment roster: %w", err)
@@ -172,7 +182,7 @@ func SaveVerifiedAssignmentRoster(ctx context.Context, db *sql.DB, assignment do
func validateSignedRosterEntry(assignment domain.Assignment, signed domain.SignedJoinAuthorisation, verify func([]byte, []byte) bool) error {
auth := signed.Authorisation
if len(signed.Signature) == 0 || verify == nil || !verify(domain.JoinAuthorisationBytes(auth), signed.Signature) || auth.MatchID != assignment.Allocation.MatchID || auth.ServerID != assignment.Allocation.ServerID || auth.Protocol != strconv.Itoa(assignment.Allocation.Protocol) || auth.PlayerID == "" || auth.Slot < 0 || auth.Slot > 5 || auth.ExpiresAt.IsZero() {
if len(signed.Signature) == 0 || verify == nil || !verify(domain.JoinAuthorisationBytes(auth), signed.Signature) || auth.MatchID != assignment.Allocation.MatchID || auth.ServerID != assignment.Allocation.ServerID || auth.Protocol != strconv.Itoa(assignment.Allocation.Protocol) || auth.PlayerID == "" || auth.Slot < 0 || auth.Slot > 5 || auth.Team < 0 || auth.Team > 1 || auth.Slot/3 != auth.Team || auth.ExpiresAt.IsZero() {
return fmt.Errorf("invalid signed assignment roster")
}
return nil