Skip to content

fix: security, stability & performance quick wins - #179

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

fix: security, stability & performance quick wins#179
Sparksx wants to merge 1 commit into
mainfrom
claude/focused-curie-ytosm3

Conversation

@Sparksx

@Sparksx Sparksx commented Jul 20, 2026

Copy link
Copy Markdown
Owner

Summary

Quick-win fixes across security, stability, performance, and developer experience — all low-risk, high-impact changes identified during a full codebase audit.

Security

  • Ban enforcement on HTTP API: banned users could bypass the ban by calling REST endpoints directly (ban was only checked on socket connections). requireAuth now checks ban status on every authenticated request.
  • CSP enabled in production: Content Security Policy was explicitly disabled; now configured with proper directives for Stripe, WebSocket, and self-hosted assets.
  • Rate limiting on /api/auth/refresh: the token refresh endpoint had no rate limiter (only the global 100/min), allowing faster token churn with a leaked refresh token.
  • JWT algorithm pinning: all jwt.verify calls now specify { algorithms: ['HS256'] } to prevent algorithm confusion attacks.
  • Competing shutdown handlers removed: server/lib/prisma.js registered its own SIGINT/SIGTERM handlers that called process.exit(0), racing the graceful shutdown in server/index.js and potentially preventing proper HTTP/socket draining.

Stability

  • Frontend global error handlers: added window.onerror and unhandledrejection listeners so errors are logged instead of silently swallowed.
  • startGame() wrapped in try/catch: a network error during init no longer leaves users on a blank screen — shows a user-friendly fallback message.
  • Health check pings the database: /api/health now runs SELECT 1 against PostgreSQL, making it useful for load balancer health probes.
  • Consistent default game state: new users registered via auth got gold: 0, but loading/saving created state with gold: 100. Centralized in server/lib/defaults.js.

Performance

  • Missing database indexes: added indexes on User.updatedAt (PvP opponent query), RefreshToken.expiresAt (24h cleanup job), Purchase.stripePaymentId (refund webhook lookup).
  • Cache-Control on monster templates: the /api/monsters/templates endpoint was the only template route missing the Cache-Control: public, max-age=3600 header.

Developer Experience

  • CI now runs lint: the GitHub Actions workflow was missing npm run lint, letting lint violations slip into main.
  • Cleaned up dead code: removed unused shopState destructuring in game routes.
  • French error messages translated: two error messages in sprites.js were in French while the rest of the API is English.

Test plan

  • All 524 tests pass (npm test)
  • Lint passes (npm run lint) — no new warnings
  • Build succeeds (npm run build)
  • Verify banned user gets 403 on API calls (not just socket)
  • Verify /api/health returns 503 when DB is unreachable
  • Verify new user starts with correct gold (100, not 0)

🤖 Generated with Claude Code

https://claude.ai/code/session_01EakBjb5ztr2j3csio31CG1


Generated by Claude Code

Security:
- Remove competing shutdown handlers in prisma.js (was racing server/index.js graceful shutdown)
- Add ban check to requireAuth middleware (banned users could still access HTTP API)
- Add rate limiting to /api/auth/refresh endpoint
- Enable Content Security Policy in production (helmet)
- Pin JWT algorithm to HS256 on all verify calls
- Translate French error messages to English in sprites routes

Stability:
- Add global error handlers (window.onerror, unhandledrejection) in frontend
- Wrap startGame() in try/catch with user-friendly fallback
- Add database connectivity check to /api/health endpoint
- Centralize default game state in server/lib/defaults.js (fixes inconsistent starting gold: 0 vs 100)

Performance:
- Add missing database indexes (User.updatedAt, RefreshToken.expiresAt, Purchase.stripePaymentId)
- Add Cache-Control header to monster templates endpoint

DevEx:
- Add lint step to CI pipeline
- Remove unused shopState destructuring in game routes

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