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>
This commit is contained in:
@@ -79,6 +79,9 @@ class ChainService:
|
||||
self._proc = None
|
||||
self._settings = load_settings()
|
||||
self._current_chain: list[str] = []
|
||||
# Sticky-exit: while time.monotonic() < self._sticky_until, leak-based
|
||||
# auto-rotation is skipped so signup flows keep the same egress IP.
|
||||
self._sticky_until: float = 0.0
|
||||
|
||||
# Shuffle-and-drain pool state — never repeat a proxy within a cycle
|
||||
self._available: list[str] = [] # proxies not yet used this cycle
|
||||
@@ -142,6 +145,21 @@ class ChainService:
|
||||
def rotate_now(self) -> None:
|
||||
self._force_rotate.set()
|
||||
|
||||
def set_sticky(self, seconds: float) -> None:
|
||||
"""Hold current exit for ``seconds`` (suppresses leak-driven rotation).
|
||||
|
||||
Manual rotation still works. Pass 0 to clear sticky mode immediately.
|
||||
"""
|
||||
if seconds <= 0:
|
||||
self._sticky_until = 0.0
|
||||
return
|
||||
self._sticky_until = time.monotonic() + float(seconds)
|
||||
|
||||
def sticky_remaining(self) -> float:
|
||||
"""Seconds remaining on sticky-exit hold (0.0 if not sticky)."""
|
||||
rem = self._sticky_until - time.monotonic()
|
||||
return rem if rem > 0 else 0.0
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────
|
||||
|
||||
def _teardown_network(self) -> None:
|
||||
@@ -588,6 +606,17 @@ class ChainService:
|
||||
|
||||
if is_chain_leak(exit_ip, real_ip, self._vpn.active):
|
||||
reason = leak_reason(exit_ip, real_ip, self._vpn.active)
|
||||
rem = self.sticky_remaining()
|
||||
if rem > 0:
|
||||
self._notify({
|
||||
"type": "log",
|
||||
"text": (
|
||||
f"Health check flagged ({reason}) — STICKY EXIT active "
|
||||
f"({int(rem)}s left), skipping rotation."
|
||||
),
|
||||
})
|
||||
self._notify({"type": "hops", "hops": chain, "status": "healthy", "exit_ip": exit_ip})
|
||||
continue
|
||||
self._notify({"type": "hops", "hops": chain, "status": "dead", "exit_ip": exit_ip})
|
||||
self._notify({"type": "log", "text": f"Health check failed ({reason}) — rotating."})
|
||||
break
|
||||
|
||||
Reference in New Issue
Block a user