from urllib.parse import unquote import json import urllib.request from .config import PROXY_PORT, DATA_DIR, CONFIG_FILE def parse_vless_url(url: str) -> dict: """Parse VLESS URL and extract connection parameters""" if not url.startswith("vless://"): raise ValueError("URL must start with vless://") # Remove scheme url_no_scheme = url[8:] # Split by fragment (#tag) if '#' in url_no_scheme: url_part, tag = url_no_scheme.split('#', 1) tag = unquote(tag) else: url_part = url_no_scheme tag = "reality" # Split by query (?) if '?' in url_part: uuid_host_port, query_string = url_part.split('?', 1) else: raise ValueError("Missing query parameters") # Parse UUID@host:port if '@' not in uuid_host_port: raise ValueError("Missing @ separator") uuid_str, host_port = uuid_host_port.split('@', 1) if ':' not in host_port: raise ValueError("Missing port") host, port_str = host_port.rsplit(':', 1) port = int(port_str) # Parse query parameters params = {} for param in query_string.split('&'): if '=' in param: key, value = param.split('=', 1) params[key] = unquote(value) # Extract required parameters pbk = params.get('pbk', '') sid = params.get('sid', '') sni = params.get('sni', host) fp = params.get('fp', 'chrome') flow = params.get('flow', '') if not pbk or not sid: raise ValueError("Missing required parameters: pbk or sid") return { 'uuid': uuid_str, 'server': host, 'server_port': port, 'tag': tag, 'public_key': pbk, 'short_id': sid, 'server_name': sni, 'fingerprint': fp, 'flow': flow } def generate_vless_config(vless_params: dict) -> dict: """Generate sing-box configuration from VLESS parameters""" config = { "dns": { "independent_cache": True }, "log": { "level": "debug", "disabled": True, "timestamp": True }, "route": { "final": vless_params['tag'], "auto_detect_interface": True }, "inbounds": [ { "tag": "mixed-in", "type": "mixed", "sniff": True, "users": [], "listen": "0.0.0.0", "listen_port": PROXY_PORT, "set_system_proxy": False } ], "outbounds": [ { "type": "vless", "tag": vless_params['tag'], "server": vless_params['server'], "server_port": vless_params['server_port'], "flow": vless_params['flow'], "tls": { "enabled": True, "server_name": vless_params['server_name'], "reality": { "enabled": True, "public_key": vless_params['public_key'], "short_id": vless_params['short_id'] }, "utls": { "enabled": True, "fingerprint": vless_params['fingerprint'] } }, "uuid": vless_params['uuid'] }, { "tag": "direct", "type": "direct" } ] } return config def generate_direct_config() -> bool: """Generate a direct connection config (bypass all proxies)""" try: config = { "dns": { "independent_cache": True }, "log": { "level": "debug", "disabled": True, "timestamp": True }, "route": { "final": "direct", "auto_detect_interface": True }, "inbounds": [ { "tag": "mixed-in", "type": "mixed", "sniff": True, "users": [], "listen": "0.0.0.0", "listen_port": PROXY_PORT, "set_system_proxy": False } ], "outbounds": [ { "tag": "direct", "type": "direct" } ] } DATA_DIR.mkdir(parents=True, exist_ok=True) CONFIG_FILE.write_text(json.dumps(config, indent=2, ensure_ascii=False)) # Reload sing-box try: urllib.request.urlopen("http://127.0.0.1:9090/reload", timeout=3) except Exception: pass return True except Exception as e: print(f"[WebUI] Failed to generate direct config: {e}") return False