#!/usr/bin/env python3
"""
NullOS v2 - Full Interactive RGB Terminal + GUI Attack Panel
Click buttons to RUN attacks with real output display
"""
import subprocess
import threading
import time
import os
import sys

try:
    import tty
    import termios
    HAS_TTY = True
except:
    HAS_TTY = False

# RGB Colors
CYAN = "\033[96m"
MAGENTA = "\033[95m"
GREEN = "\033[92m"
YELLOW = "\033[93m"
RED = "\033[91m"
WHITE = "\033[97m"
BOLD = "\033[1m"
DIM = "\033[2m"
RESET = "\033[0m"

# Attack commands
ATTACKS = {
    "wifi": [
        ("WiFi Scan", "airmon-ng", ["airmon-ng", "start", "wlan0"]),
        ("Deauth", "aireplay", ["aireplay-ng", "--deauth", "10", "-a", "AP_MAC", "wlan0mon"]),
        ("Handshake", "airodump", ["airodump-ng", "wlan0mon", "-w", "capture"]),
        ("WPS Crack", "bully", ["bully", "wlan0mon", "-b", "AP_MAC", "-c", "1"]),
        ("Hashcat", "hashcat", ["hashcat", "-m", "2500", "handshake.hc22000", "wordlist.txt"]),
        ("PMKID", "hcxdumptool", ["hcxdumptool", "-i", "wlan0", "-o", "pmkid.cap"]),
        ("Evil Twin", "hostapd", ["hostapd", "/etc/hostapd.conf"]),
        ("Monitor Mode", "airmon", ["airmon-ng", "start", "wlan0"]),
    ],
    "bluetooth": [
        ("BLE Scan", "blescan", ["hcitool", "lescan"]),
        ("BT Inquiry", "hcitool", ["hcitool", "inq"]),
        ("SPP Connect", "rfcomm", ["rfcomm", "connect", "0", "XX:XX:XX:XX:XX:XX", "1"]),
        ("L2CAP Test", "l2ping", ["l2ping", "-c", "5", "-s", "100", "XX:XX:XX:XX:XX:XX"]),
        ("BT Audit", "btscanner", ["btscanner", "-i", "hci0"]),
        ("BlueZ Console", "bluetoothctl", ["bluetoothctl", "scan", "on"]),
    ],
    "usb": [
        ("USB Devices", "lsusb", ["lsusb"]),
        ("BadUSB Detect", "dmesg", ["dmesg", "-T", "|", "grep", "-i", "usb"]),
        ("HID Test", "evtest", ["evtest", "/dev/input/event0"]),
        ("USB MITM", "usbmitm", ["usbmitm", "-f", "rules.config"]),
        ("USB Snooping", "usbsnoop", ["usbsnoop", "-o", "capture.log"]),
    ],
    "thunderbolt": [
        ("TB Devices", "boltctl", ["boltctl", "list"]),
        ("DMA Dump", "pcileech", ["pcileech", "dump", "-device", "fpga", "-dumpall"]),
        ("IOMMU Status", "dmesg", ["dmesg", "|", "grep", "-i", "iommu"]),
        ("TB Security", "bolt", ["boltctl", "authorize", "-r", "DEVICE_ID"]),
        ("PCIe Scan", "lspci", ["lspci", "-vvv"]),
    ],
    "rf": [
        ("RF Spectrum", "gqrx", ["gqrx", "-r", "433.5M", "-f", "433.5M"]),
        ("433MHz Sniff", "rtl_433", ["rtl_433", "-f", "433.92M"]),
        ("Sub-GHz Replay", "flipper", ["flipper", "subghz", "replay"]),
        ("RF Jam", "rf_jammer", ["rf_jammer", "-f", "433M", "-p", "10"]),
        ("SDR Record", "rtl_sdr", ["rtl_sdr", "-g", "40", "-s", "1.024e6", "-f", "433M", "capture.dat"]),
    ],
    "network": [
        ("Nmap Scan", "nmap", ["nmap", "-sV", "-sC", "-O", "192.168.1.0/24"]),
        ("Port Scan", "nmap", ["nmap", "-p-", "-T5", "TARGET"]),
        ("ARP Spoof", "arpspoof", ["arpspoof", "-i", "eth0", "-t", "TARGET", "GATEWAY"]),
        ("DNS Spoof", "dnsspoof", ["dnsspoof", "-i", "eth0", "-f", "hosts.txt"]),
        ("SSL Strip", "ssltrip", ["ssltrip", "-l", "8080", "-w", "ssl.log"]),
        ("Responder", "responder", ["responder", "-I", "eth0", "-wrfv"]),
        ("Ettercap", "ettercap", ["ettercap", "-i", "eth0", "-M", "ARP", "/TARGET//", "/GATEWAY//"]),
        ("Net Discover", "netdiscover", ["netdiscover", "-i", "eth0", "-r", "192.168.1.0/24"]),
    ],
    "reversing": [
        ("Binwalk", "binwalk", ["binwalk", "-e", "firmware.bin"]),
        ("Strings", "strings", ["strings", "-n", "8", "binary"]),
        ("Hex Dump", "xxd", ["xxd", "binary"]),
        ("Objdump", "objdump", ["objdump", "-d", "-M", "intel", "binary"]),
        ("Radare2", "r2", ["r2", "-c", "aaa", "binary"]),
        ("Strace", "strace", ["strace", "-f", "./program"]),
        ("GDB Debug", "gdb", ["gdb", "-ex", "run", "-ex", "bt", "binary"]),
    ],
}

current_output = []
output_lock = threading.Lock()
current_category = ["wifi"]
running = [None]
output_done = threading.Event()

def read_output(proc, label):
    """Read command output in real-time"""
    global current_output
    with output_lock:
        current_output.append(f"{DIM}{'='*50}{RESET}")
        current_output.append(f"{CYAN}[{label}]{RESET}")
        current_output.append(f"{DIM}{'='*50}{RESET}")
    
    try:
        for line in iter(proc.stdout.readline, ''):
            if not line:
                break
            with output_lock:
                current_output.append(line.rstrip())
                if len(current_output) > 200:
                    current_output = current_output[-200:]
        proc.wait()
        with output_lock:
            if proc.returncode == 0:
                current_output.append(f"{GREEN}[✓] {label} completed{RESET}")
            else:
                current_output.append(f"{RED}[✗] {label} failed (code {proc.returncode}){RESET}")
    except:
        pass
    output_done.set()

def run_command(cmd_list, label):
    """Execute attack command"""
    if running[0] and running[0].poll() is None:
        return f"{YELLOW}[!] Attack already running...{RESET}"
    
    current_output.clear()
    output_done.clear()
    
    try:
        proc = subprocess.Popen(
            cmd_list,
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT,
            shell=False
        )
        running[0] = proc
        thread = threading.Thread(target=read_output, args=(proc, label))
        thread.daemon = True
        thread.start()
        return f"{CYAN}[▶] Started: {label}{RESET}"
    except FileNotFoundError:
        return f"{RED}[!] Tool not found: {cmd_list[0]}{RESET}\n{BOLD}Install with: apt install {get_package(cmd_list[0])}{RESET}"
    except Exception as e:
        return f"{RED}[!] Error: {str(e)}{RESET}"

def get_package(cmd):
    """Get package name for command"""
    pkgs = {
        "airmon-ng": "aircrack-ng", "aireplay": "aircrack-ng", "airodump": "aircrack-ng",
        "bully": "bully", "hashcat": "hashcat", "hcxdumptool": "hcxdumptool",
        "hcitool": "bluez", "rfcomm": "bluez", "l2ping": "bluez", "btscanner": "btscanner",
        "lsusb": "usbutils", "evtest": "evtest", "boltctl": "bolt",
        "pcileech": "pcileech", "lspci": "pciutils", "gqrx": "gqrx-sdr",
        "rtl_433": "rtl-433", "nmap": "nmap", "responder": "responder",
        "ettercap": "ettercap", "binwalk": "binwalk", "strings": "binutils",
        "xxd": "vim-common", "objdump": "binutils", "r2": "radare2",
        "strace": "strace", "gdb": "gdb",
    }
    return pkgs.get(cmd, cmd)

def print_banner():
    """Print boot banner"""
    print(f"""{CYAN}
╔══════════════════════════════════════════════════════════════╗
║  {BOLD}NULLOS v2.0 - Security Testing Lab{RESET}{CYAN}                         ║
║  RGB Terminal + GUI Attack Interface                          ║
╚══════════════════════════════════════════════════════════════╝{RESET}
{DIM}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━{RESET}
""")

def print_usage():
    print(f"""{WHITE}
{BOLD}USAGE:{RESET}
  TAB (1-5)      Switch panels: [1]Terminal [2]GUI [3]Settings [4]Guide [5]Tools
  arrows        Navigate menu / scroll output
  Enter         Run selected / select menu item
  Ctrl+C        Stop current attack
  Esc           Back / Clear
  {YELLOW}GUI Mode:{RESET}
    Click numbered buttons to RUN attacks directly
    Output shows in real-time below buttons
  {MAGENTA}Quick Commands:{RESET}
    scan     - Quick network scan
    deauth   - WiFi deauth attack
    blescan  - Bluetooth LE scan
    mitm     - ARP spoofing
    dump     - USB device dump
    tb       - Thunderbolt scan
    spec     - Spectral analysis
    help     - Show this guide
{RESET}
""")

def run_attack_gui(category):
    """Show GUI panel for category with clickable buttons"""
    tools = ATTACKS.get(category, [])
    print(f"\n{CYAN}{BOLD}[ GUI ATTACK PANEL - {category.upper()} ]{RESET}")
    print(f"{DIM}{'─'*60}{RESET}")
    
    for i, (name, cmd, args) in enumerate(tools, 1):
        print(f"  {MAGENTA}[{i}]{RESET} {WHITE}{name:15}{RESET} → {DIM}{cmd}{RESET}")
    
    print(f"\n{GREEN}→ Press 1-{len(tools)} to RUN, or category key to switch{RESET}")
    return tools

def main():
    if not HAS_TTY:
        # Non-interactive fallback
        print_banner()
        print(f"{YELLOW}[!] Running in non-interactive mode{RESET}\n")
        print_usage()
        run_attack_gui("wifi")
        return
    
    print_banner()
    print_usage()
    
    # Interactive mode
    tools = run_attack_gui("wifi")
    selected = 0
    mode = "gui"
    
    print(f"\n{CYAN}NullOS>{RESET} ", end="", flush=True)
    
    try:
        fd = sys.stdin.fileno()
        old_settings = termios.tcgetattr(fd)
        tty.setraw(fd)
        
        while True:
            ch = sys.stdin.read(1)
            
            # Tab to switch modes
            if ch == '\t':
                mode = "gui" if mode == "terminal" else "terminal"
                if mode == "gui":
                    tools = run_attack_gui(current_category[0])
                print(f"\n{MAGENTA}[MODE: {mode.upper()}]{RESET}")
                print(f"\n{CYAN}NullOS>{RESET} ", end="", flush=True)
                continue
            
            # Number keys 1-5 for categories
            if ch in '1234567':
                cats = list(ATTACKS.keys())
                idx = int(ch) - 1
                if idx < len(cats):
                    current_category[0] = cats[idx]
                    tools = run_attack_gui(cats[idx])
                    print(f"\n{CYAN}NullOS>{RESET} ", end="", flush=True)
                continue
            
            # In GUI mode, number keys 1-9 run attacks
            if mode == "gui" and ch.isdigit():
                idx = int(ch) - 1
                if idx < len(tools):
                    name, cmd, args = tools[idx]
                    print(f"\n{GREEN}▶ RUNNING: {name}{RESET}")
                    result = run_command(args, name)
                    print(result)
                    
                    # Show live output
                    print(f"{DIM}")
                    timeout = 5
                    start = time.time()
                    while not output_done.is_set() and time.time() - start < timeout:
                        time.sleep(0.1)
                        with output_lock:
                            for line in current_output[-20:]:
                                print(line)
                    print(f"{RESET}")
                    
                    # Show remaining output
                    with output_lock:
                        for line in current_output[-100:]:
                            print(line)
                    print(f"\n{CYAN}NullOS>{RESET} ", end="", flush=True)
                continue
            
            # Terminal mode
            if ch == '\r':  # Enter
                print()
                print(f"\n{CYAN}NullOS>{RESET} ", end="", flush=True)
                continue
            
            # Help
            if ch in 'hH?':
                print_usage()
                print(f"\n{CYAN}NullOS>{RESET} ", end="", flush=True)
                continue
            
            # Ctrl+C
            if ch == '\x03':
                if running[0] and running[0].poll() is None:
                    running[0].terminate()
                    print(f"\n{YELLOW}[!] Attack stopped{RESET}")
                print(f"\n{CYAN}NullOS>{RESET} ", end="", flush=True)
                continue
            
            # Esc - clear
            if ch == '\x1b':
                current_output.clear()
                print(f"\n{DIM}[cleared]{RESET}\n{CYAN}NullOS>{RESET} ", end="", flush=True)
                continue
            
            if ch:
                print(ch, end="", flush=True)
    
    except KeyboardInterrupt:
        print(f"\n{YELLOW}[!] Interrupted{RESET}")
    finally:
        termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
    
    print(f"\n{GREEN}[✓] NullOS shutdown{RESET}")

if __name__ == "__main__":
    main()
