From 92d9f7a93c7603c2b2006b157612fd327127c6f8 Mon Sep 17 00:00:00 2001 From: Evan Date: Mon, 15 Dec 2025 09:07:31 -0800 Subject: [PATCH] Create a docs folder, add auth & architecture docs (#2623) ## Description: Create docs folder ## Please complete the following: - [x] I have added screenshots for all UI updates - [x] I process any text displayed to the user through translateText() and I've added it to the en.json file - [x] I have added relevant tests to the test directory - [x] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced ## Please put your Discord username so you can be contacted if a bug or regression is found: evan --- API.md => docs/API.md | 0 docs/Architecture.md | 30 ++++++++++++++++++++++++++++++ docs/Auth.md | 24 ++++++++++++++++++++++++ 3 files changed, 54 insertions(+) rename API.md => docs/API.md (100%) create mode 100644 docs/Architecture.md create mode 100644 docs/Auth.md diff --git a/API.md b/docs/API.md similarity index 100% rename from API.md rename to docs/API.md diff --git a/docs/Architecture.md b/docs/Architecture.md new file mode 100644 index 000000000..e01bd624e --- /dev/null +++ b/docs/Architecture.md @@ -0,0 +1,30 @@ +# Game Architecture + +The game is split into four components: + +1. **client** - Handles rendering and UI for the user + +2. **core** - Deterministic simulation. It is pure TypeScript/JavaScript code with no external dependencies. It must be fully deterministic. + +3. **server** - Handles coordination and relays of intents/requests + +4. **api** - A closed source Cloudflare Worker that handles auth, stats, game data storage, cosmetics, and monetization + +## Simulation Architecture + +The game simulation logic does not run on the server. Instead, each client runs their own instance of core, which is why it must be deterministic. At the end of each tick, data is sent from core to client via GameUpdates. Core and client run in different threads - the core runs in a worker thread. + +## Intents + +When a user performs an action, it creates an "Intent" which is sent to the server. The server stores all intents for that tick/turn, and at the end, relays all intents to all clients in a bundle called a "turn". Each client receives the turn and sends it to its core simulation. The core then creates an "Execution" for each intent. Executions are the only thing that can modify the game state. + +## Flow + +1. Client sends intent to game server +2. Game server sends turn to client +3. Client forwards turn to core +4. Core creates an execution for each intent +5. Core calls `executeNextTick()` +6. All executions run +7. At the end of the tick core sends updates to client +8. Client renders the updates diff --git a/docs/Auth.md b/docs/Auth.md new file mode 100644 index 000000000..1475c0c6c --- /dev/null +++ b/docs/Auth.md @@ -0,0 +1,24 @@ +# Authentication & Authorization Flow + +## Token Management + +1. **Long-lived refresh token**: Stored as an HTTP-only cookie with a 30-day TTL +2. **Token exchange**: User sends refresh token to the API server, receives a short-lived JWT in return, and the refresh token is rotated +3. **JWT properties**: + - 15-minute TTL (limits damage window if compromised) + - Contains the persistentID + - Stored in memory only (lost on page refresh) + +## WebSocket Authorization + +1. **WebSocket connection**: When user connects, server validates the JWT and creates a `clientID => persistentID` mapping, establishing that this client is authorized to act on behalf of this persistent identity + +2. **Post-connection authorization**: Once WebSocket connection is established, no further token verification is needed. For actions like pause requests, simple ownership checks suffice. + +## Key Insight + +JWT verification happens once at WebSocket connection time. After that, the established mapping allows for lightweight authorization checks based on clientID rather than repeated token validation. + +## Development Mode + +When running the game in development, the API server is not active, so the game falls back to checking only persistentIDs for verification instead of JWTs. This is less secure, as stealing a persistentID means the attacker has indefinite control of the victim's account.