From 01c6099db9575767a8e4b36a3b42c93e62f5dcd6 Mon Sep 17 00:00:00 2001 From: Justin Bollinger Date: Tue, 28 Jul 2026 17:25:37 -0400 Subject: [PATCH] fix: single-source config.json.example, stop backfilling config.json on disk hate_crack/config.json.example and the root copy had drifted (10 keys missing from the packaged copy, 4 dead PassGPT keys still shipped, hcatPath disagreeing). Replace the packaged copy with a symlink to the root file so there is exactly one set of shipped defaults, and add a test guard asserting the two stay identical. Also stop writing missing keys back into the user's config.json on load: merge defaults into the in-memory config_parser dict only. A stale example file previously meant wrong defaults got persisted to disk permanently; now the effective values are always whatever config.json.example currently ships, and users are never surprised by keys silently appearing in their config file. Fixes #150 --- hate_crack/config.json.example | 43 +------------------------------ hate_crack/main.py | 7 ----- tests/test_config_json_example.py | 22 ++++++++++++++++ 3 files changed, 23 insertions(+), 49 deletions(-) mode change 100644 => 120000 hate_crack/config.json.example create mode 100644 tests/test_config_json_example.py diff --git a/hate_crack/config.json.example b/hate_crack/config.json.example deleted file mode 100644 index fe8ffb8..0000000 --- a/hate_crack/config.json.example +++ /dev/null @@ -1,42 +0,0 @@ -{ - "hcatPath": "", - "hcatBin": "hashcat", - "hcatTuning": "", - "hcatPotfilePath": "~/.hashcat/hashcat.potfile", - "hcatDebugLogPath": "./hashcat_debug", - "hcatWordlists": "./wordlists", - "rules_directory": "./hashcat/rules", - "hcatDictionaryWordlist": ["rockyou.txt"], - "hcatCombinationWordlist": ["rockyou.txt","rockyou.txt"], - "hcatHybridlist": ["rockyou.txt"], - "hcatMiddleCombinatorMasks": ["2","4"," ","-","_","+",",",".","&"], - "hcatMiddleBaseList": "rockyou.txt", - "hcatThoroughCombinatorMasks": ["0","1","2","3","4","5","6","7","8","9"," ","-","_","+",",","!","#","$","\"","%","&","'","(",")","*",".","/",":",";","<","=",">","?","@","[","\\","]","^","`","{","|","}","~"], - "hcatThoroughBaseList": "rockyou.txt", - "hcatGoodMeasureBaseList": "rockyou.txt", - "hcatPrinceBaseList": "rockyou.txt", - "pipalPath": "/path/to/pipal", - "pipal_count" : 10, - "bandrelmaxruntime": 300, - "bandrel_common_basedwords": "welcome,password,p@ssword,p@$$word,changeme,letmein,summer,winter,spring,springtime,fall,autumn,monday,tuesday,wednesday,thursday,friday,saturday,sunday,january,february,march,april,may,june,july,august,september,october,november,december,christmas,easter,covid19", - "hashview_url": "http://localhost:8443", - "hashview_api_key": "", - "hashmob_api_key": "", - "ollamaModel": "qwen2.5:32b", - "ollamaNumCtx": 2048, - "ollamaTimeout": 300, - "ollamaMaxSampleLines": 500, - "ollamaAutoResearch": true, - "passgptModel": "javirandor/passgpt-10characters", - "passgptMaxCandidates": 1000000, - "passgptBatchSize": 1024, - "passgptTrainingList": "", - "notify_enabled": false, - "notify_pushover_token": "", - "notify_pushover_user": "", - "notify_per_crack_enabled": false, - "notify_attack_allowlist": [], - "notify_suppress_in_orchestrators": true, - "notify_max_cracks_per_burst": 5, - "notify_poll_interval_seconds": 5.0 -} diff --git a/hate_crack/config.json.example b/hate_crack/config.json.example new file mode 120000 index 0000000..0b5f7b4 --- /dev/null +++ b/hate_crack/config.json.example @@ -0,0 +1 @@ +../config.json.example \ No newline at end of file diff --git a/hate_crack/main.py b/hate_crack/main.py index 2ac9602..b4b4a22 100755 --- a/hate_crack/main.py +++ b/hate_crack/main.py @@ -262,16 +262,9 @@ except json.JSONDecodeError: print(" This is a package installation issue. Try reinstalling hate_crack.") sys.exit(1) -_missing_keys = [] for _key, _value in default_config.items(): if _key not in config_parser: config_parser[_key] = _value - _missing_keys.append(_key) -if _missing_keys: - with open(_config_path, "w") as _cf: - json.dump(config_parser, _cf, indent=2) - print(f"[config] Added {len(_missing_keys)} missing key(s) to {_config_path}") - print(f" Keys: {', '.join(_missing_keys)}") # Environment variables override config.json so the CLI can be pointed at a # different Hashview instance (e.g. a local docker stack for the live test diff --git a/tests/test_config_json_example.py b/tests/test_config_json_example.py new file mode 100644 index 0000000..a9bd52e --- /dev/null +++ b/tests/test_config_json_example.py @@ -0,0 +1,22 @@ +import json +import os + +REPO_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +ROOT_EXAMPLE = os.path.join(REPO_ROOT, "config.json.example") +PACKAGED_EXAMPLE = os.path.join(REPO_ROOT, "hate_crack", "config.json.example") + + +def test_packaged_example_is_symlink_to_root(): + assert os.path.islink(PACKAGED_EXAMPLE), ( + "hate_crack/config.json.example must be a symlink to the root " + "config.json.example so there is a single source of truth for defaults" + ) + + +def test_packaged_and_root_examples_have_identical_content(): + with open(ROOT_EXAMPLE) as f: + root_config = json.load(f) + with open(PACKAGED_EXAMPLE) as f: + packaged_config = json.load(f) + + assert packaged_config == root_config