Update ALL.txt #38
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Process WireGuard Configs | |
| on: | |
| push: | |
| paths: | |
| - 'ALL.txt' | |
| workflow_dispatch: | |
| jobs: | |
| process-configs: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Setup Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.x' | |
| - name: Install PyYAML | |
| run: pip install pyyaml | |
| - name: Deduplicate, sort, generate Clash configs and WireGuard conf files | |
| shell: python | |
| run: | | |
| import re, os, yaml, zipfile, tempfile, base64 | |
| from urllib.parse import unquote | |
| INPUT_FILE = "ALL.txt" | |
| OUTPUT_FILE = "ALL.yaml" | |
| ZIP_FILE = "wireguard_configs.zip" | |
| BASE_CONFIG = { | |
| "name": "Standard", | |
| "mixed-port": 7890, | |
| "socks-port": 7891, | |
| "port": 7892, | |
| "allow-lan": True, | |
| "bind-address": "*", | |
| "mode": "global", | |
| "log-level": "info", | |
| "ipv6": True, | |
| "external-controller": "127.0.0.1:9090", | |
| "external-ui": "ui", | |
| "secret": "", | |
| "unified-delay": True, | |
| "tcp-concurrent": True, | |
| "global-client-fingerprint": "chrome", | |
| "find-process-mode": "strict", | |
| "keep-alive-interval": 15, | |
| "profile": { | |
| "store-selected": True, | |
| "store-fake-ip": False | |
| }, | |
| "dns": { | |
| "enable": True, | |
| "ipv6": True, | |
| "listen": "0.0.0.0:5353", | |
| "enhanced-mode": "fake-ip", | |
| "fake-ip-range": "198.18.0.1/16", | |
| "fake-ip-filter": [ | |
| "*.local", | |
| "*.lan", | |
| "*.localhost", | |
| "+.stun.*.*", | |
| "+.stun.*.*.*", | |
| "time.*", | |
| "time.*.com", | |
| "connectivitycheck.gstatic.com", | |
| "detectportal.firefox.com", | |
| "captive.apple.com", | |
| "www.msftncsi.com", | |
| "cp.cloudflare.com" | |
| ], | |
| "default-nameserver": [ | |
| "1.1.1.1", "1.0.0.1", "8.8.8.8", "8.8.4.4", | |
| "9.9.9.9", "149.112.112.112", | |
| "208.67.222.222", "208.67.220.220", | |
| "94.140.14.14", "94.140.15.15", | |
| "64.6.64.6", "64.6.65.6", | |
| "84.200.69.80", "84.200.70.40", | |
| "76.76.19.19", "76.223.122.150", | |
| "8.26.56.26", "8.20.247.20" | |
| ], | |
| "nameserver": [ | |
| "https://cloudflare-dns.com/dns-query", | |
| "https://1.1.1.1/dns-query", | |
| "https://1.0.0.1/dns-query", | |
| "https://dns.google/dns-query", | |
| "https://8.8.8.8/dns-query", | |
| "https://8.8.4.4/dns-query", | |
| "https://dns.quad9.net/dns-query", | |
| "https://9.9.9.9/dns-query", | |
| "https://149.112.112.112/dns-query", | |
| "https://dns.adguard.com/dns-query", | |
| "https://94.140.14.14/dns-query", | |
| "https://94.140.15.15/dns-query", | |
| "https://doh.opendns.com/dns-query", | |
| "https://208.67.222.222/dns-query", | |
| "https://208.67.220.220/dns-query", | |
| "https://doh.comodo.com/dns-query", | |
| "https://8.26.56.26/dns-query", | |
| "https://8.20.247.20/dns-query", | |
| "https://doh.mullvad.net/dns-query", | |
| "https://doh.dns.mullvad.net/dns-query", | |
| "https://freedns.controld.com/p0", | |
| "https://freedns.controld.com/family", | |
| "tls://1.1.1.1:853", "tls://1.0.0.1:853", | |
| "tls://8.8.8.8:853", "tls://8.8.4.4:853", | |
| "tls://9.9.9.9:853", "tls://149.112.112.112:853", | |
| "tls://94.140.14.14:853", "tls://94.140.15.15:853", | |
| "tls://208.67.222.222:853", "tls://208.67.220.220:853", | |
| "tls://family-filter-dns.cleanbrowsing.org:853", | |
| "tls://adult-filter-dns.cleanbrowsing.org:853", | |
| "tls://security-filter-dns.cleanbrowsing.org:853", | |
| "1.1.1.1", "1.0.0.1", "8.8.8.8", "8.8.4.4", | |
| "9.9.9.9", "149.112.112.112", | |
| "208.67.222.222", "208.67.220.220", | |
| "94.140.14.14", "94.140.15.15", | |
| "64.6.64.6", "64.6.65.6", | |
| "84.200.69.80", "84.200.70.40", | |
| "8.26.56.26", "8.20.247.20", | |
| "76.76.19.19", "76.223.122.150", | |
| "208.67.222.123", "208.67.220.123", | |
| "195.46.39.39", "195.46.39.40", | |
| "38.132.106.139", "194.187.251.67" | |
| ] | |
| }, | |
| "proxies": [], | |
| "proxy-groups": [ | |
| { | |
| "name": "PROXY", | |
| "type": "select", | |
| "proxies": ["Fallback", "Auto", "Load Balance"] | |
| }, | |
| { | |
| "name": "Load Balance", | |
| "type": "load-balance", | |
| "strategy": "consistent-hashing", | |
| "url": "http://www.gstatic.com/generate_204", | |
| "interval": 60, | |
| "tolerance": 50, | |
| "lazy": True, | |
| "proxies": [] | |
| }, | |
| { | |
| "name": "Auto", | |
| "type": "url-test", | |
| "url": "http://www.gstatic.com/generate_204", | |
| "interval": 60, | |
| "tolerance": 50, | |
| "lazy": True, | |
| "proxies": [] | |
| }, | |
| { | |
| "name": "Fallback", | |
| "type": "fallback", | |
| "url": "http://www.gstatic.com/generate_204", | |
| "interval": 60, | |
| "lazy": True, | |
| "proxies": [] | |
| } | |
| ], | |
| "rules": ["MATCH,PROXY"] | |
| } | |
| def decode_base64_key(key): | |
| key = key.strip() | |
| padding = 4 - len(key) % 4 | |
| if padding != 4: | |
| key += '=' * padding | |
| try: | |
| decoded = base64.b64decode(key) | |
| return base64.b64encode(decoded).decode('ascii') | |
| except: | |
| return key | |
| def parse_wireguard_config(line): | |
| decoded = unquote(line) | |
| match = re.match(r'wireguard://([^@]+)@([^:]+):(\d+)\?(.+?)(?:#(.+))?$', decoded) | |
| if not match: | |
| return None | |
| private_key = decode_base64_key(match.group(1)) | |
| address = match.group(2) | |
| port = int(match.group(3)) | |
| params = match.group(4) | |
| params_dict = {} | |
| for param in params.split('&'): | |
| if '=' in param: | |
| key, value = param.split('=', 1) | |
| params_dict[key] = value | |
| public_key = decode_base64_key(params_dict.get('publickey', '')) | |
| preshared_key = decode_base64_key(params_dict.get('presharedkey', '')) | |
| addresses_raw = params_dict.get('address', '') | |
| addresses = [] | |
| for addr in addresses_raw.split(','): | |
| addr = addr.strip() | |
| if addr: | |
| addresses.append(addr) | |
| reserved_raw = params_dict.get('reserved', '0,0,0') | |
| reserved = [] | |
| for r in reserved_raw.split(','): | |
| r = r.strip() | |
| if r: | |
| reserved.append(int(r)) | |
| return { | |
| 'private_key': private_key, | |
| 'address': address, | |
| 'port': port, | |
| 'public_key': public_key, | |
| 'preshared_key': preshared_key, | |
| 'addresses': addresses, | |
| 'reserved': reserved, | |
| 'endpoint': f"{address}:{port}" | |
| } | |
| def generate_proxy_name(endpoint, index): | |
| safe_name = re.sub(r'[^a-zA-Z0-9\-]', '-', endpoint) | |
| return f"WG-{safe_name}-{index}" | |
| def generate_conf_content(config): | |
| conf = f"""[Interface] | |
| PrivateKey = {config['private_key']} | |
| Address = {', '.join(config['addresses'])} | |
| DNS = 1.1.1.1, 1.0.0.1, 2606:4700:4700::1111, 2606:4700:4700::1001 | |
| MTU = 1420 | |
| Jc = 6 | |
| Jmin = 10 | |
| Jmax = 50 | |
| S1 = 0 | |
| S2 = 0 | |
| S3 = 14 | |
| I1 = <r 2><b 0x858000010001000000000669636c6f756403636f6d0000010001c00c000100010000105a00044d583737> | |
| H1 = 1 | |
| H2 = 2 | |
| H3 = 3 | |
| H4 = 4 | |
| [Peer] | |
| PublicKey = {config['public_key']} | |
| AllowedIPs = 0.0.0.0/0, ::/0 | |
| Endpoint = {config['endpoint']} | |
| PersistentKeepalive = 10 | |
| """ | |
| if config['preshared_key']: | |
| conf = conf.replace('[Peer]\n', f'[Peer]\nPresharedKey = {config["preshared_key"]}\n') | |
| return conf.strip() + '\n' | |
| def write_yaml(config, filepath): | |
| class CustomDumper(yaml.Dumper): | |
| def increase_indent(self, flow=False, indentless=False): | |
| return super(CustomDumper, self).increase_indent(flow, False) | |
| with open(filepath, 'w', encoding='utf-8') as f: | |
| yaml.dump(config, f, Dumper=CustomDumper, | |
| default_flow_style=False, | |
| allow_unicode=True, | |
| sort_keys=False, | |
| indent=2) | |
| if not os.path.exists(INPUT_FILE): | |
| print(f"File {INPUT_FILE} not found!") | |
| exit(1) | |
| seen_endpoints = set() | |
| parsed_configs = [] | |
| with open(INPUT_FILE, 'r', encoding='utf-8') as f: | |
| for line in f: | |
| line = line.strip() | |
| if not line.startswith("wireguard://"): | |
| continue | |
| match = re.search(r'@([^?#]+)', line) | |
| if not match: | |
| continue | |
| endpoint = match.group(1) | |
| if endpoint not in seen_endpoints: | |
| seen_endpoints.add(endpoint) | |
| config = parse_wireguard_config(line) | |
| if config: | |
| parsed_configs.append(config) | |
| if parsed_configs: | |
| parsed_configs.sort(key=lambda x: x['endpoint']) | |
| with open(INPUT_FILE, 'w', encoding='utf-8') as f: | |
| for config in parsed_configs: | |
| f.write(f"wireguard://{config['private_key']}@{config['endpoint']}?publickey={config['public_key']}&address={','.join(config['addresses'])}&mtu=1420\n") | |
| print(f"{INPUT_FILE}: {len(parsed_configs)} unique configs written") | |
| proxies = [] | |
| proxy_names = [] | |
| with tempfile.TemporaryDirectory() as tmpdir: | |
| for idx, config in enumerate(parsed_configs, 1): | |
| conf_name = f"@DeltaKroneckerGithub ({idx}).conf" | |
| conf_path = os.path.join(tmpdir, conf_name) | |
| conf_content = generate_conf_content(config) | |
| with open(conf_path, 'w', encoding='utf-8') as f: | |
| f.write(conf_content) | |
| proxy_name = generate_proxy_name(config['endpoint'], idx) | |
| proxy_names.append(proxy_name) | |
| proxy = { | |
| 'name': proxy_name, | |
| 'type': 'wireguard', | |
| 'server': config['address'], | |
| 'port': config['port'], | |
| 'private-key': config['private_key'], | |
| 'public-key': config['public_key'], | |
| 'mtu': 1420, | |
| 'udp': True, | |
| 'reserved': config['reserved'], | |
| 'workers': 4, | |
| 'persistent-keepalive': 10 | |
| } | |
| if config['addresses']: | |
| for addr in config['addresses']: | |
| addr_clean = addr.strip().split('/')[0] if '/' in addr else addr.strip() | |
| if ':' in addr_clean: | |
| proxy['ipv6'] = addr_clean | |
| else: | |
| proxy['ip'] = addr_clean | |
| proxies.append(proxy) | |
| if os.path.exists(ZIP_FILE): | |
| os.remove(ZIP_FILE) | |
| with zipfile.ZipFile(ZIP_FILE, 'w', zipfile.ZIP_DEFLATED) as zipf: | |
| for i in range(1, len(parsed_configs) + 1): | |
| conf_file = f"@DeltaKroneckerGithub ({i}).conf" | |
| conf_path = os.path.join(tmpdir, conf_file) | |
| if os.path.exists(conf_path): | |
| zipf.write(conf_path, conf_file) | |
| output_config = BASE_CONFIG.copy() | |
| output_config['proxies'] = proxies | |
| for group in output_config['proxy-groups']: | |
| if group['name'] in ['Load Balance', 'Auto', 'Fallback']: | |
| group['proxies'] = proxy_names.copy() | |
| write_yaml(output_config, OUTPUT_FILE) | |
| print(f"Generated {OUTPUT_FILE} with {len(proxies)} WireGuard proxies") | |
| print(f"Generated {ZIP_FILE} with {len(parsed_configs)} WireGuard config files") | |
| - name: Commit and push changes | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git add -A | |
| git diff --staged --quiet || git commit -m "Deduplicate, sort, generate Clash config and WireGuard conf files" | |
| git push |