Commit Graph
8 Commits
Author SHA1 Message Date
DorianandClaude c162d5ebe9 fix(security): five more IDOR/missing-auth bugs in payments + queue (same class as f5f57e6)
While wiring the ai-config settings UI, found the same "trust a
client-supplied pubkey" pattern repeated across every payment-moving
route in the app — not an isolated bug. Fixed all of them:

- GET /api/payments/winnings/:botId (CRITICAL): had NO auth check at
  all AND returned the raw, spendable Cashu bearer token in the list
  response. botId is public (every fight/profile URL), so anyone could
  list any bot's unclaimed winnings and get the live token back before
  the real winner claimed it — direct fund theft, zero auth required.
  Fixed: require JWT-derived ownership of botId; the list endpoint no
  longer returns the token at all (only paymentId + amountSats) — the
  token is now only ever revealed once, via the explicit claim below.

- POST /api/payments/connect-wallet (CRITICAL): trusted a
  client-supplied pubkey with NO ownership check whatsoever. Anyone
  could attach an attacker-controlled NWC connection string or
  Lightning Address to ANY victim bot by pubkey, silently redirecting
  all future fight-winnings payouts to the attacker's wallet.

- POST /api/payments/claim/:paymentId: same pubkey-trust pattern,
  hands back a live spendable Cashu token — the single most sensitive
  check in the file.

- DELETE /api/payments/disconnect-wallet: trusted pubkey with no
  ownership check (DoS: anyone could kill a victim's payout wallet).

- POST /api/queue/join-ranked/:botId: compared a client-supplied
  pubkey directly against bot.publicKey with no signature/JWT
  verification. pubkeys are public by design in nostr (shown on every
  bot's own profile page), so this was not an ownership check at all.

Also hardened (lower severity, same fix for consistency):
POST /create-invoice, POST /confirm/:paymentId, GET /wallet-status.

Fix pattern, consistent with auth.ts (f5f57e6): pubkey is now always
derived from extractPubkeyFromAuth(Authorization: Bearer <jwt>), never
trusted from a request body or query string. Added a shared
verifyBotOwner() helper in bot-auth.ts for the dual-audience routes
(nostr-signed-in owners AND anonymous poll-mode bots via
Authorization: Bot <id>:<secret>). Schemas (connectWalletSchema,
createInvoiceSchema, joinRankedSchema, disconnectWalletSchema) no
longer declare a pubkey field — removing the field is itself a guard
against the pattern regressing. Frontend callers already used
authFetch (attaches the Bearer JWT automatically) for every one of
these, so no behavior change for legitimate callers — only closes the
hole for illegitimate ones.

Root-caused test failures this surfaced: a leaked mockReturnValueOnce
queue value cascaded through payments.test.ts once earlier tests
started 401-ing before consuming their queued mock (disconnect-wallet
-> zap Attack3 -> Attack4 -> claim Attack7). Fixed by giving each
newly-auth-gated test a real JWT (createJwt, not mocked) instead of
loosening the auth requirement.

Full server suite: 806-815/810-829 passing depending on run (only
pre-existing CPU-load-sensitive timing/throughput benchmarks flake,
all confirmed passing in isolation and confirmed untouched by this
diff — bot-auth.ts constant-time variance, lifecycle.ts fight
throughput, shutdown.ts timeout, fights.mock dev-check). tsc --noEmit
clean (server + frontend).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-31 13:00:08 -04:00
DorianandClaude Fable 5 6464231f5d feat(payments): wire Cashu as the primary entry-fee UX, fix anonymous-bot ranked auth
CI / check (push) Has been cancelled
Two pieces, both user-directed, completing what 7341ca0 only configured:

1. WalletConnect.vue: Cashu token paste is now the PRIMARY entry-fee path
   (submitCashuToken() already existed in useWallet.ts but was never called
   from any UI — added the missing wiring). Lightning/NWC is now secondary,
   behind an explicit "or connect a Lightning wallet instead" toggle.
   Emits `cashu-paid` with the redeemed paymentId; JoinBoutPage.vue's
   fightRanked() uses it directly instead of calling payEntryFee()
   (Lightning-only) when present — no duplicate invoice/charge.

2. queue.ts's POST /join-ranked/:botId required a nostr pubkey for
   ownership verification, full stop. Confirmed live during testing:
   anonymous poll-mode bots (the primary registration path for AI agents
   per BOTFIGHTS.md) have publicKey: null — staked fights were completely
   unusable for that entire audience, silently. Now accepts EITHER a
   pubkey OR Authorization: Bot <id>:<secret> (same bot-auth every other
   anonymous-bot endpoint already uses) as proof of ownership.

Verified: full server typecheck clean; payments.test.ts (23) and
queue.test.ts (8) unchanged and passing; full frontend suite (101 tests,
13 files) passing, including useWallet.test.ts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-31 10:10:55 -04:00
DorianandClaude Opus 4.6 9b0d251d1c fix: sanitize error responses to prevent internal detail leakage
Add sanitizeError() helper that strips file paths, stack traces, SQLite
errors, and system errors from messages before returning them to clients.
Applied to all route-level catch blocks in payments, queue, fights, and
admin routes. Includes 12 tests for the sanitizer and static analysis
test verifying no route files leak raw err.message.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 09:46:38 +00:00
DorianandClaude Opus 4.6 2051a95e13 refactor: add centralized Zod validators for all API inputs
Create server/src/lib/validators.ts with reusable schemas for all API
inputs (auth, fights, bets, payments, tournaments, queue, docs).
Import and use in all route handlers, replacing inline validation.
Add formatZodError helper for user-friendly error messages.
77 test cases in validators.test.ts cover valid, invalid, boundary,
and attack inputs (SQL injection, XSS, prototype pollution).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 09:16:04 +00:00
DorianandClaude Opus 4.6 e31d49898b feat: show rejoin link when bot is already in a fight
- Track active fight IDs per bot in orchestrator (Set → Map)
- Return fightId in "already in fight" error responses (409)
- Frontend shows "REJOIN FIGHT" link instead of generic error

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 09:27:48 +00:00
DorianandClaude Opus 4.6 6d390f69b2 feat: THE CREATOR god-tier character, bitcoin choreographies, omni-morph, cameos
- Guy Fawkes mask archetype with golden outline, bitcoin chest symbol, laptop, tier-gated effects
- 12 custom bitcoin-themed choreographies (8 regular + 4 exclusive ultimates)
- Omni-morph system: creator morphs into any of 80+ archetypes instead of cycling 3
- 6% per-round cameo in non-creator fights — drops golden ₿ gifts to fighters
- Custom golden code rain entrance with persistent orbiting particles
- pickChoreography: 50% ultimate chance (100% on crits), all tier ultimates + 4 exclusive
- Server auto-assigns the_creator archetype on login/register for creator pubkey
- FightViewer, payments, queue, orchestrator improvements

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 12:08:18 +00:00
DorianandClaude Opus 4.6 460564a8ee feat: payment routes + ranked queue endpoint + app wiring
Add /api/payments router (connect-wallet, wallet-status, create-invoice,
check, submit-cashu, winnings, claim, disconnect-wallet). Add ranked
queue endpoints to /api/queue. Mount payments router in app.ts with
orphan payment recovery on startup.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 01:26:11 +00:00
DorianandClaude Opus 4.6 47d20fbe66 feat: v2 — queue matchmaking, procedural audio, sprite archetypes, auth
- Add queue-based matchmaking with Elo-proximity and 10s timeout
- Procedural sound engine (SFX, voice announcer, 4-track music)
- Sprite system refactored into 6 archetypes (standard, lobster, sheep, cyborg, blob, tank)
- 42+ fight choreographies with themed/generic/wild card selection
- 4 KO finish styles, super-speed mode, hyperdetail close-ups
- Auth routes, JoinBout page, bot profile with stats
- 7-tier ranking system (Baby through Legend)
- Arena and challenge system expansions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 22:13:19 +00:00