mirror of
https://github.com/wechat-article/wxdown-service.git
synced 2026-08-29 09:01:03 +08:00
3bf0b1aaa2
- main: Ctrl+C 时直接 SIGKILL 所有 daemon 子进程,跳过 mitmproxy graceful shutdown
与 mitmdump 重启循环里的 time.sleep(3),实现秒退
- main: 启动失败时透传子进程真实错误行(端口/CA 缺失/文件权限等),告别"请切换端口后重试"
一刀切提示;Windows 下等用户按回车再退出,防止 PowerShell/双击启动窗口闪退
- mitm: start() 返回 (proxy_address, error_line);mitmdump 重启循环处理 KeyboardInterrupt
- watcher: start() 返回 (ws_address, queue, error_line);将 wss 证书生成失败纳入快速失败识别
- utils: check_system_proxy 修复 KeyError — Windows 下 getproxies() 可能返回仅含 'no' 等
非 http/https key 的字典,旧写法 proxy_obj.keys() < {'http', 'https'} 是真子集判断,
会漏掉这些场景继续访问 proxy_obj['http'] 引发崩溃
- ui/startup: 证书安装命令里 %userprofile% 在 PowerShell 下不会展开导致
certutil 报 ERROR_PATH_NOT_FOUND;改为 Python 侧展开为绝对路径,cmd/PowerShell/bash/zsh
均可直接粘贴执行,同时用双引号包住路径兼容带空格的用户名
77 lines
2.5 KiB
Python
77 lines
2.5 KiB
Python
import multiprocessing
|
|
import os
|
|
import queue
|
|
import re
|
|
import sys
|
|
import threading
|
|
import time
|
|
from pathlib import Path
|
|
|
|
from mitmproxy.tools.main import mitmdump
|
|
|
|
import utils
|
|
from logger import logger
|
|
|
|
SRC_PATH = Path.absolute(Path(__file__)).parent
|
|
PLUGIN_FILE = str(SRC_PATH / 'resources' / 'credential.py')
|
|
CREDENTIALS_FILE = str(SRC_PATH / 'resources' / 'data' / 'credentials.json')
|
|
|
|
|
|
def mitmproxy_process(args: list[str], output_queue: multiprocessing.Queue):
|
|
sys.stdout = sys.stderr = utils.Capture(output_queue)
|
|
# 清除继承自父进程/用户 shell 的代理环境变量,防止 mitmproxy 把自己当作上游代理导致死循环
|
|
for k in ('HTTP_PROXY', 'HTTPS_PROXY', 'ALL_PROXY', 'http_proxy', 'https_proxy', 'all_proxy'):
|
|
os.environ.pop(k, None)
|
|
while True:
|
|
print(f'Run mitmdump process {args} ({os.getpid()})...', flush=True)
|
|
try:
|
|
mitmdump(args)
|
|
except KeyboardInterrupt:
|
|
# mitmdump 通常会吞掉 SIGINT 然后正常 return;这里是为了处理它透传上来的极少数情况
|
|
break
|
|
logger.info(f'mitmdump process terminated')
|
|
time.sleep(3)
|
|
logger.info(f'重启 mitm 进程')
|
|
|
|
|
|
def start(port: str, debug = False):
|
|
# 启动 mitmproxy 并加载 credentials 插件
|
|
args = ['-p', port, '-s', PLUGIN_FILE, '--set', 'credentials='+CREDENTIALS_FILE]
|
|
mitm_output_queue = multiprocessing.Queue()
|
|
mitm_process = multiprocessing.Process(target=mitmproxy_process, args=(args, mitm_output_queue), daemon=True)
|
|
mitm_process.start()
|
|
|
|
start_time = time.time()
|
|
proxy_address = None
|
|
error_line = None
|
|
|
|
while time.time() - start_time < 10:
|
|
try:
|
|
line = mitm_output_queue.get(timeout=0.1)
|
|
logger.info(line)
|
|
if "HTTP(S) proxy listening at" in line:
|
|
match = re.search(r'\*:(\d+)', line)
|
|
port = match.group(1)
|
|
proxy_address = f"http://127.0.0.1:{port}"
|
|
break
|
|
elif "address already in use" in line.lower():
|
|
error_line = line
|
|
break
|
|
except queue.Empty:
|
|
pass
|
|
|
|
threading.Thread(target=log_mitmproxy_output, args=(mitm_output_queue, debug), daemon=True).start()
|
|
|
|
return proxy_address, error_line
|
|
|
|
|
|
def log_mitmproxy_output(mitm_output_queue: multiprocessing.Queue, debug):
|
|
while True:
|
|
line = mitm_output_queue.get()
|
|
|
|
if debug:
|
|
logger.debug(line)
|
|
else:
|
|
# 忽略 mitmproxy 的日志
|
|
pass
|