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:
@@ -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())),
|
||||
|
||||
Reference in New Issue
Block a user