mirror of
https://github.com/trustedsec/hate_crack.git
synced 2026-07-03 03:15:15 -07:00
274 lines
8.6 KiB
Python
274 lines
8.6 KiB
Python
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)
|