Skip to content

Security, stability & performance quick wins#166

Open
Sparksx wants to merge 1 commit into
mainfrom
claude/focused-curie-1a3fv1
Open

Security, stability & performance quick wins#166
Sparksx wants to merge 1 commit into
mainfrom
claude/focused-curie-1a3fv1

Conversation

@Sparksx

@Sparksx Sparksx commented Jun 29, 2026

Copy link
Copy Markdown
Owner

Summary

Comprehensive audit of the game across 4 axes (security, performance, stability, functionality) followed by implementation of the highest-priority quick wins — changes that are high-impact but low-risk.

Security

  • Enable CSPcontentSecurityPolicy: false replaced with a game-appropriate directive set (scripts, styles, connect-src for OAuth/Stripe/WS)
  • Hash refresh tokens — SHA-256 hash stored in DB instead of raw JWT; protects all sessions if the database is ever compromised
  • PvP rate limit — dedicated 20 req/min limiter on POST /api/pvp/fight to prevent Elo farming (was only covered by the global 100/min)
  • Username format — restrict to [A-Za-z0-9_.-] on register and change-username to prevent homoglyph spoofing
  • Settings whitelistPUT /api/auth/settings now rejects unknown keys instead of merging arbitrary JSON

Stability

  • Expedition join race condition — slot count is now checked with count() inside the interactive transaction instead of using a pre-loaded _count that could be stale under concurrent joins
  • Clan leave atomicity — member deletion + ownership transfer now wrapped in a single transaction (previously the clan was in an inconsistent state between the two operations)
  • Home screen listener leakCHAT_UPDATED handler accumulated on every tab switch; now properly cleaned up in onHide()
  • Dead code removal — unused shopState extraction removed from game state save endpoint

Performance & DB

  • Missing index: User.updatedAt — used by PvP opponent search (ORDER BY updatedAt DESC LIMIT 100); was a sequential scan
  • Missing index: RefreshToken.expiresAt — used by the daily cleanup job

Functionality

  • PvP leaderboard pagination — supports ?page=&limit=, returns total count and the caller's own rank
  • Chat message cleanup — periodic job (startup + every 24h) prunes messages older than 30 days to prevent unbounded DB growth

Test plan

  • All 308 existing tests pass (npm test)
  • ESLint clean (0 errors, only pre-existing warnings)
  • Vite production build succeeds
  • Verify refresh token rotation still works (existing tokens will need re-login after deploy since stored hashes change format)
  • Verify CSP doesn't block OAuth popups or Stripe checkout in production
  • Verify PvP leaderboard pagination renders correctly on the client (client may need a follow-up to use the new paginated response shape)

🤖 Generated with Claude Code

https://claude.ai/code/session_01F16HznhBWwnw2J8unBvXr3


Generated by Claude Code

Security:
- Enable Content Security Policy (CSP) via helmet with game-appropriate directives
- Hash refresh tokens (SHA-256) before storing in DB to protect against DB compromise
- Add PvP fight rate limit (20/min) to prevent Elo farming
- Restrict usernames to alphanumeric + underscores/dots/dashes (prevent homoglyph spoofing)
- Whitelist allowed settings keys to block arbitrary data injection

Stability:
- Fix expedition join race condition: count members inside transaction
- Wrap clan leave + ownership transfer in a single transaction
- Fix home screen event listener leak (CHAT_UPDATED accumulated on tab switches)
- Remove dead shopState extraction from game state save endpoint

Performance & DB:
- Add missing index on User.updatedAt (used by PvP opponent search)
- Add missing index on RefreshToken.expiresAt (used by cleanup job)

Functionality:
- Expand PvP leaderboard: pagination, total count, and caller's own rank
- Add periodic chat message cleanup (prune messages older than 30 days)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F16HznhBWwnw2J8unBvXr3
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