From 51811b67018515366bd56f3c3b21aed11d906db2 Mon Sep 17 00:00:00 2001 From: srdusr <99972264+srdusr@users.noreply.github.com> Date: Wed, 20 May 2026 09:29:00 +0200 Subject: Target scope: filter what gets recorded, not what gets proxied The proxy captured and stored literally everything with no way to exclude unrelated traffic - every CDN asset, analytics beacon, and third-party tracker request on a real engagement pollutes history and search right alongside the traffic that actually matters. internal/scope: Rule{Enabled, Pattern, IsRegex} and InScope(rules, host). A non-regex pattern matches by case-insensitive substring against the host - "example.com" matches "example.com", "www.example.com", and "api.example.com" alike, covering "this domain and its subdomains" without inventing a separate wildcard syntax. IsRegex mirrors the same toggle match-and-replace rules already use, for one consistent mental model across both rule types in this tool. An empty or all-disabled rule set means everything is in scope - the behavior before scope existed at all, unchanged, so a fresh install or a user who never opens the scope view keeps recording everything rather than silently nothing. Deliberately a recording filter, not access control: out-of-scope traffic still proxies completely normally, reaching its destination and the client exactly as before. internal/proxy's forward() already writes the response to the client before record() ever runs, so the scope check (new in record()) can only affect whether the exchange gets stored, never whether it happens. Blocking out-of-scope traffic outright would be a materially different, much riskier feature - a wrong scope pattern could silently break the very traffic someone's trying to test, which is a far worse failure mode than a noisier history. Repeat/Intrude (recordRaw, a separate function from record()) deliberately don't go through the scope check at all: a user explicitly resending or fuzzing a specific request wants to see the result regardless of scope, which exists to cut passive-capture noise, not second-guess a deliberate action. internal/store: new scope_rules table (CREATE TABLE IF NOT EXISTS, no migration needed - it's a new table, not a new column on an existing one) plus List/Add/SetEnabled/Delete, mirroring the existing match-and-replace rules CRUD exactly. internal/ipc: scope_list/ scope_add/scope_delete/scope_toggle request types and matching Client methods; scope_add validates a regex pattern compiles before persisting, same reasoning and same fix as the earlier rules_save validation (an invalid regex should be rejected up front, not silently never match at apply time with zero feedback). TUI: 's' from the history list opens scope management, mirroring the Rules view's own list+form pattern but simpler (add-only, no edit-in-place - a pattern and a regex toggle don't need a five-field form, delete-and-re-add covers changing one). Verified live in tmux against a running daemon: added a substring scope rule for one host, sent requests to both a matching and a non-matching host - the non-matching one proxied successfully (client got its 200) but was never recorded, the matching one was recorded normally; confirmed a Repeater resend of the excluded host WAS recorded despite being out of scope; toggled the rule off and confirmed recording resumed for everything; added and confirmed a regex-mode rule saves and displays correctly; deleted a rule and confirmed the list returns to empty ("no rules means everything is recorded"). go build/vet/gofmt/test/mod tidy all clean. --- PLAN.md | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) (limited to 'PLAN.md') diff --git a/PLAN.md b/PLAN.md index 4864012..a3ca810 100644 --- a/PLAN.md +++ b/PLAN.md @@ -272,12 +272,45 @@ Repeater request, say) is skipped rather than aborting the whole export - the status line reports how many, so a partial export is visible, not silent. +Shipped since: target scope. `s` from the history list opens scope +management - add/toggle/delete rules matching a host by substring +(case-insensitive, so "example.com" matches "www.example.com" and +"api.example.com" too, covering "this domain and its subdomains" +without a separate wildcard syntax) or by regex, mirroring the same +Match-text-or-regex toggle match-and-replace rules already use for one +consistent mental model. No rules configured (or none enabled) means +everything is recorded - today's behavior before scope existed at all, +unchanged, so a fresh install or a user who never opens the scope view +keeps recording everything rather than silently nothing. + +Scope only filters what gets recorded, not what gets proxied: an +out-of-scope request still reaches its destination and its response +still reaches the client completely normally (see `internal/proxy`'s +`forward()` - the response is already written to the client by the +time the scope check runs; skipping the record step only skips +storage). This was a deliberate choice over blocking out-of-scope +traffic outright, which would be a materially different, much riskier +feature - an access-control mechanism, not a noise filter, and a wrong +scope pattern could silently break the very traffic the user is trying +to test. Repeater and Intruder deliberately bypass the scope check +entirely (recordRaw, a separate code path from the passive-capture +record()): a user explicitly resending or fuzzing a specific request +wants to see the result regardless of scope, which exists to cut +passive-capture noise (CDNs, analytics, trackers, unrelated third-party +hosts), not to second-guess a deliberate action. Verified live: added a +substring scope rule for one host, confirmed a request to a +non-matching host still proxied successfully (200 response reached the +client) but was never recorded, confirmed the matching host's requests +were recorded, confirmed a Repeater resend of the excluded host WAS +recorded despite being out of scope, confirmed toggling the rule off +resumed recording everything, and confirmed both the substring and +regex pattern forms save and match correctly. + Still open from the expanded "worth considering" list: import (no path back in yet - HAR export was prioritized as the more common daily need, getting captured evidence OUT for a report or another tool, over -bringing traffic IN), copy-as-curl, and scope/target filtering (to keep -noise - trackers, CDNs, unrelated third-party hosts - out of history -and search). All requested explicitly; none started yet. +bringing traffic IN) and copy-as-curl. Both requested explicitly; not +started yet. Skipped deliberately (from the research, matches this tool's stated scope): active/passive vulnerability scanning, plugin marketplace, -- cgit v1.2.3