Three unrelated test issues were masking the fingerprint regression
above and need to be green for the suite to be trustworthy:
1. tests/test_cli_flags.py: 7 tests monkeypatched input() to return "5",
but in the no-hashfile main menu "5" enters the Wordlist Tools
submenu and then loops forever on "Split by Length" / "File not
found". Changed to "7" (Exit), the documented exit option.
2. tests/test_fingerprint_expander_and_hybrid.py: the iter-based
lineCount mock (iter([1,1,1])) raised StopIteration because
_run_hcat_cmd now also calls lineCount once per invocation when
notifications fire. Replaced with a constant `lambda _p: 1` so the
test no longer couples to internal call counts.
3. tests/test_submodule_hashcat_utils.py: `git submodule update --init`
exits 0 in git worktrees but does not populate submodule
directories. The test failed environmentally for anyone running it
from a worktree. After the init attempt, if the dir is still empty,
pytest.skip with a clear message rather than fail - preserves the
original intent for normal checkouts.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
When no hashes have been cracked yet, the fingerprint attack's expander
pipeline produces an empty {hash}.expanded file. Previously the function
would still launch a hashcat combinator session against two empty
wordlists (and, when invoked via the menu, six more hashcat sessions
from the secondary hybrid pass) - wasting cycles and creating confusing
empty intermediate files.
Add an early-exit guard after the expander pipeline: if .expanded is
empty, print an informative skip message and break out of the loop
before invoking hashcat or hcatHybrid.
Mirrors the existing "if hcatNewPasswords > 0" guard pattern in
hcatRecycle.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Resolves Dependabot alert #1 — vulnerable pytest tmpdir handling
(< 9.0.3) in HashcatRosetta/requirements.txt. Upstream v0.2.0
drops pytest from runtime requirements and now depends on click
for its CLI/formatting module, so add click>=8.0.0 to hate_crack
runtime deps to keep display_rule_opcodes_summary functional.
wordlist_optimize worker called wordlist_subtract_single (rli2.bin), which
requires both files to be lexicographically sorted. splitlen.bin preserves
insertion order, so rli2.bin silently missed duplicates. Switch to
wordlist_subtract (rli.bin), which loads the remove-list into a hash set and
is order-independent. Also add "(comma-separated)" to the input paths prompt.
Update worker tests to patch wordlist_subtract instead of wordlist_subtract_single.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove `allow_multiple=True` from wordlist_optimize handler to avoid
AttributeError when the return value is a list rather than a str
- Remove redundant `import tempfile` inside wordlist_optimize worker body
(tempfile is already imported at module level on line 29)
- Add TestWordlistOptimizeWorker with 6 tests covering: fast-path
(empty outdir), merge-path (subtract+append), new-length copy,
splitlen failure, subtract failure, and missing-input skip
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds wordlist_optimize worker to main.py that consolidates multiple
wordlists into per-length deduplicated files using splitlen.bin and
rli2.bin. Wires handler in attacks.py and registers it as option 8 in
the Wordlist Tools submenu. Adds 16 tests covering happy path, empty
input, missing files, empty outdir, failure path, and submenu dispatch.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Switch default from simple-term-menu (arrow-key) to plain numbered
input so all keys including 10+ can be selected by typing a number;
arrow-key mode is now opt-in via HATE_CRACK_ARROW_MENU=1
- Right-align key numbers within brackets so single- and multi-digit
items line up: [ 1] through [99]
- Use [key] format consistently in both plain and arrow-key modes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Menu options jumped from 9 to 13 because items 10-12 were removed
historically but remaining items kept their old numbers. Renumbers
the contiguous attack block to 10-21, closing the gap.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Rule numbers entered as N-M now expand to all integers in that range
before lookup, matching user expectation that 138-141 selects rules
138 through 141 sequentially. Also catches ValueError alongside
IndexError when a token cannot be converted to int.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Move simple-term-menu from the [tui] optional extra into the main
dependencies list so arrow-key menu navigation works out of the box.
Users can still opt into the plain numbered menu with
HATE_CRACK_PLAIN_MENU=1.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add transmission-cli package (provides transmission-remote binary)
- Fix SETUPTOOLS_SCM_PRETEND_VERSION placement before RUN make install
- Fix PATH to use /root/.local/bin and include venv bin
- Switch TransmissionSession.add() from watch-dir polling to transmission-remote -a
- Remove --no-auth flag (unrecognized in transmission-remote 4.1.0)
- Add test_docker_torrent_downloads_wordlists E2E test
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Transmission's watch dir scanner runs every ~10s, so a 10s deadline
could expire before the first scan completes. 30s gives 2-3 scan
cycles of headroom.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Suppress transmission-daemon stdout/stderr (background process)
- Create a watch/ subdir in the session temp config dir; start daemon
with --watch-dir instead of --no-watch-dir
- Replace transmission-remote -a with shutil.copy2 into the watch dir,
then poll until the daemon picks it up
- Save .torrent metadata files to tempfile.gettempdir() instead of the
wordlist directory; update cleanup to match
- Update TransmissionSession.add tests to cover the new watch-dir flow
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
After make install, run uv sync --reinstall-package hate_crack so
setuptools-scm regenerates the version from the new git tag. Without
this, the installed version stays at the old value and the update
checker loops indefinitely.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
_run_upgrade now runs `git pull && git fetch --tags && make install`
instead of the bespoke _install_system_deps function. make install is
idempotent, handles all platforms, installs system deps (transmission-
daemon, p7zip), rebuilds the Python package, and updates the CLI shim.
Remove the now-unnecessary uv binary pre-check (make install locates
it) and its stale test.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add _install_system_deps() called by _run_upgrade() after a successful
git pull. Installs transmission-daemon (Linux) or transmission-cli brew
formula (macOS) so users who upgrade don't need to re-run make install
manually. Also corrects _run_upgrade to exit 1 on failure.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Prevent implicit None return when no data row matches the expected
transmission-remote --info-files format. Also clarify README macOS
install note.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Delete wordlists/kill_transmission.sh (replaced by Python extraction).
Update Makefile, Dockerfile.test, lima config, README, TESTING.md, and
test_dependencies.py to reference transmission-daemon/transmission-remote
instead of transmission-cli.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>