cleanup-rules.bin requires a mode argument (1=CPU, 2=GPU) and exits with
usage text otherwise, so Rule File Tools cleanup always failed. Pass the
mode (defaulting to GPU) so cleanup actually runs.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The upload previously printed only "✓ Success: OK", so there was no way
to tell how many hashes were accepted. upload_cracked_hashes now surfaces
client-side uploaded/skipped counts in its return value, and the CLI
prints them plus the server's verified/updated/unmatched breakdown when a
newer Hashview reports them (see hashview #355/#356).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
hate_crack forwarded hashcat's $HEX[...] plaintext verbatim. A Hashview
that verifies plaintext literally hashes the string "$HEX[..]" and
rejects the batch. Decode $HEX to the exact bytes the server must
re-hash and send those on the wire (body is now bytes):
- UTF-16LE modes (NTLM 1000, MSSQL 1731): latin-1 code points -> UTF-8
- raw-byte modes (0/100/300/900/1400/1700): the decoded bytes as-is
- unsafe (embedded CR/LF) or unknown modes: keep the $HEX token verbatim
and rely on a $HEX-aware server
Also fixes the NTLM validation digest to use latin-1 -> UTF-16LE so
high-byte $HEX plaintexts verify instead of being silently unverifiable.
Verified end-to-end: the emitted wire verifies against both the old
(literal) and new ($HEX-aware) Hashview verifiers.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
upload_cracked_hashes sent every hash:plaintext pair to Hashview
untouched. A single line whose plaintext doesn't match the declared
hash mode (e.g. a stray MD5 hash mixed into an NTLM list) made
Hashview reject the entire batch with an opaque
"Plaintext for hash ... was found to be invalid" error.
Add two client-side guards (default on, disable via validate=False):
1. Length filter — drop hashes whose hex width is wrong for the mode.
2. Plaintext verification — for reproducible fast modes (MD5, SHA1,
MD4, NTLM, SHA2-256/512) recompute the digest from the plaintext
($HEX[...] decoded) and skip pairs that don't match.
Skipped lines are reported with line number and reason instead of
failing the whole upload; raise clearly if nothing valid remains.
Ships a pure-Python MD4 since OpenSSL 3 dropped it from hashlib.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Shard Wordlist (option 7) now prompts for an output base path and a shard
count, then writes all N interleaved parts as base.001..base.00N in a single
pass instead of one file per modulus/offset invocation. Matches the intended
distributed-cracking workflow: split once, copy one part per node.
Updates tests and README usage docs; bumps CHANGELOG to 2.10.11.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The auto-tag workflow already published v2.10.9 for Larry's Quick Crack
wordlist fix when main was pushed. Retitle the pytest security bump to
2.10.10 (its actual auto-tag target) and add the missing 2.10.9 entry.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The pinned dev/test dependency pytest==9.0.2 is affected by the
vulnerable tmpdir-handling advisory GHSA-6w46-j5rx-g56g (pytest < 9.0.3),
Dependabot alert #1. Bump the pin to 9.0.3 to clear it. Development
scope only (test runner); no runtime dependency change. Full test
suite passes under 9.0.3. (uv.lock is gitignored, so only the
pyproject.toml pin is tracked.)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Consolidate the release notes into a single dedicated CHANGELOG.md
(Keep a Changelog format) and replace the README's inline Version
History with a pointer, so the two no longer drift.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add HashviewAPI.list_rules and download_rules wrapping the Hashview
rule endpoints. The server gzip-compresses plaintext rules on the
fly, so download_rules decompresses before saving, yielding a file
usable directly with hashcat -r. Wired into the interactive Hashview
menu (Download Rule) and the CLI (hashview download-rules
--rules-id/--output). Unknown rule ids surface the real HTTP 404.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
get_hashfile_details used 'or' fallthrough on hash_type, so MD5
(hash_type 0, falsy) resolved to the envelope 'type' string
('message') instead of 0. Select by key presence and drop the
bogus 'type' fallback.
get_hashfile_hash_type looked for file_ids/ids/hashfile_ids keys
that the endpoint never returns; it always yielded []. Read the
actual 'hashfiles' envelope array and extract each file id.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The server now returns `users` as a native JSON array (issue #229,
no double-decode), but list_customers unconditionally ran
json.loads() on it, raising TypeError and breaking the entire
customer->hashfile enumeration flow. Accept both the native array
and the legacy double-encoded string, mirroring list_wordlists.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Old clones made before the default-branch rename sit on a local `master`
whose upstream still points at the deleted refs/heads/master, so both a
bare `git pull` and `_run_upgrade()`'s `git checkout main` failed on stale
clones. The updater now fetches origin first, checks out main via
`git checkout -B main origin/main`, repairs the upstream to origin/main,
and pulls explicitly with `git pull origin main` so it never consults the
dangling branch.*.merge config. Existing dirty-branch and detached-HEAD
guards are unchanged.
Adds tests covering the renamed-clone migration and the fetch-failure bail.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The live upload-hashfile-job subprocess tests hard-failed when pointed at
a hash type the Hashview server has no cracked-hash history for: the
hashfile upload succeeds, but Hashview's task planner refuses to create a
job ("Not enough data to determine effective tasks for this hash type").
That is a server-side data limitation, not a client defect.
Treat that specific message as a skip (after asserting the hashfile
upload itself succeeded) across all three upload-job tests, so results
don't depend on which hash types have cracked data on the target
instance.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The live Hashview tests previously could only run against a remote server
configured in config.json, and the CLI ignored env-var overrides, so the
suite always hit prod. Prod runs an older Hashview whose /v1/jobs/add 500s
on a notify_email kwarg, which masked real client/server drift.
Wire the suite up to a local Hashview docker stack:
- main.py: HASHVIEW_URL / HASHVIEW_API_KEY env vars now override config.json,
so the CLI can be pointed at a local instance without editing config.
- tests/_hashview_local.py + pytest_configure: when HASHVIEW_TEST_LOCAL=1,
bring up + seed the Hashview compose stack (HASHVIEW_REPO), verify
authenticated API access, export the HASHVIEW_* env, and tear down
(HASHVIEW_KEEP=1 keeps it). Runs in configure so collection-time skipif
on HASHVIEW_TEST_REAL sees the exported env.
- tests/hashview_local_seed.py: seed an admin api_key + non-default password
(else Hashview's setup guard redirects every request to /setup), a
customer, a hashfile, and cracked "effective task" data (else /v1/jobs/add
has no tasks to schedule).
- api.py: download_left_hashes now uses GET /v1/hashfiles/<id>; the old
/v1/hashfiles/<id>/left route 404s on current servers.
- subprocess tests: assert on the CLI's actual output ("Job ID:") rather than
the literal "Job created", and strip ambient HASHVIEW_* creds from the
no-key-configured check so the env override doesn't defeat it.
- README/CLAUDE: document HASHVIEW_TEST_LOCAL and the env overrides.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The hashfile-listing route (/v1/hashfiles/hash_type/<type>) only exists
on Hashview builds from 2026-06-08+ (v0.8.3-dev). On `main` and older
servers it 404s, which surfaced as "Could not list hashfiles" and a dead
end. The download flow is now version-adaptive:
- get_all_customer_hashfiles stops sweeping after the first 404 (the
listing endpoint is absent) instead of probing every common type.
- The menu treats listing as best-effort: when no listing is available
it prints a clear note and accepts a hashfile ID typed directly (read
from the web UI), with no list-membership check. The chosen file's
type is resolved via GET /v1/getHashType/<id> and downloaded via
GET /v1/hashfiles/<id> -- both present on all server versions.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Downloading previously required knowing/typing the hash type because
Hashview only lists hashfiles per type. The download flow now sweeps
common hashcat modes (HashviewAPI.get_all_customer_hashfiles) and shows
all of the customer's uploaded hashfiles to pick from, deduped by id.
A manual hash-type prompt remains as a fallback only when nothing is
found among the common set (uncommon modes). The chosen file's real
hash type still drives the download.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The download-hashes flow scoped the customer hashfile listing to
hcatHashType, but that is None when the Hashview menu is entered
without a hashfile loaded this session -> "No hashfiles of type None
found". Since Hashview only lists hashfiles per type, prompt for a
hashcat hash-type when none is set (Q cancels back to the menu) and
use it for the listing. Downstream selection still derives the real
type from the chosen hashfile.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Continues the v0.8.3-dev API alignment beyond the hashfile-listing 404:
- download_left_hashes: "left" hashes are GET /v1/hashfiles/<id>
(returns uncracked ciphertexts), not the nonexistent /<id>/left.
- delete_job: DELETE /v1/jobs/<id>, not GET /v1/jobs/delete/<id>.
- start_job: POST /v1/jobs/start/<id>, not GET (route is POST-only).
- stop_job: Hashview has no stop route; raise NotImplementedError
pointing at delete_job rather than calling a phantom endpoint.
- found-hash bulk export: no such route exists (only single-hash
POST /v1/search); the best-effort merge is documented and degrades
gracefully on the expected 404.
Adds offline tests asserting start_job POSTs, delete_job uses DELETE,
and stop_job raises. Documents the release in README.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The customer->hashfile flow called GET /v1/hashfiles to list all
hashfiles, then filtered client-side. That route does not exist in
Hashview (confirmed against v0.8.3-dev), so it 404'd as soon as a
customer ID was entered ("Could not list hashfiles").
Hashview exposes no list-all route; the only enumeration endpoint is
GET /v1/hashfiles/hash_type/<hash_type>, which already returns
customer_id and hash_type per file. Rebuild get_customer_hashfiles on
top of get_hashfiles_by_type, scoped to the session hash type
(hcatHashType), and filter by customer. Also fix get_hashfile_details
to call GET /v1/getHashType/<id> instead of the nonexistent
/v1/hashfiles/<id>/hash_type. Remove the dead list_hashfiles wrapper.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
binascii.unhexlify().decode() returned bytes without the trailing newline
that normal rows inherit from password[-1], so HEX-encoded cracked
passwords concatenated with the next entry in the .passwords file fed to
pipal. Pipal under-counted entries and ranked corrupted mashups as base
words. Re-append \n if missing.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>