Files
proxy-god/proxy_chain_manager/ban_tester.py
Indiana Holmes 26863fc2a5 Add ban tester, signup prep, exit IP intel, and sticky-exit hold.
New GUI tabs probe popular sites for exit-IP bans and prep signup autofill through the chain; Live tab shows geo/ASN/datacenter flags, and sticky-exit keeps the same egress IP during signup flows.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-19 15:37:28 -07:00

93 lines
2.9 KiB
Python

from __future__ import annotations
from dataclasses import dataclass
from typing import Iterable
import httpx
# High-traffic destinations that often reveal proxy bans quickly.
POPULAR_SITES: tuple[tuple[str, str], ...] = (
("Google", "https://www.google.com/generate_204"),
("YouTube", "https://www.youtube.com/"),
("Facebook", "https://www.facebook.com/"),
("Instagram", "https://www.instagram.com/"),
("X", "https://x.com/"),
("Reddit", "https://www.reddit.com/"),
("Wikipedia", "https://www.wikipedia.org/"),
("Amazon", "https://www.amazon.com/"),
("Netflix", "https://www.netflix.com/"),
("GitHub", "https://github.com/"),
("Cloudflare", "https://www.cloudflare.com/"),
("Microsoft", "https://www.microsoft.com/"),
("TikTok", "https://www.tiktok.com/"),
("BBC", "https://www.bbc.com/"),
("DuckDuckGo", "https://duckduckgo.com/"),
)
_BANNED_STATUS_CODES = {401, 403, 407, 418, 429, 451}
_BANNED_TEXT_HINTS = (
"access denied",
"forbidden",
"temporarily blocked",
"request blocked",
"unusual traffic",
"captcha",
"challenge required",
)
@dataclass(frozen=True)
class BanTestResult:
site: str
url: str
status: str # ok | banned | error
code: int | None
detail: str
def _looks_banned_body(body: str) -> bool:
t = (body or "").lower()
return any(h in t for h in _BANNED_TEXT_HINTS)
def _test_one(proxy_url: str, site: str, url: str, timeout_seconds: float) -> BanTestResult:
timeout = httpx.Timeout(timeout_seconds, connect=min(8.0, timeout_seconds))
try:
with httpx.Client(
proxy=proxy_url,
timeout=timeout,
verify=False,
follow_redirects=True,
headers={"User-Agent": "Mozilla/5.0"},
) as c:
r = c.get(url)
body = r.text[:1800] if r.text else ""
if r.status_code in _BANNED_STATUS_CODES or _looks_banned_body(body):
return BanTestResult(site, url, "banned", r.status_code, f"HTTP {r.status_code}")
if 200 <= r.status_code < 400:
return BanTestResult(site, url, "ok", r.status_code, f"HTTP {r.status_code}")
return BanTestResult(site, url, "error", r.status_code, f"HTTP {r.status_code}")
except Exception as e:
return BanTestResult(site, url, "error", None, f"{type(e).__name__}: {e}")
def run_ban_tests(
proxy_url: str,
timeout_seconds: float = 12.0,
sites: Iterable[tuple[str, str]] = POPULAR_SITES,
) -> list[BanTestResult]:
out: list[BanTestResult] = []
for site, url in sites:
out.append(_test_one(proxy_url, site, url, timeout_seconds))
return out
def test_single_site(
proxy_url: str,
site: str,
url: str,
timeout_seconds: float = 10.0,
) -> BanTestResult:
"""Probe one URL through the proxy. Used by pre-flight checks."""
return _test_one(proxy_url, site, url, timeout_seconds)