README.md

43 kB · 873 linesDownload
<a id="readme-top"></a><!-- PROJECT SHIELDS -->[![MIT License][license-shield]][license-url][![Python 3.10+][python-shield]][python-url][![Built with Textual][textual-shield]][textual-url][![Platform][platform-shield]][platform-url]<!-- PROJECT LOGO --><br /><div align="center">```      ██     ██  ▄▄▄  ▄▄ ▄▄ ▄▄▄▄▄   ██████ ▄▄▄   ▄▄▄  ▄▄     ▄▄▄▄      ██ ▄█▄ ██ ██▀██ ██▄██ ██▄▄      ██  ██▀██ ██▀██ ██    ███▄▄       ▀██▀██▀  ██▀██  ▀█▀  ██▄▄▄     ██  ▀███▀ ▀███▀ ██▄▄▄ ▄▄██▀```  <h3 align="center">WaveTools</h3>  <p align="center">    An animated terminal UI (TUI) toolbox for network, OSINT and everyday utility tools — with a live-reloading plugin system at its core.    <br />    <a href="#-plugin-architecture"><strong>Explore the architecture »</strong></a>    <br />    <br />    <a href="#-tool-catalog">Browse the Tool Catalog</a>  </p></div>> [!NOTE]> WaveTools includes **dual-use network, OSINT and website-recon tools** (port/host scanners, subdomain/directory finders, dictionary hash/ZIP crackers). They are for **authorized** use only — your own systems and accounts, engagements you are contracted for, CTFs, and education. See the [Security & Legal Notice](#-security--legal-notice).<!-- TABLE OF CONTENTS --><details>  <summary>Table of Contents</summary>  <ol>    <li><a href="#about-the-project">About The Project</a></li>    <li><a href="#built-with">Built With</a></li>    <li>      <a href="#getting-started">Getting Started</a>      <ul>        <li><a href="#prerequisites">Prerequisites</a></li>        <li><a href="#installation">Installation</a></li>      </ul>    </li>    <li>      <a href="#usage">Usage</a>      <ul>        <li><a href="#keybindings">Keybindings</a></li>      </ul>    </li>    <li>      <a href="#-plugin-architecture">Plugin Architecture</a>      <ul>        <li><a href="#components-at-a-glance">Components at a Glance</a></li>        <li><a href="#file-layout">File Layout</a></li>        <li><a href="#tool-lifecycle">Tool Lifecycle</a></li>        <li><a href="#where-tools-come-from">Where Tools Come From</a></li>      </ul>    </li>    <li>      <a href="#writing-a-plugin">Writing a Plugin</a>      <ul>        <li><a href="#adding-a-new-category">Adding a New Category</a></li>        <li><a href="#python-plugin-py">Python Plugin (<code>.py</code>)</a></li>        <li><a href="#external-command-plugin-json">External Command Plugin (<code>.json</code>)</a></li>      </ul>    </li>    <li>      <a href="#plugin-api-reference">Plugin API Reference</a>      <ul>        <li><a href="#the-tool-manifest">The <code>TOOL</code> Manifest</a></li>        <li><a href="#step-kinds">Step Kinds</a></li>        <li><a href="#validation--conditions">Validation &amp; Conditions</a></li>        <li><a href="#the-toolresult-format">The <code>ToolResult</code> Format</a></li>        <li><a href="#the-jobcontext-streaming-tools">The <code>JobContext</code> (Streaming Tools)</a></li>        <li><a href="#plugin_api-helpers">The <code>plugin_api</code> Helpers</a></li>        <li><a href="#persistent-plugin-storage-pluginstore">Persistent Plugin Storage</a></li>        <li><a href="#versioning--compatibility">Versioning &amp; Compatibility</a></li>      </ul>    </li>    <li><a href="#configuration">Configuration</a></li>    <li><a href="#-tool-catalog">Tool Catalog</a></li>    <li><a href="#-security--legal-notice">Security &amp; Legal Notice</a></li>    <li><a href="#roadmap">Roadmap</a></li>    <li><a href="#contributing">Contributing</a></li>    <li><a href="#license">License</a></li>    <li><a href="#contact">Contact</a></li>    <li><a href="#acknowledgments">Acknowledgments</a></li>  </ol></details>---## About The ProjectWaveTools is an animated terminal UI (TUI), built on [Textual](https://textual.textualize.io/), for security, OSINT, network, and utility tools. Every tool is driven through the same guided step-by-step flow — **Banner → Description → Questions → Live Run → Result** — all wrapped in a continuously animated gradient border.The real value of WaveTools is its **plugin system**: tools aren't hardcoded menu entries, they're loaded at runtime from a folder. Drop a Python file with a `TOOL` dict and a `run()` function into `wavetools/tools/`, restart, and it shows up in the menu — categories, validation, streaming output, and result rendering all come for free.Highlights:*  **Animated TUI** with selectable gradient themes, ASCII-only fallback mode, and a full onboarding wizard on first launch.*  **Runtime plugin loading** — native Python plugins *or* JSON manifests for external commands, no core changes required.*  **66 tools** across Network, OSINT, Roblox, Website, Generator, Crypto and Minecraft — plus built-in System/Text utilities.*  **Stable plugin API** (`plugin_api`) with fail-soft HTTP, file, clipboard, and browser helpers.*  **Reusable input folder** for tokens, webhooks, cookies, proxies, and wordlists — fill fields with `Ctrl+F` instead of retyping secrets every run.*  **Multi-language UI** — English, German, Spanish, Russian.*  **Versioned plugin API** with graceful compatibility/legacy handling and per-tool dependency checks.<p align="right">(<a href="#readme-top">back to top</a>)</p>### Built With* [![Python][Python-badge]][Python-url]* [![Textual][Textual-badge]][Textual-url]* [![Rich][Rich-badge]][Rich-url]* [![Cryptography][Cryptography-badge]][Cryptography-url]* [![Pillow][Pillow-badge]][Pillow-url]<p align="right">(<a href="#readme-top">back to top</a>)</p>---## Getting Started### Prerequisites* **Python 3.10+** (CPython). All core dependencies are pinned in `requirements.txt`.* On Windows, `install.bat` / `start.bat` handle the Python launcher detection for you.### Installation1. Get the code (clone your fork / this repository) and enter the folder   ```sh   cd WaveTools   ```2. Install dependencies   ```sh   pip install -r requirements.txt   ```   On Windows you can instead double-click / run `install.bat`, which finds a Python launcher, upgrades `pip`, and installs everything for you.3. Launch WaveTools   ```sh   python run.py   ```   On Windows, `start.bat` does the same with launcher auto-detection.<p align="right">(<a href="#readme-top">back to top</a>)</p>---## UsageOn first launch, a one-time setup wizard walks you through language, theme, browser, ASCII mode, and folder configuration. After that, pick a category on the left, pick a tool, answer the guided questions, and watch it run.### KeybindingsAlso always shown in the status bar at the bottom of the app:| Key | Effect ||-----|--------|| `Enter` | Confirm selection / submit step / run tool || `↑ / ↓` | Move selection / scroll || `←` `→` | Switch category || `S` then `Enter` | Skip the current question (uses the default) || `Esc` | Go back one step / to the menu / quit || `Ctrl+R` | Reset the tool back to its first question || `Ctrl+V` | Paste into a text field · `Ctrl+C` copy the result || `Ctrl+F` | Fill a text field from the input folder (when matching entries exist) || `S` (main menu) | Settings (language, theme, browser, ASCII mode, folders, editor) |<p align="right">(<a href="#readme-top">back to top</a>)</p>---## Plugin Architecture### Components at a Glance```                          ┌──────────────────────────────────────┐                          │               run.py                  │                          │   from wavetools.core.app import main │                          └──────────────────┬─────────────────────┘                                             │                 ┌───────────────────────────▼────────────────────────────┐                 │                  wavetools/app.py                       │                 │   WaveToolsApp (Textual App) + all Screens              │                 │   Loader → Start → Main (Categories+Tools) → ToolScreen │                 └───────┬───────────────────────────────┬─────────────────┘                         │                               │        ┌────────────────▼──────────────┐   ┌────────────▼──────────────────┐        │  builtin_tools.builtin_tools()│   │ plugins.discover_all(dir, …)   │        │  hardcoded built-in tools      │   │ loads tools from ./tools/      │        │  (System, Utility, Faker, …)   │   │  • *.py   → Python plugin       │        └────────────────┬──────────────┘   │  • *.json → external command    │                         │                   └────────────┬──────────────────┘                         └───────────────┬────────────────┘                                         ▼                            self.all_tools = builtin + plugins                                         │        ┌────────────────────────────────┼─────────────────────────────────┐        │ Support modules                                                    │        │  gradients.py  Themes/gradients     browsers.py  Browser picking  │        │  config.py     ~/.wavetools/config  clipboard.py Clipboard        │        │  plugin_api.py stable plugin API    ascii_art.py Banners/glyphs   │        │  faker_render.py Faker images (PIL)                                │        └──────────────────────────────────────────────────────────────────┘```Core idea: **the UI knows nothing about individual tools.** A tool is a `Tool` data object with a `run`/`job` function. `ToolScreen` asks the declared questions, calls `run`/`job`, and renders the returned `ToolResult`. That's why a hand-written plugin looks and behaves exactly like a built-in tool.### File Layout```wavetools/├── run.py                  # entry point: python run.py├── requirements.txt├── README.md                (this file)└── wavetools/               # the actual package    ├── __main__.py         # python -m wavetools    ├── core/               # app engine + shared non-tool modules    │   ├── app.py          # Textual app + screens (UI)    │   ├── builtin_tools.py # Tool/Step/ToolResult/JobContext + built-in tools    │   ├── plugins.py      # plugin loader (discover_all) for ../tools    │   ├── plugin_api.py   # stable helper API for plugins (http_get, save_file, …)    │   ├── config.py       # persistent config (~/.wavetools/config.json)    │   ├── gradients.py    # color gradients / themes    │   ├── browsers.py     # browser detection & selection    │   ├── clipboard.py    # clipboard (pyperclip)    │   ├── ascii_art.py    # logo / wave glyphs    │   ├── i18n.py         # UI translations (en/de/es/ru)    │   ├── input_folder.py # reusable input folders    │   ├── text_clean.py   # text cleanup    │   ├── tutorial.py     # onboarding tutorial    │   └── faker_render.py # Faker tools (PIL image output)    ├── input/              # saved inputs per category    ├── output/             # default output folder for generated files    ├── utils/              # shared helpers (logging, networking)    └── tools/              # >>> every plugin lives here <<<        ├── osint_dns.py          # native Python tool (TOOL + run())        ├── net_port_scanner.py   # …        ├── crack_hash_cracker.py # …        └── …```Everything under `wavetools/tools/` is scanned at startup. Files whose name starts with `_` or `.` are skipped (which is why the manifest generator is named `_generate_embedded_manifests.py` — a build helper, not a tool).### Tool Lifecycle`ToolScreen` (`app.py`) runs through three phases:``` ask  ──►  run  ──►  result  │         │          │  │         │          └─ render ToolResult (text/list/table/file),  │         │             "run again" console, Ctrl+C to copy  │         └─ run(opts) or job(ctx, opts) on a background thread;  │            streaming tools write live lines via ctx.line()/ctx.status()  └─ ask the declared Step()s in order, validate,     collect into an `answers` dict → reaches run/job as `opts````### Where Tools Come From`WaveToolsApp.__init__` (in `app.py`) builds the full tool list:```pythonbuiltin = builtin_tools()                       # hardcoded built-in toolscommunity_dir = config.resolve_community_tools_dir(cfg)plugins, reports = discover_all(BUILTIN_TOOLS_DIR, community_dir)self.all_tools = builtin + plugins```There are three tool origins (`Tool.origin`):| `origin` | Source | Note ||----------|--------|------|| `built-in` | `builtin_tools()` in `builtin_tools.py` | hardcoded in code || `bundled` | `wavetools/tools/` | shipped plugins || `community` | optional extra folder (`WAVETOOLS_TOOLS_DIR` / config) | flagged as "third-party, unverified" |For 99% of cases, the recommended path is **a `.py` plugin in `wavetools/tools/`** — see below.Three dataclasses (in `builtin_tools.py`) are the entire vocabulary:* **`Tool`** — describes a tool: name, categories, description, the `run`/`job` function, the `Step`s to ask, and metadata.* **`Step`** — one question in the guided flow (`kind`, `prompt`, `default`, validation, condition, …).* **`ToolResult`** — the outcome of a run (`ok`, `summary`, `log`, optional `table`/`items`/`path`/`copy`).Streaming adds **`JobContext`** — see the reference below.<p align="right">(<a href="#readme-top">back to top</a>)</p>---## Writing a Plugin### Adding a New Category**Categories are not hardcoded.** The left-hand column of the main menu is derived at runtime from the tools (`MainScreen._build_categories` in `app.py`): any category named by any tool shows up automatically.```pythonTOOL = {    "name": "My New Tool",    "category": "FORENSICS",      # <-- doesn't exist yet? -> created automatically    # ...}```A tool can appear in **multiple** categories at once via `categories` (a list). `category` stays the primary category (shown in the tool view's header):```pythonTOOL = {    "name": "IP Localise",    "category": "OSINT",                 # primary category    "categories": ["OSINT", "NETWORK"],  # appears under BOTH    # ...}```Order within a category is controlled via `order` (lower = higher up; equal values keep load order):```pythonTOOL = { "name": "...", "category": "NETWORK", "order": -10 }```> There's no central category list to maintain. To retire a category, just remove it from every tool that references it.### Python Plugin (`.py`)The recommended way to add a tool to an existing category is a **native Python plugin**: a file in `wavetools/tools/` that defines a `TOOL` dict and a `run` function.Complete minimal example — `wavetools/tools/reverse_text.py`:```python"""Reverses text — minimal example of a WaveTools plugin."""TOOL = {    "name": "Reverse Text",    "category": "TEXT",               # existing category    "description": "Reverses the string. Pure offline tool.",    "api_version": 1,                 # which plugin API this was written against    "author": "you",    "version": "1.0.0",    "capabilities": [],                # uses neither network nor filesystem    "supported_os": ["Windows", "Linux", "Darwin"],    "steps": [        {            "key": "text",             # ends up as opts["text"]            "prompt": "Text to reverse",            "kind": "text",            "default": "",        },    ],}def run(opts):    text = str(opts.get("text", ""))    reversed_text = text[::-1]    return {        "ok": True,        "summary": f"Reversed {len(text)} characters",        "log": [reversed_text],        "copy": reversed_text,        # what Ctrl+C copies    }```Save the file, restart WaveTools — done. The tool shows up under `TEXT`.**Two execution styles:**| Signature | Behavior ||-----------|----------|| `run(opts)` | *atomic*: runs to completion, returns a result. For fast tools. || `run(opts, ctx)` | *streaming*: receives a `JobContext`, can emit live lines and is cancellable. For slow/long-running tools. |The loader detects which one you wrote from its parameter count. Streaming example:```pythondef run(opts, ctx):    ctx.status("Working …")    for i in range(100):        if ctx.cancelled:                       # user pressed Esc            return {"ok": False, "summary": "Cancelled."}        ctx.line(f"Step {i}", style="muted")    return {"ok": True, "summary": "Done."}```> Return value: a `dict` (as above), an `(ok, summary, log)` tuple, or a plain string are all accepted — the loader coerces them into a `ToolResult` (`_coerce_result`). **Important:** the keys are `ok`/`summary`/`log` — **not** `success`/`message`. A dict using `success`/`message` still loads, but those fields are silently ignored (the tool just shows "Done.").### External Command Plugin (`.json`)If your tool **isn't** Python (a shell script, an `.exe`, a Node script, …), describe it with a JSON manifest instead. No Python required.`wavetools/tools/my_ping.json`:```json{  "name": "Quick Ping",  "category": "NETWORK",  "description": "Pings a host using the system ping.",  "api_version": 1,  "author": "you",  "version": "1.0.0",  "capabilities": ["network", "exec"],  "supported_os": ["Windows", "Linux", "Darwin"],  "steps": [    { "key": "host", "prompt": "Host", "kind": "text", "default": "8.8.8.8" }  ],  "command": {    "Windows": ["ping", "-n", "4", "{host}"],    "Linux":   ["ping", "-c", "4", "{host}"],    "Darwin":  ["ping", "-c", "4", "{host}"]  },  "timeout": 30}```How execution works (`_make_external_runner` in `plugins.py`):* `command` is either an OS map (`Windows`/`Linux`/`Darwin`/`default`) or a single value.* `{key}` placeholders in the command list are substituted with collected answers (`str.format(**opts)`). In the example, `{host}` becomes the input.* `timeout` (seconds) bounds the run; **`0` or `null` = no limit**.* stdout/stderr are captured and shown as the result log; exit code `0` counts as success.> **Watch out for interactive scripts:** external commands run without a TTY/stdin. Scripts that call `input()`, draw a menu, or clear the screen won't work sensibly this way. For those, a native Python port (above) is the right fix.<p align="right">(<a href="#readme-top">back to top</a>)</p>---## Plugin API Reference### The `TOOL` ManifestAll fields (apply equally to `.py` `TOOL` dicts and `.json` manifests unless noted):| Field | Type | Required | Meaning ||-------|------|----------|---------|| `name` | str |  | Display name + banner || `category` | str |  | primary category || `description` | str | recommended | text shown above the questions || `categories` | list[str] | – | extra categories (multi-listing) || `steps` | list[dict] | – | the steps to ask (below) || `settings` | list[dict] | – | legacy alternative to `steps` (auto-converted) || `supported_os` | list[str] | – | `Windows`/`Linux`/`Darwin`; default: all || `api_version` | int | recommended | plugin API version this was written against || `author` | str | – | shown in the transparency panel || `version` | str | – | plugin version || `requires` | list[str] | – | required Python imports/packages (dependency check) || `capabilities` | list[str] | – | declared capabilities: `network`/`filesystem`/`exec` || `order` | int | – | sort hint within the category || `prompt` / `prompt_key` | str | – | legacy single-question shorthand || `command` | dict/list/str | `.json` only | the command to run || `timeout` | int | `.json` only | limit in seconds (`0`/`null` = no limit) |`.py` plugins may additionally define these module functions: `run` (required), `steps_for(answers)`, `setup()`, `teardown()`.### Step KindsEvery entry in `steps` is a dict. Common keys: `key` (answer key in `opts`), `prompt` (question, alias: `label`), `kind`, `default` (alias: `value`).| `kind` | Input | Answer type ||--------|-------|-------------|| `text` | free text (paste allowed) | `str` || `password` | masked free text (`•`) | `str` || `number` | number, respects `min`/`max`/`integer` | `str` (numeric) || `bool` | on/off toggle | `bool` || `choice` | one option from `choices` | `str` || `multiselect` | multiple from `choices` (space toggles) | `list[str]` || `file` | local file path (existence checked) | `str` || `date` | date `YYYY-MM-DD` (validated) | `str` |```python"steps": [    {"key": "domain", "prompt": "Domain", "kind": "text", "default": "example.com"},    {"key": "port",   "prompt": "Port",   "kind": "number", "min": 1, "max": 65535, "integer": True},    {"key": "deep",   "prompt": "Deep scan?", "kind": "bool", "default": False},    {"key": "proto",  "prompt": "Protocol", "kind": "choice", "choices": ["http", "https"]},    {"key": "types",  "prompt": "Record types", "kind": "multiselect",     "choices": ["A", "AAAA", "MX"], "default": ["A"]},]```### Validation & ConditionsDeclarative per-step validation (works in `.py` **and** `.json`) via `validate`:```python{"key": "url", "prompt": "URL", "kind": "text", "validate": {"required": True, "url": True, "message": "Please enter an http(s) URL"}}```Supported validation keys (`_compile_validate` in `plugins.py`): `required`, `min_len`, `max_len`, `integer`, `url`, `email`, `regex` (+ `flags: "i"`), `message`. In `.py` plugins you can instead supply a function `validate(value, answers) -> str|None` (error text or `None`).`number`/`date`/`file` steps have additional built-in checks (numeric bounds, date format, file exists).A step can be shown only under a condition (`when`, alias `condition`). If the condition isn't met, the step is skipped and its `default` is stored:```python{"key": "platform", "prompt": "Platform", "kind": "choice", "choices": ["TikTok", "X"]},{"key": "handle",   "prompt": "TikTok handle", "kind": "text", "when": {"key": "platform", "equals": "TikTok"}}```Supported condition keys (`_compile_condition`): `equals`, `is`, `not`, `in` (list), `truthy`, `falsy`. In `.py`, a function `condition(answers) -> bool` is also allowed.### The `ToolResult` Format`run`/`job` return a `dict` (or a `ToolResult`). Fields:| Key | Type | Effect ||-----|------|--------|| `ok` | bool | success/failure (green  / red ). Default `True` || `summary` | str | result header line || `log` | list[str] | text lines (default rendering) || `table` + `headers` | list[list[str]] + list[str] | render as an aligned table || `items` | list[str] | render as a bulleted list || `path` | str | "Saved: …"; `Ctrl+O` opens the file || `copy` | str | what `Ctrl+C` copies (otherwise: log/summary) || `kind` | str | force render mode: `text`/`list`/`table`/`file`/`auto` |```pythonreturn {    "ok": True,    "summary": "3 records found",    "headers": ["Type", "Value"],    "table": [["A", "93.184.216.34"], ["MX", "mail.example.com"]],    "copy": "A 93.184.216.34\nMX mail.example.com",}```### The `JobContext` (Streaming Tools)A `job`/`run(opts, ctx)` receives `ctx` and uses it to drive the live window. All callbacks are thread-safe (the job runs on a background thread):| Call | Effect ||------|--------|| `ctx.line(text, style=None)` | emit one line; `style`: `ok`/`bad`/`warn`/`muted`/`header`/`None` || `ctx.status(text)` | update the header status line || `ctx.cancelled` | `True` once the user cancels (check it in loops!) || `ctx.set_copy(text)` | set what `Ctrl+C` copies || `ctx.open_url(url)` | open a URL in the selected browser || `ctx.browser` | the browser chosen in settings || `ctx.ascii_only` | `True` when ASCII mode is active (no fancy glyphs) || `ctx.store` | persistent plugin storage (below) |The `plugin_api` helpers are also available directly on `ctx`: `ctx.save_file(...)`, `ctx.http_get(...)`, `ctx.copy(...)`, `ctx.open_path(...)`, `ctx.get_config()`.### `plugin_api` HelpersImportable from any plugin (even from an atomic `run(opts)`):```pythonfrom wavetools.core.plugin_api import http_get, save_file, copy_text, get_store, open_url, open_path, get_config```| Function | Description ||----------|-------------|| `http_get(url, *, timeout=15, headers=None)` | GET; returns `{ok, status, text, error}` — **never** raises || `save_file(name, data, *, binary=False)` | write into the output folder; returns the path (`name` is reduced to its basename — no writing outside it) || `copy_text(text)` | copy to clipboard (best effort) || `open_url(url, browser=None)` | open in the configured browser || `open_path(path)` | open a file with the configured editor / OS default || `get_store(plugin_id)` | get persistent storage (below) || `get_config()` | reads `{output_dir, browser, ascii_only}` |Everything is **fail-soft**: a helper never raises, it reports success/failure in its return value instead.### Persistent Plugin Storage (`PluginStore`)An isolated key/value store per plugin, saved under `~/.wavetools/plugin_data/<id>.json`. One plugin can neither read nor overwrite another's data.```pythonctx.store.set("last_target", target)last = ctx.store.get("last_target", "")ctx.store.all()        # everything as a dictctx.store.delete("k")  # delete one keyctx.store.clear()      # delete everything```**Lifecycle hooks** — optional module functions in a `.py` plugin:```pythondef setup():    """Runs once when the tool is opened."""def teardown():    """Runs when the tool is left."""```Errors in hooks are fail-soft (noted in diagnostics, never crash the app).**Repeatable question groups** — if a `.py` plugin defines `steps_for(answers)`, the step list is recomputed from it after every answer. This lets questions grow dynamically ("Message #N" + "one more?") as long as the user keeps saying yes. The already-answered prefix must stay stable — only the tail may grow/shrink.```pythondef steps_for(answers):    steps = [{"key": "msg1", "prompt": "Message #1", "kind": "text"}]    n = 1    while answers.get(f"more{n}") is True:        n += 1        steps.append({"key": f"msg{n}", "prompt": f"Message #{n}", "kind": "text"})        steps.append({"key": f"more{n}", "prompt": "One more?", "kind": "bool"})    return steps```### Versioning & Compatibility* `PLUGIN_API_VERSION` (in `builtin_tools.py`) is the current API version.* A plugin declares, via `api_version`, which version it was written against. The loader decides from that (`_version_decision`):  * newer than the app → **skipped** (app is too old),  * older than `MIN_SUPPORTED_API_VERSION` → **skipped**,  * no `api_version` → **compatibility mode** ("legacy"), still loads,  * older but still supported → compatibility mode.* If a library named in `requires` is missing, the tool still loads (visibly), but explains what to `pip install` at startup (`_deps_guard`).Every load produces a `PluginReport` (status `loaded`/`compat`/`needs-deps`/`skipped`), viewable in the app's diagnostics window.**Capabilities & security model:** `capabilities` is a **self-declaration** (`network`/`filesystem`/`exec`) shown transparently in the tool description — it is not an enforced sandbox. Plugins (origin `bundled`/`community`) require a one-time confirmation before their **first** run (remembered in config); community tools are additionally flagged as "third-party, unverified". A plugin runs with the user's own privileges. **Only install/enable tools whose source you understand.**<p align="right">(<a href="#readme-top">back to top</a>)</p>---## ConfigurationConfiguration lives in `~/.wavetools/config.json` (creatable/editable via the settings menu, key `S` on the main menu). Environment variables take precedence:| Variable | Effect ||----------|--------|| `WAVETOOLS_CONFIG` | path to the config file (portable operation) || `WAVETOOLS_TOOLS_DIR` | extra community plugin folder || `WAVETOOLS_OUTPUT_DIR` | destination folder for generated files || `WAVETOOLS_INPUT_DIR` | folder for reusable inputs (tokens, webhooks, …) |Stored values include: `language`, `gradient` (theme), `browser`, `input_dir`, `output_dir`, `community_tools_dir`, `ascii_only`, `editor`, `configured` (first-run done), accepted plugins, and optional per-tool default answers. A missing/broken config silently falls back to safe defaults.**First-run wizard & languages:** on the very first launch (`configured` = `false`), a one-time setup wizard appears: language, theme, browser, ASCII mode, input/output/community folders, and editor. Everything can be changed later under **Settings (S)**. Available UI languages: **English (default)**, German, Spanish, Russian. Only the program's own UI (menus, status lines, settings, wizard) is translated — text produced by tools stays in its original language.**Input folder (reusable inputs):** instead of pasting the same cookie / proxy / wordlist on every run, drop it once into the **input folder** (`wavetools/input`, created automatically with subfolders + a README on first launch):| Subfolder | Contents (one entry per line, `#` = comment) ||-----------|-----------------------------------------------|| `roblox_cookies/` | `.ROBLOSECURITY` cookies || `proxies/` | `ip:port` or `user:pass@ip:port` || `wordlists/` | any list (passwords, names, paths, …) |When a tool asks for one of these values, WaveTools shows **"Use from Input-Folder (N)"** automatically — `Ctrl+F` fills the field straight from the folder (cycle through single values, or insert everything for lists). `.txt` files are validated and deduplicated.<p align="right">(<a href="#readme-top">back to top</a>)</p>---## Tool Catalog> **66 bundled tools** (plus built-in System/Text utilities).  = use only where you are authorized; may carry Terms-of-Service or legal weight depending on the target.<details><summary><strong>MINECRAFT (1 tool)</strong></summary>| Tool | Description | Disclaimer ||------|-------------|------------|| `mc_name_sniper` | Snipe an expiring Minecraft name onto **your own** account (Microsoft device-code login, NTP-timed change requests) |  |</details><details><summary><strong>NETWORK (16 tools)</strong></summary>| Tool | Description | Disclaimer ||------|-------------|------------|| `dns_lookup` | DNS query (A, AAAA, MX, TXT, NS, CNAME, SOA) via DNS-over-HTTPS | — || `ip_localisation` | Geolocate an IP: country, city, ISP, ASN, VPN/proxy/hosting flags, maps link | — || `net_domain_intel` | Domain A-record + HTTP header report (security headers) | — || `net_ip_all_lookup` | Parallel deep-dive: GeoIP + VPN + SSL + port scans |  || `net_ip_blacklist_checker` | Check an IP against 5 DNSBLs (Spamhaus, Barracuda, SORBS, SpamCop) | — || `net_ip_deep_scan` | Comprehensive IP scan: type, ping, rDNS, ports, GeoIP, SSL |  || `net_ip_generator` | Generate random IPs and test reachability | — || `net_port_scanner` | TCP port scan for a host (single or range) |  || `net_proxy_checker` | Validate a proxy list and check anonymity | — || `net_proxy_scraper` | Scrape free proxy lists from public sources | — || `net_ssl_checker` | Show SSL/TLS certificate details and expiry | — || `net_tcp_pinger` | TCP ping: measure connect latency to host:port | — || `network_ip_pinger` | ICMP ping multiple hosts at once (avg/min/max) | — || `system_info` | Show OS, CPU, RAM, disk, GPU, network interfaces | — |</details><details><summary><strong>OSINT (19 tools)</strong></summary>| Tool | Description | Disclaimer ||------|-------------|------------|| `osint_database_search` | Local file and database search (UTF-8/Latin-1) | — || `osint_email_info` | Fetch a domain's MX, SPF, and DMARC records | — || `osint_email_osint` | Check email registration across 8 platforms (Instagram, GitHub, Twitter/X, Spotify, Duolingo, …) | — || `osint_exif` | Extract EXIF metadata from image files | — || `osint_github_lookup` | GitHub profile: bio, followers, top repos, orgs | — || `osint_google_dork` | Generate pre-built Google dork queries | — || `osint_instagram_lookup` | Fetch Instagram profile information | — || `osint_ip_reputation` | IP reputation check with a heuristic risk score | — || `osint_ip_vpn_detector` | VPN/proxy/datacenter detection for an IP | — || `osint_mac_lookup` | MAC address → vendor lookup (OUI) | — || `osint_name_tracker` | Search a username across 18 platforms at once | — || `osint_phone_lookup` | Geolocate a phone number and fetch carrier info | — || `osint_social_platforms` | Look up Kick.com, Minecraft, Telegram, TikTok, Snapchat | — || `osint_subdomain_finder` | Find subdomains of a domain via DNS enumeration | — || `osint_username_hunter` | Look up a username across dozens of platforms | — || `osint_youtube_lookup` | Look up a YouTube channel (@handle) or video (ID/URL) | — || `email_breach_finder` | Search an email address in known data breaches (HIBP) | — |</details><details><summary><strong>ROBLOX (13 tools)</strong></summary>| Tool | Description | Disclaimer ||------|-------------|------------|| `roblox_account_info` | Look up a user by username or ID (profile, presence, followers, groups, avatar) | — || `roblox_avatar` | Avatar assets and headshot thumbnails (single or batch) | — || `roblox_badges` | Earned badges + collectibles/limiteds inventory (cookie required) | — || `roblox_cookie_info` | Account details via a `.ROBLOSECURITY` cookie (Robux, email, groups, PIN) | — || `roblox_game_extras` | Game votes, gamepass info, place → universe converter | — || `roblox_game_info` | Game stats, active players, ratings | — || `roblox_group_extras` | Group roles with member counts, group Robux balance | — || `roblox_group_info` | Group details, member count, owner | — || `roblox_id_info` | Query a user ID directly (no username resolution) | — || `roblox_items` | Item details, limited/resale price (RAP), catalog search | — || `roblox_multi` | Bulk cookie validation + profile JSON export | — || `roblox_social` | Friends list, follower/following count, account age | — || `roblox_username_checker` | Check Roblox username availability | — |</details><details><summary><strong>WEBSITE (7 tools)</strong></summary>| Tool | Description | Disclaimer ||------|-------------|------------|| `web_admin_finder` | Probe ~40 common admin/login/control-panel paths |  || `web_dir_finder` | Probe ~60 common directories and files (backups, `.env`, `.git/`, …) |  || `web_full_scanner` | Recon: resolve IP, open ports, headers, SSL, tech detection |  || `web_info_scanner` | One passive GET: status, server/x-powered-by headers, page info | — || `web_security_headers` | Grade a URL's HTTP security response headers | — || `web_url_scanner` | URL safety heuristics: scheme, redirect chain, suspicious patterns | — || `web_vuln_scanner` | Low-impact checks: weak security headers, exposed sensitive files |  |</details><details><summary><strong>GENERATOR (4 tools)</strong></summary>| Tool | Description | Disclaimer ||------|-------------|------------|| `password_generator` | Secure random passwords with configurable rules | — || `qr_code_generator` | Generate a QR code as a PNG file | — || `temporary_mail` | Disposable email address via the mail.tm API | — || `text_encoder_decoder` | Encode/decode Base64, URL, HTML, hex, binary, ROT13 | — |</details><details><summary><strong>CRYPTO (6 tools)</strong></summary>| Tool | Description | Disclaimer ||------|-------------|------------|| `crack_hash_cracker` | Offline dictionary attack on a hash (MD5, SHA1, SHA256, SHA512, bcrypt) |  || `crack_hash_identifier` | Detect hash format from length/prefix | — || `crack_jwt_decoder` | Decode a JWT, show algorithm and claims (no signature check) | — || `crack_password_hasher` | Hash text with various algorithms + optional salt | — || `crack_zip_cracker` | Offline dictionary attack on a password-protected ZIP |  || `file_hasher` | Compute MD5/SHA1/SHA256/SHA512 hash of a file | — |</details>*Tools whose filename starts with `_` or `.` are skipped by the plugin loader (build helpers, not tools).*<p align="right">(<a href="#readme-top">back to top</a>)</p>---##  Security & Legal NoticeWaveTools includes network, OSINT and website-recon tooling. Use it **exclusively** against systems, accounts, and networks you have **explicit permission** to test — your own infrastructure, authorized penetration tests, CTFs, and education. Scanning, enumeration, dictionary cracking and automated account actions can carry Terms-of-Service or legal weight depending on how and where you use them — that responsibility is yours. Tools flagged  in the [Tool Catalog](#-tool-catalog) are the ones to be especially careful with (they actively probe a target, run dictionary attacks, or automate account changes such as the Minecraft name snipe, which is against Mojang's ToS and should only ever target your own account).Plugins run with your own privileges and **without a sandbox**. Only load tools from sources you understand and trust, and consciously confirm a plugin before its first run.<p align="right">(<a href="#readme-top">back to top</a>)</p>---## Roadmap- [x] Runtime plugin loader (`.py` + `.json`)- [x] Reusable input folder with `Ctrl+F` autofill- [x] Multi-language UI (en/de/es/ru)- [x] Plugin API versioning & compatibility mode- [ ] Automated test suite / CI- [ ] Plugin marketplace / community index- [ ] Additional language packsTrack proposed features and known issues in your repository's issue tracker.<p align="right">(<a href="#readme-top">back to top</a>)</p>---## ContributingContributions make the open-source community an amazing place to learn, get inspired, and build. Any contribution you make is **greatly appreciated**.If you have a suggestion, fork the repo and open a pull request, or simply open an issue tagged "enhancement". Don't forget to star the project — thanks again!1. Fork the project2. Create your feature branch (`git checkout -b feature/AmazingFeature`)3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)4. Push to the branch (`git push origin feature/AmazingFeature`)5. Open a pull requestNew tool plugins are the easiest way to contribute — see [Writing a Plugin](#writing-a-plugin) above; a single well-formed `.py` file in `wavetools/tools/` is a complete contribution.<p align="right">(<a href="#readme-top">back to top</a>)</p>---## LicenseDistributed under the MIT License. See [`LICENSE`](LICENSE) for the full text.<p align="right">(<a href="#readme-top">back to top</a>)</p>---## ContactWaveTools — a blue, wave-themed multi-tool TUI, by AquA.For bugs and feature requests, use the issue tracker of the repository you cloned this from.<p align="right">(<a href="#readme-top">back to top</a>)</p>---## Acknowledgments* [Textual](https://textual.textualize.io/) and [Rich](https://rich.readthedocs.io/) — the TUI engine this project is built on* [Best-README-Template](https://github.com/othneildrew/Best-README-Template) — structure and inspiration for this README* [Img Shields](https://shields.io) — the badges up top* [Choose an Open Source License](https://choosealicense.com)<p align="right">(<a href="#readme-top">back to top</a>)</p><!-- MARKDOWN LINKS & IMAGES -->[license-shield]: https://img.shields.io/badge/license-MIT-green.svg?style=for-the-badge[license-url]: LICENSE[python-shield]: https://img.shields.io/badge/python-3.10%2B-blue.svg?style=for-the-badge&logo=python&logoColor=white[python-url]: https://www.python.org/downloads/[textual-shield]: https://img.shields.io/badge/built%20with-Textual-5967FF.svg?style=for-the-badge[textual-url]: https://textual.textualize.io/[platform-shield]: https://img.shields.io/badge/platform-Windows%20%7C%20Linux%20%7C%20macOS-lightgrey.svg?style=for-the-badge[platform-url]: #getting-started[Python-badge]: https://img.shields.io/badge/Python-3776AB?style=for-the-badge&logo=python&logoColor=white[Python-url]: https://www.python.org/[Textual-badge]: https://img.shields.io/badge/Textual-5967FF?style=for-the-badge&logo=python&logoColor=white[Rich-badge]: https://img.shields.io/badge/Rich-FF4785?style=for-the-badge&logo=python&logoColor=white[Rich-url]: https://rich.readthedocs.io/[Cryptography-badge]: https://img.shields.io/badge/cryptography-000000?style=for-the-badge&logo=letsencrypt&logoColor=white[Cryptography-url]: https://cryptography.io/[Pillow-badge]: https://img.shields.io/badge/Pillow-4B8BBE?style=for-the-badge&logo=python&logoColor=white[Pillow-url]: https://python-pillow.org/