From 2131cc3900e508e3dc96ccb0dc46d3cfd65ffd6f Mon Sep 17 00:00:00 2001 From: Justin Bollinger Date: Tue, 3 Feb 2026 20:05:44 -0500 Subject: [PATCH] rule download fixes from hashmob --- Makefile | 3 +-- hate_crack/api.py | 24 +++++++++++++++++++----- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 91ace09..71b9abb 100644 --- a/Makefile +++ b/Makefile @@ -46,8 +46,7 @@ install: exit 1; \ fi -reinstall: - @uv tool install . --force +reinstall: uninstall install clean: diff --git a/hate_crack/api.py b/hate_crack/api.py index aa450be..90e6184 100644 --- a/hate_crack/api.py +++ b/hate_crack/api.py @@ -1134,11 +1134,9 @@ def download_hashmob_rule(file_name, out_path): } url = hashmob_rule_urls.get(file_name) if not url: - print(f"[i] Hashmob rule not in pinned URL list, using prefix fallback: {file_name}") - if str(file_name).startswith("HashMob"): - url = f"https://hashmob.net/api/v2/downloads/research/official/hashmob_rules/{file_name}" - else: - url = f"https://www.hashmob.net/api/v2/downloads/research/rules/{file_name}" + print(f"[i] Hashmob rule not in pinned URL list, using public prefix: {file_name}") + url = f"https://www.hashmob.net/api/v2/downloads/research/rules/{file_name}" + alt_url = f"https://hashmob.net/api/v2/downloads/research/official/hashmob_rules/{file_name}" api_key = get_hashmob_api_key() headers = {"api-key": api_key} if api_key else {} import time @@ -1162,6 +1160,22 @@ def download_hashmob_rule(file_name, out_path): penalty = min(penalty + penalty_add, max_backoff) penalty_add *= 2 continue + if r.status_code == 404 and alt_url: + print(f"[i] Hashmob rule not found at primary URL, trying fallback: {alt_url}") + with requests.get(alt_url, headers=headers, stream=True, timeout=60, allow_redirects=True) as r_alt: + if r_alt.status_code == 429: + print(f"[!] Rate limit hit (429). Backing off for {penalty} seconds...") + time.sleep(penalty) + penalty = min(penalty + penalty_add, max_backoff) + penalty_add *= 2 + continue + r_alt.raise_for_status() + with open(out_path, 'wb') as f: + for chunk in r_alt.iter_content(chunk_size=8192): + if chunk: + f.write(chunk) + print(f"Downloaded {out_path}") + return True r.raise_for_status() with open(out_path, 'wb') as f: for chunk in r.iter_content(chunk_size=8192):