Skip to content

fix: pause-permission tags, role clobber, env parsing, jointeam guard, constant-time token (#552, #553, #558)#164

Open
Flegma wants to merge 2 commits into
mainfrom
audit/game-server-fixes
Open

fix: pause-permission tags, role clobber, env parsing, jointeam guard, constant-time token (#552, #553, #558)#164
Flegma wants to merge 2 commits into
mainfrom
audit/game-server-fixes

Conversation

@Flegma

@Flegma Flegma commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Self-contained game-server fixes from the 2026-07 audit. Closes #552, #553, #558.

Changes

Pause/resume permission clan tags (#552)
TimeoutSystem.CanPause/CanResume compared player.Clan to [administrator], [match_organizer], [tournament_organizer], but connect assigns [admin] / [streamer] / [organizer] (PlayerConnected.cs sets player.Clan = "[{role}]" from InitConnect's role map). The strings never matched, so admin/organizer pause and resume never worked. Now checks [admin] / [organizer].

InitConnect role assignment clobber (#558)
The role map used if (Administrator) {...} immediately followed by if (Streamer) {...} else {...}, so an Administrator (not a Streamer) fell into the else and got organizer, overwriting the admin tag set one line above. Changed to if / else if / else. (This is what made the admin tag exist for the #552 fix to match.)

Constant-time connect-token check (#558)
InitConnect verified the HMAC connect token with computedToken != password (string compare, short-circuits on first mismatch). Switched to CryptographicOperations.FixedTimeEquals.

jointeam argument guard (#558)
HandleJoinTeam did int.Parse(info.ArgByIndex(1)) on a client command argument, which throws on non-numeric input. Guarded with int.TryParse (returns HookResult.Continue on bad input).

swiftly .env parsing (#553)
EnvironmentService split each line with Split('=', RemoveEmptyEntries) and skipped anything not exactly two parts, silently dropping every value that contains = (base64 secrets, tokens, connection strings) or is empty. Now splits on the first = only, and skips blanks/comments.

Testing

  • dotnet build (Release): counterstrikesharp (net8) and swiftly (net10) both 0 errors / 0 warnings.
  • swiftly test suite: 80/80 passing (regression check for the EnvironmentService change).

Deferred from this PR

#559 (packaging): the swiftly setup.sh if $VAR = true quoting bug and the Dockerfile.dev vs Dockerfile metamod/CSS version skew. Lower value; the version alignment wants a deliberate choice of the target versions rather than a blind bump. Left for a follow-up.

Flegma added 2 commits July 10, 2026 22:09
…nt-time token

- TimeoutSystem: match the clan tags actually assigned on connect ([admin] /
  [organizer]); the old [administrator]/[match_organizer]/[tournament_organizer]
  strings never matched, so privileged pause/resume never worked (#552).
- InitConnect: the role assignment used two ifs, so an Administrator's 'admin'
  tag was immediately clobbered to 'organizer' by the else. Made it
  if/else-if/else (#558).
- InitConnect: verify the connect token with CryptographicOperations.
  FixedTimeEquals instead of string != (constant-time) (#558).
- PlayerConnected: guard the jointeam team-number arg with int.TryParse so a
  non-numeric client argument can't throw out of the hook (#558).
- swiftly EnvironmentService: split each .env line on the first '=' only. The
  previous Split('=', RemoveEmptyEntries) dropped any value containing '='
  (base64 secrets, tokens, connection strings) or any empty value (#553).

counterstrikesharp + swiftly build 0/0; swiftly suite 80/80.
…ollow-up)

- EnvironmentService: skip a line whose key trims to empty (e.g. ' =value'),
  which would otherwise throw ArgumentException from SetEnvironmentVariable('').
  Load() has no surrounding try/catch, so that would crash plugin init.
- swiftly TimeoutSystem: the same never-matching clan-tag check
  ([administrator]/[match_organizer]/[tournament_organizer]) exists in the
  SwiftlyS2 port; align it to the assigned [admin]/[organizer] tags in both
  spots so pause/resume works there too when swiftly becomes the runtime.

swiftly build 0/0, suite 80/80.
@Flegma

Flegma commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

Independent code review run on the diff. Two follow-ups in 495c279: (1) the new env parser threw on a whitespace-only key ( =value), and Load() has no try/catch so that crashes plugin init, added an empty-key skip; (2) the review flagged that the swiftly TimeoutSystem has the same never-matching clan-tag check I only fixed in the counterstrikesharp copy, so the swiftly port is now fixed too (both spots). swiftly build 0/0, suite 80/80. The role/token/jointeam changes reviewed clean.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant