mirror of
https://github.com/Such-Software/wownerogue.git
synced 2026-10-22 16:48:34 +02:00
fix: reconnect-proof rate limiting (stable id + real client IP)
Socket-event rate limits keyed on socket.id (new on every reconnect) and passed NO ip argument, so the "IP-limited" prefixes never actually applied — reconnecting reset every limit, and chat had no IP limit at all. - New rateLimitContext helper resolves a STABLE identity (anon_token -> id, falling back to socket id) and the real client IP (X-Forwarded-For honoured only when TRUST_PROXY=true, else handshake address — no spoofing on direct exposure). - game:start, address:set and chat:message now pass (stableId, action, ip); connection:new uses the real IP. 'chat:' added to IP-limited prefixes. - Express 'trust proxy' enabled when TRUST_PROXY=true; documented in .env.example. Aligned the contradictory default limit values with the production override. Adds rateLimit.test.js (reconnect can't bypass, IP backstop for fresh identities, XFF gating). Full suite: 18 suites / 143 tests.
This commit is contained in:
@@ -34,7 +34,7 @@ Key: `S` ≤ half day · `M` ~1–3 days · `L` ~1 week+ · 🔴 launch-blocker
|
||||
|
||||
## Phase 2 — Identity, abuse & concurrency (🟠)
|
||||
- [x] **2.1 L — Unify identity resolution on stable `user_id`.** ✅ `getOrCreateUser` now resolves through SessionManager's stable `anon_token`→`id` identity first (re-selecting a fresh row by stable id), falling back to the legacy `socket_id` lookup only when no session exists — eliminating the duplicate "orphan" user row that caused credit/payout desync. `gameModeManager.sessionManager` wired in SocketHandlers. `anon_token` is already `UNIQUE` (migration 003), so the stable-identity constraint exists. New `identityResolution.test.js` proves no duplicate row is created when a session exists. _Deferred: re-keying the in-memory `activeGames` map by `user_id` (invasive; already mitigated in 0.5 by stamping `dbUserId` on the game) — tracked as a follow-up._
|
||||
- [ ] **2.2 M — Reconnect-proof rate limiting.** Key on `user_id`/IP; IP-limit chat; set `trust proxy`; de-dup limit configs (`src/network/rateLimiter.js:80`).
|
||||
- [x] **2.2 M — Reconnect-proof rate limiting.** ✅ New `rateLimitContext` helper resolves a STABLE id (`anon_token`→`id`, falling back to socket id) + the real client IP. All socket-event limiters (game:start, address:set, chat:message) now pass both — previously they passed `socket.id` and **no IP at all**, so reconnecting reset every limit and the "IP-limited" prefixes never actually applied. `chat:` added to IP-limited prefixes; `connection:new` uses the real IP. Express `trust proxy` + XFF honored only when `TRUST_PROXY=true` (documented in `.env.example`). Contradictory default limit values aligned. New `rateLimit.test.js` (reconnect can't bypass, IP backstop, XFF gating).
|
||||
- [ ] **2.3 M — Input validation + leak fixes.** Validate socket payloads (`connectionHandler.js:90`); TTL-evict `mempoolNotified` (`socketHandlers.js:223`); evict `sessions` on disconnect; wire all `dispose()` into `shutdown()`; snapshot in `checkGamesTimeout` (`socketHandlers.js:1012`).
|
||||
|
||||
## Phase 3 — Game integrity (🟠)
|
||||
|
||||
Reference in New Issue
Block a user