Scope player capabilities and add replay-protected session storage#3246
Scope player capabilities and add replay-protected session storage#3246sydseter wants to merge 19 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR hardens Copi’s player authorization by moving from caller-provided identifiers to short-lived, signed player capabilities that are exchanged into a server-managed session, with replay protection and optional PostgreSQL-backed session storage.
Changes:
- Introduces signed, 5-minute player capabilities and a CSRF-protected exchange endpoint that stores
{game_id, player_id}capabilities in the session (supporting multiple players/games per browser). - Adds replay protection for capability exchange via digest tracking (in-memory by default, cluster-coordinated when enabled, and optionally PostgreSQL-backed for cross-node atomic replay prevention).
- Updates LiveView flows, API authorization checks, documentation, and adds extensive backend + frontend tests covering the new authorization model and storage modes.
Reviewed changes
Copilot reviewed 36 out of 37 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| ThreatDragonModels/copi.json | Updates threat model text to reflect capability-based auth, replay/storage modes, and remaining risks. |
| copi.owasp.org/test/copi/player_capability_registry_test.exs | Adds unit tests for single-use capability consumption, digest storage, and cluster behaviors. |
| copi.owasp.org/test/copi_web/router_test.exs | Verifies old GET exchange route is gone; asserts card-play requires a player session. |
| copi.owasp.org/test/copi_web/postgres_session_integration_test.exs | Adds integration coverage for PostgreSQL session persistence, encryption, replay rejection, and cleanup. |
| copi.owasp.org/test/copi_web/live/player_live/show_test.exs | Updates tests to require session authorization for player pages and adds redirect coverage. |
| copi.owasp.org/test/copi_web/live/player_live/form_component_test.exs | Updates player creation flow to exchange capability and navigate via clean URL. |
| copi.owasp.org/test/copi_web/live/player_live_test.exs | Updates live tests to follow the capability exchange flow after creating a player. |
| copi.owasp.org/test/copi_web/live/game_live/show_test.exs | Ensures resume links show only stored players for the current game. |
| copi.owasp.org/test/copi_web/gameplay_flow_test.exs | Adds end-to-end multi-player flow test + public-watching/unauthorized rejection checks. |
| copi.owasp.org/test/copi_web/controllers/api_controller_test.exs | Adds/updates controller tests for exchange, session semantics, and stricter authorization. |
| copi.owasp.org/SECURITY.md | Documents capability model, replay risks per mode, key separation, and operational guidance. |
| copi.owasp.org/README.md | Documents the three session/replay storage modes and configuration/operational requirements. |
| copi.owasp.org/priv/repo/migrations/20260717000001_create_security_session_tables.exs | Adds PostgreSQL tables/indexes for sessions and capability-consumption digests. |
| copi.owasp.org/lib/copi/session_record.ex | Introduces Ecto schema for server-side sessions. |
| copi.owasp.org/lib/copi/session_cleanup.ex | Adds one-time startup cleanup task for expired PostgreSQL sessions. |
| copi.owasp.org/lib/copi/release.ex | Refactors migration/rollback to use a custom with_repo/2 wrapper with stop timeout. |
| copi.owasp.org/lib/copi/player_capability_registry.ex | Implements replay protection registry with local/cluster/PostgreSQL modes. |
| copi.owasp.org/lib/copi/player_capability_consumption.ex | Adds Ecto schema for consumed capability digests. |
| copi.owasp.org/lib/copi/application.ex | Starts SessionCleanup and PlayerCapabilityRegistry in the supervision tree. |
| copi.owasp.org/lib/copi_web/session_store.ex | Adds Plug.Session.Store implementation with optional PostgreSQL-backed session storage. |
| copi.owasp.org/lib/copi_web/security_headers.ex | Adds Referrer-Policy: no-referrer for browser and live-reload responses. |
| copi.owasp.org/lib/copi_web/router.ex | Moves card-play into CSRF-protected browser JSON pipeline; adds capability exchange route. |
| copi.owasp.org/lib/copi_web/player_sessions.ex | Adds session helpers for storing/authorizing multiple {game_id, player_id} pairs. |
| copi.owasp.org/lib/copi_web/player_capability.ex | Adds signing/verifying logic for purpose-scoped player capabilities. |
| copi.owasp.org/lib/copi_web/live/player_live/show.html.heex | Adjusts client hook attribute to only request clearing when persistence is disabled. |
| copi.owasp.org/lib/copi_web/live/player_live/show.ex | Enforces that the URL-selected player must be present in the browser session. |
| copi.owasp.org/lib/copi_web/live/player_live/form_component.ex | Emits an exchange event instead of navigating directly to a capability-bearing URL. |
| copi.owasp.org/lib/copi_web/live/game_live/show.html.heex | Shows resume links for all stored players for the current game. |
| copi.owasp.org/lib/copi_web/live/game_live/show.ex | Uses session-stored player ids to compute resume players list. |
| copi.owasp.org/lib/copi_web/endpoint.ex | Switches session storage to CopiWeb.SessionStore and aligns cookie TTL to session_ttl_seconds. |
| copi.owasp.org/lib/copi_web/controllers/api_controller.ex | Adds capability exchange endpoint; enforces exact {game_id, player_id} for card play. |
| copi.owasp.org/fly.toml | Enables PostgreSQL session store by default for Fly deployments. |
| copi.owasp.org/config/runtime.exs | Adds runtime config for clustering and PostgreSQL session store toggles. |
| copi.owasp.org/config/config.exs | Adds defaults for cluster/session-store toggles and shared session TTL. |
| copi.owasp.org/assets/test/app.test.ts | Updates frontend tests for CSRF + credentials and new capability exchange hook. |
| copi.owasp.org/assets/package-lock.json | Bumps phoenix_live_view dependency version in assets lockfile. |
| copi.owasp.org/assets/js/app.js | Adds capability exchange hook, adds CSRF + credentials for card play, adjusts session clearing behavior. |
Files not reviewed (1)
- copi.owasp.org/assets/package-lock.json: Generated file
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
|
I closed most of the quality recommendations from CoPilot and qlty as I don’t think they really represent real concerns. It’s pk for md files to have line-length running beyond 120 characters as every editor has something called word wrap. The session cleanup only happens on start-up and won’t cause any db performance issues so the suggestion about moving it to cron is not warranted. The app restarts weekly anyway so this should still be ok. |
…copilot/increase-test-coverage-session-store
…ssion-store Copilot/increase test coverage session store
Increase backend ExCoveralls coverage to ≥95% on player-session-management
|
The coverage failed at 94.93% for the frontend JS tests. Increasing it. |
|
@rewtd, as you voiced the concern about no longer being able to share your hand if you can't continue playing, a share-your-hand button has been added. This will make it possible to share your hand with someone who can continue instead of keeping the session.
|
|
Fully testable from https://copi.owaspcornucopia.org/ |
|
My thinking here is that the current copi.owasp.org does not follow best practices according to OWASP ASVS. This ensures it does. It's also a step towards creating a more mature app capable of processing sensitive/personal information. Currently, it shouldn't |


Description
This PR fixes the player authorization issue where the card-play API accepted caller-provided game, player, and card identifiers without consistently proving that the browser controlled that player.
Player authorization is now based on an exact {game_id, player_id} capability stored in the player session. Public game watching remains available without authentication.
Changes
Session and Replay Storage
Three operating modes are supported:
PostgreSQL mode takes precedence over clustered and local replay storage.
Key Separation
Database Changes
Added tables for:
One-time PostgreSQL session cleanup at application startup.
Security Results
The original BOLA/IDOR issue is addressed:
Remaining risks are documented in SECURITY.md and ThreatDragonModels/copi.json, including:
Testing
Added coverage for:
Validated results:
AI Tool Disclosure
GitHub CoPilotGPT-5.6 SolAffirmation