161 lines
5.4 KiB
Python
161 lines
5.4 KiB
Python
import os
|
|
import yaml
|
|
import json
|
|
import logging
|
|
from pathlib import Path
|
|
from urllib.parse import urlparse, parse_qs
|
|
|
|
def init_config(conf_dir):
|
|
"""初始化配置文件"""
|
|
config_path = Path(conf_dir) / "config.yaml"
|
|
|
|
if not config_path.exists():
|
|
default_config = {
|
|
'proxy_url': '',
|
|
'config_version': '1.0',
|
|
'app_version': '1.0',
|
|
'domains': [
|
|
'google.com',
|
|
'youtube.com',
|
|
'facebook.com',
|
|
'twitter.com',
|
|
'instagram.com',
|
|
'netflix.com',
|
|
'github.com',
|
|
'gitlab.com',
|
|
'stackoverflow.com',
|
|
'reddit.com'
|
|
],
|
|
'v2ray_config_path': str(Path(conf_dir) / "v2ray.json"),
|
|
'v2ray_template_path': str(Path(conf_dir) / "v2ray_template.json"),
|
|
'v2ray_log_path': str(Path(__file__).parent.parent / "logs" / "v2ray.log")
|
|
}
|
|
|
|
with open(config_path, 'w') as f:
|
|
yaml.dump(default_config, f)
|
|
logging.info("Default config file created")
|
|
|
|
return load_config()
|
|
|
|
def load_config():
|
|
"""加载配置文件"""
|
|
config_path = Path(__file__).parent.parent / "conf" / "config.yaml"
|
|
|
|
try:
|
|
with open(config_path, 'r') as f:
|
|
return yaml.safe_load(f)
|
|
except Exception as e:
|
|
logging.error(f"Failed to load config: {str(e)}")
|
|
return {
|
|
'proxy_url': '',
|
|
'config_version': '1.0',
|
|
'app_version': '1.0',
|
|
'domains': [],
|
|
'v2ray_config_path': str(Path(__file__).parent.parent / "conf" / "v2ray.json"),
|
|
'v2ray_template_path': str(Path(__file__).parent.parent / "conf" / "v2ray_template.json"),
|
|
'v2ray_log_path': str(Path(__file__).parent.parent / "logs" / "v2ray.log")
|
|
}
|
|
|
|
def save_config(config):
|
|
"""保存配置文件"""
|
|
config_path = Path(__file__).parent.parent / "conf" / "config.yaml"
|
|
|
|
try:
|
|
with open(config_path, 'w') as f:
|
|
yaml.dump(config, f)
|
|
return True
|
|
except Exception as e:
|
|
logging.error(f"Failed to save config: {str(e)}")
|
|
return False
|
|
|
|
def parse_vless_url(url):
|
|
"""解析vless://URL"""
|
|
try:
|
|
# 移除URL编码
|
|
url = url.replace('%2F', '/').replace('%3D', '=').replace('%3F', '?')
|
|
|
|
# 解析URL
|
|
parsed = urlparse(url)
|
|
query_params = parse_qs(parsed.query)
|
|
|
|
# 提取必要参数
|
|
uuid = parsed.username
|
|
address = parsed.hostname
|
|
port = parsed.port
|
|
name = parsed.fragment
|
|
|
|
# 提取REALITY参数
|
|
security = query_params.get('security', ['none'])[0]
|
|
encryption = query_params.get('encryption', ['none'])[0]
|
|
flow = query_params.get('flow', [''])[0]
|
|
type_ = query_params.get('type', ['tcp'])[0]
|
|
sni = query_params.get('sni', [''])[0]
|
|
fp = query_params.get('fp', ['chrome'])[0]
|
|
pbk = query_params.get('pbk', [''])[0]
|
|
sid = query_params.get('sid', [''])[0]
|
|
spx = query_params.get('spx', [''])[0]
|
|
|
|
return {
|
|
'uuid': uuid,
|
|
'address': address,
|
|
'port': port,
|
|
'name': name,
|
|
'security': security,
|
|
'encryption': encryption,
|
|
'flow': flow,
|
|
'type': type_,
|
|
'sni': sni,
|
|
'fp': fp,
|
|
'pbk': pbk,
|
|
'sid': sid,
|
|
'spx': spx
|
|
}
|
|
except Exception as e:
|
|
logging.error(f"Failed to parse vless URL: {str(e)}")
|
|
return None
|
|
|
|
def generate_v2ray_config(template_path, output_path, proxy_info, domains):
|
|
"""生成v2ray配置文件"""
|
|
try:
|
|
# 读取模板
|
|
with open(template_path, 'r') as f:
|
|
template = json.load(f)
|
|
|
|
# 替换模板中的占位符
|
|
outbound = template['outbounds'][0]
|
|
|
|
# 设置vless服务器信息
|
|
outbound['settings']['vnext'][0]['address'] = proxy_info['address']
|
|
outbound['settings']['vnext'][0]['port'] = proxy_info['port']
|
|
outbound['settings']['vnext'][0]['users'][0]['id'] = proxy_info['uuid']
|
|
outbound['settings']['vnext'][0]['users'][0]['encryption'] = proxy_info['encryption']
|
|
outbound['settings']['vnext'][0]['users'][0]['flow'] = proxy_info['flow']
|
|
|
|
# 设置streamSettings
|
|
stream_settings = outbound['streamSettings']
|
|
stream_settings['network'] = proxy_info['type']
|
|
stream_settings['security'] = proxy_info['security']
|
|
|
|
if proxy_info['security'] == 'reality':
|
|
reality_settings = {
|
|
'serverName': proxy_info['sni'],
|
|
'fingerprint': proxy_info['fp'],
|
|
'publicKey': proxy_info['pbk'],
|
|
'shortId': proxy_info['sid'],
|
|
'spiderX': proxy_info['spx']
|
|
}
|
|
stream_settings['realitySettings'] = reality_settings
|
|
|
|
# 替换域名列表
|
|
for rule in template['routing']['rules']:
|
|
if 'domain' in rule and 'REPLACE_DOMAINS' in rule['domain']:
|
|
rule['domain'] = domains
|
|
|
|
# 保存配置
|
|
with open(output_path, 'w') as f:
|
|
json.dump(template, f, indent=2)
|
|
|
|
return True
|
|
except Exception as e:
|
|
logging.error(f"Failed to generate v2ray config: {str(e)}")
|
|
return False |