Skip to content

Traffic filter: per-country, market and abuser-score exceptions - #3602

Merged
forgetso merged 4 commits into
mainfrom
feat/traffic-filter-exceptions
Oct 24, 2026
Merged

forgetso merged 4 commits into
mainfrom
feat/traffic-filter-exceptions

Conversation

@forgetso

@forgetso forgetso commented Oct 23, 2026 •

Copy link
Copy Markdown
Member

What changed

Each traffic filter category (proxy, VPN, abuser, and so on) can now have a list of exceptions. An exception matches on any mix of:

  • countries: two-letter country codes for the visitor's IP (the UK is GB)
  • inMarket: true matches visitors whose country is in the account's market, false matches visitors outside it
  • minAbuserScore: the IP's abuser score (0–1, inclusive)

When an exception matches, its action (block or challenge, plus any captcha settings) is used instead of the category's own action. When several match, the harshest wins: a block beats any challenge, and a stricter captcha beats a milder one. The order of the list doesn't matter. The ranking is the one access rules already use. It has moved out of blacklistRequestInspector.ts into @prosopo/captcha-severity as policyHarshness and harshestPolicy, and the access rules now call it from there, with the same ordering as before.

The account's market countries now reach providers as trafficFilter.marketCountries inside each site's settings. The private portal adds them when it pushes a site. This PR also adds them on the provider's own pull from the portal database (getUpdatedClients). The new shared helper withMarketCountries always replaces whatever market a site has saved with the account's, so a stale copy can't stick.

What it does

  • Block out-of-market proxies; challenge in-market ones with a hard puzzle unless their abuser score is 0.5 or more: proxy: { action: block, exceptions: [{ inMarket: true, action: challenge, captchaType: puzzle, … }, { inMarket: true, minAbuserScore: 0.5, action: block }] }. A GB proxy at 0.7 matches both, and the block wins.

  • Challenge proxies from our market, block the rest: proxy: { action: block, exceptions: [{ inMarket: true, action: challenge }] }

  • Block UK abusers scoring 0.5 or more, challenge the rest: abuser: { action: challenge, exceptions: [{ countries: ["GB"], minAbuserScore: 0.5, action: block }] }

An inMarket exception never matches while the account has no market set, or when the visitor has no known country. If no exceptions are set, nothing changes. Mongo stores the new fields too; without that they would be dropped on save.

Tests

  • checkTrafficFilter unit tests:
    • country, market (inside and outside), abuser score, and combinations of them
    • no market set; IPs with no country
    • harshest match wins whatever the list order; a stricter captcha beats a milder one; ties keep the earlier exception
    • DNS resolver IPs judged by their own country
  • getUpdatedClients integration test: against an in-memory Mongo, the account's market ends up in the site's traffic filter.
  • @prosopo/captcha-severity tests for policyHarshness and harshestPolicy. The access-rule ranking tests pass unchanged.
  • zod and Mongo schema tests, plus withMarketCountries tests (sets the market, replaces a stale one, leaves sites without a traffic filter alone).
  • Checked with real data: settings saved through the portal end-to-end run were put through this provider's request schema, Mongo schema and checkTrafficFilter. GB and IE proxies were challenged; FR proxies and proxies with no country were blocked. A GB abuser at 0.6 was blocked; GB at 0.3 and FR at 0.9 were challenged.

Pairs with prosopo/captcha-private#5496.

🤖 Generated with Claude Code

… categories

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@forgetso forgetso changed the title Traffic filter: per-country and abuser-score exceptions Traffic filter: per-country, market and abuser-score exceptions Oct 24, 2026
forgetso and others added 2 commits October 24, 2026 09:37
Ranks matches with the access rules' harshness, now shared from
@prosopo/captcha-severity, so the order of the exceptions list no longer
changes the outcome.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@forgetso
forgetso merged commit 915f30b into main Oct 24, 2026
18 of 20 checks passed
@forgetso
forgetso deleted the feat/traffic-filter-exceptions branch October 24, 2026 20:16
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