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>
93 lines
2.9 KiB
Python
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)
|