Skip to content

refactor(net): IP limiter の鍵の作り方を戦略ごとの wrapper に包み body reader の差を固定 (R6b・掟 15) - #623

Merged
cipherwebllc merged 1 commit into
mainfrom
fix/r6-r6b-limiter-wrappers
Sep 24, 2026
Merged

cipherwebllc merged 1 commit into
mainfrom
fix/r6-r6b-limiter-wrappers

Conversation

@cipherwebllc

Copy link
Copy Markdown
Owner

概要

第 6 回レビュー Phase 6 (完全リファクタ) の R6b です (指摘 C15)。挙動を変えない整理だけです。

limiter の wrapper

lib/net/clientRateLimit.ts (server-only) に、既存の 2 つの鍵の作り方をそのまま包む関数を置きました。

  • checkClientIpBucketRateLimit: 従来の checkIpRateLimit(scope, hashIpBucket(clientIp(req)), …) と同じ呼び出し
  • checkClientIpPrefixRateLimit: 従来の checkReadRateLimit(keyFor(anonymizeIp(clientIp(req) ?? '')), …) と同じ呼び出し

差し替えた route は 11 か所です: SIWE の nonce/verify、license の products/verify、shops の無料と有料検索、directory、tip-messages、handle GET、push の subscribe/test。鍵・窓・上限・429 の応答・認証や検証との順序は変えていません。鍵の統一 (counter がリセットされる) は B-R6 で、limiter を囲む try/catch も残しています (B-R6e)。

⚠️ 掟 15: 有料 shops 検索 (guardPaidShopsApi) は、x402 の 402 の前に走る admission limiter で money の入口です。変更は limiter の式の差し替えだけで、支払いの処理には触れていませんが、merge 前に user の明示レビューをお願いします。

body reader

4 つの手書きの JSON body reader と readJsonBodyCapped を比べ、どれも挙動が違うため置き換えていません。差は characterization test で固定しました (BOM 付きで上限 +3 byte を通す・不正な UTF-8 を U+FFFD で受ける・上限ちょうどの不正 byte で 413・上限超過後も全体を読む・content-type の要求)。統一は B-R6f で route ごとに判断します。

公開文言・応答は変わりません。

固定と検証 (base = main に rebase 済み)

  • limiter の pin 127 件: 本物の relayGuards・ipHash・relayRoute を使い、KV の呼び出しだけを stub して、route ごとに KV の鍵・窓・429 の応答・未知の IP・secret の欠落・信頼しない proxy header・KV 障害・時計に揃う bucket を固定。body reader の characterization 92 件。どちらも旧コードで通ります。
  • 別セッションの Opus 5.5 のレビュー: approve。わざと壊した変更 6 通り (scope の変更・戦略の入れ替え・窓の変更・小文字化の削除 等) をすべて検出しました。
  • typecheck 0 / eslint 0 / full vitest 14,755 pass

見つかった既存の問題 (本 PR では変えない・B-R6f・掟 12/15)

relay/jpyc と csv-pass/relay は、本文が JSON の null だと typeof raw.chainId が try の外にあるため 500 と Sentry event になります (400 invalid_payload が妥当)。状態の変化や資金の危険はなく、relay は IP の admission limiter、CSV パスは SIWE session で守られています。register/claim と relay/status と同じ null 検査を足す追加のみの修正を、別 PR で提案します。

🤖 Generated with Claude Code

https://claude.ai/code/session_01HeizmagJBgL5peL5mQpxkc

@vercel

vercel Bot commented Sep 24, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
openpay Ignored Ignored Preview Sep 24, 2026 4:36pm UTC

Request Review

…(R6b・掟 15)

第 6 回レビュー Phase 6 の R6b (C15)。lib/net/clientRateLimit.ts に既存の 2 戦略
(hashIpBucket + checkIpRateLimit / anonymizeIp + checkReadRateLimit) をそのまま包む
関数を置き、非 money の 10 route (+ 有料 shops 検索の admission limiter) の呼び出しを
差し替える。鍵・窓・上限・429 応答・評価順は不変 (route ごとに実 relayGuards/ipHash で固定)。
body reader は 4 つとも readJsonBodyCapped と挙動が違う (BOM・不正 UTF-8・cap 境界・
cancel) ため置換せず、差を characterization test で固定した (統一は B-R6f)。

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HeizmagJBgL5peL5mQpxkc
@cipherwebllc
cipherwebllc force-pushed the fix/r6-r6b-limiter-wrappers branch from 16760bf to 67da1b3 Compare September 24, 2026 16:35
@cipherwebllc
cipherwebllc merged commit 0baa39e into main Sep 24, 2026
8 checks passed
@cipherwebllc
cipherwebllc deleted the fix/r6-r6b-limiter-wrappers branch September 24, 2026 17:06
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.

1 participant