Skip to content

Add LangSec recognizer for /announce#2

Merged
iksnerd merged 1 commit into
mainfrom
langsec-announce-recognizer
May 2, 2026
Merged

Add LangSec recognizer for /announce#2
iksnerd merged 1 commit into
mainfrom
langsec-announce-recognizer

Conversation

@iksnerd
Copy link
Copy Markdown
Owner

@iksnerd iksnerd commented May 2, 2026

Summary

Splits HandleAnnounce into a pure recognizer + executor, applying the LangSec principle from Sassaman & Patterson's The Science of Insecurity: recognize the input grammar completely before any business logic runs. Eliminates the shotgun-parser pattern of inline q.Get + strconv + silent fallbacks.

  • New internal/tracker/recognize.goRecognizeAnnounce(url.Values) (AnnounceParams, error) returns a typed struct with bounded info_hash/peer_id, port 1–65535, non-negative stats, PeerEvent enum, NumWant capped at 1000, and BEP 23 Compact default. Pure function — no DB, no globals, no logging.
  • Refactored HandleAnnounce — now does only prune → auth → recognize → execute. executeAnnounce reads exclusively from AnnounceParams; no q.Get or strconv past recognition. Passkey auth extracted to authenticatePasskey (it's path-based, orthogonal to query grammar).
  • New internal/tracker/recognize_test.go — 30+ table-driven subtests covering every rejection and accept path.
  • Migrated internal/tracker/announce_test.gopid20() helper pads test fixtures to BEP 3 20-byte peer IDs; new tests for short peer_id, bad port, bad event, and negative stats rejections.

Rejections use the existing BEP 3 bencoded failure_reason wire format with typed reasons (e.g. Invalid announce: peer_id must be exactly 20 bytes, got 8) — strictness is in the reason, not the HTTP code.

This is Priority 1 of 3 from the LangSec analysis. P2 (bounded bencode validator for .torrent parsing) and P3 (peer wire-protocol state machine) remain open as separate PRs.

Test plan

  • go test ./... — all packages green
  • go vet ./... — clean
  • E2E smoke against running tracker — every malformed input returns a specific typed reason in the bencoded failure reason field; valid announces return peers normally
  • Reviewer: confirm BEP 3 wire-format compliance preserved (HTTP 200 + bencoded failure)
  • Reviewer: confirm strict 20-byte peer_id enforcement is acceptable for real-world clients

🤖 Generated with Claude Code

…validation

Splits HandleAnnounce into a pure recognizer + executor following the LangSec
principle (Sassaman & Patterson, "The Science of Insecurity"): recognize the
input grammar completely before any business logic runs.

- internal/tracker/recognize.go: RecognizeAnnounce(url.Values) returns a typed
  AnnounceParams with bounded info_hash/peer_id, port 1-65535, non-negative
  stats, PeerEvent enum, NumWant capped at 1000, and BEP 23 compact default.
  Pure function — no DB, no globals, no logging.
- internal/tracker/announce.go: HandleAnnounce now does only prune → auth →
  recognize → execute. executeAnnounce reads exclusively from AnnounceParams;
  no q.Get or strconv past recognition. Auth extracted to authenticatePasskey.
- internal/tracker/recognize_test.go: 30+ table-driven subtests covering every
  rejection and accept path.
- internal/tracker/announce_test.go: pid20() helper migrates fixtures to BEP 3
  20-byte peer IDs; new tests for short peer_id, bad port, bad event, and
  negative stats rejections.

Rejections use the existing BEP 3 bencoded failure_reason wire format with
typed reasons — strictness is in the reason, not the HTTP code.
@iksnerd iksnerd merged commit ae80df0 into main May 2, 2026
1 check passed
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