Skip to content

WebDoor API: only serve sessions, saves and scores for installed, enabled WebDoors - #500

Open
SkrawlCO wants to merge 1 commit into
awehttam:claudesbbsfrom
SkrawlCO:upstream/up-033-webdoor-game-id-authorization
Open

SkrawlCO wants to merge 1 commit into
awehttam:claudesbbsfrom
SkrawlCO:upstream/up-033-webdoor-game-id-authorization

Conversation

@SkrawlCO

@SkrawlCO SkrawlCO commented Oct 5, 2026

Copy link
Copy Markdown

TITLE: WebDoor API: only serve sessions, saves and scores for installed, enabled WebDoors

Problem

WebDoorController takes the game from the caller-supplied game_id query parameter, or the /webdoors/{id}/ referer, and defaults to 'unknown'. It never checks the value against the installed WebDoors or config/webdoors.json. Any authenticated user can create sessions, write save slots (up to the size limit) and submit leaderboard scores under:

  • arbitrary game ids, including ids that are not installed;
  • WebDoors the sysop has disabled;
  • WebDoors whose requirements are not met;
  • the shared 'unknown' bucket.

Impact

Users can fill webdoor_storage, webdoor_sessions and webdoor_leaderboards with rows for games that don't exist or are switched off, and can post leaderboard scores for disabled games that show up again when the game is re-enabled.

Repair

WebDoorController::resolveGameId() resolves the requested id (explicit game_id, or the referer) against WebDoorManifest::listManifests(), by directory or game.id. It accepts the id only when the manifest has a game block, the game is enabled in config/webdoors.json, and its requirements are met. These are the same checks the WebDoor listing and game page use. The canonical manifest id is used for storage.

The seven game-scoped methods (getSession, listSaves, loadSave, saveGame, deleteSave, getLeaderboard, submitScore) return 404 errors.webdoor.game_unavailable before any query when it doesn't resolve. The new key is added to all six locales. docs/WebDoors.md documents the rule.

Compatibility

Bundled WebDoors keep working:

  • some send game_id (the SDK);
  • others (Hangman, Klondike) rely on the same-origin referer, which browsers send in full under the default referrer policy.

Requests without a resolvable game no longer fall into a shared 'unknown' bucket.

Proof

tests/Unit/WebDoorGameAuthorizationTest.php uses the real installed manifests, a controlled GameConfig and a recording PDO stub, with no database:

  • an enabled WebDoor works via game_id and via the referer, under its canonical id;
  • not-installed, disabled, unconfigured, missing and path-traversal ids are refused by all seven methods with no database query.

Fails on the current branch (5 failures); passes with the change. The i18n syntax, missing-key and error-key checks pass, and the rest of tests/Unit is unchanged.

…bled WebDoors

WebDoorController used the caller-supplied game_id (or referer, default
'unknown') without checking it, so any user could create sessions,
saves and leaderboard scores for arbitrary, disabled or uninstalled
games.

Resolve the id against the WebDoor manifests, config/webdoors.json and
manifest requirements (as the listing and game page do) and return 404
errors.webdoor.game_unavailable before any query otherwise.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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