mirror of
https://github.com/trustedsec/hate_crack.git
synced 2026-06-28 17:33:31 -07:00
fixed uv tool install
This commit is contained in:
@@ -5,3 +5,5 @@ __pycache__/
|
||||
hate_crack/__pycache__/
|
||||
tests/__pycache__/
|
||||
uv.lock
|
||||
build/
|
||||
hate_crack.egg-info/
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
PREFIX ?= /usr/local
|
||||
BINDIR ?= $(PREFIX)/bin
|
||||
SCRIPT ?= hate_crack
|
||||
WRAPPER_PATH := $(BINDIR)/$(SCRIPT)
|
||||
PROJECT_ROOT := $(abspath $(dir $(lastword $(MAKEFILE_LIST))))
|
||||
ENTRYPOINT := $(PROJECT_ROOT)/hate_crack/hate_crack.py
|
||||
UV ?= uv
|
||||
|
||||
.PHONY: install clean
|
||||
|
||||
install:
|
||||
@mkdir -p $(BINDIR)
|
||||
@printf '%s\n' "#!/bin/sh" "" "$(UV) run $(ENTRYPOINT) \"\$$@\"" > $(WRAPPER_PATH)
|
||||
@chmod +x $(WRAPPER_PATH)
|
||||
@echo "Installed $(WRAPPER_PATH)"
|
||||
|
||||
clean:
|
||||
@rm -f $(WRAPPER_PATH)
|
||||
@echo "Removed $(WRAPPER_PATH)"
|
||||
@@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env python3
|
||||
import sys
|
||||
|
||||
from .hate_crack import cli_main
|
||||
|
||||
|
||||
def main() -> int:
|
||||
return cli_main() or 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Executable
+2220
File diff suppressed because it is too large
Load Diff
@@ -8,6 +8,11 @@ def _resolve_root():
|
||||
|
||||
|
||||
def _load_root_module():
|
||||
try:
|
||||
from . import _root # type: ignore
|
||||
return _root
|
||||
except Exception:
|
||||
pass
|
||||
root_path = _resolve_root()
|
||||
if not os.path.isfile(root_path):
|
||||
raise FileNotFoundError(f"Root hate_crack.py not found at {root_path}")
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
[build-system]
|
||||
requires = ["setuptools>=69"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "hate-crack"
|
||||
version = "2.0"
|
||||
@@ -10,3 +14,9 @@ dependencies = [
|
||||
"beautifulsoup4>=4.12.0",
|
||||
"ruff>=0.9.4",
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
hate_crack = "hate_crack.__main__:main"
|
||||
|
||||
[tool.setuptools.packages.find]
|
||||
include = ["hate_crack*"]
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
import os
|
||||
import sys
|
||||
import types
|
||||
import pytest
|
||||
from unittest import mock
|
||||
|
||||
import hate_crack.api as api
|
||||
|
||||
@pytest.fixture
|
||||
def fake_file(tmp_path):
|
||||
return tmp_path / "testfile.txt"
|
||||
|
||||
@pytest.fixture
|
||||
def patch_dependencies(tmp_path):
|
||||
# Patch sanitize_filename to just return the filename
|
||||
patch1 = mock.patch("hate_crack.api.sanitize_filename", side_effect=lambda x: x)
|
||||
# Patch get_hcat_wordlists_dir to return tmp_path
|
||||
patch2 = mock.patch("hate_crack.api.get_hcat_wordlists_dir", return_value=str(tmp_path))
|
||||
# Patch extract_with_7z to just return True
|
||||
patch3 = mock.patch("hate_crack.api.extract_with_7z", return_value=True)
|
||||
# Patch os.replace to do nothing
|
||||
patch4 = mock.patch("os.replace")
|
||||
# Patch os.makedirs to do nothing
|
||||
patch5 = mock.patch("os.makedirs")
|
||||
patches = [patch1, patch2, patch3, patch4, patch5]
|
||||
for p in patches:
|
||||
p.start()
|
||||
yield
|
||||
for p in patches:
|
||||
p.stop()
|
||||
|
||||
def make_mock_response(content=b"abc", total=3, status_code=200, endswith='.txt'):
|
||||
mock_resp = mock.MagicMock()
|
||||
mock_resp.__enter__.return_value = mock_resp
|
||||
mock_resp.__exit__.return_value = False
|
||||
mock_resp.iter_content = lambda chunk_size: [content]
|
||||
mock_resp.headers = {'content-length': str(total)}
|
||||
mock_resp.status_code = status_code
|
||||
mock_resp.raise_for_status = mock.Mock()
|
||||
return mock_resp
|
||||
|
||||
def test_download_success(tmp_path, patch_dependencies):
|
||||
file_name = "wordlist.txt"
|
||||
out_path = str(tmp_path / file_name)
|
||||
mock_resp = make_mock_response(content=b"abc", total=3)
|
||||
with mock.patch("hate_crack.api.requests.get", return_value=mock_resp):
|
||||
with mock.patch("builtins.open", mock.mock_open()) as m_open:
|
||||
result = api.download_official_wordlist(file_name, out_path)
|
||||
assert result is True
|
||||
m_open.assert_called() # File was opened for writing
|
||||
|
||||
def test_download_7z_triggers_extract(tmp_path, patch_dependencies):
|
||||
file_name = "archive.7z"
|
||||
out_path = str(tmp_path / file_name)
|
||||
mock_resp = make_mock_response(content=b"abc", total=3)
|
||||
with mock.patch("hate_crack.api.requests.get", return_value=mock_resp):
|
||||
with mock.patch("builtins.open", mock.mock_open()):
|
||||
with mock.patch("hate_crack.api.extract_with_7z") as m_extract:
|
||||
m_extract.return_value = True
|
||||
result = api.download_official_wordlist(file_name, out_path)
|
||||
assert result is True
|
||||
m_extract.assert_called_once()
|
||||
|
||||
def test_download_keyboard_interrupt(tmp_path, patch_dependencies):
|
||||
file_name = "wordlist.txt"
|
||||
out_path = str(tmp_path / file_name)
|
||||
# Simulate KeyboardInterrupt in requests.get context manager
|
||||
def raise_keyboard_interrupt(*a, **kw):
|
||||
raise KeyboardInterrupt()
|
||||
with mock.patch("hate_crack.api.requests.get", side_effect=raise_keyboard_interrupt):
|
||||
result = api.download_official_wordlist(file_name, out_path)
|
||||
assert result is False
|
||||
|
||||
def test_download_exception(tmp_path, patch_dependencies):
|
||||
file_name = "wordlist.txt"
|
||||
out_path = str(tmp_path / file_name)
|
||||
# Simulate generic Exception in requests.get context manager
|
||||
def raise_exception(*a, **kw):
|
||||
raise Exception("fail")
|
||||
with mock.patch("hate_crack.api.requests.get", side_effect=raise_exception):
|
||||
result = api.download_official_wordlist(file_name, out_path)
|
||||
assert result is False
|
||||
|
||||
def test_progress_bar_prints(tmp_path, patch_dependencies, capsys):
|
||||
file_name = "wordlist.txt"
|
||||
out_path = str(tmp_path / file_name)
|
||||
# Simulate a file with a known size
|
||||
content = b"x" * 8192
|
||||
mock_resp = make_mock_response(content=content, total=8192)
|
||||
with mock.patch("hate_crack.api.requests.get", return_value=mock_resp):
|
||||
with mock.patch("builtins.open", mock.mock_open()):
|
||||
result = api.download_official_wordlist(file_name, out_path)
|
||||
assert result is True
|
||||
captured = capsys.readouterr()
|
||||
assert "Downloaded" in captured.out or "Downloaded" in captured.err
|
||||
@@ -0,0 +1,53 @@
|
||||
import importlib.util
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
PROJECT_ROOT = Path(__file__).resolve().parents[1]
|
||||
CLI_SPEC = importlib.util.spec_from_file_location("hate_crack_cli", PROJECT_ROOT / "hate_crack.py")
|
||||
CLI_MODULE = importlib.util.module_from_spec(CLI_SPEC)
|
||||
CLI_SPEC.loader.exec_module(CLI_MODULE)
|
||||
|
||||
MENU_OPTION_TEST_CASES = [
|
||||
("1", CLI_MODULE._attacks, "quick_crack", "quick-crack"),
|
||||
("2", CLI_MODULE._attacks, "extensive_crack", "extensive-crack"),
|
||||
("3", CLI_MODULE._attacks, "brute_force_crack", "brute-force"),
|
||||
("4", CLI_MODULE._attacks, "top_mask_crack", "top-mask"),
|
||||
("5", CLI_MODULE._attacks, "fingerprint_crack", "fingerprint"),
|
||||
("6", CLI_MODULE._attacks, "combinator_crack", "combinator"),
|
||||
("7", CLI_MODULE._attacks, "hybrid_crack", "hybrid"),
|
||||
("8", CLI_MODULE._attacks, "pathwell_crack", "pathwell"),
|
||||
("9", CLI_MODULE._attacks, "prince_attack", "prince"),
|
||||
("10", CLI_MODULE._attacks, "yolo_combination", "yolo"),
|
||||
("11", CLI_MODULE._attacks, "middle_combinator", "middle"),
|
||||
("12", CLI_MODULE._attacks, "thorough_combinator", "thorough"),
|
||||
("13", CLI_MODULE._attacks, "bandrel_method", "bandrel"),
|
||||
("91", CLI_MODULE, "download_hashmob_rules", "hashmob-rules"),
|
||||
("92", CLI_MODULE, "weakpass_wordlist_menu", "weakpass-menu"),
|
||||
("93", CLI_MODULE, "download_hashmob_wordlists", "hashmob-wordlists"),
|
||||
("94", CLI_MODULE, "weakpass_wordlist_menu", "weakpass-menu-secondary"),
|
||||
("95", CLI_MODULE, "hashview_api", "hashview"),
|
||||
("96", CLI_MODULE, "pipal", "pipal"),
|
||||
("97", CLI_MODULE, "export_excel", "export-excel"),
|
||||
("98", CLI_MODULE, "show_results", "show-results"),
|
||||
("99", CLI_MODULE, "show_readme", "show-readme"),
|
||||
("100", CLI_MODULE, "quit_hc", "quit"),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("option_key", "target_module", "target_attr", "expected_prefix"),
|
||||
MENU_OPTION_TEST_CASES,
|
||||
)
|
||||
def test_main_menu_option_returns_expected(monkeypatch, option_key, target_module, target_attr, expected_prefix):
|
||||
sentinel = f"{expected_prefix}-{option_key}"
|
||||
monkeypatch.setattr(
|
||||
target_module,
|
||||
target_attr,
|
||||
lambda *args, **kwargs: sentinel,
|
||||
)
|
||||
|
||||
options = CLI_MODULE.get_main_menu_options()
|
||||
assert option_key in options, f"Menu option {option_key} must exist"
|
||||
handler = options[option_key]
|
||||
assert handler() == sentinel
|
||||
Reference in New Issue
Block a user