fix: verify signed assignment rosters

This commit is contained in:
Josh Creek
2026-09-01 09:53:45 +01:00
parent 55e07648cf
commit 8b5b5333c6
4 changed files with 32 additions and 8 deletions
+12 -4
View File
@@ -132,16 +132,16 @@ func SaveAssignments(ctx context.Context, db *sql.DB, assignments []DurableAssig
// SaveVerifiedAssignmentRoster converts the backend-verified signed roster to
// player-scoped rows. It rechecks the claims at this persistence boundary so a
// caller cannot accidentally publish a token for another match or slot.
func SaveVerifiedAssignmentRoster(ctx context.Context, db *sql.DB, assignment domain.Assignment, roster []domain.SignedJoinAuthorisation) error {
if assignment.Allocation.State != domain.ServerAllocated || len(roster) == 0 {
func SaveVerifiedAssignmentRoster(ctx context.Context, db *sql.DB, assignment domain.Assignment, roster []domain.SignedJoinAuthorisation, verify func([]byte, []byte) bool) error {
if assignment.Allocation.State != domain.ServerAllocated || len(roster) == 0 || verify == nil {
return fmt.Errorf("invalid verified assignment roster")
}
digest := domain.ManifestDigest(assignment.Manifest)
rows := make([]DurableAssignment, 0, len(roster))
for _, signed := range roster {
auth := signed.Authorisation
if len(signed.Signature) == 0 || 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() {
return fmt.Errorf("invalid signed assignment roster")
if err := validateSignedRosterEntry(assignment, signed, verify); err != nil {
return err
}
envelope, err := json.Marshal(signed)
if err != nil {
@@ -159,6 +159,14 @@ func SaveVerifiedAssignmentRoster(ctx context.Context, db *sql.DB, assignment do
return SaveAssignments(ctx, db, rows)
}
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() {
return fmt.Errorf("invalid signed assignment roster")
}
return nil
}
func GetAssignment(ctx context.Context, db *sql.DB, playerID, matchID string, now time.Time) (DurableAssignment, error) {
if db == nil || playerID == "" || matchID == "" || now.IsZero() {
return DurableAssignment{}, fmt.Errorf("invalid assignment recovery arguments")