import hashlib import json import os import shutil import struct import time import urllib.error import urllib.request import zipfile ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) OUTPUT_ROOT = os.path.join(ROOT, "Payload", "Fallback", "Remote") MANIFEST_PATH = os.path.join(ROOT, "Payload", "Fallback", "remote_fallbacks.json") USER_AGENT = "Modernization-Tool build fallback fetcher" FALLBACKS = [ { "id": "wowpresence", "filename": "WowPresence.zip", "revision": "v1.3", "url": "https://github.com/Dusk-92/WowPresence/releases/download/v1.3/WowPresence.zip", "kind": "wowpresence_zip", "size": 141423, "sha256": "9b2dca9c69b5ab3b6dae3ef3b3efc9671779a227802ebb6ac98cb22bc6ea448a", }, ] def _sha256(path): digest = hashlib.sha256() with open(path, "rb") as handle: while True: chunk = handle.read(1024 * 1024) if not chunk: break digest.update(chunk) return digest.hexdigest().lower() def _download(url, destination, retries=3): os.makedirs(os.path.dirname(destination), exist_ok=True) request = urllib.request.Request(url, headers={"User-Agent": USER_AGENT}) last_error = None for attempt in range(1, retries + 1): temp_path = destination + ".new" try: with urllib.request.urlopen(request, timeout=300) as response, open(temp_path, "wb") as out: while True: chunk = response.read(1024 * 1024) if not chunk: break out.write(chunk) os.replace(temp_path, destination) return except (OSError, urllib.error.URLError, urllib.error.HTTPError, TimeoutError) as exc: last_error = exc try: os.remove(temp_path) except OSError: pass if attempt < retries: time.sleep(attempt * 2) raise RuntimeError(f"Could not download {url}: {last_error}") def _verify_x86_pe_bytes(data, label): if len(data) < 1024 or data[:2] != b"MZ": raise RuntimeError(f"{label} is not a valid PE file") pe_offset = struct.unpack_from(" len(data) - 26: raise RuntimeError(f"{label} has an invalid PE offset") if data[pe_offset:pe_offset + 4] != b"PE\0\0": raise RuntimeError(f"{label} is missing the PE signature") machine = struct.unpack_from(" len(data): raise RuntimeError(f"{label} has an invalid optional header") optional_magic = struct.unpack_from("