Proxy auth UI, verbose Live logs, build script, docs

- Fixed exit and manual chain: optional user/pass fields with URL merge and redaction in UI/logs
- config: split_proxy_for_edit, merge_proxy_credentials, redact_proxy_url, IPv6-style host bracketing
- Live tab: UILogHandler to stream proxy_chain_manager logs; Verbose toggle; Clear log; httpx quiet
- service/validator/fetcher: structured INFO/DEBUG for pool, GOST, validation, fetches
- setup_and_build.ps1: pip upgrade, deps, PyInstaller, desktop copy + shortcut; build_exe.bat delegates
- README: clone/pull to one-script desktop build flow

Made-with: Cursor
This commit is contained in:
Dr Jones
2026-04-16 00:27:39 -07:00
parent 0316b1befc
commit 214d2d2ff7
9 changed files with 495 additions and 89 deletions

View File

@@ -4,7 +4,14 @@ from __future__ import annotations
import asyncio
import unittest
from proxy_chain_manager.config import Settings, normalize_proxy_url, sanitize_settings
from proxy_chain_manager.config import (
Settings,
merge_proxy_credentials,
normalize_proxy_url,
redact_proxy_url,
sanitize_settings,
split_proxy_for_edit,
)
from proxy_chain_manager.fetcher import fetch_proxy_json, normalize_entries
from proxy_chain_manager.validator import (
check_chain_exit_ip,
@@ -19,6 +26,26 @@ class TestConfig(unittest.TestCase):
self.assertEqual(normalize_proxy_url("1.2.3.4:8080"), "http://1.2.3.4:8080")
self.assertEqual(normalize_proxy_url("socks5://x:1"), "socks5://x:1")
def test_merge_split_proxy_auth(self) -> None:
merged = merge_proxy_credentials("http://1.2.3.4:8080", "user", "p:ass")
self.assertIn("user", merged)
self.assertIn("p%3Aass", merged)
base, u, pw = split_proxy_for_edit(merged)
self.assertEqual(base, "http://1.2.3.4:8080")
self.assertEqual(u, "user")
self.assertEqual(pw, "p:ass")
def test_merge_preserves_embedded_auth_when_fields_empty(self) -> None:
raw = normalize_proxy_url("http://x:y@9.9.9.9:12")
self.assertEqual(merge_proxy_credentials(raw, "", ""), raw)
def test_redact_proxy_url(self) -> None:
r = redact_proxy_url("http://alice:secret@proxy.example:8888")
self.assertIn("***:***@", r)
self.assertIn("proxy.example", r)
self.assertNotIn("secret", r)
self.assertNotIn("alice", r)
def test_sanitize_clamps_extremes(self) -> None:
s = Settings(
chain_length=0,