1
0
mirror of https://github.com/Z4nzu/hackingtool.git synced 2026-06-09 00:16:18 +02:00
Files
hackingtool/core.py
T

299 lines
9.9 KiB
Python
Raw Normal View History

import os
import sys
import webbrowser
from collections.abc import Callable
from platform import system
from rich import box
2025-10-14 02:02:18 -04:00
from rich.console import Console
from rich.panel import Panel
from rich.prompt import Prompt
2025-10-14 02:02:18 -04:00
from rich.table import Table
from rich.theme import Theme
from rich.traceback import install
2025-10-14 02:02:18 -04:00
from constants import (
THEME_PRIMARY, THEME_BORDER, THEME_ACCENT,
THEME_SUCCESS, THEME_ERROR, THEME_WARNING,
THEME_DIM, THEME_ARCHIVED, THEME_URL,
)
2025-10-14 02:02:18 -04:00
# Enable rich tracebacks globally
2025-10-14 02:02:18 -04:00
install()
_theme = Theme({
"purple": "#7B61FF",
"success": THEME_SUCCESS,
"error": THEME_ERROR,
"warning": THEME_WARNING,
"archived": THEME_ARCHIVED,
"url": THEME_URL,
"dim": THEME_DIM,
})
# Single shared console — all tool files do: from core import console
2025-10-14 02:02:18 -04:00
console = Console(theme=_theme)
2020-08-14 16:41:59 +05:30
def clear_screen():
2022-06-13 12:56:48 +02:00
os.system("cls" if system() == "Windows" else "clear")
2020-08-14 16:41:59 +05:30
def validate_input(ip, val_range: list) -> int | None:
"""Return the integer if it is in val_range, else None."""
if not val_range:
return None
2020-08-14 16:41:59 +05:30
try:
ip = int(ip)
if ip in val_range:
return ip
except (TypeError, ValueError):
pass
2022-06-13 12:56:48 +02:00
return None
2020-08-14 16:41:59 +05:30
class HackingTool:
TITLE: str = ""
DESCRIPTION: str = ""
INSTALL_COMMANDS: list[str] = []
UNINSTALL_COMMANDS: list[str] = []
RUN_COMMANDS: list[str] = []
OPTIONS: list[tuple[str, Callable]] = []
PROJECT_URL: str = ""
# OS / capability metadata
SUPPORTED_OS: list[str] = ["linux", "macos"]
REQUIRES_ROOT: bool = False
REQUIRES_WIFI: bool = False
REQUIRES_GO: bool = False
REQUIRES_RUBY: bool = False
REQUIRES_JAVA: bool = False
REQUIRES_DOCKER: bool = False
# Archived tool flags
ARCHIVED: bool = False
ARCHIVED_REASON: str = ""
2020-08-14 16:41:59 +05:30
2025-10-14 02:02:18 -04:00
def __init__(self, options=None, installable=True, runnable=True):
2022-06-13 12:59:39 +02:00
options = options or []
if not isinstance(options, list):
raise TypeError("options must be a list of (option_name, option_fn) tuples")
self.OPTIONS = []
if installable:
self.OPTIONS.append(("Install", self.install))
if runnable:
self.OPTIONS.append(("Run", self.run))
self.OPTIONS.extend(options)
2020-08-14 16:41:59 +05:30
def show_info(self):
2025-10-14 02:02:18 -04:00
desc = f"[cyan]{self.DESCRIPTION}[/cyan]"
2020-08-14 16:41:59 +05:30
if self.PROJECT_URL:
desc += f"\n[url]🔗 {self.PROJECT_URL}[/url]"
if self.ARCHIVED:
desc += f"\n[archived]⚠ ARCHIVED: {self.ARCHIVED_REASON}[/archived]"
console.print(Panel(
desc,
title=f"[{THEME_PRIMARY}]{self.TITLE}[/{THEME_PRIMARY}]",
border_style="purple",
box=box.DOUBLE,
))
2020-08-14 16:41:59 +05:30
2025-10-14 02:02:18 -04:00
def show_options(self, parent=None):
"""Iterative menu loop — no recursion, no stack growth."""
while True:
clear_screen()
self.show_info()
table = Table(title="Options", box=box.SIMPLE_HEAVY)
table.add_column("No.", style="bold cyan", justify="center")
table.add_column("Action", style="bold yellow")
for index, option in enumerate(self.OPTIONS):
table.add_row(str(index + 1), option[0])
if self.PROJECT_URL:
table.add_row("98", "Open Project Page")
table.add_row("99", f"Back to {parent.TITLE if parent else 'Main Menu'}")
console.print(table)
raw = Prompt.ask("\n[bold cyan][?] Select an option[/bold cyan]", default="")
if not raw.strip():
continue
try:
choice = int(raw)
except ValueError:
console.print("[error]⚠ Please enter a number.[/error]")
Prompt.ask("[dim]Press Enter to continue[/dim]", default="")
continue
if choice == 99:
return
elif choice == 98 and self.PROJECT_URL:
self.show_project_page()
elif 1 <= choice <= len(self.OPTIONS):
try:
self.OPTIONS[choice - 1][1]()
except Exception:
console.print_exception(show_locals=True)
Prompt.ask("[dim]Press Enter to continue[/dim]", default="")
else:
console.print("[error]⚠ Invalid option.[/error]")
2020-08-14 16:41:59 +05:30
2025-10-14 02:02:18 -04:00
def before_install(self): pass
2020-08-14 16:41:59 +05:30
def install(self):
self.before_install()
if isinstance(self.INSTALL_COMMANDS, (list, tuple)):
for cmd in self.INSTALL_COMMANDS:
console.print(f"[warning]→ {cmd}[/warning]")
os.system(cmd)
self.after_install()
2020-08-14 16:41:59 +05:30
def after_install(self):
console.print("[success]✔ Successfully installed![/success]")
2020-08-14 16:41:59 +05:30
def before_uninstall(self) -> bool:
return True
def uninstall(self):
if self.before_uninstall():
if isinstance(self.UNINSTALL_COMMANDS, (list, tuple)):
for cmd in self.UNINSTALL_COMMANDS:
console.print(f"[error]→ {cmd}[/error]")
os.system(cmd)
self.after_uninstall()
2020-08-14 16:41:59 +05:30
2025-10-14 02:02:18 -04:00
def after_uninstall(self): pass
2020-08-14 16:41:59 +05:30
2025-10-14 02:02:18 -04:00
def before_run(self): pass
2020-08-14 16:41:59 +05:30
def run(self):
self.before_run()
if isinstance(self.RUN_COMMANDS, (list, tuple)):
for cmd in self.RUN_COMMANDS:
console.print(f"[cyan]⚙ Running:[/cyan] [bold]{cmd}[/bold]")
os.system(cmd)
self.after_run()
2020-08-14 16:41:59 +05:30
2025-10-14 02:02:18 -04:00
def after_run(self): pass
2020-08-14 16:41:59 +05:30
def show_project_page(self):
console.print(f"[url]🌐 Opening: {self.PROJECT_URL}[/url]")
2020-08-14 16:41:59 +05:30
webbrowser.open_new_tab(self.PROJECT_URL)
class HackingToolsCollection:
TITLE: str = ""
2020-08-14 16:41:59 +05:30
DESCRIPTION: str = ""
TOOLS: list = []
2020-08-14 16:41:59 +05:30
def __init__(self):
pass
def show_info(self):
console.rule(f"[{THEME_PRIMARY}]{self.TITLE}[/{THEME_PRIMARY}]", style="purple")
if self.DESCRIPTION:
console.print(f"[italic cyan]{self.DESCRIPTION}[/italic cyan]\n")
def _active_tools(self) -> list:
"""Return tools that are not archived and are OS-compatible."""
from os_detect import CURRENT_OS
return [
t for t in self.TOOLS
if not getattr(t, "ARCHIVED", False)
and CURRENT_OS.system in getattr(t, "SUPPORTED_OS", ["linux", "macos"])
]
def _archived_tools(self) -> list:
return [t for t in self.TOOLS if getattr(t, "ARCHIVED", False)]
def _incompatible_tools(self) -> list:
from os_detect import CURRENT_OS
return [
t for t in self.TOOLS
if not getattr(t, "ARCHIVED", False)
and CURRENT_OS.system not in getattr(t, "SUPPORTED_OS", ["linux", "macos"])
]
def _show_archived_tools(self):
"""Show archived tools sub-menu (option 98)."""
archived = self._archived_tools()
if not archived:
console.print("[dim]No archived tools in this category.[/dim]")
Prompt.ask("[dim]Press Enter to return[/dim]", default="")
return
while True:
clear_screen()
console.rule(f"[archived]Archived Tools — {self.TITLE}[/archived]", style="yellow")
table = Table(box=box.MINIMAL_DOUBLE_HEAD, show_lines=True)
table.add_column("No.", justify="center", style="bold yellow")
table.add_column("Tool", style="dim yellow")
table.add_column("Reason", style="dim white")
for i, tool in enumerate(archived):
reason = getattr(tool, "ARCHIVED_REASON", "No reason given")
table.add_row(str(i + 1), tool.TITLE, reason)
table.add_row("99", "Back", "")
console.print(table)
raw = Prompt.ask("[bold yellow][?] Select[/bold yellow]", default="99")
try:
choice = int(raw)
except ValueError:
continue
if choice == 99:
return
elif 1 <= choice <= len(archived):
archived[choice - 1].show_options(parent=self)
2020-08-14 16:41:59 +05:30
2025-10-14 02:02:18 -04:00
def show_options(self, parent=None):
"""Iterative menu loop — no recursion, no stack growth."""
while True:
clear_screen()
self.show_info()
active = self._active_tools()
incompatible = self._incompatible_tools()
archived = self._archived_tools()
table = Table(title="Available Tools", box=box.MINIMAL_DOUBLE_HEAD)
table.add_column("No.", justify="center", style="bold cyan")
table.add_column("Tool", style="bold yellow")
for index, tool in enumerate(active):
table.add_row(str(index), tool.TITLE)
if archived:
table.add_row("[dim]98[/dim]", f"[archived]Archived tools ({len(archived)})[/archived]")
if incompatible:
console.print(f"[dim]({len(incompatible)} tools hidden — not supported on current OS)[/dim]")
table.add_row("99", f"Back to {parent.TITLE if parent else 'Main Menu'}")
console.print(table)
raw = Prompt.ask("\n[bold cyan][?] Choose a tool[/bold cyan]", default="")
if not raw.strip():
continue
try:
choice = int(raw)
except ValueError:
console.print("[error]⚠ Please enter a number.[/error]")
continue
if choice == 99:
return
elif choice == 98 and archived:
self._show_archived_tools()
elif 0 <= choice < len(active):
try:
ret = active[choice].show_options(parent=self)
except Exception:
console.print_exception(show_locals=True)
Prompt.ask("[dim]Press Enter to continue[/dim]", default="")
else:
console.print("[error]⚠ Invalid option.[/error]")