icoa-cli 2.19.332 → 2.19.333
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/commands/env.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import chalk from"chalk";import{execSync as e}from"node:child_process";import{appendFileSync as o,existsSync as n,mkdirSync as t,readFileSync as r}from"node:fs";import{homedir as a,platform as c}from"node:os";import{delimiter as s,dirname as i,join as l}from"node:path";import{fileURLToPath as g}from"node:url";import{icoaStandalonePython as p}from"../lib/aienv.js";import{placeSampleRunner as y,RUNNER_PY as h,sampleRunnerInstalled as d}from"../lib/sample-runner.js";import{computeAndCacheToolsetHash as m}from"../lib/toolset-hash.js";const u="3.12.13",w="22.22.3";function b(e){const o=e.split(".").map(Number),n=w.split(".").map(Number);return o[0]!==n[0]?o[0]>n[0]:o[1]!==n[1]?o[1]>n[1]:o[2]>=n[2]}const f="5.9.8",k=[{name:"pwntools",check:'python3 -c "import pwn"',install:"pwntools==4.12.0",category:"CTF Core"},{name:"pycryptodome",check:'python3 -c "import Crypto"',install:"pycryptodome==3.20.0",category:"CTF Core"},{name:"z3-solver",check:'python3 -c "import z3"',install:"z3-solver==4.13.0.0",category:"CTF Core"},{name:"angr",check:'python3 -c "import angr"',install:"angr",category:"CTF Core"},{name:"requests",check:'python3 -c "import requests"',install:"requests==2.31.0",category:"Web & Network"},{name:"beautifulsoup4",check:'python3 -c "import bs4"',install:"beautifulsoup4==4.12.3",category:"Web & Network"},{name:"flask",check:'python3 -c "import flask"',install:"flask==3.0.0",category:"Web & Network"},{name:"scapy",check:'python3 -c "import scapy"',install:"scapy==2.5.0",category:"Web & Network"},{name:"paramiko",check:'python3 -c "import paramiko"',install:"paramiko==3.4.0",category:"Web & Network"},{name:"sympy",check:'python3 -c "import sympy"',install:"sympy==1.12",category:"Crypto & Math"},{name:"gmpy2",check:"darwin"===process.platform?'/opt/homebrew/opt/python@3.12/bin/python3.12 -c "import gmpy2"':'python3 -c "import gmpy2"',install:"gmpy2>=2.2.0",category:"Crypto & Math"},{name:"cryptography",check:'python3 -c "import cryptography"',install:"cryptography==42.0.0",category:"Crypto & Math"},{name:"capstone",check:'python3 -c "import capstone"',install:"capstone==5.0.6",category:"Binary & RE"},{name:"ropper",check:'python3 -c "import ropper"',install:"ropper==1.13.8",category:"Binary & RE"},{name:"ROPgadget",check:"which ROPgadget",install:"ROPgadget==7.4",category:"Binary & RE"},{name:"pefile",check:'python3 -c "import pefile"',install:"pefile==2024.8.26",category:"Binary & RE"},{name:"pillow",check:'python3 -c "import PIL"',install:"pillow==10.2.0",category:"Data & Forensics"},{name:"numpy",check:'python3 -c "import numpy"',install:"numpy==1.26.4",category:"Data & Forensics"},{name:"python-magic",check:'python3 -c "import magic"',install:"python-magic==0.4.27",category:"Data & Forensics"},{name:"yara-python",check:'python3 -c "import yara"',install:"yara-python==4.5.0",category:"Data & Forensics"},{name:"sqlmap",check:"which sqlmap",install:"sqlmap",category:"Security Tools"},{name:"ipython",check:"which ipython3 || which ipython",install:"ipython",category:"Security Tools"},{name:"uncompyle6",check:'python3 -c "import uncompyle6"',install:"uncompyle6==3.9.1",category:"Security Tools"},{name:"volatility3",check:'python3 -c "import volatility3"',install:"volatility3",category:"Security Tools"},{name:"pyserial",check:'python3 -c "import serial"',install:"pyserial==3.5",category:"Security Tools"}],$="win32"===process.platform,v=(e,o)=>$?o||`where ${e}`:`which ${e}`,x=[{name:"vim",check:v("vim"),brew:"vim",apt:"vim",choco:"vim",category:"Editors & Terminal"},{name:"nano",check:v("nano"),brew:"nano",apt:"nano",choco:"nano",category:"Editors & Terminal"},{name:"tmux",check:v("tmux"),brew:"tmux",apt:"tmux",category:"Editors & Terminal"},{name:"screen",check:v("screen"),brew:"screen",apt:"screen",category:"Editors & Terminal"},{name:"less",check:v("less"),category:"Editors & Terminal"},{name:"gcc",check:v("gcc"),brew:"gcc",apt:"gcc",choco:"mingw",category:"Compilers & Build"},{name:"g++",check:v("g++"),brew:"gcc",apt:"g++",choco:"mingw",category:"Compilers & Build"},{name:"make",check:v("make"),brew:"make",apt:"make",choco:"make",category:"Compilers & Build"},{name:"nasm",check:v("nasm"),brew:"nasm",apt:"nasm",choco:"nasm",category:"Compilers & Build"},{name:"cmake",check:v("cmake"),brew:"cmake",apt:"cmake",choco:"cmake",category:"Compilers & Build"},{name:"as",check:v("as"),category:"Compilers & Build"},{name:"ld",check:v("ld"),category:"Compilers & Build"},{name:"pkg-config",check:v("pkg-config"),brew:"pkg-config",apt:"pkg-config",category:"Compilers & Build"},{name:"python3",check:"darwin"===process.platform?"/opt/homebrew/opt/python@3.12/bin/python3.12 --version":$?"python --version":"python3 --version",brew:"python@3.12",apt:"python3",choco:"python312",category:"Python Runtime"},{name:"pip3",check:"darwin"===process.platform?"/opt/homebrew/opt/python@3.12/bin/pip3.12 --version":$?"pip --version":"pip3 --version",category:"Python Runtime"},{name:"python3-venv",check:$?'python -c "import venv"':'python3 -c "import venv"',apt:"python3-venv",category:"Python Runtime"},{name:"curl",check:v("curl"),brew:"curl",apt:"curl",choco:"curl",category:"Networking"},{name:"wget",check:v("wget"),brew:"wget",apt:"wget",choco:"wget",category:"Networking"},{name:"nc",check:v("nc","where ncat"),brew:"netcat",apt:"netcat-openbsd",choco:"nmap",category:"Networking"},{name:"socat",check:v("socat"),brew:"socat",apt:"socat",category:"Networking"},{name:"nmap",check:v("nmap"),brew:"nmap",apt:"nmap",choco:"nmap",category:"Networking"},{name:"ssh",check:v("ssh"),apt:"openssh-client",category:"Networking"},{name:"dig",check:v("dig"),brew:"bind",apt:"dnsutils",category:"Networking"},{name:"whois",check:v("whois"),brew:"whois",apt:"whois",choco:"whois",category:"Networking"},{name:"ping",check:v("ping"),apt:"iputils-ping",category:"Networking"},{name:"traceroute",check:v("traceroute","where tracert"),brew:"traceroute",apt:"traceroute",category:"Networking"},{name:"tcpdump",check:v("tcpdump"),brew:"tcpdump",apt:"tcpdump",category:"Networking"},{name:"tshark",check:v("tshark"),brew:"wireshark",apt:"tshark",choco:"wireshark",aptNoRecommends:!0,debconfSeed:"wireshark-common wireshark-common/install-setuid boolean false",installTimeoutMs:6e5,installHint:"tshark is only needed for packet-capture (pcap) challenges — setup continues without it.",category:"Networking"},{name:"gdb",check:v("gdb"),brew:"gdb",apt:"gdb",choco:"mingw",category:"Debuggers"},..."darwin"!==process.platform?[{name:"ltrace",check:v("ltrace"),apt:"ltrace",category:"Debuggers"},{name:"strace",check:v("strace"),apt:"strace",category:"Debuggers"}]:[],{name:"objdump",check:v("objdump"),category:"Debuggers"},..."darwin"!==process.platform?[{name:"readelf",check:v("readelf"),category:"Debuggers"}]:[],{name:"radare2",check:v("r2"),brew:"radare2",apt:"radare2",choco:"radare2",aptFallback:`ARCH=$(dpkg --print-architecture) && cd /tmp && curl -fsSL -o r2.deb "https://github.com/radareorg/radare2/releases/download/${f}/radare2_${f}_\${ARCH}.deb" && sudo dpkg -i r2.deb && rm -f r2.deb`,category:"Reverse Engineering"},{name:"rabin2",check:v("rabin2"),category:"Reverse Engineering"},{name:"upx",check:v("upx"),brew:"upx",apt:"upx",choco:"upx",category:"Reverse Engineering"},{name:"strings",check:v("strings"),category:"Reverse Engineering"},{name:"binwalk",check:v("binwalk"),brew:"binwalk",apt:"binwalk",category:"Forensics"},..."darwin"!==process.platform?[{name:"foremost",check:v("foremost"),apt:"foremost",category:"Forensics"}]:[],{name:"exiftool",check:v("exiftool"),brew:"exiftool",apt:"exiftool",choco:"exiftool",category:"Forensics"},..."darwin"!==process.platform?[{name:"steghide",check:v("steghide"),apt:"steghide",category:"Forensics"}]:[],{name:"file",check:v("file"),category:"Forensics"},{name:"xxd",check:v("xxd"),brew:"vim",apt:"xxd",category:"Forensics"},{name:"pdftotext",check:v("pdftotext"),brew:"poppler",apt:"poppler-utils",category:"Forensics"},{name:"pngcheck",check:v("pngcheck"),brew:"pngcheck",apt:"pngcheck",category:"Forensics"},{name:"sleuthkit",check:v("mmls"),brew:"sleuthkit",apt:"sleuthkit",choco:"sleuthkit",category:"Forensics"},{name:"john",check:v("john"),brew:"john",apt:"john",choco:"john",category:"Crypto & Password"},{name:"hashcat",check:v("hashcat"),brew:"hashcat",apt:"hashcat",choco:"hashcat",category:"Crypto & Password"},{name:"openssl",check:v("openssl"),category:"Crypto & Password"},{name:"gpg",check:v("gpg"),brew:"gnupg",apt:"gpg",choco:"gnupg",category:"Crypto & Password"},{name:"jq",check:v("jq"),brew:"jq",apt:"jq",choco:"jq",category:"Data Processing"},{name:"sqlite3",check:v("sqlite3"),brew:"sqlite",apt:"sqlite3",choco:"sqlite",category:"Data Processing"},{name:"base64",check:v("base64"),category:"Data Processing"},{name:"hexdump",check:v("hexdump"),category:"Data Processing"},{name:"od",check:v("od"),category:"Data Processing"},{name:"sort",check:v("sort"),category:"Data Processing"},{name:"uniq",check:v("uniq"),category:"Data Processing"},{name:"wc",check:v("wc"),category:"Data Processing"},{name:"unzip",check:v("unzip"),brew:"unzip",apt:"unzip",category:"Archive"},{name:"zip",check:v("zip"),brew:"zip",apt:"zip",category:"Archive"},{name:"tar",check:v("tar"),category:"Archive"},{name:"gzip",check:v("gzip"),category:"Archive"},{name:"bzip2",check:v("bzip2"),category:"Archive"},{name:"xz",check:v("xz"),brew:"xz",apt:"xz-utils",category:"Archive"},{name:"cat",check:v("cat"),category:"Core Unix"},{name:"grep",check:v("grep"),category:"Core Unix"},{name:"sed",check:v("sed"),category:"Core Unix"},{name:"awk",check:v("awk"),category:"Core Unix"},{name:"find",check:v("find"),category:"Core Unix"},{name:"head",check:v("head"),category:"Core Unix"},{name:"tail",check:v("tail"),category:"Core Unix"},{name:"diff",check:v("diff"),category:"Core Unix"},{name:"patch",check:v("patch"),category:"Core Unix"},{name:"chmod",check:v("chmod"),category:"Core Unix"},{name:"chown",check:v("chown"),category:"Core Unix"},{name:"ln",check:v("ln"),category:"Core Unix"},{name:"cp",check:v("cp"),category:"Core Unix"},{name:"mv",check:v("mv"),category:"Core Unix"},{name:"mkdir",check:v("mkdir"),category:"Core Unix"},{name:"rm",check:v("rm"),category:"Core Unix"},{name:"git",check:v("git"),brew:"git",apt:"git",choco:"git",category:"Git & Docker"},{name:"docker",check:v("docker"),brew:"--cask docker",choco:"docker-desktop",optional:!0,category:"Git & Docker"}],P=x.length+k.length;export function probeEnv(){const e=a(),o=[l(e,".local","bin")];return"darwin"===c()&&o.push(l(e,"Library","Python","3.12","bin")),{...process.env,PATH:`${o.join(s)}${s}${process.env.PATH??""}`}}function C(o){const n=o.startsWith("python3 ")?H()+o.slice(7):o;try{return e(n,{stdio:"ignore",env:probeEnv()}),!0}catch{return!1}}export function ensureLocalBinOnPath(){const e=a(),t="# icoa: ensure ~/.local/bin on PATH",c=`\n${t}\ncase ":$PATH:" in *":$HOME/.local/bin:"*) ;; *) export PATH="$HOME/.local/bin:$PATH" ;; esac\n`,s=[],i=[{rc:".bashrc",createIfMissing:!0},{rc:".zshrc",createIfMissing:!1}];for(const{rc:a,createIfMissing:g}of i){const i=l(e,a);try{const e=n(i);if(!e&&!g)continue;if((e?r(i,"utf-8"):"").includes(t))continue;o(i,c),s.push(`~/${a}`)}catch{}}return s}function E(o){const n={python3:`${H()} --version`,pip3:"darwin"===process.platform?"/opt/homebrew/opt/python@3.12/bin/pip3.12 --version":"linux"===process.platform?`${H()} -m pip --version`:"pip --version",gcc:"gcc --version","g++":"g++ --version",make:"make --version",nasm:"nasm --version",cmake:"cmake --version",vim:"vim --version",nano:"nano --version",tmux:"tmux -V",screen:"screen --version",curl:"curl --version",wget:"wget --version",nmap:"nmap --version",ssh:"ssh -V",socat:"socat -V",gdb:"gdb --version",radare2:"r2 -v",upx:"upx --version",binwalk:"binwalk --help",exiftool:"exiftool -ver",john:"john --help",hashcat:"hashcat --version",openssl:"openssl version",gpg:"gpg --version",jq:"jq --version",sqlite3:"sqlite3 --version",git:"git --version",docker:"docker --version",tshark:"tshark --version",tcpdump:"tcpdump --version",pdftotext:"pdftotext -v",pngcheck:"pngcheck 2>&1"}[o];if(!n)return"";try{const o=e(`${n} 2>&1`,{encoding:"utf-8",timeout:3e3}).trim().match(/(\d+\.\d+[.\d]*)/);return o?.[1]||""}catch{}return""}let T=null;export function resetPyBin(){T=null}function H(){if(T)return T;if("darwin"===process.platform)return T="/opt/homebrew/opt/python@3.12/bin/python3.12",T;if("win32"===process.platform)return T="python",T;try{return e("python3.12 --version",{stdio:"ignore"}),T="python3.12",T}catch{}const o=p(a(),"linux");try{return e(`"${o}" --version`,{stdio:"ignore"}),T=o,T}catch{}return T="python3",T}function A(){try{return e(`${H()} -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')"`,{encoding:"utf-8"}).trim()}catch{return""}}function M(){try{return e(`${H()} --version`,{encoding:"utf-8"}).trim().replace("Python ","")}catch{return""}}export function registerEnvCommand(o){const s=o.command("env").description("Manage competition environment");s.command("status").alias("check").description(`Check all ${P} tools`).action(()=>S()),s.command("setup").description("Install all Python libraries + system tools").action(async()=>{await async function(){console.log();const o=c(),s="darwin"===o||"linux"===o?"--break-system-packages":"";console.log(chalk.bold.white(" ICOA Environment Setup")),console.log(chalk.gray(" ─────────────────────────────────────────────")),console.log(chalk.gray(" This will install:")),console.log(chalk.white(" Python 3.12")+chalk.gray(" Runtime for CTF tools")),console.log(chalk.white(` ${k.length} Python libraries`)+chalk.gray(" pwntools, z3, crypto...")),console.log(chalk.white(` ${x.length} system tools`)+chalk.gray(" gcc, gdb, nmap, wireshark...")),console.log(),console.log(chalk.gray(" Estimated: ~500 MB disk, 5-15 min (depends on network)")),console.log(chalk.gray(" Already installed tools will be skipped.")),console.log(chalk.gray(" ─────────────────────────────────────────────")),console.log(),O("Installing system packages needs administrator access"),console.log();const d=process.versions.node;if(b(d))console.log(chalk.green(` ✓ Node.js ${d}`)+chalk.gray(` (>= ${w})`));else{console.log(chalk.yellow(` Node.js ${d} — installing latest 22.x (>= ${w})...`));try{"darwin"===o?e("brew install node@22",{stdio:"inherit"}):"linux"===o?(await N(),e("curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - && sudo apt-get install -y nodejs",{stdio:"inherit"})):e(`winget install OpenJS.NodeJS.LTS --version ${w}`,{stdio:"inherit"}),console.log(chalk.green(` ✓ Node.js (latest 22.x, >= ${w}) installed`)),console.log(chalk.gray(" Restart icoa to use the new version."))}catch{console.log(chalk.yellow(` ~ Node.js upgrade skipped. Install manually: nvm install ${w}`))}}console.log();const u=A(),f=M();if("3.12"===u)console.log(chalk.green(` ✓ Python ${f}`)),console.log();else{console.log(chalk.yellow(` Python ${f||"not found"} — installing Python 3.12 (side-by-side)...`));try{if("darwin"===o)e("brew install python@3.12",{stdio:"inherit"}),resetPyBin(),console.log(chalk.green(" ✓ Python 3.12 installed")),console.log(chalk.gray(" icoa uses it at: /opt/homebrew/opt/python@3.12/bin/python3.12"));else if("linux"===o){console.log(chalk.gray(" Installing python3.12 (your system python3 stays untouched)..."));let o=!1,c=!1;await N();try{e("sudo apt-get install -y python3.12 python3.12-venv python3.12-dev",{stdio:"inherit"}),o=!0}catch{}if(!o&&function(){try{const e=r("/etc/os-release","utf-8"),o=e.match(/^ID=("?)(.+?)\1$/m)?.[2]?.toLowerCase()??"",n=(e.match(/^ID_LIKE=("?)(.+?)\1$/m)?.[2]?.toLowerCase()??"").split(/\s+/);return"ubuntu"===o||n.includes("ubuntu")}catch{return!1}}())try{console.log(chalk.gray(" Not in default repos — adding deadsnakes PPA (Ubuntu)...")),await N(),e("sudo apt-get install -y software-properties-common && sudo add-apt-repository -y ppa:deadsnakes/ppa && sudo apt-get update",{stdio:"inherit"}),await N(),e("sudo apt-get install -y python3.12 python3.12-venv python3.12-dev",{stdio:"inherit"}),o=!0}catch{}if(o||(o=await async function(){const o=a(),r=l(o,".icoa","python312"),c=p(o,"linux");try{if(n(c))return e(`"${c}" --version`,{stdio:"ignore"}),!0}catch{}const s=(()=>{try{return e("uname -m",{encoding:"utf-8"}).trim()}catch{return""}})(),i="aarch64"===s||"arm64"===s?"aarch64":"x86_64"===s?"x86_64":"";if(!i)return console.log(chalk.yellow(` ~ No prebuilt Python 3.12 available for arch '${s||"unknown"}'`)),!1;console.log(chalk.gray(" Not in apt repos and no PPA (Kali/Debian) — fetching a standalone Python 3.12..."));let g="";try{const e=await fetch("https://api.github.com/repos/astral-sh/python-build-standalone/releases/latest",{headers:{"User-Agent":"icoa-cli",Accept:"application/vnd.github+json"}});if(!e.ok)throw new Error(`GitHub API ${e.status}`);const o=await e.json(),n=new RegExp(`^cpython-3\\.12\\.\\d+\\+\\d+-${i}-unknown-linux-gnu-install_only\\.tar\\.gz$`),t=(o.assets??[]).find(e=>n.test(e.name));if(!t)throw new Error("no matching CPython 3.12 asset in the latest release");if(g=t.browser_download_url,!/^https:\/\/github\.com\/astral-sh\/python-build-standalone\/releases\/download\/[\w.+-]+\/cpython-3\.12\.[\w.+-]+\.tar\.gz$/.test(g))throw new Error("asset URL failed the allowlist check")}catch(e){return console.log(chalk.red(" ✗ Could not resolve a standalone Python 3.12")+chalk.gray(` (${e.message})`)),!1}try{t(l(o,".icoa"),{recursive:!0}),e(`set -e; tmp="$(mktemp -d)"; curl -fsSL -o "$tmp/py.tgz" '${g}'; tar -xzf "$tmp/py.tgz" -C "$tmp"; rm -rf '${r}'; mv "$tmp/python" '${r}'; rm -rf "$tmp"`,{stdio:["ignore","ignore","pipe"]});const n=e(`"${c}" --version`,{encoding:"utf-8"}).trim();if(!/^Python 3\.12\./.test(n))throw new Error(`unexpected version: ${n}`);return resetPyBin(),console.log(chalk.green(` ✓ ${n} provisioned`)+chalk.gray(` → ${c} (system python3 unchanged)`)),!0}catch(e){return console.log(chalk.red(" ✗ Standalone Python 3.12 install failed")+chalk.gray(` (${D(e)||e.message})`)),!1}}(),c=o),!o)throw new Error("python3.12 install failed");if(!c)try{e("sudo python3.12 -m ensurepip --upgrade",{stdio:"inherit"})}catch{try{e("curl -sS https://bootstrap.pypa.io/get-pip.py | sudo python3.12",{stdio:"inherit"})}catch{}}resetPyBin(),console.log(chalk.green(" ✓ Python 3.12 installed (system python3 unchanged)")),console.log(chalk.gray(c?` Run Python challenges with: ${H()}`:" Run Python challenges with `python3.12`, or use the sandbox where `python3` is 3.12."))}else{try{e("winget install Python.Python.3.12 --accept-package-agreements --accept-source-agreements",{stdio:"inherit"})}catch{e("choco install -y python312",{stdio:"inherit"})}console.log(chalk.green(" ✓ Python 3.12 installed"))}}catch{console.log(chalk.red(" ✗ Failed to install Python 3.12"));const e="darwin"===o?"brew install python@3.12":"linux"===o?"sudo apt install python3.12":"winget install Python.Python.3.12";console.log(chalk.gray(` Manual install: ${e}`))}console.log()}"win32"===o&&(console.log(chalk.yellow(" Windows: Most CTF tools require Linux. Recommended:")),console.log(chalk.white(" wsl --install")),console.log(chalk.gray(" Then run icoa inside WSL Ubuntu for full tool support.")),console.log());const $=[];for(const e of x)e.optional||C(e.check)||("darwin"===o?e.brew:"linux"===o?e.apt:e.choco)&&$.push(e);const v=$.filter(e=>F.has(e.name)),P=$.filter(e=>!F.has(e.name));if(P.length>0&&"win32"!==o){const n="darwin"===o?"brew":"apt";if(console.log(chalk.bold.white(` System Tools via ${n} (${P.length} missing)`)),console.log(chalk.gray(" ─────────────────────────────────────────────")),await N(),O("Installing system tools needs administrator access"),"linux"===o){try{e("sudo apt-get install -y software-properties-common",{stdio:["ignore","ignore","pipe"]}),e("sudo add-apt-repository -y universe",{stdio:["ignore","ignore","pipe"]})}catch{}try{e("sudo apt-get update",{stdio:["ignore","ignore","pipe"]})}catch{}}for(const e of P)q(e,o,n);console.log()}let T="pip3";if("darwin"===o){const o="/opt/homebrew/opt/python@3.12/bin/pip3.12";try{e(`${o} --version`,{stdio:"ignore"}),T=o,console.log(chalk.gray(` Using: ${o}`))}catch{try{e("pip3.12 --version",{stdio:"ignore"}),T="pip3.12"}catch{}}}else if("linux"===o){const o=H();try{e(`"${o}" -m pip --version`,{stdio:"ignore"}),T=`"${o}" -m pip`}catch{try{e("pip3.12 --version",{stdio:"ignore"}),T="pip3.12"}catch{}}}else"win32"===o&&(T="pip");if("darwin"===o){console.log(chalk.gray(" Installing build dependencies..."));try{e("brew install gmp mpfr libmpc libmagic",{stdio:"ignore"}),console.log(chalk.green(" ✓ Build dependencies ready (gmp, mpfr, libmpc, libmagic)"))}catch{}}else if("linux"===o){console.log(chalk.gray(" Installing build dependencies..."));try{await N(),O("Build dependencies need administrator access"),e("sudo apt-get install -y libgmp-dev libmpfr-dev libmpc-dev libmagic1",{stdio:["ignore","ignore","pipe"]}),console.log(chalk.green(" ✓ Build dependencies ready (libgmp, libmpfr, libmpc, libmagic)"))}catch(e){const o=D(e);console.log(chalk.yellow(" ~ Build dependencies may be incomplete")+(o?chalk.gray(`: ${o}`):"")),console.log(chalk.gray(" gmpy2 needs: sudo apt-get install -y libgmp-dev libmpfr-dev libmpc-dev"))}}console.log();const S={...process.env};"darwin"===o&&(S.CFLAGS=`-I/opt/homebrew/include ${S.CFLAGS||""}`.trim(),S.LDFLAGS=`-L/opt/homebrew/lib ${S.LDFLAGS||""}`.trim(),S.C_INCLUDE_PATH=`/opt/homebrew/include:${S.C_INCLUDE_PATH||""}`,S.LIBRARY_PATH=`/opt/homebrew/lib:${S.LIBRARY_PATH||""}`);const j=l(i(g(import.meta.url)),"..","..","docker","constraints.txt"),I=n(j)?`-c '${j}'`:"";let U=0,B=0;console.log(chalk.bold.white(` Python Libraries (${k.length} packages)`)),console.log(chalk.gray(" ─────────────────────────────────────────────"));for(const o of k)if(o.install)if(C(o.check))console.log(chalk.green(` ✓ ${o.name}`)+chalk.gray(" (installed)")),U++;else{R(o.name);try{e(`${T} install ${s} ${I} '${o.install}'`,{stdio:["ignore","ignore","pipe"],env:S}),L(),console.log(chalk.green(` ✓ ${o.name}`)+chalk.gray(` (${o.install})`)),U++}catch(n){try{e(`${T} install ${s} --ignore-installed ${I} '${o.install}'`,{stdio:["ignore","ignore","pipe"],env:S}),L(),console.log(chalk.green(` ✓ ${o.name}`)+chalk.gray(" (installed over system copy)")),U++}catch(e){L();const n=D(e);console.log(chalk.red(` ✗ ${o.name}`)+chalk.gray(" (failed)")+(n?chalk.gray(`\n ${n}`):"")),B++}}}if(console.log(),console.log(chalk.gray(" ─────────────────────────────────────────────")),console.log(` ${chalk.green(`✓ ${U} installed`)} ${B>0?chalk.red(`✗ ${B} failed`):chalk.green("All ready!")}`),console.log(),"win32"!==o){const e=ensureLocalBinOnPath();e.length>0?(console.log(chalk.green(" ✓ PATH")+chalk.gray(` (added ~/.local/bin to ${e.join(", ")})`)),console.log(chalk.yellow(" → Run `source ~/.bashrc` or open a new terminal")+chalk.gray(" so sqlmap / ROPgadget / ipython are on PATH."))):console.log(chalk.gray(" ✓ PATH (~/.local/bin already configured)")),console.log()}if("win32"!==o){console.log(chalk.bold.white(" GDB Extension (bata24/gef default · pwndbg optional)")),console.log(chalk.gray(" ─────────────────────────────────────────────")),R("bata24/gef");try{e(`if test -s "$HOME/.gef-bata24.py"; then :; else for u in ${["https://raw.githubusercontent.com/bata24/gef/master/gef.py","https://cdn.jsdelivr.net/gh/bata24/gef@master/gef.py"].join(" ")}; do wget -q --timeout=20 --tries=1 -O "$HOME/.gef-bata24.py.tmp" "$u" && test "$(wc -c < "$HOME/.gef-bata24.py.tmp")" -gt 100000 && mv "$HOME/.gef-bata24.py.tmp" "$HOME/.gef-bata24.py" && break; done; rm -f "$HOME/.gef-bata24.py.tmp"; fi && test -s "$HOME/.gef-bata24.py" && touch "$HOME/.gdbinit" && (grep -q gef-bata24 "$HOME/.gdbinit" || printf '\\nsource %s/.gef-bata24.py\\n' "$HOME" >> "$HOME/.gdbinit")`,{stdio:["ignore","ignore","pipe"]}),L(),console.log(chalk.green(" ✓ bata24/gef")+chalk.gray(" (default gdb)"))}catch(e){L();const o=D(e);console.log(chalk.red(" ✗ bata24/gef")+(o?chalk.gray(`\n ${o}`):""))}if(C('test -d "$HOME/pwndbg"'))console.log(chalk.green(" ✓ pwndbg")+chalk.gray(" (run: gdb-pwndbg)"));else{const n="darwin"===o?"command -v uv >/dev/null 2>&1 || brew install uv":"command -v uv >/dev/null 2>&1 || pip3 install --user uv";R("pwndbg (optional)");try{e(`export PATH="$HOME/.local/bin:$PATH" && ${n} && rm -rf "$HOME/pwndbg" && git clone --depth 1 https://github.com/pwndbg/pwndbg "$HOME/pwndbg" && cd "$HOME/pwndbg" && ./setup.sh && mkdir -p "$HOME/.local/bin" && printf '#!/bin/sh\\nexec gdb -q -nx -ex "source $HOME/pwndbg/gdbinit.py" "$@"\\n' > "$HOME/.local/bin/gdb-pwndbg" && chmod +x "$HOME/.local/bin/gdb-pwndbg" && sed -i.bak '/pwndbg/d' "$HOME/.gdbinit" 2>/dev/null || true`,{stdio:["ignore","ignore","pipe"],env:S}),L(),console.log(chalk.green(" ✓ pwndbg")+chalk.gray(" (run: gdb-pwndbg)"))}catch{L(),console.log(chalk.yellow(" ~ pwndbg skipped")+chalk.gray(" (optional — bata24/gef is your default debugger)"))}}console.log(chalk.gray(" Default `gdb` loads bata24/gef; where installed, `gdb-pwndbg` loads pwndbg.")),console.log(chalk.gray(" (ensure ~/.local/bin is on PATH for gdb-pwndbg)")),console.log()}console.log(chalk.bold.white(" Sample-test runner (icoa-judge)")),console.log(chalk.gray(" ─────────────────────────────────────────────"));const z=y();if(z.ok?(console.log(chalk.green(" ✓ icoa-judge")+chalk.gray(` (${z.updated?"installed":"up to date"} → ${h})`)),console.log(chalk.gray(" Run your solution on its samples: python3 ~/.icoa/bin/icoa-judge.py sol.py samples/")),"win32"!==o&&console.log(chalk.gray(" (or just `icoa-judge sol.py samples/` once ~/.icoa/bin is on PATH)")),console.log(chalk.gray(" PyPy is an optional speed boost (not required): run with `--py pypy3`."))):console.log(chalk.yellow(" ~ icoa-judge skipped")+chalk.gray(` (${z.why??"write failed"})`)),console.log(),v.length>0&&"win32"!==o){const e="darwin"===o?"brew":"apt";console.log(chalk.bold.white(` Final tools (${v.map(e=>e.name).join(", ")}) — slowest, installed last`)),console.log(chalk.gray(" ─────────────────────────────────────────────")),"linux"===o&&(await N(),O("Installing the final tools needs administrator access"));for(const n of v)q(n,o,e,"linux"===o?{DEBIAN_FRONTEND:"noninteractive"}:{});console.log()}try{const e=x.map(e=>({name:e.name,version:C(e.check)?E(e.name):""}));m(e)}catch{}}()}),s.command("python").description("Show Python 3.12 install guide for your platform").action(()=>function(){const o=c();console.log(),console.log(chalk.bold.white(" Python 3.12 — Installation Guide")),console.log(chalk.gray(" ─────────────────────────────────────────────")),console.log();let n="",t="missing";const r=["python3.12 --version","/opt/homebrew/opt/python@3.12/bin/python3.12 --version","/usr/local/opt/python@3.12/bin/python3.12 --version","python3 --version"];for(const o of r)try{const r=e(o,{encoding:"utf-8",timeout:3e3}).trim().replace("Python ",""),a=r.split(".").map(Number);if(3===a[0]&&12===a[1]){n=r,t="ok";break}n=r,t=3===a[0]&&a[1]>=10&&a[1]<12?"old":3===a[0]&&a[1]>12?"new":"missing"}catch{}if("ok"===t)return console.log(chalk.green(` ✓ Python ${n} — you're good!`)),console.log(chalk.gray(" Exam toolkit ready. Next: ")+chalk.bold.cyan("exam setup")),void console.log();if("old"===t?console.log(chalk.yellow(` ⚠ Python ${n} — works, but 3.12 recommended`)):"new"===t?(console.log(chalk.yellow(` ⚠ Python ${n} — some packages (pwntools, scapy) lack wheels`)),console.log(chalk.gray(" Downgrading to 3.12 is strongly recommended"))):console.log(chalk.red(" ✗ Python 3 not found")),console.log(),"darwin"===o)console.log(chalk.bold.white(" macOS (Homebrew)")),console.log(),console.log(chalk.green(" brew install python@3.12"));else if("linux"===o){let o="ubuntu";try{const n=e("cat /etc/os-release 2>/dev/null",{encoding:"utf-8",timeout:2e3});o=/fedora|rhel|centos/i.test(n)?"fedora":/arch|manjaro/i.test(n)?"arch":"ubuntu"}catch{}"ubuntu"===o?(console.log(chalk.bold.white(" Ubuntu / Debian / Kali (deadsnakes PPA)")),console.log(),console.log(chalk.gray(" Copy-paste this one-liner:")),console.log(),console.log(chalk.green(" sudo add-apt-repository ppa:deadsnakes/ppa -y && \\")),console.log(chalk.green(" sudo apt update && \\")),console.log(chalk.green(" sudo apt install -y python3.12 python3.12-venv python3.12-dev")),console.log(),console.log(chalk.gray(" This installs ")+chalk.cyan("python3.12")+chalk.gray(" alongside your system python3 — run it as ")+chalk.cyan("python3.12")),console.log(chalk.gray(" (don’t repoint /usr/bin/python3 — it breaks apt & command-not-found on Ubuntu)."))):"fedora"===o?(console.log(chalk.bold.white(" Fedora / RHEL / CentOS")),console.log(),console.log(chalk.green(" sudo dnf install -y python3.12 python3.12-pip"))):"arch"===o&&(console.log(chalk.bold.white(" Arch / Manjaro (via pyenv)")),console.log(),console.log(chalk.green(" sudo pacman -S pyenv && pyenv install 3.12 && pyenv global 3.12")))}else"win32"===o?(console.log(chalk.bold.white(" Windows (WSL recommended)")),console.log(),console.log(chalk.gray(" WSL + Ubuntu (best):")),console.log(chalk.green(" wsl --install")),console.log(chalk.gray(" Then inside Ubuntu, run the Ubuntu commands.")),console.log(),console.log(chalk.gray(" Or native:")),console.log(chalk.green(" winget install Python.Python.3.12"))):console.log(chalk.gray(" https://www.python.org/downloads/"));console.log(),console.log(chalk.white(" After installing, verify:")),console.log(chalk.bold.cyan(" env python")+chalk.gray(" # re-check Python")),console.log(chalk.bold.cyan(" exam setup")+chalk.gray(" # install the 13 exam packages")),console.log()}()),s.action(()=>S())}function S(){console.log();const o=c(),t="darwin"===o?"brew":"linux"===o?"apt":"winget";console.log(chalk.bold.white(" ICOA Competition Environment")),console.log(chalk.gray(" ─────────────────────────────────────────────")),console.log(),console.log(chalk.gray(" These tools power your CTF competition environment.")),console.log(chalk.gray(" Not all are required — here's what matters:")),console.log(),console.log(chalk.green(" Essential")+chalk.gray(" pwntools, z3, requests, numpy")),console.log(chalk.gray(" You need these for most challenges")),console.log(chalk.yellow(" Recommended")+chalk.gray(" pycryptodome, beautifulsoup4, scapy, sympy")),console.log(chalk.gray(" Covers Web, Crypto, and Forensics")),console.log(chalk.gray(` Full (${P}) All tools for every category`)),console.log(),console.log(chalk.gray(" Missing tools? Run ")+chalk.bold.cyan("env setup")+chalk.gray(" to install everything.")),console.log(chalk.gray(" ─────────────────────────────────────────────")),console.log(),console.log(chalk.gray(" OS: ")+chalk.white(function(){const o=c();try{if("darwin"===o)return`macOS ${e("sw_vers -productVersion",{encoding:"utf-8"}).trim()} (${e("uname -m",{encoding:"utf-8"}).trim()})`;if("linux"===o)try{let o="Linux";try{const n=e("cat /etc/os-release | grep PRETTY_NAME",{encoding:"utf-8"}).match(/PRETTY_NAME="(.+)"/);n&&(o=n[1])}catch{}const t=e("uname -m",{encoding:"utf-8"}).trim(),a=function(){try{if(process.env.WSL_DISTRO_NAME)return"WSL";if(r("/proc/version","utf-8").toLowerCase().includes("microsoft"))return"WSL"}catch{}try{if(n("/opt/google/cros-containers"))return"Crostini"}catch{}return""}();return a?`${o} (${t}, ${a})`:`${o} (${t})`}catch{return"Linux"}else if("win32"===o)return e("ver",{encoding:"utf-8"}).trim()||"Windows"}catch{}return o}())),console.log(chalk.gray(" Node: ")+chalk.white(`Node.js ${process.version}`)),console.log(chalk.gray(" Package: ")+chalk.white(t)),console.log(chalk.gray(" Target: ")+chalk.white(`Node ${w} | Python ${u}`)),"win32"===o&&(console.log(),console.log(chalk.yellow(" Windows: recommend WSL (Ubuntu) for full CTF tool support")),console.log(chalk.gray(" Install WSL: ")+chalk.white("wsl --install")),console.log(chalk.gray(" Then run icoa inside WSL for 100% tool compatibility"))),console.log(chalk.gray(" ─────────────────────────────────────────────"));const a=process.versions.node;b(a)?console.log(chalk.green(` ✓ Node.js ${a}`)+chalk.gray(` (>= ${w})`)):(console.log(chalk.red(` ✗ Node.js ${a}`)+chalk.gray(` (>= ${w} required)`)),console.log(chalk.gray(" Install: nvm install 22 or visit https://nodejs.org/")));const s=A(),i=M();"3.12"===s?console.log(chalk.green(` ✓ Python ${i}`)+chalk.gray(i===u?" (official)":"")):s?console.log(chalk.yellow(` ~ Python ${i}`)+chalk.gray(" (3.12 required, run env setup)")):console.log(chalk.red(" ✗ Python 3 not found")),d()?console.log(chalk.green(" ✓ icoa-judge")+chalk.gray(" (sample-test runner)")):console.log(chalk.gray(" ○ icoa-judge")+chalk.gray(" (sample-test runner — run env setup to install)")),console.log();let l=0,g=0,p="";for(const e of x){e.category!==p&&(p=e.category,console.log(chalk.bold.gray(` ${p}`)));const o=C(e.check),n=o?E(e.name):"",t=n?chalk.gray(` (${n})`):"";e.optional?o?console.log(chalk.green(` ✓ ${e.name}`)+t+chalk.gray(" (optional)")):console.log(chalk.gray(` ○ ${e.name}`)+chalk.gray(" (optional — only for shell sandbox; not needed)")):o?(console.log(chalk.green(` ✓ ${e.name}`)+t),l++):(console.log(chalk.red(` ✗ ${e.name}`)),g++)}"win32"!==o&&(console.log(chalk.bold.gray(" GDB Extension")),C('grep -qi pwndbg "$HOME/.gdbinit" 2>/dev/null || test -f "$HOME/.gef-bata24.py"')?(console.log(chalk.green(" ✓ bata24-gef (+pwndbg)")),l++):(console.log(chalk.red(" ✗ bata24-gef (+pwndbg)")+chalk.gray(" (run env setup)")),g++)),p="";const y="darwin"===o?"/opt/homebrew/opt/python@3.12/bin/pip3.12":"win32"===o?"pip":"pip3";for(const o of k)if(o.category!==p&&(p=o.category,console.log(chalk.bold.gray(` ${p}`))),C(o.check)){let n="";for(const t of[y,"pip3","pip"])try{const r=o.name.replace("python-magic","python_magic"),a=e(`${t} show ${r}`,{encoding:"utf-8",timeout:3e3,stdio:["pipe","pipe","ignore"]}).match(/Version:\s*(\S+)/);if(a){n=a[1];break}}catch{}console.log(chalk.green(` ✓ ${o.name}`)+chalk.gray(n?` (${n})`:"")),l++}else console.log(chalk.red(` ✗ ${o.name}`)+chalk.gray(` → ${o.install||"latest"}`)),g++;const h=l+g;console.log(),console.log(chalk.gray(" ─────────────────────────────────────────────")),console.log(` ${chalk.green(`✓ ${l}/${h}`)} ${g>0?chalk.red(`✗ ${g} missing`):chalk.green(`All ${h} ready!`)}`),g>0&&console.log(chalk.gray(" Install everything: ")+chalk.white("env setup")+chalk.gray(" (~5 min, one-time)")),console.log(chalk.gray(" You are back at the ")+chalk.cyan("icoa>")+chalk.gray(" prompt. ")+chalk.cyan("help")+chalk.gray(" for all commands.")),console.log()}function j(){for(const o of["/var/lib/dpkg/lock-frontend","/var/lib/dpkg/lock","/var/lib/apt/lists/lock"])try{return e(`sudo fuser ${o} 2>/dev/null`,{stdio:"ignore",timeout:5e3}),!0}catch{}return!1}async function N(e=3e5){if("linux"!==c())return;if(!j())return;console.log(chalk.yellow(" ⏳ System package manager is busy")+chalk.gray(" (ChromeOS may be updating in the background).")),console.log(chalk.gray(` Waiting up to ${Math.round(e/6e4)} min for it to finish… `)+chalk.gray("(Ctrl+C to cancel, or re-run ")+chalk.cyan("env setup")+chalk.gray(" later)")),process.stdout.write(chalk.gray(" "));const o=Date.now();let n=0;for(;j();){if(Date.now()-o>e)return console.log(),console.log(chalk.yellow(" ~ Still busy after waiting. Skipping the wait.")),void console.log(chalk.gray(" If installs fail, re-run ")+chalk.cyan("env setup")+chalk.gray(" in a few minutes."));process.stdout.write(chalk.gray(".")),++n%50==0&&process.stdout.write(chalk.gray("\n ")),await new Promise(e=>setTimeout(e,3e3))}console.log(),console.log(chalk.green(" ✓ Package manager free — continuing."))}function O(o){if("linux"===c()){try{return void e("sudo -n true",{stdio:"ignore"})}catch{}console.log(chalk.yellow(` 🔑 ${o}`)+chalk.gray(" — enter your password if prompted:"));try{e("sudo -v",{stdio:"inherit"})}catch{console.log(chalk.gray(" (sudo unavailable — some installs may fail)"))}}}function R(e){process.stdout.isTTY&&process.stdout.write(chalk.gray(` ⏳ ${e}...`))}function L(){process.stdout.isTTY&&process.stdout.write("\r[2K")}function D(e){const o=e,n=(o?.stderr?o.stderr.toString():"").split("\n").map(e=>e.trim()).filter(Boolean);return n.length?n[n.length-1].slice(0,100):""}const F=new Set(["tshark"]);function q(o,n,t,r={}){const a="darwin"===n?o.brew:"linux"===n?o.apt:o.choco,c={...process.env,...r};R(o.name);try{if("linux"===n&&o.debconfSeed)try{e(`echo "${o.debconfSeed}" | sudo debconf-set-selections`,{stdio:["ignore","ignore","pipe"],env:c})}catch{}let t;t="darwin"===n?`brew install ${a}`:"linux"===n?`sudo apt-get install -y ${o.aptNoRecommends?"--no-install-recommends ":""}${a}`:`choco install -y ${a}`,e(t,{stdio:["ignore","ignore","pipe"],env:c,timeout:o.installTimeoutMs}),L(),console.log(chalk.green(` ✓ ${o.name}`))}catch(r){if("linux"===n&&o.aptFallback)try{return R(`${o.name} (fallback)`),e(o.aptFallback,{stdio:["ignore","ignore","pipe"],env:c}),L(),void console.log(chalk.green(` ✓ ${o.name}`)+chalk.gray(" (official .deb)"))}catch{}L();const s=r,i=!0===s?.killed||"SIGTERM"===s?.signal||"ETIMEDOUT"===s?.code,l="darwin"===n?`brew install ${a}`:"linux"===n?`sudo apt-get install -y ${o.aptNoRecommends?"--no-install-recommends ":""}${a}`:`choco install -y ${a}`;if(i){const e=Math.round((o.installTimeoutMs??0)/6e4);console.log(chalk.red(` ✗ ${o.name}`)+chalk.gray(` (timed out${e?` after ${e} min`:""} — stalled mirror or apt lock)`)+(o.installHint?chalk.gray(`\n ${o.installHint}`):"")+chalk.gray(`\n Install it later with: ${l}`))}else{const e=D(r);console.log(chalk.red(` ✗ ${o.name}`)+chalk.gray(` (${t} install ${a})`)+(e?chalk.gray(`\n ${e}`):"")+(o.installHint?chalk.gray(`\n ${o.installHint}`):""))}}}
|
|
1
|
+
import chalk from"chalk";import{execSync as e}from"node:child_process";import{appendFileSync as o,existsSync as n,mkdirSync as t,readFileSync as r}from"node:fs";import{homedir as a,platform as c}from"node:os";import{delimiter as s,dirname as i,join as l}from"node:path";import{fileURLToPath as g}from"node:url";import{icoaStandalonePython as p}from"../lib/aienv.js";import{placeSampleRunner as y,RUNNER_PY as h,sampleRunnerInstalled as d}from"../lib/sample-runner.js";import{computeAndCacheToolsetHash as m}from"../lib/toolset-hash.js";const u="3.12.13",w="22.22.3";function b(e){const o=e.split(".").map(Number),n=w.split(".").map(Number);return o[0]!==n[0]?o[0]>n[0]:o[1]!==n[1]?o[1]>n[1]:o[2]>=n[2]}const f="5.9.8",k=[{name:"pwntools",check:'python3 -c "import pwn"',install:"pwntools==4.12.0",category:"CTF Core"},{name:"pycryptodome",check:'python3 -c "import Crypto"',install:"pycryptodome==3.20.0",category:"CTF Core"},{name:"z3-solver",check:'python3 -c "import z3"',install:"z3-solver==4.13.0.0",category:"CTF Core"},{name:"angr",check:'python3 -c "import angr"',install:"angr",category:"CTF Core"},{name:"requests",check:'python3 -c "import requests"',install:"requests==2.31.0",category:"Web & Network"},{name:"beautifulsoup4",check:'python3 -c "import bs4"',install:"beautifulsoup4==4.12.3",category:"Web & Network"},{name:"flask",check:'python3 -c "import flask"',install:"flask==3.0.0",category:"Web & Network"},{name:"scapy",check:'python3 -c "import scapy"',install:"scapy==2.5.0",category:"Web & Network"},{name:"paramiko",check:'python3 -c "import paramiko"',install:"paramiko==3.4.0",category:"Web & Network"},{name:"sympy",check:'python3 -c "import sympy"',install:"sympy==1.12",category:"Crypto & Math"},{name:"gmpy2",check:"darwin"===process.platform?'/opt/homebrew/opt/python@3.12/bin/python3.12 -c "import gmpy2"':'python3 -c "import gmpy2"',install:"gmpy2>=2.2.0",category:"Crypto & Math"},{name:"cryptography",check:'python3 -c "import cryptography"',install:"cryptography==42.0.0",category:"Crypto & Math"},{name:"capstone",check:'python3 -c "import capstone"',install:"capstone==5.0.6",category:"Binary & RE"},{name:"ropper",check:'python3 -c "import ropper"',install:"ropper==1.13.8",category:"Binary & RE"},{name:"ROPgadget",check:"which ROPgadget",install:"ROPgadget==7.4",category:"Binary & RE"},{name:"pefile",check:'python3 -c "import pefile"',install:"pefile==2024.8.26",category:"Binary & RE"},{name:"pillow",check:'python3 -c "from PIL import Image"',install:"pillow==10.2.0",category:"Data & Forensics"},{name:"numpy",check:'python3 -c "import numpy"',install:"numpy==1.26.4",category:"Data & Forensics"},{name:"python-magic",check:'python3 -c "import magic"',install:"python-magic==0.4.27",category:"Data & Forensics"},{name:"yara-python",check:'python3 -c "import yara"',install:"yara-python==4.5.0",category:"Data & Forensics"},{name:"sqlmap",check:"which sqlmap",install:"sqlmap",category:"Security Tools"},{name:"ipython",check:"which ipython3 || which ipython",install:"ipython",category:"Security Tools"},{name:"uncompyle6",check:'python3 -c "import uncompyle6"',install:"uncompyle6==3.9.1",category:"Security Tools"},{name:"volatility3",check:'python3 -c "import volatility3"',install:"volatility3",category:"Security Tools"},{name:"pyserial",check:'python3 -c "import serial"',install:"pyserial==3.5",category:"Security Tools"}],$="win32"===process.platform,v=(e,o)=>$?o||`where ${e}`:`which ${e}`,x=[{name:"vim",check:v("vim"),brew:"vim",apt:"vim",choco:"vim",category:"Editors & Terminal"},{name:"nano",check:v("nano"),brew:"nano",apt:"nano",choco:"nano",category:"Editors & Terminal"},{name:"tmux",check:v("tmux"),brew:"tmux",apt:"tmux",category:"Editors & Terminal"},{name:"screen",check:v("screen"),brew:"screen",apt:"screen",category:"Editors & Terminal"},{name:"less",check:v("less"),category:"Editors & Terminal"},{name:"gcc",check:v("gcc"),brew:"gcc",apt:"gcc",choco:"mingw",category:"Compilers & Build"},{name:"g++",check:v("g++"),brew:"gcc",apt:"g++",choco:"mingw",category:"Compilers & Build"},{name:"make",check:v("make"),brew:"make",apt:"make",choco:"make",category:"Compilers & Build"},{name:"nasm",check:v("nasm"),brew:"nasm",apt:"nasm",choco:"nasm",category:"Compilers & Build"},{name:"cmake",check:v("cmake"),brew:"cmake",apt:"cmake",choco:"cmake",category:"Compilers & Build"},{name:"as",check:v("as"),category:"Compilers & Build"},{name:"ld",check:v("ld"),category:"Compilers & Build"},{name:"pkg-config",check:v("pkg-config"),brew:"pkg-config",apt:"pkg-config",category:"Compilers & Build"},{name:"python3",check:"darwin"===process.platform?"/opt/homebrew/opt/python@3.12/bin/python3.12 --version":$?"python --version":"python3 --version",brew:"python@3.12",apt:"python3",choco:"python312",category:"Python Runtime"},{name:"pip3",check:"darwin"===process.platform?"/opt/homebrew/opt/python@3.12/bin/pip3.12 --version":$?"pip --version":"pip3 --version",category:"Python Runtime"},{name:"python3-venv",check:$?'python -c "import venv"':'python3 -c "import venv"',apt:"python3-venv",category:"Python Runtime"},{name:"curl",check:v("curl"),brew:"curl",apt:"curl",choco:"curl",category:"Networking"},{name:"wget",check:v("wget"),brew:"wget",apt:"wget",choco:"wget",category:"Networking"},{name:"nc",check:v("nc","where ncat"),brew:"netcat",apt:"netcat-openbsd",choco:"nmap",category:"Networking"},{name:"socat",check:v("socat"),brew:"socat",apt:"socat",category:"Networking"},{name:"nmap",check:v("nmap"),brew:"nmap",apt:"nmap",choco:"nmap",category:"Networking"},{name:"ssh",check:v("ssh"),apt:"openssh-client",category:"Networking"},{name:"dig",check:v("dig"),brew:"bind",apt:"dnsutils",category:"Networking"},{name:"whois",check:v("whois"),brew:"whois",apt:"whois",choco:"whois",category:"Networking"},{name:"ping",check:v("ping"),apt:"iputils-ping",category:"Networking"},{name:"traceroute",check:v("traceroute","where tracert"),brew:"traceroute",apt:"traceroute",category:"Networking"},{name:"tcpdump",check:v("tcpdump"),brew:"tcpdump",apt:"tcpdump",category:"Networking"},{name:"tshark",check:v("tshark"),brew:"wireshark",apt:"tshark",choco:"wireshark",aptNoRecommends:!0,debconfSeed:"wireshark-common wireshark-common/install-setuid boolean false",installTimeoutMs:6e5,installHint:"tshark is only needed for packet-capture (pcap) challenges — setup continues without it.",category:"Networking"},{name:"gdb",check:v("gdb"),brew:"gdb",apt:"gdb",choco:"mingw",category:"Debuggers"},..."darwin"!==process.platform?[{name:"ltrace",check:v("ltrace"),apt:"ltrace",category:"Debuggers"},{name:"strace",check:v("strace"),apt:"strace",category:"Debuggers"}]:[],{name:"objdump",check:v("objdump"),category:"Debuggers"},..."darwin"!==process.platform?[{name:"readelf",check:v("readelf"),category:"Debuggers"}]:[],{name:"radare2",check:v("r2"),brew:"radare2",apt:"radare2",choco:"radare2",aptFallback:`ARCH=$(dpkg --print-architecture) && cd /tmp && curl -fsSL -o r2.deb "https://github.com/radareorg/radare2/releases/download/${f}/radare2_${f}_\${ARCH}.deb" && sudo dpkg -i r2.deb && rm -f r2.deb`,category:"Reverse Engineering"},{name:"rabin2",check:v("rabin2"),category:"Reverse Engineering"},{name:"upx",check:v("upx"),brew:"upx",apt:"upx",choco:"upx",category:"Reverse Engineering"},{name:"strings",check:v("strings"),category:"Reverse Engineering"},{name:"binwalk",check:v("binwalk"),brew:"binwalk",apt:"binwalk",category:"Forensics"},..."darwin"!==process.platform?[{name:"foremost",check:v("foremost"),apt:"foremost",category:"Forensics"}]:[],{name:"exiftool",check:v("exiftool"),brew:"exiftool",apt:"exiftool",choco:"exiftool",category:"Forensics"},..."darwin"!==process.platform?[{name:"steghide",check:v("steghide"),apt:"steghide",category:"Forensics"}]:[],{name:"file",check:v("file"),category:"Forensics"},{name:"xxd",check:v("xxd"),brew:"vim",apt:"xxd",category:"Forensics"},{name:"pdftotext",check:v("pdftotext"),brew:"poppler",apt:"poppler-utils",category:"Forensics"},{name:"pngcheck",check:v("pngcheck"),brew:"pngcheck",apt:"pngcheck",category:"Forensics"},{name:"sleuthkit",check:v("mmls"),brew:"sleuthkit",apt:"sleuthkit",choco:"sleuthkit",category:"Forensics"},{name:"john",check:v("john"),brew:"john",apt:"john",choco:"john",category:"Crypto & Password"},{name:"hashcat",check:v("hashcat"),brew:"hashcat",apt:"hashcat",choco:"hashcat",category:"Crypto & Password"},{name:"openssl",check:v("openssl"),category:"Crypto & Password"},{name:"gpg",check:v("gpg"),brew:"gnupg",apt:"gpg",choco:"gnupg",category:"Crypto & Password"},{name:"jq",check:v("jq"),brew:"jq",apt:"jq",choco:"jq",category:"Data Processing"},{name:"sqlite3",check:v("sqlite3"),brew:"sqlite",apt:"sqlite3",choco:"sqlite",category:"Data Processing"},{name:"base64",check:v("base64"),category:"Data Processing"},{name:"hexdump",check:v("hexdump"),category:"Data Processing"},{name:"od",check:v("od"),category:"Data Processing"},{name:"sort",check:v("sort"),category:"Data Processing"},{name:"uniq",check:v("uniq"),category:"Data Processing"},{name:"wc",check:v("wc"),category:"Data Processing"},{name:"unzip",check:v("unzip"),brew:"unzip",apt:"unzip",category:"Archive"},{name:"zip",check:v("zip"),brew:"zip",apt:"zip",category:"Archive"},{name:"tar",check:v("tar"),category:"Archive"},{name:"gzip",check:v("gzip"),category:"Archive"},{name:"bzip2",check:v("bzip2"),category:"Archive"},{name:"xz",check:v("xz"),brew:"xz",apt:"xz-utils",category:"Archive"},{name:"cat",check:v("cat"),category:"Core Unix"},{name:"grep",check:v("grep"),category:"Core Unix"},{name:"sed",check:v("sed"),category:"Core Unix"},{name:"awk",check:v("awk"),category:"Core Unix"},{name:"find",check:v("find"),category:"Core Unix"},{name:"head",check:v("head"),category:"Core Unix"},{name:"tail",check:v("tail"),category:"Core Unix"},{name:"diff",check:v("diff"),category:"Core Unix"},{name:"patch",check:v("patch"),category:"Core Unix"},{name:"chmod",check:v("chmod"),category:"Core Unix"},{name:"chown",check:v("chown"),category:"Core Unix"},{name:"ln",check:v("ln"),category:"Core Unix"},{name:"cp",check:v("cp"),category:"Core Unix"},{name:"mv",check:v("mv"),category:"Core Unix"},{name:"mkdir",check:v("mkdir"),category:"Core Unix"},{name:"rm",check:v("rm"),category:"Core Unix"},{name:"git",check:v("git"),brew:"git",apt:"git",choco:"git",category:"Git & Docker"},{name:"docker",check:v("docker"),brew:"--cask docker",choco:"docker-desktop",optional:!0,category:"Git & Docker"}],P=x.length+k.length;export function probeEnv(){const e=a(),o=[l(e,".local","bin")];return"darwin"===c()&&o.push(l(e,"Library","Python","3.12","bin")),{...process.env,PATH:`${o.join(s)}${s}${process.env.PATH??""}`}}function C(o){const n=o.startsWith("python3 ")?H()+o.slice(7):o;try{return e(n,{stdio:"ignore",env:probeEnv()}),!0}catch{return!1}}export function ensureLocalBinOnPath(){const e=a(),t="# icoa: ensure ~/.local/bin on PATH",c=`\n${t}\ncase ":$PATH:" in *":$HOME/.local/bin:"*) ;; *) export PATH="$HOME/.local/bin:$PATH" ;; esac\n`,s=[],i=[{rc:".bashrc",createIfMissing:!0},{rc:".zshrc",createIfMissing:!1}];for(const{rc:a,createIfMissing:g}of i){const i=l(e,a);try{const e=n(i);if(!e&&!g)continue;if((e?r(i,"utf-8"):"").includes(t))continue;o(i,c),s.push(`~/${a}`)}catch{}}return s}function E(o){const n={python3:`${H()} --version`,pip3:"darwin"===process.platform?"/opt/homebrew/opt/python@3.12/bin/pip3.12 --version":"linux"===process.platform?`${H()} -m pip --version`:"pip --version",gcc:"gcc --version","g++":"g++ --version",make:"make --version",nasm:"nasm --version",cmake:"cmake --version",vim:"vim --version",nano:"nano --version",tmux:"tmux -V",screen:"screen --version",curl:"curl --version",wget:"wget --version",nmap:"nmap --version",ssh:"ssh -V",socat:"socat -V",gdb:"gdb --version",radare2:"r2 -v",upx:"upx --version",binwalk:"binwalk --help",exiftool:"exiftool -ver",john:"john --help",hashcat:"hashcat --version",openssl:"openssl version",gpg:"gpg --version",jq:"jq --version",sqlite3:"sqlite3 --version",git:"git --version",docker:"docker --version",tshark:"tshark --version",tcpdump:"tcpdump --version",pdftotext:"pdftotext -v",pngcheck:"pngcheck 2>&1"}[o];if(!n)return"";try{const o=e(`${n} 2>&1`,{encoding:"utf-8",timeout:3e3}).trim().match(/(\d+\.\d+[.\d]*)/);return o?.[1]||""}catch{}return""}let T=null;export function resetPyBin(){T=null}function H(){if(T)return T;if("darwin"===process.platform)return T="/opt/homebrew/opt/python@3.12/bin/python3.12",T;if("win32"===process.platform)return T="python",T;try{return e("python3.12 --version",{stdio:"ignore"}),T="python3.12",T}catch{}const o=p(a(),"linux");try{return e(`"${o}" --version`,{stdio:"ignore"}),T=o,T}catch{}return T="python3",T}function A(){try{return e(`${H()} -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')"`,{encoding:"utf-8"}).trim()}catch{return""}}function M(){try{return e(`${H()} --version`,{encoding:"utf-8"}).trim().replace("Python ","")}catch{return""}}export function registerEnvCommand(o){const s=o.command("env").description("Manage competition environment");s.command("status").alias("check").description(`Check all ${P} tools`).action(()=>S()),s.command("setup").description("Install all Python libraries + system tools").action(async()=>{await async function(){console.log();const o=c(),s="darwin"===o||"linux"===o?"--break-system-packages":"";console.log(chalk.bold.white(" ICOA Environment Setup")),console.log(chalk.gray(" ─────────────────────────────────────────────")),console.log(chalk.gray(" This will install:")),console.log(chalk.white(" Python 3.12")+chalk.gray(" Runtime for CTF tools")),console.log(chalk.white(` ${k.length} Python libraries`)+chalk.gray(" pwntools, z3, crypto...")),console.log(chalk.white(` ${x.length} system tools`)+chalk.gray(" gcc, gdb, nmap, wireshark...")),console.log(),console.log(chalk.gray(" Estimated: ~500 MB disk, 5-15 min (depends on network)")),console.log(chalk.gray(" Already installed tools will be skipped.")),console.log(chalk.gray(" ─────────────────────────────────────────────")),console.log(),O("Installing system packages needs administrator access"),console.log();const d=process.versions.node;if(b(d))console.log(chalk.green(` ✓ Node.js ${d}`)+chalk.gray(` (>= ${w})`));else{console.log(chalk.yellow(` Node.js ${d} — installing latest 22.x (>= ${w})...`));try{"darwin"===o?e("brew install node@22",{stdio:"inherit"}):"linux"===o?(await N(),e("curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - && sudo apt-get install -y nodejs",{stdio:"inherit"})):e(`winget install OpenJS.NodeJS.LTS --version ${w}`,{stdio:"inherit"}),console.log(chalk.green(` ✓ Node.js (latest 22.x, >= ${w}) installed`)),console.log(chalk.gray(" Restart icoa to use the new version."))}catch{console.log(chalk.yellow(` ~ Node.js upgrade skipped. Install manually: nvm install ${w}`))}}console.log();const u=A(),f=M();if("3.12"===u)console.log(chalk.green(` ✓ Python ${f}`)),console.log();else{console.log(chalk.yellow(` Python ${f||"not found"} — installing Python 3.12 (side-by-side)...`));try{if("darwin"===o)e("brew install python@3.12",{stdio:"inherit"}),resetPyBin(),console.log(chalk.green(" ✓ Python 3.12 installed")),console.log(chalk.gray(" icoa uses it at: /opt/homebrew/opt/python@3.12/bin/python3.12"));else if("linux"===o){console.log(chalk.gray(" Installing python3.12 (your system python3 stays untouched)..."));let o=!1,c=!1;await N();try{e("sudo apt-get install -y python3.12 python3.12-venv python3.12-dev",{stdio:"inherit"}),o=!0}catch{}if(!o&&function(){try{const e=r("/etc/os-release","utf-8"),o=e.match(/^ID=("?)(.+?)\1$/m)?.[2]?.toLowerCase()??"",n=(e.match(/^ID_LIKE=("?)(.+?)\1$/m)?.[2]?.toLowerCase()??"").split(/\s+/);return"ubuntu"===o||n.includes("ubuntu")}catch{return!1}}())try{console.log(chalk.gray(" Not in default repos — adding deadsnakes PPA (Ubuntu)...")),await N(),e("sudo apt-get install -y software-properties-common && sudo add-apt-repository -y ppa:deadsnakes/ppa && sudo apt-get update",{stdio:"inherit"}),await N(),e("sudo apt-get install -y python3.12 python3.12-venv python3.12-dev",{stdio:"inherit"}),o=!0}catch{}if(o||(o=await async function(){const o=a(),r=l(o,".icoa","python312"),c=p(o,"linux");try{if(n(c))return e(`"${c}" --version`,{stdio:"ignore"}),!0}catch{}const s=(()=>{try{return e("uname -m",{encoding:"utf-8"}).trim()}catch{return""}})(),i="aarch64"===s||"arm64"===s?"aarch64":"x86_64"===s?"x86_64":"";if(!i)return console.log(chalk.yellow(` ~ No prebuilt Python 3.12 available for arch '${s||"unknown"}'`)),!1;console.log(chalk.gray(" Not in apt repos and no PPA (Kali/Debian) — fetching a standalone Python 3.12..."));let g="";try{const e=await fetch("https://api.github.com/repos/astral-sh/python-build-standalone/releases/latest",{headers:{"User-Agent":"icoa-cli",Accept:"application/vnd.github+json"}});if(!e.ok)throw new Error(`GitHub API ${e.status}`);const o=await e.json(),n=new RegExp(`^cpython-3\\.12\\.\\d+\\+\\d+-${i}-unknown-linux-gnu-install_only\\.tar\\.gz$`),t=(o.assets??[]).find(e=>n.test(e.name));if(!t)throw new Error("no matching CPython 3.12 asset in the latest release");if(g=t.browser_download_url,!/^https:\/\/github\.com\/astral-sh\/python-build-standalone\/releases\/download\/[\w.+-]+\/cpython-3\.12\.[\w.+-]+\.tar\.gz$/.test(g))throw new Error("asset URL failed the allowlist check")}catch(e){return console.log(chalk.red(" ✗ Could not resolve a standalone Python 3.12")+chalk.gray(` (${e.message})`)),!1}try{t(l(o,".icoa"),{recursive:!0}),e(`set -e; tmp="$(mktemp -d)"; curl -fsSL -o "$tmp/py.tgz" '${g}'; tar -xzf "$tmp/py.tgz" -C "$tmp"; rm -rf '${r}'; mv "$tmp/python" '${r}'; rm -rf "$tmp"`,{stdio:["ignore","ignore","pipe"]});const n=e(`"${c}" --version`,{encoding:"utf-8"}).trim();if(!/^Python 3\.12\./.test(n))throw new Error(`unexpected version: ${n}`);return resetPyBin(),console.log(chalk.green(` ✓ ${n} provisioned`)+chalk.gray(` → ${c} (system python3 unchanged)`)),!0}catch(e){return console.log(chalk.red(" ✗ Standalone Python 3.12 install failed")+chalk.gray(` (${D(e)||e.message})`)),!1}}(),c=o),!o)throw new Error("python3.12 install failed");if(!c)try{e("sudo python3.12 -m ensurepip --upgrade",{stdio:"inherit"})}catch{try{e("curl -sS https://bootstrap.pypa.io/get-pip.py | sudo python3.12",{stdio:"inherit"})}catch{}}resetPyBin(),console.log(chalk.green(" ✓ Python 3.12 installed (system python3 unchanged)")),console.log(chalk.gray(c?` Run Python challenges with: ${H()}`:" Run Python challenges with `python3.12`, or use the sandbox where `python3` is 3.12."))}else{try{e("winget install Python.Python.3.12 --accept-package-agreements --accept-source-agreements",{stdio:"inherit"})}catch{e("choco install -y python312",{stdio:"inherit"})}console.log(chalk.green(" ✓ Python 3.12 installed"))}}catch{console.log(chalk.red(" ✗ Failed to install Python 3.12"));const e="darwin"===o?"brew install python@3.12":"linux"===o?"sudo apt install python3.12":"winget install Python.Python.3.12";console.log(chalk.gray(` Manual install: ${e}`))}console.log()}"win32"===o&&(console.log(chalk.yellow(" Windows: Most CTF tools require Linux. Recommended:")),console.log(chalk.white(" wsl --install")),console.log(chalk.gray(" Then run icoa inside WSL Ubuntu for full tool support.")),console.log());const $=[];for(const e of x)e.optional||C(e.check)||("darwin"===o?e.brew:"linux"===o?e.apt:e.choco)&&$.push(e);const v=$.filter(e=>F.has(e.name)),P=$.filter(e=>!F.has(e.name));if(P.length>0&&"win32"!==o){const n="darwin"===o?"brew":"apt";if(console.log(chalk.bold.white(` System Tools via ${n} (${P.length} missing)`)),console.log(chalk.gray(" ─────────────────────────────────────────────")),await N(),O("Installing system tools needs administrator access"),"linux"===o){try{e("sudo apt-get install -y software-properties-common",{stdio:["ignore","ignore","pipe"]}),e("sudo add-apt-repository -y universe",{stdio:["ignore","ignore","pipe"]})}catch{}try{e("sudo apt-get update",{stdio:["ignore","ignore","pipe"]})}catch{}}for(const e of P)I(e,o,n);console.log()}let T="pip3";if("darwin"===o){const o="/opt/homebrew/opt/python@3.12/bin/pip3.12";try{e(`${o} --version`,{stdio:"ignore"}),T=o,console.log(chalk.gray(` Using: ${o}`))}catch{try{e("pip3.12 --version",{stdio:"ignore"}),T="pip3.12"}catch{}}}else if("linux"===o){const o=H();try{e(`"${o}" -m pip --version`,{stdio:"ignore"}),T=`"${o}" -m pip`}catch{try{e("pip3.12 --version",{stdio:"ignore"}),T="pip3.12"}catch{}}}else"win32"===o&&(T="pip");if("darwin"===o){console.log(chalk.gray(" Installing build dependencies..."));try{e("brew install gmp mpfr libmpc libmagic",{stdio:"ignore"}),console.log(chalk.green(" ✓ Build dependencies ready (gmp, mpfr, libmpc, libmagic)"))}catch{}}else if("linux"===o){console.log(chalk.gray(" Installing build dependencies..."));try{await N(),O("Build dependencies need administrator access"),e("sudo apt-get install -y libgmp-dev libmpfr-dev libmpc-dev libmagic1",{stdio:["ignore","ignore","pipe"]}),console.log(chalk.green(" ✓ Build dependencies ready (libgmp, libmpfr, libmpc, libmagic)"))}catch(e){const o=D(e);console.log(chalk.yellow(" ~ Build dependencies may be incomplete")+(o?chalk.gray(`: ${o}`):"")),console.log(chalk.gray(" gmpy2 needs: sudo apt-get install -y libgmp-dev libmpfr-dev libmpc-dev"))}}console.log();const S={...process.env};"darwin"===o&&(S.CFLAGS=`-I/opt/homebrew/include ${S.CFLAGS||""}`.trim(),S.LDFLAGS=`-L/opt/homebrew/lib ${S.LDFLAGS||""}`.trim(),S.C_INCLUDE_PATH=`/opt/homebrew/include:${S.C_INCLUDE_PATH||""}`,S.LIBRARY_PATH=`/opt/homebrew/lib:${S.LIBRARY_PATH||""}`);const j=l(i(g(import.meta.url)),"..","..","docker","constraints.txt"),q=n(j)?`-c '${j}'`:"";let U=0,B=0;console.log(chalk.bold.white(` Python Libraries (${k.length} packages)`)),console.log(chalk.gray(" ─────────────────────────────────────────────"));for(const o of k)if(o.install)if(C(o.check))console.log(chalk.green(` ✓ ${o.name}`)+chalk.gray(" (installed)")),U++;else{R(o.name);try{e(`${T} install ${s} ${q} '${o.install}'`,{stdio:["ignore","ignore","pipe"],env:S}),L(),console.log(chalk.green(` ✓ ${o.name}`)+chalk.gray(` (${o.install})`)),U++}catch(n){try{e(`${T} install ${s} --ignore-installed ${q} '${o.install}'`,{stdio:["ignore","ignore","pipe"],env:S}),L(),console.log(chalk.green(` ✓ ${o.name}`)+chalk.gray(" (installed over system copy)")),U++}catch(e){L();const n=D(e);console.log(chalk.red(` ✗ ${o.name}`)+chalk.gray(" (failed)")+(n?chalk.gray(`\n ${n}`):"")),B++}}}if(console.log(),console.log(chalk.gray(" ─────────────────────────────────────────────")),console.log(` ${chalk.green(`✓ ${U} installed`)} ${B>0?chalk.red(`✗ ${B} failed`):chalk.green("All ready!")}`),console.log(),"win32"!==o){const e=ensureLocalBinOnPath();e.length>0?(console.log(chalk.green(" ✓ PATH")+chalk.gray(` (added ~/.local/bin to ${e.join(", ")})`)),console.log(chalk.yellow(" → Run `source ~/.bashrc` or open a new terminal")+chalk.gray(" so sqlmap / ROPgadget / ipython are on PATH."))):console.log(chalk.gray(" ✓ PATH (~/.local/bin already configured)")),console.log()}if("win32"!==o){console.log(chalk.bold.white(" GDB Extension (bata24/gef default · pwndbg optional)")),console.log(chalk.gray(" ─────────────────────────────────────────────")),R("bata24/gef");try{e(`if test -s "$HOME/.gef-bata24.py"; then :; else for u in ${["https://raw.githubusercontent.com/bata24/gef/master/gef.py","https://cdn.jsdelivr.net/gh/bata24/gef@master/gef.py"].join(" ")}; do wget -q --timeout=20 --tries=1 -O "$HOME/.gef-bata24.py.tmp" "$u" && test "$(wc -c < "$HOME/.gef-bata24.py.tmp")" -gt 100000 && mv "$HOME/.gef-bata24.py.tmp" "$HOME/.gef-bata24.py" && break; done; rm -f "$HOME/.gef-bata24.py.tmp"; fi && test -s "$HOME/.gef-bata24.py" && touch "$HOME/.gdbinit" && (grep -q gef-bata24 "$HOME/.gdbinit" || printf '\\nsource %s/.gef-bata24.py\\n' "$HOME" >> "$HOME/.gdbinit")`,{stdio:["ignore","ignore","pipe"]}),L(),console.log(chalk.green(" ✓ bata24/gef")+chalk.gray(" (default gdb)"))}catch(e){L();const o=D(e);console.log(chalk.red(" ✗ bata24/gef")+(o?chalk.gray(`\n ${o}`):""))}if(C('test -d "$HOME/pwndbg"'))console.log(chalk.green(" ✓ pwndbg")+chalk.gray(" (run: gdb-pwndbg)"));else{const n="darwin"===o?"command -v uv >/dev/null 2>&1 || brew install uv":"command -v uv >/dev/null 2>&1 || pip3 install --user uv";R("pwndbg (optional)");try{e(`export PATH="$HOME/.local/bin:$PATH" && ${n} && rm -rf "$HOME/pwndbg" && git clone --depth 1 https://github.com/pwndbg/pwndbg "$HOME/pwndbg" && cd "$HOME/pwndbg" && ./setup.sh && mkdir -p "$HOME/.local/bin" && printf '#!/bin/sh\\nexec gdb -q -nx -ex "source $HOME/pwndbg/gdbinit.py" "$@"\\n' > "$HOME/.local/bin/gdb-pwndbg" && chmod +x "$HOME/.local/bin/gdb-pwndbg" && sed -i.bak '/pwndbg/d' "$HOME/.gdbinit" 2>/dev/null || true`,{stdio:["ignore","ignore","pipe"],env:S}),L(),console.log(chalk.green(" ✓ pwndbg")+chalk.gray(" (run: gdb-pwndbg)"))}catch{L(),console.log(chalk.yellow(" ~ pwndbg skipped")+chalk.gray(" (optional — bata24/gef is your default debugger)"))}}console.log(chalk.gray(" Default `gdb` loads bata24/gef; where installed, `gdb-pwndbg` loads pwndbg.")),console.log(chalk.gray(" (ensure ~/.local/bin is on PATH for gdb-pwndbg)")),console.log()}console.log(chalk.bold.white(" Sample-test runner (icoa-judge)")),console.log(chalk.gray(" ─────────────────────────────────────────────"));const z=y();if(z.ok?(console.log(chalk.green(" ✓ icoa-judge")+chalk.gray(` (${z.updated?"installed":"up to date"} → ${h})`)),console.log(chalk.gray(" Run your solution on its samples: python3 ~/.icoa/bin/icoa-judge.py sol.py samples/")),"win32"!==o&&console.log(chalk.gray(" (or just `icoa-judge sol.py samples/` once ~/.icoa/bin is on PATH)")),console.log(chalk.gray(" PyPy is an optional speed boost (not required): run with `--py pypy3`."))):console.log(chalk.yellow(" ~ icoa-judge skipped")+chalk.gray(` (${z.why??"write failed"})`)),console.log(),v.length>0&&"win32"!==o){const e="darwin"===o?"brew":"apt";console.log(chalk.bold.white(` Final tools (${v.map(e=>e.name).join(", ")}) — slowest, installed last`)),console.log(chalk.gray(" ─────────────────────────────────────────────")),"linux"===o&&(await N(),O("Installing the final tools needs administrator access"));for(const n of v)I(n,o,e,"linux"===o?{DEBIAN_FRONTEND:"noninteractive"}:{});console.log()}try{const e=x.map(e=>({name:e.name,version:C(e.check)?E(e.name):""}));m(e)}catch{}}()}),s.command("python").description("Show Python 3.12 install guide for your platform").action(()=>function(){const o=c();console.log(),console.log(chalk.bold.white(" Python 3.12 — Installation Guide")),console.log(chalk.gray(" ─────────────────────────────────────────────")),console.log();let n="",t="missing";const r=["python3.12 --version","/opt/homebrew/opt/python@3.12/bin/python3.12 --version","/usr/local/opt/python@3.12/bin/python3.12 --version","python3 --version"];for(const o of r)try{const r=e(o,{encoding:"utf-8",timeout:3e3}).trim().replace("Python ",""),a=r.split(".").map(Number);if(3===a[0]&&12===a[1]){n=r,t="ok";break}n=r,t=3===a[0]&&a[1]>=10&&a[1]<12?"old":3===a[0]&&a[1]>12?"new":"missing"}catch{}if("ok"===t)return console.log(chalk.green(` ✓ Python ${n} — you're good!`)),console.log(chalk.gray(" Exam toolkit ready. Next: ")+chalk.bold.cyan("exam setup")),void console.log();if("old"===t?console.log(chalk.yellow(` ⚠ Python ${n} — works, but 3.12 recommended`)):"new"===t?(console.log(chalk.yellow(` ⚠ Python ${n} — some packages (pwntools, scapy) lack wheels`)),console.log(chalk.gray(" Downgrading to 3.12 is strongly recommended"))):console.log(chalk.red(" ✗ Python 3 not found")),console.log(),"darwin"===o)console.log(chalk.bold.white(" macOS (Homebrew)")),console.log(),console.log(chalk.green(" brew install python@3.12"));else if("linux"===o){let o="ubuntu";try{const n=e("cat /etc/os-release 2>/dev/null",{encoding:"utf-8",timeout:2e3});o=/fedora|rhel|centos/i.test(n)?"fedora":/arch|manjaro/i.test(n)?"arch":"ubuntu"}catch{}"ubuntu"===o?(console.log(chalk.bold.white(" Ubuntu / Debian / Kali (deadsnakes PPA)")),console.log(),console.log(chalk.gray(" Copy-paste this one-liner:")),console.log(),console.log(chalk.green(" sudo add-apt-repository ppa:deadsnakes/ppa -y && \\")),console.log(chalk.green(" sudo apt update && \\")),console.log(chalk.green(" sudo apt install -y python3.12 python3.12-venv python3.12-dev")),console.log(),console.log(chalk.gray(" This installs ")+chalk.cyan("python3.12")+chalk.gray(" alongside your system python3 — run it as ")+chalk.cyan("python3.12")),console.log(chalk.gray(" (don’t repoint /usr/bin/python3 — it breaks apt & command-not-found on Ubuntu)."))):"fedora"===o?(console.log(chalk.bold.white(" Fedora / RHEL / CentOS")),console.log(),console.log(chalk.green(" sudo dnf install -y python3.12 python3.12-pip"))):"arch"===o&&(console.log(chalk.bold.white(" Arch / Manjaro (via pyenv)")),console.log(),console.log(chalk.green(" sudo pacman -S pyenv && pyenv install 3.12 && pyenv global 3.12")))}else"win32"===o?(console.log(chalk.bold.white(" Windows (WSL recommended)")),console.log(),console.log(chalk.gray(" WSL + Ubuntu (best):")),console.log(chalk.green(" wsl --install")),console.log(chalk.gray(" Then inside Ubuntu, run the Ubuntu commands.")),console.log(),console.log(chalk.gray(" Or native:")),console.log(chalk.green(" winget install Python.Python.3.12"))):console.log(chalk.gray(" https://www.python.org/downloads/"));console.log(),console.log(chalk.white(" After installing, verify:")),console.log(chalk.bold.cyan(" env python")+chalk.gray(" # re-check Python")),console.log(chalk.bold.cyan(" exam setup")+chalk.gray(" # install the 13 exam packages")),console.log()}()),s.action(()=>S())}function S(){console.log();const o=c(),t="darwin"===o?"brew":"linux"===o?"apt":"winget";console.log(chalk.bold.white(" ICOA Competition Environment")),console.log(chalk.gray(" ─────────────────────────────────────────────")),console.log(),console.log(chalk.gray(" These tools power your CTF competition environment.")),console.log(chalk.gray(" Not all are required — here's what matters:")),console.log(),console.log(chalk.green(" Essential")+chalk.gray(" pwntools, z3, requests, numpy")),console.log(chalk.gray(" You need these for most challenges")),console.log(chalk.yellow(" Recommended")+chalk.gray(" pycryptodome, beautifulsoup4, scapy, sympy")),console.log(chalk.gray(" Covers Web, Crypto, and Forensics")),console.log(chalk.gray(` Full (${P}) All tools for every category`)),console.log(),console.log(chalk.gray(" Missing tools? Run ")+chalk.bold.cyan("env setup")+chalk.gray(" to install everything.")),console.log(chalk.gray(" ─────────────────────────────────────────────")),console.log(),console.log(chalk.gray(" OS: ")+chalk.white(function(){const o=c();try{if("darwin"===o)return`macOS ${e("sw_vers -productVersion",{encoding:"utf-8"}).trim()} (${e("uname -m",{encoding:"utf-8"}).trim()})`;if("linux"===o)try{let o="Linux";try{const n=e("cat /etc/os-release | grep PRETTY_NAME",{encoding:"utf-8"}).match(/PRETTY_NAME="(.+)"/);n&&(o=n[1])}catch{}const t=e("uname -m",{encoding:"utf-8"}).trim(),a=function(){try{if(process.env.WSL_DISTRO_NAME)return"WSL";if(r("/proc/version","utf-8").toLowerCase().includes("microsoft"))return"WSL"}catch{}try{if(n("/opt/google/cros-containers"))return"Crostini"}catch{}return""}();return a?`${o} (${t}, ${a})`:`${o} (${t})`}catch{return"Linux"}else if("win32"===o)return e("ver",{encoding:"utf-8"}).trim()||"Windows"}catch{}return o}())),console.log(chalk.gray(" Node: ")+chalk.white(`Node.js ${process.version}`)),console.log(chalk.gray(" Package: ")+chalk.white(t)),console.log(chalk.gray(" Target: ")+chalk.white(`Node ${w} | Python ${u}`)),"win32"===o&&(console.log(),console.log(chalk.yellow(" Windows: recommend WSL (Ubuntu) for full CTF tool support")),console.log(chalk.gray(" Install WSL: ")+chalk.white("wsl --install")),console.log(chalk.gray(" Then run icoa inside WSL for 100% tool compatibility"))),console.log(chalk.gray(" ─────────────────────────────────────────────"));const a=process.versions.node;b(a)?console.log(chalk.green(` ✓ Node.js ${a}`)+chalk.gray(` (>= ${w})`)):(console.log(chalk.red(` ✗ Node.js ${a}`)+chalk.gray(` (>= ${w} required)`)),console.log(chalk.gray(" Install: nvm install 22 or visit https://nodejs.org/")));const s=A(),i=M();"3.12"===s?console.log(chalk.green(` ✓ Python ${i}`)+chalk.gray(i===u?" (official)":"")):s?console.log(chalk.yellow(` ~ Python ${i}`)+chalk.gray(" (3.12 required, run env setup)")):console.log(chalk.red(" ✗ Python 3 not found")),d()?console.log(chalk.green(" ✓ icoa-judge")+chalk.gray(" (sample-test runner)")):console.log(chalk.gray(" ○ icoa-judge")+chalk.gray(" (sample-test runner — run env setup to install)")),console.log();let l=0,g=0,p="";for(const e of x){e.category!==p&&(p=e.category,console.log(chalk.bold.gray(` ${p}`)));const o=C(e.check),n=o?E(e.name):"",t=n?chalk.gray(` (${n})`):"";e.optional?o?console.log(chalk.green(` ✓ ${e.name}`)+t+chalk.gray(" (optional)")):console.log(chalk.gray(` ○ ${e.name}`)+chalk.gray(" (optional — only for shell sandbox; not needed)")):o?(console.log(chalk.green(` ✓ ${e.name}`)+t),l++):(console.log(chalk.red(` ✗ ${e.name}`)),g++)}"win32"!==o&&(console.log(chalk.bold.gray(" GDB Extension")),C('grep -qi pwndbg "$HOME/.gdbinit" 2>/dev/null || test -f "$HOME/.gef-bata24.py"')?(console.log(chalk.green(" ✓ bata24-gef (+pwndbg)")),l++):(console.log(chalk.red(" ✗ bata24-gef (+pwndbg)")+chalk.gray(" (run env setup)")),g++)),p="";const y="darwin"===o?"/opt/homebrew/opt/python@3.12/bin/pip3.12":"win32"===o?"pip":"pip3";for(const o of k)if(o.category!==p&&(p=o.category,console.log(chalk.bold.gray(` ${p}`))),C(o.check)){let n="";for(const t of[y,"pip3","pip"])try{const r=o.name.replace("python-magic","python_magic"),a=e(`${t} show ${r}`,{encoding:"utf-8",timeout:3e3,stdio:["pipe","pipe","ignore"]}).match(/Version:\s*(\S+)/);if(a){n=a[1];break}}catch{}console.log(chalk.green(` ✓ ${o.name}`)+chalk.gray(n?` (${n})`:"")),l++}else console.log(chalk.red(` ✗ ${o.name}`)+chalk.gray(` → ${o.install||"latest"}`)),g++;const h=l+g;console.log(),console.log(chalk.gray(" ─────────────────────────────────────────────")),console.log(` ${chalk.green(`✓ ${l}/${h}`)} ${g>0?chalk.red(`✗ ${g} missing`):chalk.green(`All ${h} ready!`)}`),g>0&&console.log(chalk.gray(" Install everything: ")+chalk.white("env setup")+chalk.gray(" (~5 min, one-time)")),console.log(chalk.gray(" You are back at the ")+chalk.cyan("icoa>")+chalk.gray(" prompt. ")+chalk.cyan("help")+chalk.gray(" for all commands.")),console.log()}function j(){for(const o of["/var/lib/dpkg/lock-frontend","/var/lib/dpkg/lock","/var/lib/apt/lists/lock"])try{return e(`sudo fuser ${o} 2>/dev/null`,{stdio:"ignore",timeout:5e3}),!0}catch{}return!1}async function N(e=3e5){if("linux"!==c())return;if(!j())return;console.log(chalk.yellow(" ⏳ System package manager is busy")+chalk.gray(" (ChromeOS may be updating in the background).")),console.log(chalk.gray(` Waiting up to ${Math.round(e/6e4)} min for it to finish… `)+chalk.gray("(Ctrl+C to cancel, or re-run ")+chalk.cyan("env setup")+chalk.gray(" later)")),process.stdout.write(chalk.gray(" "));const o=Date.now();let n=0;for(;j();){if(Date.now()-o>e)return console.log(),console.log(chalk.yellow(" ~ Still busy after waiting. Skipping the wait.")),void console.log(chalk.gray(" If installs fail, re-run ")+chalk.cyan("env setup")+chalk.gray(" in a few minutes."));process.stdout.write(chalk.gray(".")),++n%50==0&&process.stdout.write(chalk.gray("\n ")),await new Promise(e=>setTimeout(e,3e3))}console.log(),console.log(chalk.green(" ✓ Package manager free — continuing."))}function O(o){if("linux"===c()){try{return void e("sudo -n true",{stdio:"ignore"})}catch{}console.log(chalk.yellow(` 🔑 ${o}`)+chalk.gray(" — enter your password if prompted:"));try{e("sudo -v",{stdio:"inherit"})}catch{console.log(chalk.gray(" (sudo unavailable — some installs may fail)"))}}}function R(e){process.stdout.isTTY&&process.stdout.write(chalk.gray(` ⏳ ${e}...`))}function L(){process.stdout.isTTY&&process.stdout.write("\r[2K")}function D(e){const o=e,n=(o?.stderr?o.stderr.toString():"").split("\n").map(e=>e.trim()).filter(Boolean);return n.length?n[n.length-1].slice(0,100):""}const F=new Set(["tshark"]);function I(o,n,t,r={}){const a="darwin"===n?o.brew:"linux"===n?o.apt:o.choco,c={...process.env,...r};R(o.name);try{if("linux"===n&&o.debconfSeed)try{e(`echo "${o.debconfSeed}" | sudo debconf-set-selections`,{stdio:["ignore","ignore","pipe"],env:c})}catch{}let t;t="darwin"===n?`brew install ${a}`:"linux"===n?`sudo apt-get install -y ${o.aptNoRecommends?"--no-install-recommends ":""}${a}`:`choco install -y ${a}`,e(t,{stdio:["ignore","ignore","pipe"],env:c,timeout:o.installTimeoutMs}),L(),console.log(chalk.green(` ✓ ${o.name}`))}catch(r){if("linux"===n&&o.aptFallback)try{return R(`${o.name} (fallback)`),e(o.aptFallback,{stdio:["ignore","ignore","pipe"],env:c}),L(),void console.log(chalk.green(` ✓ ${o.name}`)+chalk.gray(" (official .deb)"))}catch{}L();const s=r,i=!0===s?.killed||"SIGTERM"===s?.signal||"ETIMEDOUT"===s?.code,l="darwin"===n?`brew install ${a}`:"linux"===n?`sudo apt-get install -y ${o.aptNoRecommends?"--no-install-recommends ":""}${a}`:`choco install -y ${a}`;if(i){const e=Math.round((o.installTimeoutMs??0)/6e4);console.log(chalk.red(` ✗ ${o.name}`)+chalk.gray(` (timed out${e?` after ${e} min`:""} — stalled mirror or apt lock)`)+(o.installHint?chalk.gray(`\n ${o.installHint}`):"")+chalk.gray(`\n Install it later with: ${l}`))}else{const e=D(r);console.log(chalk.red(` ✗ ${o.name}`)+chalk.gray(` (${t} install ${a})`)+(e?chalk.gray(`\n ${e}`):"")+(o.installHint?chalk.gray(`\n ${o.installHint}`):""))}}}
|