diff --git a/scripts/mirror_plugin_archive_contents.py b/scripts/mirror_plugin_archive_contents.py index ab4dd64..3961ba5 100644 --- a/scripts/mirror_plugin_archive_contents.py +++ b/scripts/mirror_plugin_archive_contents.py @@ -40,6 +40,7 @@ # /// script # requires-python = ">=3.13" # dependencies = [ +# "httpx", # "ida-hcli", # "rich", # ] @@ -49,8 +50,10 @@ import hashlib import logging import shutil +import urllib.request from pathlib import Path +import httpx import rich.console import rich.progress from hcli.lib.ida.plugin import ( @@ -68,6 +71,25 @@ stderr_console = rich.console.Console(stderr=True) +def fetch_plugin_archive_with_redirects(url: str) -> bytes: + try: + return fetch_plugin_archive(url) + except httpx.HTTPStatusError as e: + if e.response.status_code not in {301, 302, 303, 307, 308}: + raise + + logger.info( + "retrying with urllib.request to follow redirect (%s) for plugin archive: %s", + e.response.status_code, + url, + ) + with urllib.request.urlopen(url, timeout=30) as response: + redirected_url = response.geturl() + if not redirected_url.startswith("https://"): + raise ValueError(f"redirected plugin archive URL is not HTTPS: {redirected_url}") + return response.read() + + def do_cache(json_path: Path, out_path: Path, no_cache: bool = False): repo = JSONFilePluginRepo.from_file(json_path) plugins = repo.get_plugins() @@ -104,7 +126,7 @@ def do_cache(json_path: Path, out_path: Path, no_cache: bool = False): assert location.url.startswith("https://") - zip_data = fetch_plugin_archive(location.url) + zip_data = fetch_plugin_archive_with_redirects(location.url) metadata_path, metadata = get_metadata_from_plugin_archive(zip_data, plugin.name) validate_metadata_in_plugin_archive(zip_data, metadata_path, metadata)