Harden Windows Server compatibility and system-wide proxy.

Fix exit-IP checks for HTTP-only proxies, apply proxy via WinINet Connections blob and WinHTTP, improve VPN detection on legacy Server, add SOCKS5 host:port:user:pass exit parsing, and add win_compat probe for PowerShell 2.0 hosts.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Indiana Holmes
2026-05-16 18:03:30 -07:00
parent 8bd8d4267f
commit 8f012402a6
10 changed files with 579 additions and 43 deletions

View File

@@ -24,6 +24,7 @@ from .config import (
load_settings,
merge_proxy_credentials,
normalize_proxy_url,
parse_exit_proxy_input,
redact_proxy_url,
save_settings,
split_proxy_for_edit,
@@ -490,7 +491,7 @@ def main() -> None:
exit_test_dot.pack(side="left", padx=(8, 4))
exit_proxy_entry = ctk.CTkEntry(
exit_fix_frame,
placeholder_text="http://host:port or socks5://host:port (optional)",
placeholder_text="host:port:user:pass (defaults to socks5 — paste any format)",
font=("Consolas", 10),
fg_color=BG,
border_color=ACCENT,
@@ -527,13 +528,49 @@ def main() -> None:
exit_btn_row = ctk.CTkFrame(exit_fix_frame, fg_color="transparent")
exit_btn_row.pack(fill="x", padx=10, pady=(0, 4))
def _auto_split_exit_paste(_event: Any | None = None) -> None:
"""If the URL field looks like ``host:port:user:pass``, distribute
the user/pass parts into their own fields so the user sees what got
parsed. Triggered on key release and explicit paste.
"""
raw = exit_proxy_entry.get()
if "://" in raw:
return
bits = [b for b in raw.strip().split(":") if b != ""]
if len(bits) < 4 and "@" not in raw and not any(c in raw for c in (" ", "\t")):
return
base, user, pw = parse_exit_proxy_input(raw, default_scheme="socks5")
if not base:
return
if base != raw:
exit_proxy_entry.delete(0, "end")
exit_proxy_entry.insert(0, base)
if user and not exit_user_entry.get().strip():
exit_user_entry.delete(0, "end")
exit_user_entry.insert(0, user)
if pw and not exit_pass_entry.get().strip():
exit_pass_entry.delete(0, "end")
exit_pass_entry.insert(0, pw)
exit_proxy_entry.bind("<KeyRelease>", _auto_split_exit_paste)
exit_proxy_entry.bind("<<Paste>>", lambda e: exit_proxy_entry.after(1, _auto_split_exit_paste))
exit_proxy_entry.bind("<FocusOut>", _auto_split_exit_paste)
def _exit_url() -> str:
raw = exit_proxy_entry.get().strip()
if not raw:
"""Build the final exit-proxy URL.
Accepts every paste format ``parse_exit_proxy_input`` understands
(host:port:user:pass, user:pass@host:port, scheme://…). Defaults to
SOCKS5 when no scheme is supplied.
"""
base, parsed_user, parsed_pw = parse_exit_proxy_input(
exit_proxy_entry.get(), default_scheme="socks5"
)
if not base:
return ""
if "://" not in raw:
raw = "http://" + raw
return merge_proxy_credentials(raw, exit_user_entry.get(), exit_pass_entry.get())
user = (exit_user_entry.get() or "").strip() or parsed_user
pw = (exit_pass_entry.get() or "").strip() or parsed_pw
return merge_proxy_credentials(base, user, pw)
def _test_exit() -> None:
url = _exit_url()
@@ -567,8 +604,11 @@ def main() -> None:
ctk.CTkLabel(
exit_fix_frame,
text="Appended after your chain hops when running. Leave empty to use last chain hop as exit.\n"
"Auth: User/Pass fields or user:pass@host in the URL.",
text=(
"Appended after your chain hops. Leave empty to use last chain hop as exit.\n"
"Paste any of: host:port:user:pass • user:pass@host:port • scheme://host:port\n"
"No scheme = SOCKS5. Paste auto-splits into User/Pass below."
),
font=(FONT, 9),
text_color=TEXT2,
justify="left",
@@ -1247,11 +1287,7 @@ def main() -> None:
obfuscation_mode=mode_var.get(),
use_pinned_chain=bool(use_manual_var.get()),
pinned_chain=list(manual_chain),
manual_exit_proxy=merge_proxy_credentials(
exit_proxy_entry.get(),
exit_user_entry.get(),
exit_pass_entry.get(),
),
manual_exit_proxy=_exit_url(),
health_check_seconds=min(3600, max(10, int(entries["health"].get().strip()))),
full_refresh_seconds=min(86400, max(60, int(entries["refresh"].get().strip()))),
validation_concurrency=max(1, int(entries["conc"].get().strip())),