from utils.display import Display # ESP32 Commands organized by module (matches Kconfig modules) ESP_MODULES = { "system": { "description": "Core system commands", "commands": { "system_reboot": "Reboot the ESP32 device", "system_mem": "Get memory info (heap, internal)", "system_uptime": "Get device uptime", } }, "network": { "description": "Network tools", "commands": { "ping": "Ping a host (ping )", "arp_scan": "ARP scan the local network", "proxy_start": "Start TCP proxy (proxy_start )", "proxy_stop": "Stop TCP proxy", "dos_tcp": "TCP flood (dos_tcp )", } }, "fakeap": { "description": "Fake Access Point module", "commands": { "fakeap_start": "Start fake AP (fakeap_start [open|wpa2] [pass])", "fakeap_stop": "Stop fake AP", "fakeap_status": "Show fake AP status", "fakeap_clients": "List connected clients", "fakeap_portal_start": "Start captive portal", "fakeap_portal_stop": "Stop captive portal", "fakeap_sniffer_on": "Enable packet sniffer", "fakeap_sniffer_off": "Disable packet sniffer", } }, "recon": { "description": "Reconnaissance module (Camera + MLAT)", "commands": { "cam_start": "Start camera streaming (cam_start )", "cam_stop": "Stop camera streaming", "mlat config": "Set position (mlat config [gps|local] )", "mlat mode": "Set scan mode (mlat mode )", "mlat start": "Start MLAT scanning (mlat start )", "mlat stop": "Stop MLAT scanning", "mlat status": "Show MLAT status", } } } class HelpManager: def __init__(self, command_registry, dev_mode: bool = False): self.commands = command_registry self.dev_mode = dev_mode def _out(self, text: str): """Output helper that works in both CLI and TUI mode.""" Display.system_message(text) def show(self, args: list[str]): if args: self._show_command_help(args[0]) else: self._show_global_help() def show_modules(self): """Show ESP commands organized by module.""" self._out("=== ESP32 COMMANDS BY MODULE ===") self._out("") for module_name, module_info in ESP_MODULES.items(): self._out(f"[{module_name.upper()}] - {module_info['description']}") for cmd_name, cmd_desc in module_info["commands"].items(): self._out(f" {cmd_name:<20} {cmd_desc}") self._out("") self._out("Use 'help ' for detailed help on a specific command.") self._out("Send commands with: send [args...]") def _show_global_help(self): self._out("=== ESPILON C2 HELP ===") self._out("") self._out("C2 Commands:") self._out(" help [command] Show help or help for a specific command") self._out(" list List connected ESP devices") self._out(" modules List ESP commands organized by module") self._out(" send Send a command to ESP device(s)") self._out(" group Manage device groups (add, remove, list, show)") self._out(" active_commands List currently running commands") self._out(" clear Clear terminal screen") self._out(" exit Exit C2") self._out("") self._out("Server Commands:") self._out(" web start|stop|status Web dashboard server") self._out(" camera start|stop|status Camera UDP receiver") self._out("") self._out("ESP Commands: (use 'modules' for detailed list)") registered_cmds = self.commands.list() if registered_cmds: for name in registered_cmds: handler = self.commands.get(name) self._out(f" {name:<15} {handler.description}") else: self._out(" (no registered commands - use 'send' with any ESP command)") if self.dev_mode: self._out("") self._out("DEV MODE: Send arbitrary text: send ") def _show_command_help(self, command_name: str): # CLI Commands if command_name == "list": self._out("Help for 'list' command:") self._out(" Usage: list") self._out(" Description: Displays all connected ESP devices with ID, IP, status,") self._out(" connection duration, and last seen timestamp.") elif command_name == "send": self._out("Help for 'send' command:") self._out(" Usage: send > [args...]") self._out(" Description: Sends a command to one or more ESP devices.") self._out(" Examples:") self._out(" send ESP_ABC123 reboot") self._out(" send all wifi status") self._out(" send group scanners mlat start AA:BB:CC:DD:EE:FF") elif command_name == "group": self._out("Help for 'group' command:") self._out(" Usage: group [args...]") self._out(" Actions:") self._out(" add [id2...] Add devices to a group") self._out(" remove [id2...] Remove devices from a group") self._out(" list List all groups") self._out(" show Show group members") elif command_name == "web": self._out("Help for 'web' command:") self._out(" Usage: web ") self._out(" Description: Control the web dashboard server.") self._out(" Actions:") self._out(" start Start the web server (dashboard, cameras, MLAT)") self._out(" stop Stop the web server") self._out(" status Show server status and MLAT engine info") self._out(" Default URL: http://127.0.0.1:8000 (configurable via .env)") elif command_name == "camera": self._out("Help for 'camera' command:") self._out(" Usage: camera ") self._out(" Description: Control the camera UDP receiver.") self._out(" Actions:") self._out(" start Start UDP receiver for camera frames") self._out(" stop Stop UDP receiver") self._out(" status Show receiver stats (packets, frames, errors)") self._out(" Default port: 5000 (configurable via .env)") elif command_name == "modules": self._out("Help for 'modules' command:") self._out(" Usage: modules") self._out(" Description: List all ESP32 commands organized by module.") self._out(" Modules: system, network, fakeap, recon") elif command_name in ["clear", "exit", "active_commands"]: self._out(f"Help for '{command_name}' command:") self._out(f" Usage: {command_name}") descs = { "clear": "Clear the terminal screen", "exit": "Exit the C2 application", "active_commands": "Show all commands currently being executed" } self._out(f" Description: {descs.get(command_name, '')}") # ESP Commands (by module or registered) else: # Check in modules first for module_name, module_info in ESP_MODULES.items(): if command_name in module_info["commands"]: self._out(f"ESP Command '{command_name}' [{module_name.upper()}]:") self._out(f" Description: {module_info['commands'][command_name]}") self._show_esp_command_detail(command_name) return # Check registered commands handler = self.commands.get(command_name) if handler: self._out(f"ESP Command '{command_name}':") self._out(f" Description: {handler.description}") if hasattr(handler, 'usage'): self._out(f" Usage: {handler.usage}") else: Display.error(f"No help available for '{command_name}'.") def _show_esp_command_detail(self, cmd: str): """Show detailed help for specific ESP commands.""" details = { # MLAT subcommands "mlat config": [ " Usage: send mlat config [gps|local] ", " GPS mode: mlat config gps - degrees", " Local mode: mlat config local - meters", " Examples:", " send ESP1 mlat config gps 48.8566 2.3522", " send ESP1 mlat config local 10.0 5.5", ], "mlat mode": [ " Usage: send mlat mode ", " Example: send ESP1 mlat mode ble", ], "mlat start": [ " Usage: send mlat start ", " Example: send ESP1 mlat start AA:BB:CC:DD:EE:FF", ], "mlat stop": [ " Usage: send mlat stop", ], "mlat status": [ " Usage: send mlat status", ], "cam_start": [ " Usage: send cam_start ", " Description: Start camera streaming to C2 UDP receiver", " Example: send ESP_CAM cam_start 192.168.1.100 12345", ], "cam_stop": [ " Usage: send cam_stop", " Description: Stop camera streaming", ], "fakeap_start": [ " Usage: send fakeap_start [open|wpa2] [password]", " Examples:", " send ESP1 fakeap_start FreeWiFi", " send ESP1 fakeap_start SecureNet wpa2 mypassword", ], "fakeap_stop": [ " Usage: send fakeap_stop", ], "fakeap_status": [ " Usage: send fakeap_status", " Shows: AP running, portal status, sniffer status, client count", ], "fakeap_clients": [ " Usage: send fakeap_clients", " Lists all connected clients to the fake AP", ], "fakeap_portal_start": [ " Usage: send fakeap_portal_start", " Description: Enable captive portal (requires fakeap running)", ], "fakeap_portal_stop": [ " Usage: send fakeap_portal_stop", ], "fakeap_sniffer_on": [ " Usage: send fakeap_sniffer_on", " Description: Enable packet sniffing", ], "fakeap_sniffer_off": [ " Usage: send fakeap_sniffer_off", ], "ping": [ " Usage: send ping ", " Example: send ESP1 ping 8.8.8.8", ], "arp_scan": [ " Usage: send arp_scan", " Description: Scan local network for hosts", ], "proxy_start": [ " Usage: send proxy_start ", " Example: send ESP1 proxy_start 192.168.1.100 8080", ], "proxy_stop": [ " Usage: send proxy_stop", ], "dos_tcp": [ " Usage: send dos_tcp ", " Example: send ESP1 dos_tcp 192.168.1.100 80 1000", ], "system_reboot": [ " Usage: send system_reboot", " Description: Reboot the ESP32 device", ], "system_mem": [ " Usage: send system_mem", " Shows: heap_free, heap_min, internal_free", ], "system_uptime": [ " Usage: send system_uptime", " Shows: uptime in days/hours/minutes/seconds", ], } if cmd in details: for line in details[cmd]: self._out(line)