#!/usr/bin/env bash
# gen-tools-json.sh — build-time catalog generator for /pentester/tools.json
#
# Probes every curated tool with `command -v` and emits ONLY tools that exist
# in the built image, so the catalog never drifts from what the Agent can
# actually run. Descriptions/examples are maintained here next to the tool
# (the Dockerfile just installs packages; this file owns the metadata).
#
# Usage (run inside the image at build time):
#   gen-tools-json.sh [output-path]   (default: /pentester/tools.json)
set -euo pipefail

OUT="${1:-/pentester/tools.json}"
IMAGE='fb0sh/dsh-pentester-kali:latest'

declare -a CATEGORY_NAMES=(
  'base'
  'cli-extras'
  'traffic'
  'network'
  'network-discovery'
  'dns-osint'
  'web-discovery'
  'vulnerability'
  'password'
  'smb-ad'
  'wordlists'
  'misc'
)

# Entry format: <category>|<name>|<description>|<example-tail>
#   - Regular tools: name IS the binary to probe (command -v).
#   - `bin=<actual>` as name: probe <actual>, expose display name in the next
#     field (e.g. `misc|bin=r2|radare2|desc|-a <bin>`).
#   - `dir:<path>` as name: path hint (not an executable), always emitted.
#   - name containing `*` (impacket-*): family placeholder, skipped.
declare -a TOOLS=(
  # ── base ────────────────────────────────────────────────────────────────
  'base|bash|Bourne Again SHell|-c "echo hi"'
  'base|zsh|Z shell|-c "echo hi"'
  'base|python3|Python 3 interpreter|-V'
  'base|pip|Python package installer|install --user <pkg>'
  'base|pipx|Isolated Python CLI installer|install <pkg>'
  'base|git|Distributed version control|clone <url>'
  'base|curl|HTTP/HTTPS/FTP transfer client|-sS <url>'
  'base|wget|Non-interactive network downloader|-q <url>'
  'base|aria2c|Multi-protocol download utility|-x16 <url>'
  'base|jq|JSON processor|.key <file>'
  'base|yq|YAML/JSON processor|.key <file>'
  'base|ruby|Ruby interpreter|-e "puts 1"'
  'base|perl|Perl interpreter|-e "print 1"'
  'base|go|Go toolchain|version'
  'base|java|JRE launcher|-version'
  'base|gcc|C compiler|-o out in.c'
  'base|make|Build automation|-j4'
  'base|unzip|ZIP extractor|-l <file>'
  'base|7z|7-Zip archiver|x <file>'
  'base|tar|Tape archiver|-xzf <file>'
  'base|openssl|TLS/SSL toolkit|s_client -connect <host>:443'
  'base|file|File type identification|<file>'
  'base|tree|Directory tree viewer|-L2'
  'base|gdb|GNU debugger|-batch <bin>'
  'base|tmux|Terminal multiplexer|new -s <name>'
  'base|screen|Terminal multiplexer|-S <name>'
  'base|red-tldr|Red team TL;DR|red-tldr <command>'
  # ── cli-extras（现代化 CLI 基础件，来自用户愿望清单）───────────────────
  'cli-extras|rg|Ripgrep: fast recursive grep|pattern -l'
  'cli-extras|fd|fd: friendly find|".txt"'
  'cli-extras|xh|xh: curl replacement for HTTP|-S GET <url>'
  'cli-extras|hurl|HTTP request runner (chains, asserts)|<file.hurl>'
  'cli-extras|sd|sd: intuitive sed replacement|old new <file>'
  'cli-extras|mlr|Miller: csv/tsv/json awk|-i json cat <file>'
  'cli-extras|jc|Converts anything (CLI output, files) to JSON|ls | jc --ls'
  'cli-extras|gron|Grep from JSON (flatten to assignments)|gron <file.json>'
  # ── web-discovery 补充（builder 阶段编译）─────────────────────────────────
  'web-discovery|interactsh-client|OOB interaction detector (DNS/HTTP/LDAP callbacks)|-n'
  'web-discovery|gospider|Fast web spider|-s 10 <url>'
  # ── 反序列化 / 利用辅助（/pentester/tools/jars jar 包装脚本）──────────────
  'vulnerability|ysoserial|Java deserialization payload generator|-u CommonsCollections1'
  'vulnerability|marshalsec|Java marshalling gadget generator|MarshalledObject'
  'vulnerability|jndi-injection-exploit|JNDI/LDAP injection exploitation helper|-C <cmd>'
  'vulnerability|usql|Universal command-line interface for SQL databases|DSN -c "SELECT * FROM <table>" --json'
  # ── traffic（全流量记录：只记录，不分析）──────────────────────────────
  'traffic|tcpdump|Full packet capture (always recording to /workspace/traffic/pcap)|-r /workspace/traffic/pcap/capture.pcap'
  'traffic|mitmdump|mitmproxy CLI: HTTP(S) flow recorder on :8080 (flows -> /workspace/traffic/flows.mitm)|-r /workspace/traffic/flows.mitm'
  # ── network ─────────────────────────────────────────────────────────────
  'network|ip|IP routing/addresses (iproute2)|addr'
  'network|ping|ICMP echo (iputils)|-c4 <host>'
  'network|dig|DNS lookup|<host>'
  'network|nslookup|DNS query tool|<host>'
  'network|host|DNS lookup utility|<host>'
  'network|whois|WHOIS client|<domain>'
  'network|traceroute|Path tracing|<host>'
  'network|mtr|Network diagnostic (traceroute+ping)|-r <host>'
  'network|tcpdump|Packet capture|-i eth0 port 80'
  'network|tshark|Wireshark CLI analyzer|-i eth0'
  'network|nc|Netcat: read/write TCP/UDP|-vz <host> 443'
  'network|ncat|Nmap netcat variant|-v <host> 443'
  'network|socat|Bidirectional data relay|TCP:<host>:443 -'
  'network|telnet|Telnet client|<host> 23'
  'network|ssh|OpenSSH client|-o StrictHostKeyChecking=no <host>'
  'network|proxychains4|Route traffic via SOCKS/HTTP proxy|nmap -sT <host>'
  'network|torsocks|Route traffic via Tor|curl <url>'
  # ── network-discovery ───────────────────────────────────────────────────
  'network-discovery|nmap|Network discovery and port scanner|-sV -p- <host>'
  'network-discovery|masscan|High-speed port scanner|-p 1-65535 <host>'
  'network-discovery|naabu|ProjectDiscovery fast port scanner|-host <host>'
  'network-discovery|arp-scan|ARP host discovery|--localnet'
  'network-discovery|fscan|内网综合扫描工具，一键自动化漏扫|-h 192.168.1.1/24'
  'network-discovery|kscan|轻量化全方位扫描器|-t 192.168.1.1/24'
  'network-discovery|netdiscover|ARP host discovery (passive/active)|-r 192.168.1.0/24'
  # ── dns-osint ───────────────────────────────────────────────────────────
  'dns-osint|dnsrecon|DNS enumeration|-d <domain>'
  'dns-osint|dnsenum|DNS enumeration|<domain>'
  'dns-osint|fierce|DNS/domain scanner|--domain <domain>'
  'dns-osint|amass|Attack surface mapping (OSINT)|enum -d <domain>'
  'dns-osint|subfinder|Fast subdomain discovery|-d <domain>'
  'dns-osint|dnsx|ProjectDiscovery DNS prober|-d <domain>'
  'dns-osint|theHarvester|Email/subdomain OSINT|-d <domain> -b all'
  'dns-osint|whatweb|Website fingerprinting|<url>'
  'dns-osint|wafw00f|WAF detection|<url>'
  'dns-osint|fofax|FOFAX是一个基于fofa.info的API命令行查询工具|-q 'app="APACHE-Solr"''
  # ── web-discovery ───────────────────────────────────────────────────────
  'web-discovery|ffuf|Web fuzzer|-w <wordlist> -u <url>/FUZZ'
  'web-discovery|gobuster|Directory/DNS/HTTP brute force|dir -u <url> -w <wordlist>'
  'web-discovery|feroxbuster|Recursive content discovery|-u <url> -w <wordlist>'
  'web-discovery|dirb|Web content scanner|<url> <wordlist>'
  'web-discovery|dirbuster|Web content scanner (Java)|-u <url>'
  'web-discovery|katana|ProjectDiscovery crawler|-u <url>'
  'web-discovery|httpx|ProjectDiscovery HTTP prober|-l <hosts> -status-code'
  'web-discovery|nikto|Web server vulnerability scanner|-h <host>'
  # ── vulnerability ───────────────────────────────────────────────────────
  'vulnerability|nuclei|Template-based vulnerability scanner|-u <url>'
  'vulnerability|sqlmap|SQL injection automation|-u <url> --batch'
  # ── password ────────────────────────────────────────────────────────────
  'password|hydra|Network login brute forcer|-l <user> -P <passwords> ssh://<host>'
  'password|john|John the Ripper password cracker|--wordlist=<list> <hashfile>'
  'password|medusa|Parallel network login brute forcer|-h <host> -u <user> -P <passwords> -M ssh'
  'password|crunch|Wordlist generator|8 8 abc123 > <out>'
  'password|hashid|Hash type identification|<hash>'
  'password|hashcat|Advanced password recovery utility|-m 0 -a 0 <hash> <wordlist>'
  'password|defaulthound|Default password scanner|<host>'
  # ── smb-ad ──────────────────────────────────────────────────────────────
  'smb-ad|smbclient|SMB/CIFS client|-L <host>'
  'smb-ad|enum4linux-ng|SMB/AD enumeration|-A <host>'
  'smb-ad|impacket-*|Impacket scripts (psexec, smbexec, secretsdump)|psexec domain/user@<host>'
  'smb-ad|netexec|Network exec suite (SMB/WinRM/LDAP)|smb <host> -u <user> -p <pass>'
  'smb-ad|evil-winrm|WinRM shell client|-i <host> -u <user> -p <pass>'
  # ── wordlists (path hints, not executable tools) ────────────────────────
  'wordlists|dir:/usr/share/seclists|Wordlist collection (seclists)'
  'wordlists|dir:/usr/share/wordlists/rockyou.txt.gz|rockyou wordlist'
  # ── misc ────────────────────────────────────────────────────────────────
  'misc|exiftool|EXIF metadata extraction|<file>'
  'misc|binwalk|Firmware/file carving|<file>'
  'misc|foremost|File carving|-i <file>'
  'misc|bin=r2|radare2|Reverse engineering framework|-a <bin>'
  'misc|responder|LLMNR/NBT-NS/mDNS poisoner|-I eth0'
  'misc|bettercap|MITM framework|-iface eth0'
)

# Collect all_bins: every probed binary that actually exists (dir: excluded).
# 可选知识库层（--build-arg WITH_KB=1 构建时才存在；存在才进目录）
if [ -d /pentester/kb ]; then
  TOOLS+=('knowledge|dir:/pentester/kb|Offline knowledge bases: vulhub, PayloadsAllTheThings, Awesome-POC, exphub|see /pentester/kb/INDEX.txt')
fi

mapfile -t ALL_BINS < <(printf '%s\n' "${TOOLS[@]}" | while IFS='|' read -r _cat name _desc _tail; do
  case "$name" in
    dir:*) continue ;;
    bin=*) probe="${name#bin=}" ;;
    *'*') continue ;;
    *) probe="$name" ;;
  esac
  if command -v "$probe" >/dev/null 2>&1; then
    printf '%s\n' "$probe"
  fi
done | sort -u)

{
  printf '{\n'
  printf '  "version": "%s",\n' "$(cat /pentester/VERSION 2>/dev/null || echo '1.0.0')"
  printf '  "image": "%s",\n' "$IMAGE"
  printf '  "categories": {\n'
} > "$OUT"

first_category=1
for category in "${CATEGORY_NAMES[@]}"; do
  entries=$(printf '%s\n' "${TOOLS[@]}" | while IFS='|' read -r cat name desc tail; do
    [ "$cat" != "$category" ] && continue
    case "$name" in
      *'*') continue ;; # family placeholder
      dir:*)
        # Path hint: bin = the path, always emitted.
        path="${name#dir:}"
        binname="${path##*/}"
        jq -nc --arg n "$binname" --arg b "$path" --arg d "$desc" \
          '{ name: $n, bin: $b, description: $d, common_flags: [], examples: [$b] }'
        ;;
      bin=*)
        # name = bin=<probe>, desc = <display>, tail = <description>|<example-tail>
        probe="${name#bin=}"
        display="$desc"
        description="${tail%%|*}"
        example_tail=""
        if [ "$tail" != "$description" ]; then
          example_tail="${tail#*|}"
        fi
        if command -v "$probe" >/dev/null 2>&1; then
          example="$probe"
          [ -n "$example_tail" ] && example="$example $example_tail"
          jq -nc --arg n "$display" --arg b "$probe" --arg d "$description" --arg e "$example" \
            '{ name: $n, bin: $b, description: $d, common_flags: [], examples: [$e] }'
        fi
        ;;
      *)
        if command -v "$name" >/dev/null 2>&1; then
          example="$name"
          [ -n "$tail" ] && example="$example $tail"
          jq -nc --arg n "$name" --arg b "$name" --arg d "$desc" --arg e "$example" \
            '{ name: $n, bin: $b, description: $d, common_flags: [], examples: [$e] }'
        fi
        ;;
    esac
  done)
  if [ -n "$entries" ]; then
    if [ "$first_category" -eq 0 ]; then
      printf ',\n' >> "$OUT"
    fi
    {
      printf '    "%s": [\n' "$category"
      printf '%s\n' "$entries" | paste -sd, -
      printf '\n    ]'
    } >> "$OUT"
    first_category=0
  fi
done

{
  printf '\n  },\n'
  printf '  "all_bins": [\n'
  printf '%s\n' "${ALL_BINS[@]}" | sed 's/^/    "/; s/$/",/' | sed '$ s/,$//'
  printf '\n  ]\n'
  printf '}\n'
} >> "$OUT"

echo "tools.json written: $(wc -l < "$OUT") lines, ${#ALL_BINS[@]} bins"
