Commit Graph

5 Commits

Author SHA1 Message Date
Kazuki Yamada b9388665d2 fix(website): Key isBot() cache on UA string for shared-process safety
Previous memoization stored a single boolean at module scope. In any
Node context where the same module instance might be reused across
requests (VitePress SSG, dev server, preview server with `navigator`
polyfilled per request), the first request's UA would silently leak
into subsequent calls.

In production this code is browser-only — Cloud Run's Hono server
doesn't import `botDetect.ts`, and Cloudflare Pages serves the bundle
as static files with one fresh module instance per browser tab — so
the bug was theoretical. But the UA-keyed memo costs nothing extra
and removes the foot-gun: a long-lived process now invalidates the
cache automatically when a different UA shows up.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 20:12:15 +09:00
Kazuki Yamada e4a635c2f2 fix(website): Address PR review feedback on isBot pre-mint guard
Four items from gemini and claude reviews:

- botDetect.ts: Memoize isBot() result. navigator.userAgent is immutable
  for the page lifetime, so re-running the isbot regex on every Turnstile
  pre-mint debounce and post-submit re-mint check is wasted work. SSR
  fallback is intentionally not cached so a module instance reused across
  SSR/CSR still reaches the real UA check on first CSR call.
- usePackRequest.ts: Disambiguate the "submit-path NOT gated" comment —
  it was confusing because the new post-submit re-mint also lives inside
  submitRequest's finally. Reworded to "click-path acquireTurnstileToken"
  to make clear which call site is intentionally skipped.
- usePackRequest.ts: Update the userTouched comment to reflect autofill
  reality — modern Chromium/Firefox DO fire input events on autofill, so
  the rationale ("autofill doesn't trigger") was already stale. The new
  isBot() guard covers the gap for well-behaved crawler UAs.
- usePackRequest.ts: Add English glosses for the Japanese CF dashboard
  labels (提示チャレンジ / 未解決) so non-Japanese-reading maintainers can
  follow the comment.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 20:07:08 +09:00
Kazuki Yamada c82accf641 refactor(website): Use isbot package on client side for consistency
Replace hand-rolled bot regex with the isbot package (~6.5 KB ESM,
zero deps) to match server-side detection. Eliminates divergence
between client and server bot detection logic.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 22:44:19 +09:00
Kazuki Yamada cc8c0b3932 fix(server): Address PR review feedback
- Move throttle state inside factory function (gemini)
- Rename inner function to botGuardHandler to avoid shadowing (gemini)
- Add requestId fallback to 'unknown' for undefined case (coderabbit)
- Remove bare 'bot'/'spider'/'crawler' from client regex to prevent
  false positives on legitimate devices like Cubot phones (devin)
- Update server package-lock.json with isbot dependency (devin)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 22:44:19 +09:00
Kazuki Yamada 4741bf36fa fix(server): Block bot/crawler requests to prevent OOM crashes
Applebot and other JS-capable crawlers were visiting permalink URLs
(repomix.com/?repo=xxx), executing the frontend JS which auto-triggers
POST /api/pack on mount. This caused massive parallel git clone
operations that exceeded the 1024 MiB memory limit on Cloud Run,
resulting in OOM crash loops.

- Add server-side botGuardMiddleware using `isbot` package to reject
  bot requests to /api/* with 403 before they consume resources
- Add frontend bot detection to skip auto-pack execution in onMounted
  when the user agent is a known crawler
- Place bot guard before rate limiter to avoid counting bot requests

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 22:44:19 +09:00