mirror of
https://github.com/trustedsec/hate_crack.git
synced 2026-07-28 14:47:22 -07:00
fix: separate hcatPath (hashcat dir) from hate_path (asset dir)
hcatPath now exclusively points to the hashcat install directory and is auto-discovered from PATH when not configured. hate_path is resolved from the package directory (installed) or repo root (development) with no auto-discovery. Extracted vendor-assets/clean-vendor Makefile targets to deduplicate the install logic. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
c260787985
commit
91906e3313
@@ -1,5 +1,5 @@
|
||||
.DEFAULT_GOAL := submodules
|
||||
.PHONY: install reinstall dev-install dev-reinstall clean hashcat-utils submodules submodules-pre test coverage lint check ruff mypy
|
||||
.PHONY: install reinstall dev-install dev-reinstall clean hashcat-utils submodules submodules-pre vendor-assets clean-vendor test coverage lint check ruff mypy
|
||||
|
||||
hashcat-utils: submodules
|
||||
$(MAKE) -C hashcat-utils
|
||||
@@ -28,40 +28,38 @@ submodules-pre:
|
||||
@# Patch hashcat-utils/src/Makefile so these new expanders are compiled by default.
|
||||
@bases="hashcat-utils hate_crack/hashcat-utils"; for base in $$bases; do src="$$base/src/expander.c"; test -f "$$src" || continue; for i in $$(seq 8 36); do dst="$$base/src/expander$$i.c"; if [ ! -f "$$dst" ]; then cp "$$src" "$$dst"; perl -pi -e "s/#define LEN_MAX 7/#define LEN_MAX $$i/g" "$$dst"; fi; done; mk="$$base/src/Makefile"; test -f "$$mk" || continue; exp_bins=""; exp_exes=""; for i in $$(seq 8 36); do exp_bins="$$exp_bins expander$$i.bin"; exp_exes="$$exp_exes expander$$i.exe"; done; EXP_BINS="$$exp_bins" perl -pi -e 'if(/^native:/ && index($$_, "expander8.bin") < 0){chomp; $$_ .= "$$ENV{EXP_BINS}"; $$_ .= "\n";}' "$$mk"; EXP_EXES="$$exp_exes" perl -pi -e 'if(/^windows:/ && index($$_, "expander8.exe") < 0){chomp; $$_ .= "$$ENV{EXP_EXES}"; $$_ .= "\n";}' "$$mk"; perl -0777 -pi -e 's/\n# Auto-added by hate_crack \\(submodules-pre\\)\n.*\z/\n/s' "$$mk"; printf '%s\n' '' '# Auto-added by hate_crack (submodules-pre)' 'expander%.bin: src/expander%.c' >> "$$mk"; printf '\t%s\n' '$${CC_NATIVE} $${CFLAGS_NATIVE} $${LDFLAGS_NATIVE} -o bin/$$@ $$<' >> "$$mk"; printf '%s\n' '' 'expander%.exe: src/expander%.c' >> "$$mk"; printf '\t%s\n' '$${CC_WINDOWS} $${CFLAGS_WINDOWS} -o bin/$$@ $$<' >> "$$mk"; done
|
||||
|
||||
install:
|
||||
@echo "Detecting OS and installing dependencies..."
|
||||
vendor-assets:
|
||||
@if [ ! -f princeprocessor/pp64.bin ] && [ ! -f princeprocessor/pp64.app ] && [ ! -f princeprocessor/pp64.exe ]; then \
|
||||
echo "princeprocessor binaries are missing; please ensure the princeprocessor directory is present."; \
|
||||
exit 1; \
|
||||
fi
|
||||
@echo "Syncing assets into package for uv tool install..."
|
||||
@rm -rf hate_crack/hashcat-utils hate_crack/princeprocessor
|
||||
@cp -R hashcat-utils hate_crack/
|
||||
@cp -R princeprocessor hate_crack/
|
||||
@rm -rf hate_crack/hashcat-utils/.git hate_crack/princeprocessor/.git
|
||||
|
||||
clean-vendor:
|
||||
@echo "Cleaning up vendored assets from working tree..."
|
||||
@rm -rf hate_crack/hashcat-utils hate_crack/princeprocessor
|
||||
|
||||
install: submodules vendor-assets
|
||||
@echo "Detecting OS and installing dependencies..."
|
||||
@if [ "$(shell uname)" = "Darwin" ]; then \
|
||||
echo "Detected macOS"; \
|
||||
command -v brew >/dev/null 2>&1 || { echo >&2 "Homebrew not found. Please install Homebrew first: https://brew.sh/"; exit 1; }; \
|
||||
brew install p7zip transmission-cli; \
|
||||
echo "Syncing assets into package for uv tool install..."; \
|
||||
rm -rf hate_crack/hashcat-utils hate_crack/princeprocessor; \
|
||||
cp -R hashcat-utils hate_crack/; \
|
||||
cp -R princeprocessor hate_crack/; \
|
||||
rm -rf hate_crack/hashcat-utils/.git hate_crack/princeprocessor/.git; \
|
||||
uv tool install .; \
|
||||
echo "Cleaning up vendored assets from working tree..."; \
|
||||
rm -rf hate_crack/hashcat-utils hate_crack/princeprocessor; \
|
||||
elif [ -f /etc/debian_version ]; then \
|
||||
echo "Detected Debian/Ubuntu"; \
|
||||
sudo apt-get update; \
|
||||
sudo apt-get install -y p7zip-full transmission-cli; \
|
||||
echo "Syncing assets into package for uv tool install..."; \
|
||||
rm -rf hate_crack/hashcat-utils hate_crack/princeprocessor; \
|
||||
cp -R hashcat-utils hate_crack/; \
|
||||
cp -R princeprocessor hate_crack/; \
|
||||
rm -rf hate_crack/hashcat-utils/.git hate_crack/princeprocessor/.git; \
|
||||
uv tool install .; \
|
||||
echo "Cleaning up vendored assets from working tree..."; \
|
||||
rm -rf hate_crack/hashcat-utils hate_crack/princeprocessor; \
|
||||
else \
|
||||
echo "Unsupported OS. Please install dependencies manually."; \
|
||||
$(MAKE) clean-vendor; \
|
||||
exit 1; \
|
||||
fi
|
||||
@uv tool install .
|
||||
@$(MAKE) clean-vendor
|
||||
|
||||
reinstall: uninstall install
|
||||
|
||||
|
||||
@@ -139,7 +139,7 @@ cd /path/to/hate_crack
|
||||
hate_crack <hash_file> <hash_type>
|
||||
```
|
||||
|
||||
To keep `uv tool install .` happy, run the tool from the hate_crack checkout directory or one of the auto-discovered locations below.
|
||||
Run `make install` to install the tool with all assets bundled into the package.
|
||||
|
||||
**Note:** The `hcatPath` in `config.json` is for the hashcat binary location (optional if hashcat is in PATH), not for hate_crack assets.
|
||||
|
||||
@@ -168,26 +168,19 @@ Error: Build directory /opt/hashcat/hashcat-utils does not exist.
|
||||
Expected to find expander at /opt/hashcat/hashcat-utils/bin/expander.
|
||||
```
|
||||
|
||||
This means the tool cannot find the hate_crack repository assets. The `hashcat-utils` and `princeprocessor` directories are part of the **hate_crack repository**, not the hashcat installation.
|
||||
This means the hate_crack assets were not bundled into the installed package.
|
||||
|
||||
**Understanding the paths:**
|
||||
- `hcatPath` in config.json → points to **hashcat binary location** (optional, can be in PATH)
|
||||
- `hashcat-utils/` and `princeprocessor/` → located in the **hate_crack repository directory**
|
||||
|
||||
The tool automatically searches for hate_crack assets in these locations:
|
||||
1. The directory that contains the hate_crack checkout (and includes `config.json`, `hashcat-utils/`, and `princeprocessor/`)
|
||||
2. Current working directory and parent directory
|
||||
3. `~/hate_crack`, `~/hate-crack`, or `~/.hate_crack`
|
||||
- `hashcat-utils/` and `princeprocessor/` → bundled into the package by `make install`
|
||||
|
||||
**Solution:**
|
||||
Run `hate_crack` from within the repository directory:
|
||||
Reinstall using the Makefile, which vendors the assets into the package:
|
||||
```bash
|
||||
cd /opt/hate_crack # or wherever you cloned the repository
|
||||
hate_crack <hash_file> <hash_type>
|
||||
cd /path/to/hate_crack # the repository checkout
|
||||
make install
|
||||
```
|
||||
|
||||
If the assets live elsewhere, update `"hcatPath"` in `config.json` to point to the directory that contains `hashcat-utils` and `princeprocessor`.
|
||||
|
||||
**Example config.json:**
|
||||
```json
|
||||
{
|
||||
|
||||
+5
-13
@@ -3,26 +3,18 @@
|
||||
## Overview
|
||||
The test suite uses mocked API responses and local fixtures so it can run without external services (Hashview, Hashmob, Weakpass). Most tests are fast and run entirely offline. Live network checks and system dependency checks are now opt-in via environment variables.
|
||||
|
||||
## Important: Asset Location (hcatPath)
|
||||
## Important: Asset Location
|
||||
|
||||
The application requires access to `hashcat-utils` and `princeprocessor` as subdirectories. When running tests or the tool outside the repository directory, configure the asset location in `config.json` by setting `hcatPath`:
|
||||
The application requires `hashcat-utils` and `princeprocessor` as subdirectories of the package. When installed via `make install`, these are vendored into the package automatically.
|
||||
|
||||
```json
|
||||
{
|
||||
"hcatPath": "/path/to/hate_crack",
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Then run tests or the tool normally:
|
||||
For development, run tests from the repository directory:
|
||||
|
||||
```bash
|
||||
cd /path/to/hate_crack
|
||||
uv run pytest -v
|
||||
# or
|
||||
hate_crack <hash_file> <hash_type>
|
||||
```
|
||||
|
||||
If `hcatPath` is not set (empty string), the application will search the current directory and parent directory for these assets.
|
||||
**Note:** `hcatPath` in `config.json` is for the **hashcat binary location** (optional if hashcat is in PATH), not for hate_crack assets.
|
||||
|
||||
## Changes Made
|
||||
|
||||
|
||||
+24
-55
@@ -111,34 +111,6 @@ def _resolve_config_destination():
|
||||
return os.getcwd()
|
||||
|
||||
|
||||
def _resolve_hate_path(package_path, config_dict=None):
|
||||
# Try to use hcatPath from config.json if it's set and contains assets
|
||||
if config_dict and config_dict.get("hcatPath"):
|
||||
assets_path = config_dict.get("hcatPath")
|
||||
if _has_hate_crack_assets(assets_path):
|
||||
return assets_path
|
||||
|
||||
# Check common locations for the repo
|
||||
for candidate in _candidate_roots():
|
||||
if _has_hate_crack_assets(candidate):
|
||||
return candidate
|
||||
|
||||
# When installed as a tool, assets should be defined in config.json hcatPath
|
||||
# If not set, default to package path (which may not have assets)
|
||||
if _has_hate_crack_assets(package_path):
|
||||
return package_path
|
||||
|
||||
# Last resort: return package_path, but this likely means assets are missing
|
||||
if not config_dict or not config_dict.get("hcatPath"):
|
||||
print(
|
||||
"\nWarning: Could not find hate_crack assets (hashcat-utils, princeprocessor)."
|
||||
)
|
||||
print("Set 'hcatPath' in config.json to the installation directory:")
|
||||
print(' "hcatPath": "/path/to/hate_crack"')
|
||||
print("Or run from the repository directory where these assets are located.\n")
|
||||
|
||||
return package_path
|
||||
|
||||
|
||||
def _ensure_hashfile_in_cwd(hashfile_path):
|
||||
"""Ensure hashfile path points to cwd to keep output files in execution dir."""
|
||||
@@ -167,13 +139,22 @@ def _ensure_hashfile_in_cwd(hashfile_path):
|
||||
return hashfile_path
|
||||
|
||||
|
||||
# First get a temporary path to load config
|
||||
_initial_package_path = os.path.dirname(os.path.realpath(__file__))
|
||||
# hate_path is where hate_crack assets live (hashcat-utils, princeprocessor, etc.)
|
||||
# When installed via `make install`, assets are vendored into the package directory.
|
||||
# During development, assets live in the repo root (parent of the package directory).
|
||||
_package_path = os.path.dirname(os.path.realpath(__file__))
|
||||
_repo_root = os.path.dirname(_package_path)
|
||||
if os.path.isdir(os.path.join(_package_path, "hashcat-utils")):
|
||||
hate_path = _package_path
|
||||
elif os.path.isdir(os.path.join(_repo_root, "hashcat-utils")):
|
||||
hate_path = _repo_root
|
||||
else:
|
||||
hate_path = _package_path
|
||||
_config_path = _resolve_config_path()
|
||||
if not _config_path:
|
||||
print("Initializing config.json from config.json.example")
|
||||
src_config = os.path.abspath(
|
||||
os.path.join(_initial_package_path, "config.json.example")
|
||||
os.path.join(_package_path, "config.json.example")
|
||||
)
|
||||
config_dir = _resolve_config_destination()
|
||||
dst_config = os.path.abspath(os.path.join(config_dir, "config.json"))
|
||||
@@ -188,22 +169,10 @@ with open(_config_path) as config:
|
||||
config_dir = os.path.dirname(_config_path)
|
||||
defaults_path = os.path.join(config_dir, "config.json.example")
|
||||
if not os.path.isfile(defaults_path):
|
||||
defaults_path = os.path.join(_initial_package_path, "config.json.example")
|
||||
defaults_path = os.path.join(_package_path, "config.json.example")
|
||||
with open(defaults_path) as defaults:
|
||||
default_config = json.load(defaults)
|
||||
|
||||
# Now resolve hate_path using config
|
||||
hate_path = _resolve_hate_path(_initial_package_path, config_parser)
|
||||
|
||||
# If hate_path differs from initial path, reload config from the new location
|
||||
if hate_path != _initial_package_path:
|
||||
if os.path.isfile(hate_path + "/config.json"):
|
||||
with open(hate_path + "/config.json") as config:
|
||||
config_parser = json.load(config)
|
||||
if os.path.isfile(hate_path + "/config.json.example"):
|
||||
with open(hate_path + "/config.json.example") as defaults:
|
||||
default_config = json.load(defaults)
|
||||
|
||||
try:
|
||||
hashview_url = config_parser["hashview_url"]
|
||||
except KeyError as e:
|
||||
@@ -241,14 +210,11 @@ def ensure_binary(binary_path, build_dir=None, name=None):
|
||||
"\nThe hate_crack assets (hashcat-utils, princeprocessor) could not be found."
|
||||
)
|
||||
print(
|
||||
"These are part of the hate_crack repository, not hashcat installation."
|
||||
"\nRun 'make install' from the repository directory to install with assets:"
|
||||
)
|
||||
print("\nPlease run hate_crack from the repository directory:")
|
||||
print(" cd /path/to/hate_crack && hate_crack <hash_file> <hash_type>")
|
||||
print(
|
||||
'\nOr set "hcatPath" in config.json to the hate_crack directory that contains hashcat-utils and princeprocessor:'
|
||||
" cd /path/to/hate_crack && make install"
|
||||
)
|
||||
print(' "hcatPath": "/path/to/hate_crack"')
|
||||
quit(1)
|
||||
|
||||
# Binary missing - need to build
|
||||
@@ -265,16 +231,20 @@ def ensure_binary(binary_path, build_dir=None, name=None):
|
||||
return binary_path
|
||||
|
||||
|
||||
# NOTE: hcatPath is for hashcat binary location, NOT for hate_crack assets
|
||||
# If empty in config, we fall back to hate_path as a convenience
|
||||
# But hashcat-utils and princeprocessor should ALWAYS use hate_path
|
||||
hcatPath = config_parser.get("hcatPath", "") or hate_path
|
||||
# NOTE: hcatPath is the hashcat install directory, NOT for hate_crack assets.
|
||||
# hashcat-utils and princeprocessor should ALWAYS use hate_path.
|
||||
hcatPath = config_parser.get("hcatPath", "")
|
||||
hcatBin = config_parser["hcatBin"]
|
||||
# If hcatBin is not absolute and hcatPath is set, construct full path from hcatPath + hcatBin
|
||||
if not os.path.isabs(hcatBin) and hcatPath:
|
||||
_candidate = os.path.join(hcatPath, hcatBin)
|
||||
if os.path.isfile(_candidate):
|
||||
hcatBin = _candidate
|
||||
# When hcatPath is not configured, discover it from the hashcat binary in PATH
|
||||
if not hcatPath:
|
||||
_which = shutil.which(hcatBin)
|
||||
if _which:
|
||||
hcatPath = os.path.dirname(os.path.realpath(_which))
|
||||
hcatTuning = config_parser["hcatTuning"]
|
||||
hcatWordlists = config_parser["hcatWordlists"]
|
||||
hcatOptimizedWordlists = config_parser["hcatOptimizedWordlists"]
|
||||
@@ -621,8 +591,7 @@ hcatPrinceBaseList = _normalize_wordlist_setting(hcatPrinceBaseList, wordlists_d
|
||||
|
||||
if not SKIP_INIT:
|
||||
# Verify hashcat binary is available
|
||||
# hcatPath is for assets (hashcat-utils, princeprocessor), not hashcat binary location
|
||||
# hcatBin should be in PATH or be an absolute path
|
||||
# hcatBin should be in PATH or be an absolute path (resolved from hcatPath + hcatBin if configured)
|
||||
try:
|
||||
if os.path.isabs(hcatBin):
|
||||
if not os.path.isfile(hcatBin):
|
||||
|
||||
@@ -28,8 +28,7 @@ def test_hashcat_utils_uses_hate_path_not_hcat_path(tmp_path, monkeypatch):
|
||||
assert os.path.isdir(main.hate_path)
|
||||
assert os.path.isdir(os.path.join(main.hate_path, "hashcat-utils"))
|
||||
|
||||
# The hcatPath might be different (fallback to hate_path if empty)
|
||||
# But utilities should ALWAYS use hate_path
|
||||
# hcatPath is the hashcat install directory, not the hate_crack package directory
|
||||
assert main.hcatPath is not None
|
||||
|
||||
# Key assertion: even if hcatPath != hate_path,
|
||||
|
||||
@@ -28,7 +28,7 @@ def test_ensure_binary_error_message(monkeypatch, capsys):
|
||||
captured = capsys.readouterr()
|
||||
assert "Build directory" in captured.out or "does not exist" in captured.out
|
||||
assert "hate_crack" in captured.out.lower() # Should mention hate_crack assets
|
||||
assert "hcatPath" in captured.out or "repository" in captured.out
|
||||
assert "make install" in captured.out
|
||||
|
||||
|
||||
def test_ensure_binary_with_existing_binary():
|
||||
|
||||
Reference in New Issue
Block a user