diff --git a/Makefile b/Makefile index 9858a01..50d2299 100644 --- a/Makefile +++ b/Makefile @@ -81,7 +81,7 @@ clean-vendor: @echo "Cleaning up vendored assets from working tree..." @rm -rf hate_crack/hashcat hate_crack/hashcat-utils hate_crack/princeprocessor hate_crack/omen -install: submodules vendor-assets +install: submodules @echo "Detecting OS and installing dependencies..." @if [ "$(shell uname)" = "Darwin" ]; then \ echo "Detected macOS"; \ @@ -105,7 +105,7 @@ install: submodules vendor-assets @command -v uv >/dev/null 2>&1 || { echo "uv not found. Installing uv..."; curl -LsSf https://astral.sh/uv/install.sh | sh; } @uv tool install -e . -update: submodules vendor-assets +update: submodules @uv tool install -e . --force --reinstall reinstall: uninstall install diff --git a/hate_crack/main.py b/hate_crack/main.py index 09816a3..eaac628 100755 --- a/hate_crack/main.py +++ b/hate_crack/main.py @@ -151,6 +151,13 @@ elif os.path.isdir(os.path.join(_repo_root, "hashcat-utils")): hate_path = _repo_root else: hate_path = _package_path +# omen may not be vendored into hate_path (e.g. dev checkout with only some submodules built). +# Check hate_path first, then fall back to repo root. +_omen_dir = ( + os.path.join(hate_path, "omen") + if os.path.isdir(os.path.join(hate_path, "omen")) + else os.path.join(_repo_root, "omen") +) _config_path = _resolve_config_path() if not _config_path: print("Initializing config.json from config.json.example") @@ -727,17 +734,17 @@ if not SKIP_INIT: print("LLM attacks will not be available.") # Verify OMEN binaries (optional, for OMEN attack) - omen_create_path = os.path.join(hate_path, "omen", hcatOmenCreateBin) - omen_enum_path = os.path.join(hate_path, "omen", hcatOmenEnumBin) + omen_create_path = os.path.join(_omen_dir, hcatOmenCreateBin) + omen_enum_path = os.path.join(_omen_dir, hcatOmenEnumBin) try: ensure_binary( omen_create_path, - build_dir=os.path.join(hate_path, "omen"), + build_dir=_omen_dir, name="OMEN createNG", ) ensure_binary( omen_enum_path, - build_dir=os.path.join(hate_path, "omen"), + build_dir=_omen_dir, name="OMEN enumNG", ) except SystemExit: @@ -2173,7 +2180,7 @@ def _omen_model_dir(): # OMEN Attack - Train model def hcatOmenTrain(training_file): - omen_dir = os.path.join(hate_path, "omen") + omen_dir = _omen_dir create_bin = os.path.join(omen_dir, hcatOmenCreateBin) if not os.path.isfile(create_bin): print(f"Error: OMEN createNG binary not found: {create_bin}") @@ -2217,7 +2224,7 @@ def hcatOmenTrain(training_file): # OMEN Attack - Generate candidates and pipe to hashcat def hcatOmen(hcatHashType, hcatHashFile, max_candidates): global hcatProcess - omen_dir = os.path.join(hate_path, "omen") + omen_dir = _omen_dir enum_bin = os.path.join(omen_dir, hcatOmenEnumBin) if not os.path.isfile(enum_bin): print(f"Error: OMEN enumNG binary not found: {enum_bin}") diff --git a/pyproject.toml b/pyproject.toml index 4fb7201..d65dd34 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,9 +32,6 @@ include = ["hate_crack*"] [tool.setuptools.package-data] hate_crack = [ "config.json.example", - "hashcat-utils/**", - "princeprocessor/**", - "omen/**", ] [tool.setuptools_scm] @@ -61,9 +58,8 @@ exclude = [ "wordlists/", "HashcatRosetta/", "hashcat-utils/", - "hate_crack/hashcat-utils/", - "hate_crack/omen/", - "hate_crack/princeprocessor/", + "omen/", + "princeprocessor/", ] [tool.ty.rules] diff --git a/tests/test_omen_attack.py b/tests/test_omen_attack.py index 84bc412..6ee3f40 100644 --- a/tests/test_omen_attack.py +++ b/tests/test_omen_attack.py @@ -23,6 +23,8 @@ class TestHcatOmenTrain: model_dir.mkdir() with patch.object(main_module, "hate_path", str(tmp_path)), patch.object( + main_module, "_omen_dir", str(omen_dir) + ), patch.object( main_module, "hcatOmenCreateBin", "createNG" ), patch( "hate_crack.main._omen_model_dir", return_value=str(model_dir) @@ -58,8 +60,8 @@ class TestHcatOmenTrain: training_file.write_text("test\n") with patch.object(main_module, "hate_path", str(tmp_path)), patch.object( - main_module, "hcatOmenCreateBin", "createNG" - ): + main_module, "_omen_dir", str(tmp_path / "omen") + ), patch.object(main_module, "hcatOmenCreateBin", "createNG"): main_module.hcatOmenTrain(str(training_file)) captured = capsys.readouterr() assert "createNG binary not found" in captured.out @@ -73,6 +75,8 @@ class TestHcatOmenTrain: model_dir.mkdir() with patch.object(main_module, "hate_path", str(tmp_path)), patch.object( + main_module, "_omen_dir", str(omen_dir) + ), patch.object( main_module, "hcatOmenCreateBin", "createNG" ), patch("hate_crack.main._omen_model_dir", return_value=str(model_dir)): main_module.hcatOmenTrain("/nonexistent/file.txt") @@ -92,6 +96,8 @@ class TestHcatOmen: (model_dir / "createConfig").write_text("# test config\n") with patch.object(main_module, "hate_path", str(tmp_path)), patch.object( + main_module, "_omen_dir", str(omen_dir) + ), patch.object( main_module, "hcatOmenEnumBin", "enumNG" ), patch.object(main_module, "hcatBin", "hashcat"), patch.object( main_module, "hcatTuning", "--force" @@ -132,8 +138,8 @@ class TestHcatOmen: def test_missing_binary(self, main_module, tmp_path, capsys): with patch.object(main_module, "hate_path", str(tmp_path)), patch.object( - main_module, "hcatOmenEnumBin", "enumNG" - ): + main_module, "_omen_dir", str(tmp_path / "omen") + ), patch.object(main_module, "hcatOmenEnumBin", "enumNG"): main_module.hcatOmen("1000", "/tmp/hashes.txt", 500000) captured = capsys.readouterr() assert "enumNG binary not found" in captured.out @@ -149,6 +155,8 @@ class TestHcatOmen: # No createConfig in model_dir with patch.object(main_module, "hate_path", str(tmp_path)), patch.object( + main_module, "_omen_dir", str(omen_dir) + ), patch.object( main_module, "hcatOmenEnumBin", "enumNG" ), patch("hate_crack.main._omen_model_dir", return_value=str(model_dir)): main_module.hcatOmen("1000", "/tmp/hashes.txt", 500000)