mirror of
https://github.com/trustedsec/hate_crack.git
synced 2026-07-28 14:47:22 -07:00
rule download fixes from hashmob
This commit is contained in:
+73
-1
@@ -1066,7 +1066,79 @@ def download_hashmob_rule_list():
|
||||
|
||||
def download_hashmob_rule(file_name, out_path):
|
||||
"""Download a rule file from Hashmob by file name."""
|
||||
url = f"https://hashmob.net/api/v2/downloads/research/official/hashmob_rules/{file_name}"
|
||||
hashmob_rule_urls = {
|
||||
"nsa64.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/nsa64.rule",
|
||||
"OneRuleToRuleThemAll.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/OneRuleToRuleThemAll.rule",
|
||||
"pantagrule.hashorg.v6.one.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/pantagrule.hashorg.v6.one.rule",
|
||||
"_NSAKEY.v2.dive.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/_NSAKEY.v2.dive.rule",
|
||||
"append_digits_and_special.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/append_digits_and_special.rule",
|
||||
"best64.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/best64.rule",
|
||||
"blandyuk.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/blandyuk.rule",
|
||||
"blandyuk_basic.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/blandyuk_basic.rule",
|
||||
"combinator.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/combinator.rule",
|
||||
"dive.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/dive.rule",
|
||||
"fordy10k.txt": "https://www.hashmob.net/api/v2/downloads/research/rules/fordy10k.txt",
|
||||
"fordy50k.txt": "https://www.hashmob.net/api/v2/downloads/research/rules/fordy50k.txt",
|
||||
"FordyBigBoy.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/FordyBigBoy.rule",
|
||||
"fordyv1.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/fordyv1.rule",
|
||||
"Incisive-leetspeak.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/Incisive-leetspeak.rule",
|
||||
"InsidePro-HashManager.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/InsidePro-HashManager.rule",
|
||||
"InsidePro-PasswordsPro.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/InsidePro-PasswordsPro.rule",
|
||||
"Robot-Best10.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/Robot-Best10.rule",
|
||||
"Robot_CurrentBestRules.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/Robot_CurrentBestRules.rule",
|
||||
"Robot_MyFavorite.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/Robot_MyFavorite.rule",
|
||||
"Robot_ReverseRules.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/Robot_ReverseRules.rule",
|
||||
"Robot_Top1268Rules.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/Robot_Top1268Rules.rule",
|
||||
"Robot_toporder.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/Robot_toporder.rule",
|
||||
"Top1268.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/Top1268.rule",
|
||||
"top_1500.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/top_1500.rule",
|
||||
"top_250.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/top_250.rule",
|
||||
"top_3000.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/top_3000.rule",
|
||||
"top_500.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/top_500.rule",
|
||||
"top_5000.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/top_5000.rule",
|
||||
"top_750.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/top_750.rule",
|
||||
"Fordyv2.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/Fordyv2.rule",
|
||||
"combinator_ngram.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/combinator_ngram.rule",
|
||||
"d3ad0ne.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/d3ad0ne.rule",
|
||||
"generated.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/generated.rule",
|
||||
"generated2.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/generated2.rule",
|
||||
"leetspeak.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/leetspeak.rule",
|
||||
"oscommerce.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/oscommerce.rule",
|
||||
"specific.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/specific.rule",
|
||||
"T0XlC-insert_00-99_1950-2050_toprules_0_F.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/T0XlC-insert_00-99_1950-2050_toprules_0_F.rule",
|
||||
"T0XlC-insert_space_and_special_0_F.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/T0XlC-insert_space_and_special_0_F.rule",
|
||||
"T0XlC-insert_top_100_passwords_1_G.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/T0XlC-insert_top_100_passwords_1_G.rule",
|
||||
"T0XlC.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/T0XlC.rule",
|
||||
"T0XlCv1.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/T0XlCv1.rule",
|
||||
"toggles1.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/toggles1.rule",
|
||||
"toggles2.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/toggles2.rule",
|
||||
"toggles3.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/toggles3.rule",
|
||||
"toggles4.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/toggles4.rule",
|
||||
"toggles5.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/toggles5.rule",
|
||||
"unix-ninja-leetspeak.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/unix-ninja-leetspeak.rule",
|
||||
"OneRuleToRuleThemStill.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/OneRuleToRuleThemStill.rule",
|
||||
"Pantacorn.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/Pantacorn.rule",
|
||||
"SuperUnicorn.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/SuperUnicorn.rule",
|
||||
"buka_400k.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/buka_400k.rule",
|
||||
"rockyou-30000.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/rockyou-30000.rule",
|
||||
"HashMob.100k.rule": "https://hashmob.net/api/v2/downloads/research/official/hashmob_rules/HashMob.100k.rule",
|
||||
"HashMob.10k.rule": "https://hashmob.net/api/v2/downloads/research/official/hashmob_rules/HashMob.10k.rule",
|
||||
"HashMob.150k.rule": "https://hashmob.net/api/v2/downloads/research/official/hashmob_rules/HashMob.150k.rule",
|
||||
"HashMob.1k.rule": "https://hashmob.net/api/v2/downloads/research/official/hashmob_rules/HashMob.1k.rule",
|
||||
"HashMob.20k.rule": "https://hashmob.net/api/v2/downloads/research/official/hashmob_rules/HashMob.20k.rule",
|
||||
"HashMob.50k.rule": "https://hashmob.net/api/v2/downloads/research/official/hashmob_rules/HashMob.50k.rule",
|
||||
"HashMob.5k.rule": "https://hashmob.net/api/v2/downloads/research/official/hashmob_rules/HashMob.5k.rule",
|
||||
"HashMob.75k.rule": "https://hashmob.net/api/v2/downloads/research/official/hashmob_rules/HashMob.75k.rule",
|
||||
"HashMob._100.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/HashMob._100.rule",
|
||||
"HashMob._66.rule": "https://www.hashmob.net/api/v2/downloads/research/rules/HashMob._66.rule",
|
||||
}
|
||||
url = hashmob_rule_urls.get(file_name)
|
||||
if not url:
|
||||
print(f"[i] Hashmob rule not in pinned URL list, using prefix fallback: {file_name}")
|
||||
if str(file_name).startswith("HashMob"):
|
||||
url = f"https://hashmob.net/api/v2/downloads/research/official/hashmob_rules/{file_name}"
|
||||
else:
|
||||
url = f"https://www.hashmob.net/api/v2/downloads/research/rules/{file_name}"
|
||||
api_key = get_hashmob_api_key()
|
||||
headers = {"api-key": api_key} if api_key else {}
|
||||
import time
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
import os
|
||||
import sys
|
||||
import pytest
|
||||
|
||||
import hate_crack.main as hc_main
|
||||
|
||||
|
||||
class DummyHashviewAPI:
|
||||
def __init__(self, base_url, api_key, debug=False):
|
||||
self.base_url = base_url
|
||||
self.api_key = api_key
|
||||
self.debug = debug
|
||||
self.calls = []
|
||||
|
||||
def upload_cracked_hashes(self, file_path, hash_type='1000'):
|
||||
self.calls.append(("upload_cracked_hashes", file_path, hash_type))
|
||||
return {"msg": "Cracked hashes uploaded", "count": 2}
|
||||
|
||||
def upload_wordlist_file(self, wordlist_path, wordlist_name=None):
|
||||
self.calls.append(("upload_wordlist_file", wordlist_path, wordlist_name))
|
||||
return {"msg": "Wordlist uploaded", "wordlist_id": 123}
|
||||
|
||||
def download_left_hashes(self, customer_id, hashfile_id, output_file=None):
|
||||
self.calls.append(("download_left_hashes", customer_id, hashfile_id, output_file))
|
||||
return {"output_file": output_file or f"left_{customer_id}_{hashfile_id}.txt", "size": 10}
|
||||
|
||||
def download_found_hashes(self, customer_id, hashfile_id, output_file=None):
|
||||
self.calls.append(("download_found_hashes", customer_id, hashfile_id, output_file))
|
||||
return {"output_file": output_file or f"found_{customer_id}_{hashfile_id}.txt", "size": 12}
|
||||
|
||||
def upload_hashfile(self, file_path, customer_id, hash_type, file_format=5, hashfile_name=None):
|
||||
self.calls.append(("upload_hashfile", file_path, customer_id, hash_type, file_format, hashfile_name))
|
||||
return {"msg": "Hashfile uploaded", "hashfile_id": 456}
|
||||
|
||||
def create_job(self, name, hashfile_id, customer_id, limit_recovered=False, notify_email=True):
|
||||
self.calls.append(("create_job", name, hashfile_id, customer_id, limit_recovered, notify_email))
|
||||
return {"msg": "Job created", "job_id": 789}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def _patch_hashview(monkeypatch):
|
||||
monkeypatch.setattr(hc_main, "HashviewAPI", DummyHashviewAPI)
|
||||
hc_main.hashview_api_key = "dummy"
|
||||
hc_main.hashview_url = "https://hashview.example.com"
|
||||
|
||||
|
||||
def _run_main_with_args(monkeypatch, args):
|
||||
monkeypatch.setattr(sys, "argv", ["hate_crack.py"] + args)
|
||||
with pytest.raises(SystemExit) as excinfo:
|
||||
hc_main.main()
|
||||
return excinfo.value.code
|
||||
|
||||
|
||||
def test_hashview_cli_upload_cracked(_patch_hashview, monkeypatch, tmp_path, capsys):
|
||||
cracked_file = tmp_path / "cracked.out"
|
||||
cracked_file.write_text("hash:pass\n")
|
||||
code = _run_main_with_args(
|
||||
monkeypatch,
|
||||
[
|
||||
"hashview",
|
||||
"upload-cracked",
|
||||
"--file",
|
||||
str(cracked_file),
|
||||
"--hash-type",
|
||||
"1000",
|
||||
],
|
||||
)
|
||||
captured = capsys.readouterr()
|
||||
assert code == 0
|
||||
assert "Cracked hashes uploaded" in captured.out
|
||||
|
||||
|
||||
def test_hashview_cli_upload_wordlist(_patch_hashview, monkeypatch, tmp_path, capsys):
|
||||
wordlist_file = tmp_path / "wordlist.txt"
|
||||
wordlist_file.write_text("password\n")
|
||||
code = _run_main_with_args(
|
||||
monkeypatch,
|
||||
[
|
||||
"hashview",
|
||||
"upload-wordlist",
|
||||
"--file",
|
||||
str(wordlist_file),
|
||||
"--name",
|
||||
"TestWordlist",
|
||||
],
|
||||
)
|
||||
captured = capsys.readouterr()
|
||||
assert code == 0
|
||||
assert "Wordlist uploaded" in captured.out
|
||||
|
||||
|
||||
def test_hashview_cli_download_found(_patch_hashview, monkeypatch, tmp_path, capsys):
|
||||
out_file = tmp_path / "found_1_2.txt"
|
||||
code = _run_main_with_args(
|
||||
monkeypatch,
|
||||
[
|
||||
"hashview",
|
||||
"download-found",
|
||||
"--customer-id",
|
||||
"1",
|
||||
"--hashfile-id",
|
||||
"2",
|
||||
"--out",
|
||||
str(out_file),
|
||||
],
|
||||
)
|
||||
captured = capsys.readouterr()
|
||||
assert code == 0
|
||||
assert "Downloaded" in captured.out
|
||||
assert str(out_file) in captured.out
|
||||
|
||||
|
||||
def test_hashview_cli_upload_hashfile_job(_patch_hashview, monkeypatch, tmp_path, capsys):
|
||||
hashfile = tmp_path / "hashes.txt"
|
||||
hashfile.write_text("hash1\n")
|
||||
code = _run_main_with_args(
|
||||
monkeypatch,
|
||||
[
|
||||
"hashview",
|
||||
"upload-hashfile-job",
|
||||
"--file",
|
||||
str(hashfile),
|
||||
"--customer-id",
|
||||
"1",
|
||||
"--hash-type",
|
||||
"1000",
|
||||
"--job-name",
|
||||
"TestJob",
|
||||
],
|
||||
)
|
||||
captured = capsys.readouterr()
|
||||
assert code == 0
|
||||
assert "Hashfile uploaded" in captured.out
|
||||
assert "Job created" in captured.out
|
||||
@@ -0,0 +1,273 @@
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
from hate_crack.api import HashviewAPI
|
||||
|
||||
|
||||
HATE_CRACK_SCRIPT = os.path.join(os.path.dirname(__file__), "..", "hate_crack.py")
|
||||
REPO_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
|
||||
|
||||
|
||||
def _config_has_hashview_key():
|
||||
config_path = os.path.join(REPO_ROOT, "config.json")
|
||||
if not os.path.isfile(config_path):
|
||||
return False
|
||||
try:
|
||||
with open(config_path, "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
return bool(data.get("hashview_api_key"))
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
def _ensure_customer_one():
|
||||
api = HashviewAPI(os.environ["HASHVIEW_URL"], os.environ["HASHVIEW_API_KEY"])
|
||||
try:
|
||||
customers_result = api.list_customers()
|
||||
except Exception as exc:
|
||||
pytest.skip(f"Unable to list customers from HASHVIEW_URL: {exc}")
|
||||
customers = customers_result.get("customers", []) if isinstance(customers_result, dict) else customers_result
|
||||
if not any(int(cust.get("id", 0)) == 1 for cust in customers or []):
|
||||
api.create_customer("Example Customer")
|
||||
return 1
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"args",
|
||||
[
|
||||
["hashview", "upload-cracked", "--file", "dummy.out", "--hash-type", "1000"],
|
||||
["hashview", "upload-wordlist", "--file", "dummy.txt", "--name", "TestWordlist"],
|
||||
["hashview", "download-left", "--customer-id", "1", "--hashfile-id", "2"],
|
||||
["hashview", "download-found", "--customer-id", "1", "--hashfile-id", "2"],
|
||||
[
|
||||
"hashview",
|
||||
"upload-hashfile-job",
|
||||
"--file",
|
||||
"dummy_hashes.txt",
|
||||
"--customer-id",
|
||||
"1",
|
||||
"--hash-type",
|
||||
"1000",
|
||||
"--job-name",
|
||||
"TestJob",
|
||||
],
|
||||
],
|
||||
)
|
||||
def test_hashview_subcommands_require_api_key(tmp_path, args):
|
||||
if _config_has_hashview_key():
|
||||
pytest.skip("config.json has hashview_api_key set; skip API-key missing checks.")
|
||||
|
||||
# Ensure any dummy files referenced exist to avoid confusion if the code path changes.
|
||||
for idx, arg in enumerate(args):
|
||||
if arg == "--file":
|
||||
path = tmp_path / args[idx + 1]
|
||||
path.write_text("dummy\n")
|
||||
args[idx + 1] = str(path)
|
||||
|
||||
cli_cmd = [sys.executable, HATE_CRACK_SCRIPT] + args
|
||||
result = subprocess.run(
|
||||
cli_cmd,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True,
|
||||
cwd=REPO_ROOT,
|
||||
env={**os.environ, "PYTHONUNBUFFERED": "1"},
|
||||
)
|
||||
output = result.stdout + result.stderr
|
||||
assert "Hashview API key not configured" in output
|
||||
assert result.returncode == 1
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
os.environ.get("HASHVIEW_TEST_REAL", "").lower() not in ("1", "true", "yes"),
|
||||
reason="Set HASHVIEW_TEST_REAL=1 to run live Hashview subprocess tests.",
|
||||
)
|
||||
def test_hashview_subcommands_live_downloads():
|
||||
required = ["HASHVIEW_URL", "HASHVIEW_API_KEY", "HASHVIEW_HASHFILE_ID"]
|
||||
missing = [key for key in required if not os.environ.get(key)]
|
||||
if missing:
|
||||
pytest.skip(f"Missing required env vars: {', '.join(missing)}")
|
||||
|
||||
env = {**os.environ, "PYTHONUNBUFFERED": "1"}
|
||||
base_cmd = [sys.executable, HATE_CRACK_SCRIPT, "hashview"]
|
||||
customer_id = _ensure_customer_one()
|
||||
|
||||
left_cmd = base_cmd + [
|
||||
"download-left",
|
||||
"--customer-id",
|
||||
str(customer_id),
|
||||
"--hashfile-id",
|
||||
os.environ["HASHVIEW_HASHFILE_ID"],
|
||||
]
|
||||
left = subprocess.run(
|
||||
left_cmd,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True,
|
||||
cwd=REPO_ROOT,
|
||||
env=env,
|
||||
)
|
||||
left_out = left.stdout + left.stderr
|
||||
assert left.returncode == 0, left_out
|
||||
assert "Downloaded" in left_out
|
||||
assert "left_" in left_out
|
||||
|
||||
found_cmd = base_cmd + [
|
||||
"download-found",
|
||||
"--customer-id",
|
||||
str(customer_id),
|
||||
"--hashfile-id",
|
||||
os.environ["HASHVIEW_HASHFILE_ID"],
|
||||
]
|
||||
found = subprocess.run(
|
||||
found_cmd,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True,
|
||||
cwd=REPO_ROOT,
|
||||
env=env,
|
||||
)
|
||||
found_out = found.stdout + found.stderr
|
||||
assert found.returncode == 0, found_out
|
||||
assert "Downloaded" in found_out
|
||||
assert "found_" in found_out
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
os.environ.get("HASHVIEW_TEST_REAL", "").lower() not in ("1", "true", "yes"),
|
||||
reason="Set HASHVIEW_TEST_REAL=1 to run live Hashview subprocess tests.",
|
||||
)
|
||||
def test_hashview_subcommands_live_upload_hashfile_job(tmp_path):
|
||||
required = ["HASHVIEW_URL", "HASHVIEW_API_KEY", "HASHVIEW_HASH_TYPE"]
|
||||
missing = [key for key in required if not os.environ.get(key)]
|
||||
if missing:
|
||||
pytest.skip(f"Missing required env vars: {', '.join(missing)}")
|
||||
|
||||
env = {**os.environ, "PYTHONUNBUFFERED": "1"}
|
||||
base_cmd = [sys.executable, HATE_CRACK_SCRIPT, "hashview"]
|
||||
customer_id = _ensure_customer_one()
|
||||
|
||||
hash_type = os.environ["HASHVIEW_HASH_TYPE"]
|
||||
hashfile = tmp_path / "hashes.txt"
|
||||
# Provide a simple hash-only line; ensure HASHVIEW_HASH_TYPE matches this format.
|
||||
hashfile.write_text("5f4dcc3b5aa765d61d8327deb882cf99\n")
|
||||
|
||||
cmd = base_cmd + [
|
||||
"upload-hashfile-job",
|
||||
"--file",
|
||||
str(hashfile),
|
||||
"--customer-id",
|
||||
str(customer_id),
|
||||
"--hash-type",
|
||||
hash_type,
|
||||
"--job-name",
|
||||
"TestJobSubprocess",
|
||||
]
|
||||
run = subprocess.run(
|
||||
cmd,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True,
|
||||
cwd=REPO_ROOT,
|
||||
env=env,
|
||||
)
|
||||
output = run.stdout + run.stderr
|
||||
assert run.returncode == 0, output
|
||||
assert ("Hashfile uploaded" in output) or ("Hashfile added" in output)
|
||||
assert ("Job created" in output) or ("Failed to add job" in output)
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
os.environ.get("HASHVIEW_TEST_REAL", "").lower() not in ("1", "true", "yes"),
|
||||
reason="Set HASHVIEW_TEST_REAL=1 to run live Hashview subprocess tests.",
|
||||
)
|
||||
def test_hashview_subcommands_live_upload_hashfile_job_pwdump(tmp_path):
|
||||
required = ["HASHVIEW_URL", "HASHVIEW_API_KEY"]
|
||||
missing = [key for key in required if not os.environ.get(key)]
|
||||
if missing:
|
||||
pytest.skip(f"Missing required env vars: {', '.join(missing)}")
|
||||
|
||||
env = {**os.environ, "PYTHONUNBUFFERED": "1"}
|
||||
base_cmd = [sys.executable, HATE_CRACK_SCRIPT, "hashview"]
|
||||
customer_id = _ensure_customer_one()
|
||||
|
||||
hashfile = tmp_path / "hashes_pwdump.txt"
|
||||
# Pwdump format: user:RID:LM:NTLM:::
|
||||
hashfile.write_text(
|
||||
"user:500:aad3b435b51404eeaad3b435b51404ee:5f4dcc3b5aa765d61d8327deb882cf99:::\n"
|
||||
)
|
||||
|
||||
cmd = base_cmd + [
|
||||
"upload-hashfile-job",
|
||||
"--file",
|
||||
str(hashfile),
|
||||
"--customer-id",
|
||||
str(customer_id),
|
||||
"--hash-type",
|
||||
"1000",
|
||||
"--file-format",
|
||||
"0",
|
||||
"--job-name",
|
||||
"TestJobSubprocessPwdump",
|
||||
]
|
||||
run = subprocess.run(
|
||||
cmd,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True,
|
||||
cwd=REPO_ROOT,
|
||||
env=env,
|
||||
)
|
||||
output = run.stdout + run.stderr
|
||||
assert run.returncode == 0, output
|
||||
assert ("Hashfile uploaded" in output) or ("Hashfile added" in output)
|
||||
assert ("Job created" in output) or ("Failed to add job" in output)
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
os.environ.get("HASHVIEW_TEST_REAL", "").lower() not in ("1", "true", "yes"),
|
||||
reason="Set HASHVIEW_TEST_REAL=1 to run live Hashview subprocess tests.",
|
||||
)
|
||||
def test_hashview_subcommands_live_upload_hashfile_job_hashonly(tmp_path):
|
||||
required = ["HASHVIEW_URL", "HASHVIEW_API_KEY", "HASHVIEW_HASH_TYPE"]
|
||||
missing = [key for key in required if not os.environ.get(key)]
|
||||
if missing:
|
||||
pytest.skip(f"Missing required env vars: {', '.join(missing)}")
|
||||
|
||||
env = {**os.environ, "PYTHONUNBUFFERED": "1"}
|
||||
base_cmd = [sys.executable, HATE_CRACK_SCRIPT, "hashview"]
|
||||
customer_id = _ensure_customer_one()
|
||||
|
||||
hash_type = os.environ["HASHVIEW_HASH_TYPE"]
|
||||
hashfile = tmp_path / "hashes_hashonly.txt"
|
||||
hashfile.write_text("5f4dcc3b5aa765d61d8327deb882cf99\n")
|
||||
|
||||
cmd = base_cmd + [
|
||||
"upload-hashfile-job",
|
||||
"--file",
|
||||
str(hashfile),
|
||||
"--customer-id",
|
||||
str(customer_id),
|
||||
"--hash-type",
|
||||
hash_type,
|
||||
"--file-format",
|
||||
"5",
|
||||
"--job-name",
|
||||
"TestJobSubprocessHashOnly",
|
||||
]
|
||||
run = subprocess.run(
|
||||
cmd,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True,
|
||||
cwd=REPO_ROOT,
|
||||
env=env,
|
||||
)
|
||||
output = run.stdout + run.stderr
|
||||
assert run.returncode == 0, output
|
||||
assert ("Hashfile uploaded" in output) or ("Hashfile added" in output)
|
||||
assert ("Job created" in output) or ("Failed to add job" in output)
|
||||
Reference in New Issue
Block a user