fix: pass configured rules_directory to all rule download and listing callers

api.py's get_rules_dir() independently re-parsed config.json and could
resolve a different rules path than main.py's rulesDirectory global.
Thread the already-resolved rulesDirectory through download_hashmob_rules
and list_and_download_hashmob_rules so all callers (menu option 90,
--rules flag, quick_crack, loopback_attack) use the same path from config.
This commit is contained in:
Justin Bollinger
2026-03-16 14:44:28 -04:00
parent 0dbe593660
commit 42c2f0d50b
3 changed files with 22 additions and 19 deletions

View File

@@ -1680,7 +1680,7 @@ def list_and_download_official_wordlists():
print(f"Error listing official wordlists: {e}")
def list_and_download_hashmob_rules():
def list_and_download_hashmob_rules(rules_dir=None):
"""List rules via the Hashmob API, prompt for selection, and download."""
rules = download_hashmob_rule_list()
if not rules:
@@ -1703,7 +1703,8 @@ def list_and_download_hashmob_rules():
)
if sel.lower() == "q":
return
rules_dir = get_rules_dir()
if not rules_dir:
rules_dir = get_rules_dir()
def parse_indices(selection, max_index):
indices = set()
@@ -1871,9 +1872,9 @@ def download_hashmob_wordlists(print_fn=print) -> None:
print_fn("Hashmob wordlist download complete.")
def download_hashmob_rules(print_fn=print) -> None:
def download_hashmob_rules(print_fn=print, rules_dir=None) -> None:
"""Download Hashmob rules."""
list_and_download_hashmob_rules()
list_and_download_hashmob_rules(rules_dir=rules_dir)
print_fn("Hashmob rules download complete.")

View File

@@ -87,7 +87,8 @@ def quick_crack(ctx: Any) -> None:
except ValueError:
print("Please enter a valid number.")
rule_files = sorted(f for f in os.listdir(ctx.rulesDirectory) if f != ".DS_Store")
rules_dir = ctx.rulesDirectory
rule_files = sorted(f for f in os.listdir(rules_dir) if f != ".DS_Store")
if not rule_files:
download_rules = (
input("\nNo rules found. Download rules from Hashmob now? (Y/n): ")
@@ -95,8 +96,8 @@ def quick_crack(ctx: Any) -> None:
.lower()
)
if download_rules in ("", "y", "yes"):
download_hashmob_rules(print_fn=print)
rule_files = sorted(os.listdir(ctx.rulesDirectory))
download_hashmob_rules(print_fn=print, rules_dir=rules_dir)
rule_files = sorted(os.listdir(rules_dir))
if not rule_files:
print("No rules available. Proceeding without rules.")
@@ -138,7 +139,7 @@ def quick_crack(ctx: Any) -> None:
return
if "98" in rule_choice:
for rule in rule_files:
selected_hcatRules.append(f"-r {os.path.join(ctx.rulesDirectory, rule)}")
selected_hcatRules.append(f"-r {os.path.join(rules_dir, rule)}")
elif "0" in rule_choice:
selected_hcatRules = [""]
else:
@@ -148,14 +149,14 @@ def quick_crack(ctx: Any) -> None:
choices = choice.split("+")
for rule in choices:
try:
rule_path = os.path.join(ctx.rulesDirectory, rule_files[int(rule) - 1])
rule_path = os.path.join(rules_dir, rule_files[int(rule) - 1])
combined_choice = f"{combined_choice} -r {rule_path}"
except Exception:
continue
selected_hcatRules.append(combined_choice)
else:
try:
rule_path = os.path.join(ctx.rulesDirectory, rule_files[int(choice) - 1])
rule_path = os.path.join(rules_dir, rule_files[int(choice) - 1])
selected_hcatRules.append(f"-r {rule_path}")
except IndexError:
continue
@@ -178,7 +179,8 @@ def loopback_attack(ctx: Any) -> None:
rule_choice = None
selected_hcatRules = []
rule_files = sorted(f for f in os.listdir(ctx.rulesDirectory) if f != ".DS_Store")
rules_dir = ctx.rulesDirectory
rule_files = sorted(f for f in os.listdir(rules_dir) if f != ".DS_Store")
if not rule_files:
download_rules = (
input("\nNo rules found. Download rules from Hashmob now? (Y/n): ")
@@ -186,8 +188,8 @@ def loopback_attack(ctx: Any) -> None:
.lower()
)
if download_rules in ("", "y", "yes"):
download_hashmob_rules(print_fn=print)
rule_files = sorted(os.listdir(ctx.rulesDirectory))
download_hashmob_rules(print_fn=print, rules_dir=rules_dir)
rule_files = sorted(os.listdir(rules_dir))
if not rule_files:
print("No rules available. Proceeding without rules.")
@@ -229,7 +231,7 @@ def loopback_attack(ctx: Any) -> None:
return
if "98" in rule_choice:
for rule in rule_files:
selected_hcatRules.append(f"-r {os.path.join(ctx.rulesDirectory, rule)}")
selected_hcatRules.append(f"-r {os.path.join(rules_dir, rule)}")
elif "0" in rule_choice:
selected_hcatRules = [""]
else:
@@ -239,14 +241,14 @@ def loopback_attack(ctx: Any) -> None:
choices = choice.split("+")
for rule in choices:
try:
rule_path = os.path.join(ctx.rulesDirectory, rule_files[int(rule) - 1])
rule_path = os.path.join(rules_dir, rule_files[int(rule) - 1])
combined_choice = f"{combined_choice} -r {rule_path}"
except Exception:
continue
selected_hcatRules.append(combined_choice)
else:
try:
rule_path = os.path.join(ctx.rulesDirectory, rule_files[int(choice) - 1])
rule_path = os.path.join(rules_dir, rule_files[int(choice) - 1])
selected_hcatRules.append(f"-r {rule_path}")
except IndexError:
continue

View File

@@ -3329,7 +3329,7 @@ def get_main_menu_options():
"14": loopback_attack,
"15": ollama_attack,
"16": omen_attack,
"90": download_hashmob_rules,
"90": lambda: download_hashmob_rules(rules_dir=rulesDirectory),
"91": analyze_rules,
"92": download_hashmob_wordlists,
"93": weakpass_wordlist_menu,
@@ -3725,7 +3725,7 @@ def main():
download_hashmob_wordlists(print_fn=print)
sys.exit(0)
if args.rules:
download_hashmob_rules(print_fn=print)
download_hashmob_rules(print_fn=print, rules_dir=rulesDirectory)
sys.exit(0)
if args.hashfile and args.hashtype:
@@ -3781,7 +3781,7 @@ def main():
sys.exit(0)
# Otherwise continue the menu loop
elif choice == "4" or args.rules:
download_hashmob_rules(print_fn=print)
download_hashmob_rules(print_fn=print, rules_dir=rulesDirectory)
if args.rules:
sys.exit(0)
# Otherwise continue the menu loop