Files
npub1qyvc0c5kl4gqv2fd97fsk46tu378sqgy35vc83rvgfwne90sel7s0ed67dandTyler Longwell ed33878b7d feat(relay): wire shared NIP-98 replay guard + per-IP connection fence
Land the auth fences from buzz-auth/buzz-pubsub into the relay's request
paths, replacing the per-pod moka NIP-98 cache that does not carry the
freshness proof under any-pod-any-connection (bus-scoping B).

- AppState: add Arc<RedisNip98ReplayGuard> + Arc<RedisRateLimiter>,
  constructed from the existing redis_pool. Drop the dead nip98_seen moka
  cache (its only caller was the bridge replay check).
- bridge.rs: check_nip98_replay is now async + tenant-scoped, calling the
  shared seen-set's try_mark under the resolved community (the seen-set is
  community-scoped per S1). Resolve the tenant BEFORE the replay check in
  all three NIP-98 handlers; DRY the duplicated host-resolve into
  resolve_request_tenant. /count now resolves a tenant (required for the
  per-community replay check). Replay and invalid responses are
  wire-indistinguishable (Quinn P2) and fail closed on Redis error.
- router.rs: per-IP connection fence (check_ip_connection) runs in the WS
  upgrade path BEFORE host resolution, so an unmappable Host cannot bypass
  the cap. Operator-global, tenant-free; fail-closed -> 429.
- config.rs: BUZZ_MAX_CONNECTIONS_PER_IP (default 60) +
  BUZZ_IP_CONNECTION_WINDOW_SECS (default 60).

cargo test -p buzz-relay: 378 passed / 0 failed. clippy clean (one
pre-existing unrelated warning in side_effects.rs).

Co-authored-by: Tyler Longwell <tlongwell@block.xyz>
Signed-off-by: Tyler Longwell <tlongwell@block.xyz>
2026-06-26 13:29:28 -04:00
..