Skip to content

Restrict starting a game to its participants when it is ready - #55

Open
paskal wants to merge 1 commit into
masterfrom
fix/start-game-authorization
Open

Restrict starting a game to its participants when it is ready#55
paskal wants to merge 1 commit into
masterfrom
fix/start-game-authorization

Conversation

@paskal

@paskal paskal commented Jul 3, 2026

Copy link
Copy Markdown
Collaborator

Problem

POST /start/:id only ran authMiddleware: any logged-in user could start any game, in any phase. startGame did no membership or phase check, and starting a game that was already in progress reshuffled the letters and wiped turns, score and result — so one request could destroy an ongoing game belonging to other people.

Fix

startGame(gameId, currentUserId) now validates, before touching the game:

  • game exists → otherwise StartGameError(404, "game_not_found")
  • caller is one of the game's players → otherwise StartGameError(403, "not_a_participant")
  • phase is "ready" → otherwise StartGameError(409, "game_not_ready")

The route passes req.user.id and maps StartGameError to its status code; anything else still goes to the default error handler. Legitimate flow (a participant starting a ready game) is unchanged.

@paskal
paskal requested a review from Ksinia as a code owner July 3, 2026 23:48
@paskal
paskal requested a review from Copilot July 3, 2026 23:49

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens the /start/:id game-start flow so only legitimate participants can start a game, and only when the game is in the correct phase, preventing unauthorized users from disrupting or resetting in-progress games.

Changes:

  • Added StartGameError and validation in startGame(gameId, currentUserId) for: game existence (404), participant membership (403), and "ready" phase (409).
  • Updated the /start/:id route to pass req.user.id and to translate StartGameError into the corresponding HTTP status code + JSON error payload.
  • Replaced the prior instance update with an atomic Game.update(... where phase="ready") guard to prevent concurrent double-starts from both reshuffling/wiping state.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
services/start.ts Adds start-time authorization/phase validation and an atomic update guard to prevent unauthorized or concurrent destructive starts.
routers/game.ts Passes the authenticated user into startGame and maps domain errors to appropriate HTTP responses.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Previously, POST /start/:id only required authentication: any logged-in
user could start any game in any phase, and starting an in-progress game
reshuffled the letters and wiped its turns and score.

After this change, startGame verifies the game exists (404), the caller
is one of its players (403) and the phase is "ready" (409), so games
can no longer be started by outsiders or restarted mid-play.
@paskal
paskal force-pushed the fix/start-game-authorization branch from 2570a67 to c836955 Compare July 4, 2026 12:05
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.

2 participants