49 lines
2.1 KiB
Python
Executable File
49 lines
2.1 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Download a pinned official release, verify GitHub's asset SHA256, and unpack it."""
|
|
import argparse
|
|
import gzip
|
|
import hashlib
|
|
import json
|
|
import os
|
|
import platform
|
|
import tempfile
|
|
import urllib.request
|
|
from pathlib import Path
|
|
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument('--version', default='v1.19.32')
|
|
parser.add_argument('--output', default='bin/mihomo')
|
|
args = parser.parse_args()
|
|
machine = platform.machine()
|
|
arch = {'x86_64': 'amd64-compatible', 'aarch64': 'arm64'}.get(machine)
|
|
if arch is None:
|
|
raise SystemExit(f'Unsupported architecture: {machine}')
|
|
if not args.version.startswith('v') or any(c not in 'v0123456789.' for c in args.version):
|
|
raise SystemExit('Use an explicit stable version such as v1.19.32')
|
|
request = urllib.request.Request(f'https://api.github.com/repos/MetaCubeX/mihomo/releases/tags/{args.version}', headers={'User-Agent': 'ClashWeb-build'})
|
|
with urllib.request.urlopen(request, timeout=30) as response:
|
|
release = json.load(response)
|
|
name = f'mihomo-linux-{arch}-{args.version}.gz'
|
|
asset = next((a for a in release['assets'] if a['name'] == name), None)
|
|
if not asset or not asset.get('digest', '').startswith('sha256:'):
|
|
raise SystemExit('Release asset or authoritative SHA256 digest is missing; download aborted.')
|
|
print(f'Downloading {name}', flush=True)
|
|
with urllib.request.urlopen(asset['browser_download_url'], timeout=120) as response:
|
|
compressed = response.read(100 * 1024 * 1024 + 1)
|
|
if len(compressed) > 100 * 1024 * 1024:
|
|
raise SystemExit('Asset exceeds download limit')
|
|
if hashlib.sha256(compressed).hexdigest() != asset['digest'].split(':', 1)[1]:
|
|
raise SystemExit('SHA256 mismatch; download aborted')
|
|
output = Path(args.output)
|
|
output.parent.mkdir(parents=True, exist_ok=True)
|
|
fd, temporary = tempfile.mkstemp(dir=output.parent, prefix='.mihomo-')
|
|
try:
|
|
with os.fdopen(fd, 'wb') as stream:
|
|
stream.write(gzip.decompress(compressed))
|
|
os.chmod(temporary, 0o755)
|
|
os.replace(temporary, output)
|
|
finally:
|
|
if os.path.exists(temporary):
|
|
os.unlink(temporary)
|
|
print(f'Verified {asset["digest"]}; installed to {output}')
|