icoa-cli 2.19.100 → 2.19.101
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/ai4ctf.js +1 -700
- package/dist/commands/connect.js +1 -66
- package/dist/commands/ctf.js +1 -620
- package/dist/commands/ctf4ai-demo.js +1 -525
- package/dist/commands/env.js +1 -738
- package/dist/commands/exam.js +1 -2353
- package/dist/commands/files.js +1 -52
- package/dist/commands/hint.js +1 -119
- package/dist/commands/lang.js +1 -155
- package/dist/commands/log.js +1 -165
- package/dist/commands/note.js +1 -40
- package/dist/commands/ref.js +1 -68
- package/dist/commands/setup.js +1 -122
- package/dist/commands/shell.js +1 -55
- package/dist/commands/theme.js +1 -50
- package/dist/index.js +1 -225
- package/dist/lib/access.js +1 -246
- package/dist/lib/budget.js +1 -42
- package/dist/lib/colors.js +1 -21
- package/dist/lib/config.js +1 -60
- package/dist/lib/ctfd-client.js +1 -274
- package/dist/lib/demo-exam.js +1 -249
- package/dist/lib/demo-flags.js +1 -27
- package/dist/lib/demo-stats.js +1 -65
- package/dist/lib/exam-client.js +1 -57
- package/dist/lib/exam-setup.js +1 -23
- package/dist/lib/exam-state.js +1 -112
- package/dist/lib/gemini.js +1 -235
- package/dist/lib/i18n.js +1 -273
- package/dist/lib/log-sync.js +1 -110
- package/dist/lib/logger.js +1 -59
- package/dist/lib/paper-upgrade.js +1 -117
- package/dist/lib/platform.js +1 -86
- package/dist/lib/sandbox.js +1 -93
- package/dist/lib/terminal.js +1 -49
- package/dist/lib/theme.js +1 -108
- package/dist/lib/translation.js +1 -66
- package/dist/lib/ui.js +1 -80
- package/dist/lib/update-check.js +1 -102
- package/dist/postinstall.js +1 -48
- package/dist/repl.js +1 -1281
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.js +1 -38
- package/package.json +6 -2
- package/translations/sw/i18n-snippet.ts +1 -0
package/dist/commands/env.js
CHANGED
|
@@ -1,738 +1 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
|
-
import { execSync } from 'node:child_process';
|
|
3
|
-
import { platform } from 'node:os';
|
|
4
|
-
// Target versions for full compatibility
|
|
5
|
-
const PYTHON_TARGET = '3.12';
|
|
6
|
-
const PYTHON_EXACT = '3.12.13';
|
|
7
|
-
const NODE_TARGET = '22';
|
|
8
|
-
const NODE_EXACT = '22.22.2';
|
|
9
|
-
// ══════════════════════════════════════════════════════════
|
|
10
|
-
// 27 Python Libraries — ALL LOCKED VERSIONS
|
|
11
|
-
// Tested on Python 3.12.x (recommended)
|
|
12
|
-
// ══════════════════════════════════════════════════════════
|
|
13
|
-
const PYTHON_LIBS = [
|
|
14
|
-
// Core CTF
|
|
15
|
-
{ name: 'pwntools', check: 'python3 -c "import pwn"', install: 'pwntools==4.12.0', category: 'CTF Core' },
|
|
16
|
-
{ name: 'pycryptodome', check: 'python3 -c "import Crypto"', install: 'pycryptodome==3.20.0', category: 'CTF Core' },
|
|
17
|
-
{ name: 'z3-solver', check: 'python3 -c "import z3"', install: 'z3-solver==4.12.6', category: 'CTF Core' },
|
|
18
|
-
{ name: 'angr', check: 'python3 -c "import angr"', install: 'angr', category: 'CTF Core' },
|
|
19
|
-
// Networking & Web
|
|
20
|
-
{ name: 'requests', check: 'python3 -c "import requests"', install: 'requests==2.31.0', category: 'Web & Network' },
|
|
21
|
-
{ name: 'beautifulsoup4', check: 'python3 -c "import bs4"', install: 'beautifulsoup4==4.12.3', category: 'Web & Network' },
|
|
22
|
-
{ name: 'flask', check: 'python3 -c "import flask"', install: 'flask==3.0.0', category: 'Web & Network' },
|
|
23
|
-
{ name: 'scapy', check: 'python3 -c "import scapy"', install: 'scapy==2.5.0', category: 'Web & Network' },
|
|
24
|
-
{ name: 'paramiko', check: 'python3 -c "import paramiko"', install: 'paramiko==3.4.0', category: 'Web & Network' },
|
|
25
|
-
// Crypto & Math
|
|
26
|
-
{ name: 'sympy', check: 'python3 -c "import sympy"', install: 'sympy==1.12', category: 'Crypto & Math' },
|
|
27
|
-
{ name: 'gmpy2', check: process.platform === 'darwin' ? '/opt/homebrew/opt/python@3.12/bin/python3.12 -c "import gmpy2"' : 'python3 -c "import gmpy2"', install: 'gmpy2>=2.2.0', category: 'Crypto & Math' },
|
|
28
|
-
{ name: 'cryptography', check: 'python3 -c "import cryptography"', install: 'cryptography==42.0.0', category: 'Crypto & Math' },
|
|
29
|
-
// Binary & RE
|
|
30
|
-
{ name: 'capstone', check: 'python3 -c "import capstone"', install: 'capstone==5.0.1', category: 'Binary & RE' },
|
|
31
|
-
{ name: 'ropper', check: 'python3 -c "import ropper"', install: 'ropper==1.13.8', category: 'Binary & RE' },
|
|
32
|
-
{ name: 'ROPgadget', check: 'which ROPgadget', install: 'ROPgadget==7.4', category: 'Binary & RE' },
|
|
33
|
-
{ name: 'pefile', check: 'python3 -c "import pefile"', install: 'pefile==2023.2.7', category: 'Binary & RE' },
|
|
34
|
-
// Data & Forensics
|
|
35
|
-
{ name: 'pillow', check: 'python3 -c "import PIL"', install: 'pillow==10.2.0', category: 'Data & Forensics' },
|
|
36
|
-
{ name: 'numpy', check: 'python3 -c "import numpy"', install: 'numpy==1.26.4', category: 'Data & Forensics' },
|
|
37
|
-
{ name: 'python-magic', check: 'python3 -c "import magic"', install: 'python-magic==0.4.27', category: 'Data & Forensics' },
|
|
38
|
-
{ name: 'yara-python', check: 'python3 -c "import yara"', install: 'yara-python==4.5.0', category: 'Data & Forensics' },
|
|
39
|
-
// Tools
|
|
40
|
-
{ name: 'sqlmap', check: 'which sqlmap', install: 'sqlmap', category: 'Security Tools' },
|
|
41
|
-
{ name: 'ipython', check: 'which ipython3 || which ipython', install: 'ipython', category: 'Security Tools' },
|
|
42
|
-
{ name: 'uncompyle6', check: 'python3 -c "import uncompyle6"', install: 'uncompyle6==3.9.1', category: 'Security Tools' },
|
|
43
|
-
{ name: 'volatility3', check: 'python3 -c "import volatility3"', install: 'volatility3', category: 'Security Tools' },
|
|
44
|
-
{ name: 'pyserial', check: 'python3 -c "import serial"', install: 'pyserial==3.5', category: 'Security Tools' },
|
|
45
|
-
];
|
|
46
|
-
// ══════════════════════════════════════════════════════════
|
|
47
|
-
// 83 System Tools — brew (Mac) / apt (Ubuntu) / choco (Win)
|
|
48
|
-
// ══════════════════════════════════════════════════════════
|
|
49
|
-
const W = process.platform === 'win32';
|
|
50
|
-
const CMD = (unix, win) => W ? (win || `where ${unix}`) : `which ${unix}`;
|
|
51
|
-
const SYSTEM_TOOLS = [
|
|
52
|
-
// Editors & Terminal (5)
|
|
53
|
-
{ name: 'vim', check: CMD('vim'), brew: 'vim', apt: 'vim', choco: 'vim', category: 'Editors & Terminal' },
|
|
54
|
-
{ name: 'nano', check: CMD('nano'), brew: 'nano', apt: 'nano', choco: 'nano', category: 'Editors & Terminal' },
|
|
55
|
-
{ name: 'tmux', check: CMD('tmux'), brew: 'tmux', apt: 'tmux', category: 'Editors & Terminal' },
|
|
56
|
-
{ name: 'screen', check: CMD('screen'), brew: 'screen', apt: 'screen', category: 'Editors & Terminal' },
|
|
57
|
-
{ name: 'less', check: CMD('less'), category: 'Editors & Terminal' },
|
|
58
|
-
// Compilers & Build (8)
|
|
59
|
-
{ name: 'gcc', check: CMD('gcc'), brew: 'gcc', apt: 'gcc', choco: 'mingw', category: 'Compilers & Build' },
|
|
60
|
-
{ name: 'g++', check: CMD('g++'), brew: 'gcc', apt: 'g++', choco: 'mingw', category: 'Compilers & Build' },
|
|
61
|
-
{ name: 'make', check: CMD('make'), brew: 'make', apt: 'make', choco: 'make', category: 'Compilers & Build' },
|
|
62
|
-
{ name: 'nasm', check: CMD('nasm'), brew: 'nasm', apt: 'nasm', choco: 'nasm', category: 'Compilers & Build' },
|
|
63
|
-
{ name: 'cmake', check: CMD('cmake'), brew: 'cmake', apt: 'cmake', choco: 'cmake', category: 'Compilers & Build' },
|
|
64
|
-
{ name: 'as', check: CMD('as'), category: 'Compilers & Build' },
|
|
65
|
-
{ name: 'ld', check: CMD('ld'), category: 'Compilers & Build' },
|
|
66
|
-
{ name: 'pkg-config', check: CMD('pkg-config'), brew: 'pkg-config', apt: 'pkg-config', category: 'Compilers & Build' },
|
|
67
|
-
// Python (3) — prefer brew 3.12 on macOS
|
|
68
|
-
{ name: 'python3', check: process.platform === 'darwin' ? '/opt/homebrew/opt/python@3.12/bin/python3.12 --version' : (W ? 'python --version' : 'python3 --version'), brew: 'python@3.12', apt: 'python3', choco: 'python312', category: 'Python Runtime' },
|
|
69
|
-
{ name: 'pip3', check: process.platform === 'darwin' ? '/opt/homebrew/opt/python@3.12/bin/pip3.12 --version' : (W ? 'pip --version' : 'pip3 --version'), category: 'Python Runtime' },
|
|
70
|
-
{ name: 'python3-venv', check: W ? 'python -c "import venv"' : 'python3 -c "import venv"', apt: 'python3-venv', category: 'Python Runtime' },
|
|
71
|
-
// Networking (12)
|
|
72
|
-
{ name: 'curl', check: CMD('curl'), brew: 'curl', apt: 'curl', choco: 'curl', category: 'Networking' },
|
|
73
|
-
{ name: 'wget', check: CMD('wget'), brew: 'wget', apt: 'wget', choco: 'wget', category: 'Networking' },
|
|
74
|
-
{ name: 'nc', check: CMD('nc', 'where ncat'), brew: 'netcat', apt: 'netcat-openbsd', choco: 'nmap', category: 'Networking' },
|
|
75
|
-
{ name: 'socat', check: CMD('socat'), brew: 'socat', apt: 'socat', category: 'Networking' },
|
|
76
|
-
{ name: 'nmap', check: CMD('nmap'), brew: 'nmap', apt: 'nmap', choco: 'nmap', category: 'Networking' },
|
|
77
|
-
{ name: 'ssh', check: CMD('ssh'), apt: 'openssh-client', category: 'Networking' },
|
|
78
|
-
{ name: 'dig', check: CMD('dig'), brew: 'bind', apt: 'dnsutils', category: 'Networking' },
|
|
79
|
-
{ name: 'whois', check: CMD('whois'), brew: 'whois', apt: 'whois', choco: 'whois', category: 'Networking' },
|
|
80
|
-
{ name: 'ping', check: CMD('ping'), apt: 'iputils-ping', category: 'Networking' },
|
|
81
|
-
{ name: 'traceroute', check: CMD('traceroute', 'where tracert'), brew: 'traceroute', apt: 'traceroute', category: 'Networking' },
|
|
82
|
-
{ name: 'tcpdump', check: CMD('tcpdump'), brew: 'tcpdump', apt: 'tcpdump', category: 'Networking' },
|
|
83
|
-
{ name: 'tshark', check: CMD('tshark'), brew: 'wireshark', apt: 'tshark', choco: 'wireshark', category: 'Networking' },
|
|
84
|
-
// Debuggers & Tracing (5)
|
|
85
|
-
{ name: 'gdb', check: CMD('gdb'), brew: 'gdb', apt: 'gdb', choco: 'mingw', category: 'Debuggers' },
|
|
86
|
-
...(process.platform !== 'darwin' ? [
|
|
87
|
-
{ name: 'ltrace', check: CMD('ltrace'), apt: 'ltrace', category: 'Debuggers' },
|
|
88
|
-
{ name: 'strace', check: CMD('strace'), apt: 'strace', category: 'Debuggers' },
|
|
89
|
-
] : []),
|
|
90
|
-
{ name: 'objdump', check: CMD('objdump'), category: 'Debuggers' },
|
|
91
|
-
...(process.platform !== 'darwin' ? [
|
|
92
|
-
{ name: 'readelf', check: CMD('readelf'), category: 'Debuggers' },
|
|
93
|
-
] : []),
|
|
94
|
-
// Reverse Engineering (4)
|
|
95
|
-
{ name: 'radare2', check: CMD('r2'), brew: 'radare2', apt: 'radare2', choco: 'radare2', category: 'Reverse Engineering' },
|
|
96
|
-
{ name: 'rabin2', check: CMD('rabin2'), category: 'Reverse Engineering' },
|
|
97
|
-
{ name: 'upx', check: CMD('upx'), brew: 'upx', apt: 'upx', choco: 'upx', category: 'Reverse Engineering' },
|
|
98
|
-
{ name: 'strings', check: CMD('strings'), category: 'Reverse Engineering' },
|
|
99
|
-
// Forensics (7)
|
|
100
|
-
{ name: 'binwalk', check: CMD('binwalk'), brew: 'binwalk', apt: 'binwalk', category: 'Forensics' },
|
|
101
|
-
...(process.platform !== 'darwin' ? [
|
|
102
|
-
{ name: 'foremost', check: CMD('foremost'), apt: 'foremost', category: 'Forensics' },
|
|
103
|
-
] : []),
|
|
104
|
-
{ name: 'exiftool', check: CMD('exiftool'), brew: 'exiftool', apt: 'exiftool', choco: 'exiftool', category: 'Forensics' },
|
|
105
|
-
...(process.platform !== 'darwin' ? [
|
|
106
|
-
{ name: 'steghide', check: CMD('steghide'), apt: 'steghide', category: 'Forensics' },
|
|
107
|
-
] : []),
|
|
108
|
-
{ name: 'file', check: CMD('file'), category: 'Forensics' },
|
|
109
|
-
{ name: 'xxd', check: CMD('xxd'), brew: 'vim', apt: 'xxd', category: 'Forensics' },
|
|
110
|
-
{ name: 'pdftotext', check: CMD('pdftotext'), brew: 'poppler', apt: 'poppler-utils', category: 'Forensics' },
|
|
111
|
-
{ name: 'pngcheck', check: CMD('pngcheck'), brew: 'pngcheck', apt: 'pngcheck', category: 'Forensics' },
|
|
112
|
-
// sleuthkit — disk-image forensics (mmls/fls/icat/blkcat + 20 more)
|
|
113
|
-
{ name: 'sleuthkit', check: CMD('mmls'), brew: 'sleuthkit', apt: 'sleuthkit', choco: 'sleuthkit', category: 'Forensics' },
|
|
114
|
-
// Crypto & Password (4)
|
|
115
|
-
{ name: 'john', check: CMD('john'), brew: 'john', apt: 'john', choco: 'john', category: 'Crypto & Password' },
|
|
116
|
-
{ name: 'hashcat', check: CMD('hashcat'), brew: 'hashcat', apt: 'hashcat', choco: 'hashcat', category: 'Crypto & Password' },
|
|
117
|
-
{ name: 'openssl', check: CMD('openssl'), category: 'Crypto & Password' },
|
|
118
|
-
{ name: 'gpg', check: CMD('gpg'), brew: 'gnupg', apt: 'gpg', choco: 'gnupg', category: 'Crypto & Password' },
|
|
119
|
-
// Data Processing (8)
|
|
120
|
-
{ name: 'jq', check: CMD('jq'), brew: 'jq', apt: 'jq', choco: 'jq', category: 'Data Processing' },
|
|
121
|
-
{ name: 'sqlite3', check: CMD('sqlite3'), brew: 'sqlite', apt: 'sqlite3', choco: 'sqlite', category: 'Data Processing' },
|
|
122
|
-
{ name: 'base64', check: CMD('base64'), category: 'Data Processing' },
|
|
123
|
-
{ name: 'hexdump', check: CMD('hexdump'), category: 'Data Processing' },
|
|
124
|
-
{ name: 'od', check: CMD('od'), category: 'Data Processing' },
|
|
125
|
-
{ name: 'sort', check: CMD('sort'), category: 'Data Processing' },
|
|
126
|
-
{ name: 'uniq', check: CMD('uniq'), category: 'Data Processing' },
|
|
127
|
-
{ name: 'wc', check: CMD('wc'), category: 'Data Processing' },
|
|
128
|
-
// Archive (6)
|
|
129
|
-
{ name: 'unzip', check: CMD('unzip'), brew: 'unzip', apt: 'unzip', category: 'Archive' },
|
|
130
|
-
{ name: 'zip', check: CMD('zip'), brew: 'zip', apt: 'zip', category: 'Archive' },
|
|
131
|
-
{ name: 'tar', check: CMD('tar'), category: 'Archive' },
|
|
132
|
-
{ name: 'gzip', check: CMD('gzip'), category: 'Archive' },
|
|
133
|
-
{ name: 'bzip2', check: CMD('bzip2'), category: 'Archive' },
|
|
134
|
-
{ name: 'xz', check: CMD('xz'), brew: 'xz', apt: 'xz-utils', category: 'Archive' },
|
|
135
|
-
// Core Unix (16)
|
|
136
|
-
{ name: 'cat', check: CMD('cat'), category: 'Core Unix' },
|
|
137
|
-
{ name: 'grep', check: CMD('grep'), category: 'Core Unix' },
|
|
138
|
-
{ name: 'sed', check: CMD('sed'), category: 'Core Unix' },
|
|
139
|
-
{ name: 'awk', check: CMD('awk'), category: 'Core Unix' },
|
|
140
|
-
{ name: 'find', check: CMD('find'), category: 'Core Unix' },
|
|
141
|
-
{ name: 'head', check: CMD('head'), category: 'Core Unix' },
|
|
142
|
-
{ name: 'tail', check: CMD('tail'), category: 'Core Unix' },
|
|
143
|
-
{ name: 'diff', check: CMD('diff'), category: 'Core Unix' },
|
|
144
|
-
{ name: 'patch', check: CMD('patch'), category: 'Core Unix' },
|
|
145
|
-
{ name: 'chmod', check: CMD('chmod'), category: 'Core Unix' },
|
|
146
|
-
{ name: 'chown', check: CMD('chown'), category: 'Core Unix' },
|
|
147
|
-
{ name: 'ln', check: CMD('ln'), category: 'Core Unix' },
|
|
148
|
-
{ name: 'cp', check: CMD('cp'), category: 'Core Unix' },
|
|
149
|
-
{ name: 'mv', check: CMD('mv'), category: 'Core Unix' },
|
|
150
|
-
{ name: 'mkdir', check: CMD('mkdir'), category: 'Core Unix' },
|
|
151
|
-
{ name: 'rm', check: CMD('rm'), category: 'Core Unix' },
|
|
152
|
-
// Version Control & Container (2)
|
|
153
|
-
{ name: 'git', check: CMD('git'), brew: 'git', apt: 'git', choco: 'git', category: 'Git & Docker' },
|
|
154
|
-
{ name: 'docker', check: CMD('docker'), brew: '--cask docker', choco: 'docker-desktop', category: 'Git & Docker' },
|
|
155
|
-
];
|
|
156
|
-
function isInstalled(check) {
|
|
157
|
-
try {
|
|
158
|
-
execSync(check, { stdio: 'ignore' });
|
|
159
|
-
return true;
|
|
160
|
-
}
|
|
161
|
-
catch {
|
|
162
|
-
return false;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
function getVersion(name) {
|
|
166
|
-
// Version commands for each tool
|
|
167
|
-
const versionCmds = {
|
|
168
|
-
'python3': process.platform === 'darwin' ? '/opt/homebrew/opt/python@3.12/bin/python3.12 --version' : 'python3 --version',
|
|
169
|
-
'pip3': process.platform === 'darwin' ? '/opt/homebrew/opt/python@3.12/bin/pip3.12 --version' : 'pip3 --version',
|
|
170
|
-
'gcc': 'gcc --version',
|
|
171
|
-
'g++': 'g++ --version',
|
|
172
|
-
'make': 'make --version',
|
|
173
|
-
'nasm': 'nasm --version',
|
|
174
|
-
'cmake': 'cmake --version',
|
|
175
|
-
'vim': 'vim --version',
|
|
176
|
-
'nano': 'nano --version',
|
|
177
|
-
'tmux': 'tmux -V',
|
|
178
|
-
'screen': 'screen --version',
|
|
179
|
-
'curl': 'curl --version',
|
|
180
|
-
'wget': 'wget --version',
|
|
181
|
-
'nmap': 'nmap --version',
|
|
182
|
-
'ssh': 'ssh -V',
|
|
183
|
-
'socat': 'socat -V',
|
|
184
|
-
'gdb': 'gdb --version',
|
|
185
|
-
'radare2': 'r2 -v',
|
|
186
|
-
'upx': 'upx --version',
|
|
187
|
-
'binwalk': 'binwalk --help',
|
|
188
|
-
'exiftool': 'exiftool -ver',
|
|
189
|
-
'john': 'john --help',
|
|
190
|
-
'hashcat': 'hashcat --version',
|
|
191
|
-
'openssl': 'openssl version',
|
|
192
|
-
'gpg': 'gpg --version',
|
|
193
|
-
'jq': 'jq --version',
|
|
194
|
-
'sqlite3': 'sqlite3 --version',
|
|
195
|
-
'git': 'git --version',
|
|
196
|
-
'docker': 'docker --version',
|
|
197
|
-
'tshark': 'tshark --version',
|
|
198
|
-
'tcpdump': 'tcpdump --version',
|
|
199
|
-
'pdftotext': 'pdftotext -v',
|
|
200
|
-
'pngcheck': 'pngcheck 2>&1',
|
|
201
|
-
};
|
|
202
|
-
const cmd = versionCmds[name];
|
|
203
|
-
if (!cmd)
|
|
204
|
-
return '';
|
|
205
|
-
try {
|
|
206
|
-
const out = execSync(cmd + ' 2>&1', { encoding: 'utf-8', timeout: 3000 }).trim();
|
|
207
|
-
// Extract version number pattern
|
|
208
|
-
const m = out.match(/(\d+\.\d+[\.\d]*)/);
|
|
209
|
-
return m?.[1] || '';
|
|
210
|
-
}
|
|
211
|
-
catch { /* ignore */ }
|
|
212
|
-
return '';
|
|
213
|
-
}
|
|
214
|
-
function getOsInfo() {
|
|
215
|
-
const os = platform();
|
|
216
|
-
try {
|
|
217
|
-
if (os === 'darwin') {
|
|
218
|
-
const ver = execSync('sw_vers -productVersion', { encoding: 'utf-8' }).trim();
|
|
219
|
-
const arch = execSync('uname -m', { encoding: 'utf-8' }).trim();
|
|
220
|
-
return `macOS ${ver} (${arch})`;
|
|
221
|
-
}
|
|
222
|
-
else if (os === 'linux') {
|
|
223
|
-
try {
|
|
224
|
-
const pretty = execSync('cat /etc/os-release | grep PRETTY_NAME', { encoding: 'utf-8' });
|
|
225
|
-
const m = pretty.match(/PRETTY_NAME="(.+)"/);
|
|
226
|
-
const arch = execSync('uname -m', { encoding: 'utf-8' }).trim();
|
|
227
|
-
return m ? `${m[1]} (${arch})` : `Linux (${arch})`;
|
|
228
|
-
}
|
|
229
|
-
catch {
|
|
230
|
-
return 'Linux';
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
else if (os === 'win32') {
|
|
234
|
-
const ver = execSync('ver', { encoding: 'utf-8' }).trim();
|
|
235
|
-
return ver || 'Windows';
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
catch { /* ignore */ }
|
|
239
|
-
return os;
|
|
240
|
-
}
|
|
241
|
-
function getNodeInfo() {
|
|
242
|
-
return `Node.js ${process.version}`;
|
|
243
|
-
}
|
|
244
|
-
function getPythonMajorMinor() {
|
|
245
|
-
// On macOS, prefer brew Python 3.12
|
|
246
|
-
if (process.platform === 'darwin') {
|
|
247
|
-
try {
|
|
248
|
-
return execSync('/opt/homebrew/opt/python@3.12/bin/python3.12 -c "import sys; print(f\'{sys.version_info.major}.{sys.version_info.minor}\')"', { encoding: 'utf-8' }).trim();
|
|
249
|
-
}
|
|
250
|
-
catch { /* fall through */ }
|
|
251
|
-
}
|
|
252
|
-
try {
|
|
253
|
-
return execSync('python3 -c "import sys; print(f\'{sys.version_info.major}.{sys.version_info.minor}\')"', { encoding: 'utf-8' }).trim();
|
|
254
|
-
}
|
|
255
|
-
catch {
|
|
256
|
-
return '';
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
function getPythonFullVersion() {
|
|
260
|
-
if (process.platform === 'darwin') {
|
|
261
|
-
try {
|
|
262
|
-
return execSync('/opt/homebrew/opt/python@3.12/bin/python3.12 --version', { encoding: 'utf-8' }).trim().replace('Python ', '');
|
|
263
|
-
}
|
|
264
|
-
catch { /* fall through */ }
|
|
265
|
-
}
|
|
266
|
-
try {
|
|
267
|
-
return execSync('python3 --version', { encoding: 'utf-8' }).trim().replace('Python ', '');
|
|
268
|
-
}
|
|
269
|
-
catch {
|
|
270
|
-
return '';
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
export function registerEnvCommand(program) {
|
|
274
|
-
const envCmd = program.command('env').description('Manage competition environment');
|
|
275
|
-
envCmd.command('status').alias('check').description('Check all 110 tools').action(() => showStatus());
|
|
276
|
-
envCmd.command('setup').description('Install all Python libraries + system tools').action(async () => { await installAll(); });
|
|
277
|
-
envCmd.command('python').description('Show Python 3.12 install guide for your platform').action(() => showPythonInstallGuide());
|
|
278
|
-
envCmd.action(() => showStatus());
|
|
279
|
-
}
|
|
280
|
-
// Lightweight Python 3.12 install guide for Selection mode (no 110-tool check).
|
|
281
|
-
// Detects distro on Linux so contestants get the right command the first time.
|
|
282
|
-
function showPythonInstallGuide() {
|
|
283
|
-
const os = platform();
|
|
284
|
-
console.log();
|
|
285
|
-
console.log(chalk.bold.white(' Python 3.12 — Installation Guide'));
|
|
286
|
-
console.log(chalk.gray(' ─────────────────────────────────────────────'));
|
|
287
|
-
console.log();
|
|
288
|
-
let currentPy = '';
|
|
289
|
-
let pyStatus = 'missing';
|
|
290
|
-
// Prefer the versioned binary if available. On macOS with Homebrew, `python3`
|
|
291
|
-
// often points to the latest (e.g. 3.13) while python@3.12 is also installed
|
|
292
|
-
// at /opt/homebrew/opt/python@3.12/bin/python3.12. Don't force the user to
|
|
293
|
-
// reinstall just because the default changed.
|
|
294
|
-
const pyProbes = [
|
|
295
|
-
'python3.12 --version',
|
|
296
|
-
'/opt/homebrew/opt/python@3.12/bin/python3.12 --version',
|
|
297
|
-
'/usr/local/opt/python@3.12/bin/python3.12 --version',
|
|
298
|
-
'python3 --version',
|
|
299
|
-
];
|
|
300
|
-
for (const cmd of pyProbes) {
|
|
301
|
-
try {
|
|
302
|
-
const out = execSync(cmd, { encoding: 'utf-8', timeout: 3000 }).trim();
|
|
303
|
-
const ver = out.replace('Python ', '');
|
|
304
|
-
const parts = ver.split('.').map(Number);
|
|
305
|
-
// Only accept as "ok" if this probe returned 3.12. Otherwise keep trying.
|
|
306
|
-
if (parts[0] === 3 && parts[1] === 12) {
|
|
307
|
-
currentPy = ver;
|
|
308
|
-
pyStatus = 'ok';
|
|
309
|
-
break;
|
|
310
|
-
}
|
|
311
|
-
// Remember the last-seen version for fallback reporting
|
|
312
|
-
currentPy = ver;
|
|
313
|
-
if (parts[0] === 3 && parts[1] >= 10 && parts[1] < 12)
|
|
314
|
-
pyStatus = 'old';
|
|
315
|
-
else if (parts[0] === 3 && parts[1] > 12)
|
|
316
|
-
pyStatus = 'new';
|
|
317
|
-
else
|
|
318
|
-
pyStatus = 'missing';
|
|
319
|
-
}
|
|
320
|
-
catch { /* try next probe */ }
|
|
321
|
-
}
|
|
322
|
-
if (pyStatus === 'ok') {
|
|
323
|
-
console.log(chalk.green(` ✓ Python ${currentPy} — you're good!`));
|
|
324
|
-
console.log(chalk.gray(' Exam toolkit ready. Next: ') + chalk.bold.cyan('exam setup'));
|
|
325
|
-
console.log();
|
|
326
|
-
return;
|
|
327
|
-
}
|
|
328
|
-
if (pyStatus === 'old') {
|
|
329
|
-
console.log(chalk.yellow(` ⚠ Python ${currentPy} — works, but 3.12 recommended`));
|
|
330
|
-
}
|
|
331
|
-
else if (pyStatus === 'new') {
|
|
332
|
-
console.log(chalk.yellow(` ⚠ Python ${currentPy} — some packages (pwntools, scapy) lack wheels`));
|
|
333
|
-
console.log(chalk.gray(' Downgrading to 3.12 is strongly recommended'));
|
|
334
|
-
}
|
|
335
|
-
else {
|
|
336
|
-
console.log(chalk.red(' ✗ Python 3 not found'));
|
|
337
|
-
}
|
|
338
|
-
console.log();
|
|
339
|
-
if (os === 'darwin') {
|
|
340
|
-
console.log(chalk.bold.white(' macOS (Homebrew)'));
|
|
341
|
-
console.log();
|
|
342
|
-
console.log(chalk.green(' brew install python@3.12'));
|
|
343
|
-
}
|
|
344
|
-
else if (os === 'linux') {
|
|
345
|
-
let distro = 'ubuntu';
|
|
346
|
-
try {
|
|
347
|
-
const release = execSync('cat /etc/os-release 2>/dev/null', { encoding: 'utf-8', timeout: 2000 });
|
|
348
|
-
if (/fedora|rhel|centos/i.test(release))
|
|
349
|
-
distro = 'fedora';
|
|
350
|
-
else if (/arch|manjaro/i.test(release))
|
|
351
|
-
distro = 'arch';
|
|
352
|
-
else
|
|
353
|
-
distro = 'ubuntu';
|
|
354
|
-
}
|
|
355
|
-
catch { }
|
|
356
|
-
if (distro === 'ubuntu') {
|
|
357
|
-
console.log(chalk.bold.white(' Ubuntu / Debian / Kali (deadsnakes PPA)'));
|
|
358
|
-
console.log();
|
|
359
|
-
console.log(chalk.gray(' Copy-paste this one-liner:'));
|
|
360
|
-
console.log();
|
|
361
|
-
console.log(chalk.green(' sudo add-apt-repository ppa:deadsnakes/ppa -y && \\'));
|
|
362
|
-
console.log(chalk.green(' sudo apt update && \\'));
|
|
363
|
-
console.log(chalk.green(' sudo apt install -y python3.12 python3.12-venv python3.12-distutils && \\'));
|
|
364
|
-
console.log(chalk.green(' sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.12 1'));
|
|
365
|
-
}
|
|
366
|
-
else if (distro === 'fedora') {
|
|
367
|
-
console.log(chalk.bold.white(' Fedora / RHEL / CentOS'));
|
|
368
|
-
console.log();
|
|
369
|
-
console.log(chalk.green(' sudo dnf install -y python3.12 python3.12-pip'));
|
|
370
|
-
}
|
|
371
|
-
else if (distro === 'arch') {
|
|
372
|
-
console.log(chalk.bold.white(' Arch / Manjaro (via pyenv)'));
|
|
373
|
-
console.log();
|
|
374
|
-
console.log(chalk.green(' sudo pacman -S pyenv && pyenv install 3.12 && pyenv global 3.12'));
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
else if (os === 'win32') {
|
|
378
|
-
console.log(chalk.bold.white(' Windows (WSL recommended)'));
|
|
379
|
-
console.log();
|
|
380
|
-
console.log(chalk.gray(' WSL + Ubuntu (best):'));
|
|
381
|
-
console.log(chalk.green(' wsl --install'));
|
|
382
|
-
console.log(chalk.gray(' Then inside Ubuntu, run the Ubuntu commands.'));
|
|
383
|
-
console.log();
|
|
384
|
-
console.log(chalk.gray(' Or native:'));
|
|
385
|
-
console.log(chalk.green(' winget install Python.Python.3.12'));
|
|
386
|
-
}
|
|
387
|
-
else {
|
|
388
|
-
console.log(chalk.gray(' https://www.python.org/downloads/'));
|
|
389
|
-
}
|
|
390
|
-
console.log();
|
|
391
|
-
console.log(chalk.white(' After installing, verify:'));
|
|
392
|
-
console.log(chalk.bold.cyan(' env python') + chalk.gray(' # re-check Python'));
|
|
393
|
-
console.log(chalk.bold.cyan(' exam setup') + chalk.gray(' # install the 13 exam packages'));
|
|
394
|
-
console.log();
|
|
395
|
-
}
|
|
396
|
-
function showStatus() {
|
|
397
|
-
console.log();
|
|
398
|
-
const os = platform();
|
|
399
|
-
const pm = os === 'darwin' ? 'brew' : os === 'linux' ? 'apt' : 'winget';
|
|
400
|
-
console.log(chalk.bold.white(' ICOA Competition Environment'));
|
|
401
|
-
console.log(chalk.gray(' ─────────────────────────────────────────────'));
|
|
402
|
-
console.log();
|
|
403
|
-
console.log(chalk.gray(' These tools power your CTF competition environment.'));
|
|
404
|
-
console.log(chalk.gray(' Not all are required — here\'s what matters:'));
|
|
405
|
-
console.log();
|
|
406
|
-
console.log(chalk.green(' Essential') + chalk.gray(' pwntools, z3, requests, numpy'));
|
|
407
|
-
console.log(chalk.gray(' You need these for most challenges'));
|
|
408
|
-
console.log(chalk.yellow(' Recommended') + chalk.gray(' pycryptodome, beautifulsoup4, scapy, sympy'));
|
|
409
|
-
console.log(chalk.gray(' Covers Web, Crypto, and Forensics'));
|
|
410
|
-
console.log(chalk.gray(' Full (110) All tools for every category'));
|
|
411
|
-
console.log();
|
|
412
|
-
console.log(chalk.gray(' Missing tools? Run ') + chalk.bold.cyan('env setup') + chalk.gray(' to install everything.'));
|
|
413
|
-
console.log(chalk.gray(' ─────────────────────────────────────────────'));
|
|
414
|
-
console.log();
|
|
415
|
-
console.log(chalk.gray(' OS: ') + chalk.white(getOsInfo()));
|
|
416
|
-
console.log(chalk.gray(' Node: ') + chalk.white(getNodeInfo()));
|
|
417
|
-
console.log(chalk.gray(' Package: ') + chalk.white(pm));
|
|
418
|
-
console.log(chalk.gray(' Target: ') + chalk.white(`Node ${NODE_EXACT} | Python ${PYTHON_EXACT}`));
|
|
419
|
-
if (os === 'win32') {
|
|
420
|
-
console.log();
|
|
421
|
-
console.log(chalk.yellow(' Windows: recommend WSL (Ubuntu) for full CTF tool support'));
|
|
422
|
-
console.log(chalk.gray(' Install WSL: ') + chalk.white('wsl --install'));
|
|
423
|
-
console.log(chalk.gray(' Then run icoa inside WSL for 100% tool compatibility'));
|
|
424
|
-
}
|
|
425
|
-
console.log(chalk.gray(' ─────────────────────────────────────────────'));
|
|
426
|
-
// Node.js version check — >= 22.22.2
|
|
427
|
-
const nodeVer = process.versions.node;
|
|
428
|
-
const nodeParts = nodeVer.split('.').map(Number);
|
|
429
|
-
const nodeOk = nodeParts[0] > 22 || (nodeParts[0] === 22 && nodeParts[1] > 22) || (nodeParts[0] === 22 && nodeParts[1] === 22 && nodeParts[2] >= 2);
|
|
430
|
-
if (nodeOk) {
|
|
431
|
-
console.log(chalk.green(` ✓ Node.js ${nodeVer}`) + chalk.gray(` (>= ${NODE_EXACT})`));
|
|
432
|
-
}
|
|
433
|
-
else {
|
|
434
|
-
console.log(chalk.red(` ✗ Node.js ${nodeVer}`) + chalk.gray(` (>= ${NODE_EXACT} required)`));
|
|
435
|
-
console.log(chalk.gray(' Install: nvm install 22 or visit https://nodejs.org/'));
|
|
436
|
-
}
|
|
437
|
-
// Python version check
|
|
438
|
-
const pyVer = getPythonMajorMinor();
|
|
439
|
-
const fullVer = getPythonFullVersion();
|
|
440
|
-
if (fullVer === PYTHON_EXACT) {
|
|
441
|
-
console.log(chalk.green(` ✓ Python ${fullVer}`) + chalk.gray(' (official)'));
|
|
442
|
-
}
|
|
443
|
-
else if (pyVer === '3.12') {
|
|
444
|
-
console.log(chalk.yellow(` ~ Python ${fullVer}`) + chalk.gray(` (${PYTHON_EXACT} recommended, run env setup)`));
|
|
445
|
-
}
|
|
446
|
-
else if (pyVer) {
|
|
447
|
-
console.log(chalk.yellow(` ~ Python ${fullVer}`) + chalk.gray(` (${PYTHON_EXACT} required, run env setup)`));
|
|
448
|
-
}
|
|
449
|
-
else {
|
|
450
|
-
console.log(chalk.red(' ✗ Python 3 not found'));
|
|
451
|
-
}
|
|
452
|
-
console.log();
|
|
453
|
-
let installed = 0;
|
|
454
|
-
let missing = 0;
|
|
455
|
-
let currentCategory = '';
|
|
456
|
-
for (const tool of SYSTEM_TOOLS) {
|
|
457
|
-
if (tool.category !== currentCategory) {
|
|
458
|
-
currentCategory = tool.category;
|
|
459
|
-
console.log(chalk.bold.gray(` ${currentCategory}`));
|
|
460
|
-
}
|
|
461
|
-
const ok = isInstalled(tool.check);
|
|
462
|
-
const ver = ok ? getVersion(tool.name) : '';
|
|
463
|
-
const verStr = ver ? chalk.gray(` (${ver})`) : '';
|
|
464
|
-
if (ok) {
|
|
465
|
-
console.log(chalk.green(` ✓ ${tool.name}`) + verStr);
|
|
466
|
-
installed++;
|
|
467
|
-
}
|
|
468
|
-
else {
|
|
469
|
-
console.log(chalk.red(` ✗ ${tool.name}`));
|
|
470
|
-
missing++;
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
currentCategory = '';
|
|
474
|
-
const pipExe = os === 'darwin' ? '/opt/homebrew/opt/python@3.12/bin/pip3.12' : os === 'win32' ? 'pip' : 'pip3';
|
|
475
|
-
for (const lib of PYTHON_LIBS) {
|
|
476
|
-
if (lib.category !== currentCategory) {
|
|
477
|
-
currentCategory = lib.category;
|
|
478
|
-
console.log(chalk.bold.gray(` ${currentCategory}`));
|
|
479
|
-
}
|
|
480
|
-
const ok = isInstalled(lib.check);
|
|
481
|
-
if (ok) {
|
|
482
|
-
// Get actual installed version
|
|
483
|
-
let ver = '';
|
|
484
|
-
for (const pip of [pipExe, 'pip3', 'pip']) {
|
|
485
|
-
try {
|
|
486
|
-
const pkgName = lib.name.replace('python-magic', 'python_magic');
|
|
487
|
-
const out = execSync(`${pip} show ${pkgName}`, { encoding: 'utf-8', timeout: 3000, stdio: ['pipe', 'pipe', 'ignore'] });
|
|
488
|
-
const m = out.match(/Version:\s*(\S+)/);
|
|
489
|
-
if (m) {
|
|
490
|
-
ver = m[1];
|
|
491
|
-
break;
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
catch { /* try next */ }
|
|
495
|
-
}
|
|
496
|
-
console.log(chalk.green(` ✓ ${lib.name}`) + chalk.gray(ver ? ` (${ver})` : ''));
|
|
497
|
-
installed++;
|
|
498
|
-
}
|
|
499
|
-
else {
|
|
500
|
-
console.log(chalk.red(` ✗ ${lib.name}`) + chalk.gray(` → ${lib.install || 'latest'}`));
|
|
501
|
-
missing++;
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
const total = installed + missing;
|
|
505
|
-
console.log();
|
|
506
|
-
console.log(chalk.gray(' ─────────────────────────────────────────────'));
|
|
507
|
-
console.log(` ${chalk.green(`✓ ${installed}/${total}`)} ${missing > 0 ? chalk.red(`✗ ${missing} missing`) : chalk.green('All 110 ready!')}`);
|
|
508
|
-
if (missing > 0) {
|
|
509
|
-
console.log(chalk.gray(' Install everything: ') + chalk.white('env setup') + chalk.gray(' (~5 min, one-time)'));
|
|
510
|
-
}
|
|
511
|
-
console.log(chalk.gray(' You are back at the ') + chalk.cyan('icoa>') + chalk.gray(' prompt. ') + chalk.cyan('help') + chalk.gray(' for all commands.'));
|
|
512
|
-
console.log();
|
|
513
|
-
}
|
|
514
|
-
async function installAll() {
|
|
515
|
-
console.log();
|
|
516
|
-
const os = platform();
|
|
517
|
-
const pipFlag = os === 'darwin' || os === 'linux' ? '--break-system-packages' : '';
|
|
518
|
-
console.log(chalk.bold.white(' ICOA Environment Setup'));
|
|
519
|
-
console.log(chalk.gray(' ─────────────────────────────────────────────'));
|
|
520
|
-
console.log(chalk.gray(' This will install:'));
|
|
521
|
-
console.log(chalk.white(' Python 3.12') + chalk.gray(' Runtime for CTF tools'));
|
|
522
|
-
console.log(chalk.white(` ${PYTHON_LIBS.length} Python libraries`) + chalk.gray(' pwntools, z3, crypto...'));
|
|
523
|
-
console.log(chalk.white(` ${SYSTEM_TOOLS.length} system tools`) + chalk.gray(' gcc, gdb, nmap, wireshark...'));
|
|
524
|
-
console.log();
|
|
525
|
-
console.log(chalk.gray(' Estimated: ~500 MB disk, 5-15 min (depends on network)'));
|
|
526
|
-
console.log(chalk.gray(' Already installed tools will be skipped.'));
|
|
527
|
-
console.log(chalk.gray(' ─────────────────────────────────────────────'));
|
|
528
|
-
console.log();
|
|
529
|
-
// Node.js version check
|
|
530
|
-
const nodeVer = process.versions.node;
|
|
531
|
-
if (nodeVer === NODE_EXACT) {
|
|
532
|
-
console.log(chalk.green(` ✓ Node.js ${NODE_EXACT}`));
|
|
533
|
-
}
|
|
534
|
-
else {
|
|
535
|
-
console.log(chalk.yellow(` Node.js ${nodeVer} — installing ${NODE_EXACT}...`));
|
|
536
|
-
try {
|
|
537
|
-
if (os === 'darwin') {
|
|
538
|
-
execSync(`brew install node@22`, { stdio: 'inherit' });
|
|
539
|
-
}
|
|
540
|
-
else if (os === 'linux') {
|
|
541
|
-
execSync(`curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - && sudo apt-get install -y nodejs`, { stdio: 'inherit' });
|
|
542
|
-
}
|
|
543
|
-
else {
|
|
544
|
-
execSync(`winget install OpenJS.NodeJS.LTS --version ${NODE_EXACT}`, { stdio: 'inherit' });
|
|
545
|
-
}
|
|
546
|
-
console.log(chalk.green(` ✓ Node.js ${NODE_EXACT} installed`));
|
|
547
|
-
console.log(chalk.gray(' Restart icoa to use the new version.'));
|
|
548
|
-
}
|
|
549
|
-
catch {
|
|
550
|
-
console.log(chalk.yellow(` ~ Node.js upgrade skipped. Install manually: nvm install ${NODE_EXACT}`));
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
console.log();
|
|
554
|
-
// Python version check — install 3.12.13 if needed
|
|
555
|
-
const pyVer = getPythonMajorMinor();
|
|
556
|
-
const currentFullVer = getPythonFullVersion();
|
|
557
|
-
if (currentFullVer === PYTHON_EXACT) {
|
|
558
|
-
console.log(chalk.green(` ✓ Python ${PYTHON_EXACT}`));
|
|
559
|
-
console.log();
|
|
560
|
-
}
|
|
561
|
-
else {
|
|
562
|
-
console.log(chalk.yellow(` Python ${currentFullVer || 'not found'} — installing Python ${PYTHON_EXACT}...`));
|
|
563
|
-
try {
|
|
564
|
-
if (os === 'darwin') {
|
|
565
|
-
execSync('brew install python@3.12', { stdio: 'inherit' });
|
|
566
|
-
// Link python3.12 as default python3
|
|
567
|
-
try {
|
|
568
|
-
execSync('brew link --overwrite python@3.12', { stdio: 'ignore' });
|
|
569
|
-
}
|
|
570
|
-
catch { /* ok */ }
|
|
571
|
-
console.log(chalk.green(' ✓ Python 3.12 installed'));
|
|
572
|
-
console.log(chalk.gray(' Use: /opt/homebrew/opt/python@3.12/bin/python3.12'));
|
|
573
|
-
console.log(chalk.gray(' Or: brew link --overwrite python@3.12'));
|
|
574
|
-
}
|
|
575
|
-
else if (os === 'linux') {
|
|
576
|
-
console.log(chalk.gray(` Building Python ${PYTHON_EXACT} from source...`));
|
|
577
|
-
// Install build dependencies
|
|
578
|
-
execSync('sudo apt-get update && sudo apt-get install -y build-essential libssl-dev zlib1g-dev libncurses5-dev libncursesw5-dev libreadline-dev libsqlite3-dev libgdbm-dev libdb5.3-dev libbz2-dev libexpat1-dev liblzma-dev libffi-dev tk-dev curl', { stdio: 'inherit' });
|
|
579
|
-
// Download and build
|
|
580
|
-
execSync(`curl -sS https://www.python.org/ftp/python/${PYTHON_EXACT}/Python-${PYTHON_EXACT}.tgz -o /tmp/Python-${PYTHON_EXACT}.tgz`, { stdio: 'inherit' });
|
|
581
|
-
execSync(`cd /tmp && tar xzf Python-${PYTHON_EXACT}.tgz && cd Python-${PYTHON_EXACT} && ./configure --prefix=/usr/local --enable-optimizations 2>&1 | tail -1 && make -j$(nproc) 2>&1 | tail -1 && sudo make altinstall`, { stdio: 'inherit', timeout: 600000 });
|
|
582
|
-
// Install pip
|
|
583
|
-
try {
|
|
584
|
-
execSync('curl -sS https://bootstrap.pypa.io/get-pip.py | sudo /usr/local/bin/python3.12', { stdio: 'inherit' });
|
|
585
|
-
}
|
|
586
|
-
catch { /* ok */ }
|
|
587
|
-
// Set as default
|
|
588
|
-
try {
|
|
589
|
-
execSync('sudo update-alternatives --install /usr/bin/python3 python3 /usr/local/bin/python3.12 2', { stdio: 'ignore' });
|
|
590
|
-
execSync('sudo update-alternatives --set python3 /usr/local/bin/python3.12', { stdio: 'ignore' });
|
|
591
|
-
}
|
|
592
|
-
catch { /* ok */ }
|
|
593
|
-
console.log(chalk.green(` ✓ Python ${PYTHON_EXACT} installed`));
|
|
594
|
-
}
|
|
595
|
-
else {
|
|
596
|
-
// Windows: try winget first, then choco
|
|
597
|
-
try {
|
|
598
|
-
execSync('winget install Python.Python.3.12 --accept-package-agreements --accept-source-agreements', { stdio: 'inherit' });
|
|
599
|
-
}
|
|
600
|
-
catch {
|
|
601
|
-
execSync('choco install -y python312', { stdio: 'inherit' });
|
|
602
|
-
}
|
|
603
|
-
console.log(chalk.green(' ✓ Python 3.12 installed'));
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
catch {
|
|
607
|
-
console.log(chalk.red(' ✗ Failed to install Python 3.12'));
|
|
608
|
-
const hint = os === 'darwin' ? 'brew install python@3.12' : os === 'linux' ? 'sudo apt install python3.12' : 'winget install Python.Python.3.12';
|
|
609
|
-
console.log(chalk.gray(` Manual install: ${hint}`));
|
|
610
|
-
}
|
|
611
|
-
console.log();
|
|
612
|
-
}
|
|
613
|
-
// Windows: recommend WSL instead of installing tools natively
|
|
614
|
-
if (os === 'win32') {
|
|
615
|
-
console.log(chalk.yellow(' Windows: Most CTF tools require Linux. Recommended:'));
|
|
616
|
-
console.log(chalk.white(' wsl --install'));
|
|
617
|
-
console.log(chalk.gray(' Then run icoa inside WSL Ubuntu for full tool support.'));
|
|
618
|
-
console.log();
|
|
619
|
-
}
|
|
620
|
-
// Install system tools via brew (macOS) / apt (Linux)
|
|
621
|
-
const missingSystem = [];
|
|
622
|
-
for (const tool of SYSTEM_TOOLS) {
|
|
623
|
-
if (!isInstalled(tool.check)) {
|
|
624
|
-
const pkg = os === 'darwin' ? tool.brew : os === 'linux' ? tool.apt : tool.choco;
|
|
625
|
-
if (pkg)
|
|
626
|
-
missingSystem.push(tool);
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
if (missingSystem.length > 0 && os !== 'win32') {
|
|
630
|
-
const pmName = os === 'darwin' ? 'brew' : 'apt';
|
|
631
|
-
console.log(chalk.bold.white(` System Tools via ${pmName} (${missingSystem.length} missing)`));
|
|
632
|
-
console.log(chalk.gray(' ─────────────────────────────────────────────'));
|
|
633
|
-
for (const tool of missingSystem) {
|
|
634
|
-
const pkg = os === 'darwin' ? tool.brew : os === 'linux' ? tool.apt : tool.choco;
|
|
635
|
-
process.stdout.write(chalk.gray(` ⏳ ${tool.name}...`));
|
|
636
|
-
try {
|
|
637
|
-
let cmd;
|
|
638
|
-
if (os === 'darwin')
|
|
639
|
-
cmd = `brew install ${pkg}`;
|
|
640
|
-
else if (os === 'linux')
|
|
641
|
-
cmd = `sudo apt-get install -y ${pkg}`;
|
|
642
|
-
else
|
|
643
|
-
cmd = `choco install -y ${pkg}`;
|
|
644
|
-
execSync(cmd, { stdio: 'ignore' });
|
|
645
|
-
process.stdout.write('\r');
|
|
646
|
-
console.log(chalk.green(` ✓ ${tool.name}`));
|
|
647
|
-
}
|
|
648
|
-
catch {
|
|
649
|
-
process.stdout.write('\r');
|
|
650
|
-
console.log(chalk.red(` ✗ ${tool.name}`) + chalk.gray(` (${pmName} install ${pkg})`));
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
console.log();
|
|
654
|
-
}
|
|
655
|
-
// Find the correct pip for Python 3.12
|
|
656
|
-
let pipCmd = 'pip3';
|
|
657
|
-
if (os === 'darwin') {
|
|
658
|
-
// Prefer brew Python 3.12 pip over conda/system pip
|
|
659
|
-
const brewPip = '/opt/homebrew/opt/python@3.12/bin/pip3.12';
|
|
660
|
-
try {
|
|
661
|
-
execSync(`${brewPip} --version`, { stdio: 'ignore' });
|
|
662
|
-
pipCmd = brewPip;
|
|
663
|
-
console.log(chalk.gray(` Using: ${brewPip}`));
|
|
664
|
-
}
|
|
665
|
-
catch {
|
|
666
|
-
// Try generic pip3.12
|
|
667
|
-
try {
|
|
668
|
-
execSync('pip3.12 --version', { stdio: 'ignore' });
|
|
669
|
-
pipCmd = 'pip3.12';
|
|
670
|
-
}
|
|
671
|
-
catch { /* fall back to pip3 */ }
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
else if (os === 'linux') {
|
|
675
|
-
try {
|
|
676
|
-
execSync('pip3.12 --version', { stdio: 'ignore' });
|
|
677
|
-
pipCmd = 'pip3.12';
|
|
678
|
-
}
|
|
679
|
-
catch { /* fall back to pip3 */ }
|
|
680
|
-
}
|
|
681
|
-
else if (os === 'win32') {
|
|
682
|
-
pipCmd = 'pip';
|
|
683
|
-
}
|
|
684
|
-
// Pre-install system dependencies for packages that need them
|
|
685
|
-
if (os === 'darwin') {
|
|
686
|
-
console.log(chalk.gray(' Installing build dependencies...'));
|
|
687
|
-
try {
|
|
688
|
-
execSync('brew install gmp mpfr libmpc libmagic', { stdio: 'ignore' });
|
|
689
|
-
console.log(chalk.green(' ✓ Build dependencies ready (gmp, mpfr, libmpc, libmagic)'));
|
|
690
|
-
}
|
|
691
|
-
catch { /* some may already exist */ }
|
|
692
|
-
}
|
|
693
|
-
else if (os === 'linux') {
|
|
694
|
-
try {
|
|
695
|
-
execSync('sudo apt-get install -y libgmp-dev libmpfr-dev libmpc-dev libmagic1', { stdio: 'ignore' });
|
|
696
|
-
}
|
|
697
|
-
catch { /* ignore */ }
|
|
698
|
-
}
|
|
699
|
-
console.log();
|
|
700
|
-
// Build environment for native extensions (gmpy2 etc.)
|
|
701
|
-
const buildEnv = { ...process.env };
|
|
702
|
-
if (os === 'darwin') {
|
|
703
|
-
buildEnv['CFLAGS'] = `-I/opt/homebrew/include ${buildEnv['CFLAGS'] || ''}`.trim();
|
|
704
|
-
buildEnv['LDFLAGS'] = `-L/opt/homebrew/lib ${buildEnv['LDFLAGS'] || ''}`.trim();
|
|
705
|
-
buildEnv['C_INCLUDE_PATH'] = `/opt/homebrew/include:${buildEnv['C_INCLUDE_PATH'] || ''}`;
|
|
706
|
-
buildEnv['LIBRARY_PATH'] = `/opt/homebrew/lib:${buildEnv['LIBRARY_PATH'] || ''}`;
|
|
707
|
-
}
|
|
708
|
-
// Install Python libraries
|
|
709
|
-
let pipInstalled = 0;
|
|
710
|
-
let pipFailed = 0;
|
|
711
|
-
console.log(chalk.bold.white(` Python Libraries (${PYTHON_LIBS.length} packages)`));
|
|
712
|
-
console.log(chalk.gray(' ─────────────────────────────────────────────'));
|
|
713
|
-
for (const lib of PYTHON_LIBS) {
|
|
714
|
-
if (!lib.install)
|
|
715
|
-
continue;
|
|
716
|
-
if (isInstalled(lib.check)) {
|
|
717
|
-
console.log(chalk.green(` ✓ ${lib.name}`) + chalk.gray(' (installed)'));
|
|
718
|
-
pipInstalled++;
|
|
719
|
-
continue;
|
|
720
|
-
}
|
|
721
|
-
process.stdout.write(chalk.gray(` ⏳ ${lib.name}...`));
|
|
722
|
-
try {
|
|
723
|
-
execSync(`${pipCmd} install ${pipFlag} ${lib.install}`, { stdio: 'ignore', env: buildEnv });
|
|
724
|
-
process.stdout.write('\r');
|
|
725
|
-
console.log(chalk.green(` ✓ ${lib.name}`) + chalk.gray(` (${lib.install})`));
|
|
726
|
-
pipInstalled++;
|
|
727
|
-
}
|
|
728
|
-
catch {
|
|
729
|
-
process.stdout.write('\r');
|
|
730
|
-
console.log(chalk.red(` ✗ ${lib.name}`) + chalk.gray(' (failed)'));
|
|
731
|
-
pipFailed++;
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
console.log();
|
|
735
|
-
console.log(chalk.gray(' ─────────────────────────────────────────────'));
|
|
736
|
-
console.log(` ${chalk.green(`✓ ${pipInstalled} installed`)} ${pipFailed > 0 ? chalk.red(`✗ ${pipFailed} failed`) : chalk.green('All ready!')}`);
|
|
737
|
-
console.log();
|
|
738
|
-
}
|
|
1
|
+
import chalk from"chalk";import{execSync as e}from"node:child_process";import{platform as o}from"node:os";const n="3.12.13",t="22.22.2",c=[{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.12.6",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.1",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==2023.2.7",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"}],r="win32"===process.platform,a=(e,o)=>r?o||`where ${e}`:`which ${e}`,s=[{name:"vim",check:a("vim"),brew:"vim",apt:"vim",choco:"vim",category:"Editors & Terminal"},{name:"nano",check:a("nano"),brew:"nano",apt:"nano",choco:"nano",category:"Editors & Terminal"},{name:"tmux",check:a("tmux"),brew:"tmux",apt:"tmux",category:"Editors & Terminal"},{name:"screen",check:a("screen"),brew:"screen",apt:"screen",category:"Editors & Terminal"},{name:"less",check:a("less"),category:"Editors & Terminal"},{name:"gcc",check:a("gcc"),brew:"gcc",apt:"gcc",choco:"mingw",category:"Compilers & Build"},{name:"g++",check:a("g++"),brew:"gcc",apt:"g++",choco:"mingw",category:"Compilers & Build"},{name:"make",check:a("make"),brew:"make",apt:"make",choco:"make",category:"Compilers & Build"},{name:"nasm",check:a("nasm"),brew:"nasm",apt:"nasm",choco:"nasm",category:"Compilers & Build"},{name:"cmake",check:a("cmake"),brew:"cmake",apt:"cmake",choco:"cmake",category:"Compilers & Build"},{name:"as",check:a("as"),category:"Compilers & Build"},{name:"ld",check:a("ld"),category:"Compilers & Build"},{name:"pkg-config",check:a("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":r?"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":r?"pip --version":"pip3 --version",category:"Python Runtime"},{name:"python3-venv",check:r?'python -c "import venv"':'python3 -c "import venv"',apt:"python3-venv",category:"Python Runtime"},{name:"curl",check:a("curl"),brew:"curl",apt:"curl",choco:"curl",category:"Networking"},{name:"wget",check:a("wget"),brew:"wget",apt:"wget",choco:"wget",category:"Networking"},{name:"nc",check:a("nc","where ncat"),brew:"netcat",apt:"netcat-openbsd",choco:"nmap",category:"Networking"},{name:"socat",check:a("socat"),brew:"socat",apt:"socat",category:"Networking"},{name:"nmap",check:a("nmap"),brew:"nmap",apt:"nmap",choco:"nmap",category:"Networking"},{name:"ssh",check:a("ssh"),apt:"openssh-client",category:"Networking"},{name:"dig",check:a("dig"),brew:"bind",apt:"dnsutils",category:"Networking"},{name:"whois",check:a("whois"),brew:"whois",apt:"whois",choco:"whois",category:"Networking"},{name:"ping",check:a("ping"),apt:"iputils-ping",category:"Networking"},{name:"traceroute",check:a("traceroute","where tracert"),brew:"traceroute",apt:"traceroute",category:"Networking"},{name:"tcpdump",check:a("tcpdump"),brew:"tcpdump",apt:"tcpdump",category:"Networking"},{name:"tshark",check:a("tshark"),brew:"wireshark",apt:"tshark",choco:"wireshark",category:"Networking"},{name:"gdb",check:a("gdb"),brew:"gdb",apt:"gdb",choco:"mingw",category:"Debuggers"},..."darwin"!==process.platform?[{name:"ltrace",check:a("ltrace"),apt:"ltrace",category:"Debuggers"},{name:"strace",check:a("strace"),apt:"strace",category:"Debuggers"}]:[],{name:"objdump",check:a("objdump"),category:"Debuggers"},..."darwin"!==process.platform?[{name:"readelf",check:a("readelf"),category:"Debuggers"}]:[],{name:"radare2",check:a("r2"),brew:"radare2",apt:"radare2",choco:"radare2",category:"Reverse Engineering"},{name:"rabin2",check:a("rabin2"),category:"Reverse Engineering"},{name:"upx",check:a("upx"),brew:"upx",apt:"upx",choco:"upx",category:"Reverse Engineering"},{name:"strings",check:a("strings"),category:"Reverse Engineering"},{name:"binwalk",check:a("binwalk"),brew:"binwalk",apt:"binwalk",category:"Forensics"},..."darwin"!==process.platform?[{name:"foremost",check:a("foremost"),apt:"foremost",category:"Forensics"}]:[],{name:"exiftool",check:a("exiftool"),brew:"exiftool",apt:"exiftool",choco:"exiftool",category:"Forensics"},..."darwin"!==process.platform?[{name:"steghide",check:a("steghide"),apt:"steghide",category:"Forensics"}]:[],{name:"file",check:a("file"),category:"Forensics"},{name:"xxd",check:a("xxd"),brew:"vim",apt:"xxd",category:"Forensics"},{name:"pdftotext",check:a("pdftotext"),brew:"poppler",apt:"poppler-utils",category:"Forensics"},{name:"pngcheck",check:a("pngcheck"),brew:"pngcheck",apt:"pngcheck",category:"Forensics"},{name:"sleuthkit",check:a("mmls"),brew:"sleuthkit",apt:"sleuthkit",choco:"sleuthkit",category:"Forensics"},{name:"john",check:a("john"),brew:"john",apt:"john",choco:"john",category:"Crypto & Password"},{name:"hashcat",check:a("hashcat"),brew:"hashcat",apt:"hashcat",choco:"hashcat",category:"Crypto & Password"},{name:"openssl",check:a("openssl"),category:"Crypto & Password"},{name:"gpg",check:a("gpg"),brew:"gnupg",apt:"gpg",choco:"gnupg",category:"Crypto & Password"},{name:"jq",check:a("jq"),brew:"jq",apt:"jq",choco:"jq",category:"Data Processing"},{name:"sqlite3",check:a("sqlite3"),brew:"sqlite",apt:"sqlite3",choco:"sqlite",category:"Data Processing"},{name:"base64",check:a("base64"),category:"Data Processing"},{name:"hexdump",check:a("hexdump"),category:"Data Processing"},{name:"od",check:a("od"),category:"Data Processing"},{name:"sort",check:a("sort"),category:"Data Processing"},{name:"uniq",check:a("uniq"),category:"Data Processing"},{name:"wc",check:a("wc"),category:"Data Processing"},{name:"unzip",check:a("unzip"),brew:"unzip",apt:"unzip",category:"Archive"},{name:"zip",check:a("zip"),brew:"zip",apt:"zip",category:"Archive"},{name:"tar",check:a("tar"),category:"Archive"},{name:"gzip",check:a("gzip"),category:"Archive"},{name:"bzip2",check:a("bzip2"),category:"Archive"},{name:"xz",check:a("xz"),brew:"xz",apt:"xz-utils",category:"Archive"},{name:"cat",check:a("cat"),category:"Core Unix"},{name:"grep",check:a("grep"),category:"Core Unix"},{name:"sed",check:a("sed"),category:"Core Unix"},{name:"awk",check:a("awk"),category:"Core Unix"},{name:"find",check:a("find"),category:"Core Unix"},{name:"head",check:a("head"),category:"Core Unix"},{name:"tail",check:a("tail"),category:"Core Unix"},{name:"diff",check:a("diff"),category:"Core Unix"},{name:"patch",check:a("patch"),category:"Core Unix"},{name:"chmod",check:a("chmod"),category:"Core Unix"},{name:"chown",check:a("chown"),category:"Core Unix"},{name:"ln",check:a("ln"),category:"Core Unix"},{name:"cp",check:a("cp"),category:"Core Unix"},{name:"mv",check:a("mv"),category:"Core Unix"},{name:"mkdir",check:a("mkdir"),category:"Core Unix"},{name:"rm",check:a("rm"),category:"Core Unix"},{name:"git",check:a("git"),brew:"git",apt:"git",choco:"git",category:"Git & Docker"},{name:"docker",check:a("docker"),brew:"--cask docker",choco:"docker-desktop",category:"Git & Docker"}];function i(o){try{return e(o,{stdio:"ignore"}),!0}catch{return!1}}function l(o){const n={python3:"darwin"===process.platform?"/opt/homebrew/opt/python@3.12/bin/python3.12 --version":"python3 --version",pip3:"darwin"===process.platform?"/opt/homebrew/opt/python@3.12/bin/pip3.12 --version":"pip3 --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""}function g(){if("darwin"===process.platform)try{return e("/opt/homebrew/opt/python@3.12/bin/python3.12 -c \"import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')\"",{encoding:"utf-8"}).trim()}catch{}try{return e("python3 -c \"import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')\"",{encoding:"utf-8"}).trim()}catch{return""}}function p(){if("darwin"===process.platform)try{return e("/opt/homebrew/opt/python@3.12/bin/python3.12 --version",{encoding:"utf-8"}).trim().replace("Python ","")}catch{}try{return e("python3 --version",{encoding:"utf-8"}).trim().replace("Python ","")}catch{return""}}export function registerEnvCommand(r){const a=r.command("env").description("Manage competition environment");a.command("status").alias("check").description("Check all 110 tools").action(()=>h()),a.command("setup").description("Install all Python libraries + system tools").action(async()=>{await async function(){console.log();const r=o(),a="darwin"===r||"linux"===r?"--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(` ${c.length} Python libraries`)+chalk.gray(" pwntools, z3, crypto...")),console.log(chalk.white(` ${s.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();const l=process.versions.node;if(l===t)console.log(chalk.green(` ✓ Node.js ${t}`));else{console.log(chalk.yellow(` Node.js ${l} — installing ${t}...`));try{e("darwin"===r?"brew install node@22":"linux"===r?"curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - && sudo apt-get install -y nodejs":`winget install OpenJS.NodeJS.LTS --version ${t}`,{stdio:"inherit"}),console.log(chalk.green(` ✓ Node.js ${t} 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 ${t}`))}}console.log(),g();const h=p();if(h===n)console.log(chalk.green(` ✓ Python ${n}`)),console.log();else{console.log(chalk.yellow(` Python ${h||"not found"} — installing Python ${n}...`));try{if("darwin"===r){e("brew install python@3.12",{stdio:"inherit"});try{e("brew link --overwrite python@3.12",{stdio:"ignore"})}catch{}console.log(chalk.green(" ✓ Python 3.12 installed")),console.log(chalk.gray(" Use: /opt/homebrew/opt/python@3.12/bin/python3.12")),console.log(chalk.gray(" Or: brew link --overwrite python@3.12"))}else if("linux"===r){console.log(chalk.gray(` Building Python ${n} from source...`)),e("sudo apt-get update && sudo apt-get install -y build-essential libssl-dev zlib1g-dev libncurses5-dev libncursesw5-dev libreadline-dev libsqlite3-dev libgdbm-dev libdb5.3-dev libbz2-dev libexpat1-dev liblzma-dev libffi-dev tk-dev curl",{stdio:"inherit"}),e(`curl -sS https://www.python.org/ftp/python/${n}/Python-${n}.tgz -o /tmp/Python-${n}.tgz`,{stdio:"inherit"}),e(`cd /tmp && tar xzf Python-${n}.tgz && cd Python-${n} && ./configure --prefix=/usr/local --enable-optimizations 2>&1 | tail -1 && make -j$(nproc) 2>&1 | tail -1 && sudo make altinstall`,{stdio:"inherit",timeout:6e5});try{e("curl -sS https://bootstrap.pypa.io/get-pip.py | sudo /usr/local/bin/python3.12",{stdio:"inherit"})}catch{}try{e("sudo update-alternatives --install /usr/bin/python3 python3 /usr/local/bin/python3.12 2",{stdio:"ignore"}),e("sudo update-alternatives --set python3 /usr/local/bin/python3.12",{stdio:"ignore"})}catch{}console.log(chalk.green(` ✓ Python ${n} installed`))}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"===r?"brew install python@3.12":"linux"===r?"sudo apt install python3.12":"winget install Python.Python.3.12";console.log(chalk.gray(` Manual install: ${e}`))}console.log()}"win32"===r&&(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 y=[];for(const e of s)i(e.check)||("darwin"===r?e.brew:"linux"===r?e.apt:e.choco)&&y.push(e);if(y.length>0&&"win32"!==r){const o="darwin"===r?"brew":"apt";console.log(chalk.bold.white(` System Tools via ${o} (${y.length} missing)`)),console.log(chalk.gray(" ─────────────────────────────────────────────"));for(const n of y){const t="darwin"===r?n.brew:"linux"===r?n.apt:n.choco;process.stdout.write(chalk.gray(` ⏳ ${n.name}...`));try{let o;o="darwin"===r?`brew install ${t}`:"linux"===r?`sudo apt-get install -y ${t}`:`choco install -y ${t}`,e(o,{stdio:"ignore"}),process.stdout.write("\r"),console.log(chalk.green(` ✓ ${n.name}`))}catch{process.stdout.write("\r"),console.log(chalk.red(` ✗ ${n.name}`)+chalk.gray(` (${o} install ${t})`))}}console.log()}let m="pip3";if("darwin"===r){const o="/opt/homebrew/opt/python@3.12/bin/pip3.12";try{e(`${o} --version`,{stdio:"ignore"}),m=o,console.log(chalk.gray(` Using: ${o}`))}catch{try{e("pip3.12 --version",{stdio:"ignore"}),m="pip3.12"}catch{}}}else if("linux"===r)try{e("pip3.12 --version",{stdio:"ignore"}),m="pip3.12"}catch{}else"win32"===r&&(m="pip");if("darwin"===r){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"===r)try{e("sudo apt-get install -y libgmp-dev libmpfr-dev libmpc-dev libmagic1",{stdio:"ignore"})}catch{}console.log();const d={...process.env};"darwin"===r&&(d.CFLAGS=`-I/opt/homebrew/include ${d.CFLAGS||""}`.trim(),d.LDFLAGS=`-L/opt/homebrew/lib ${d.LDFLAGS||""}`.trim(),d.C_INCLUDE_PATH=`/opt/homebrew/include:${d.C_INCLUDE_PATH||""}`,d.LIBRARY_PATH=`/opt/homebrew/lib:${d.LIBRARY_PATH||""}`);let u=0,w=0;console.log(chalk.bold.white(` Python Libraries (${c.length} packages)`)),console.log(chalk.gray(" ─────────────────────────────────────────────"));for(const o of c)if(o.install)if(i(o.check))console.log(chalk.green(` ✓ ${o.name}`)+chalk.gray(" (installed)")),u++;else{process.stdout.write(chalk.gray(` ⏳ ${o.name}...`));try{e(`${m} install ${a} ${o.install}`,{stdio:"ignore",env:d}),process.stdout.write("\r"),console.log(chalk.green(` ✓ ${o.name}`)+chalk.gray(` (${o.install})`)),u++}catch{process.stdout.write("\r"),console.log(chalk.red(` ✗ ${o.name}`)+chalk.gray(" (failed)")),w++}}console.log(),console.log(chalk.gray(" ─────────────────────────────────────────────")),console.log(` ${chalk.green(`✓ ${u} installed`)} ${w>0?chalk.red(`✗ ${w} failed`):chalk.green("All ready!")}`),console.log()}()}),a.command("python").description("Show Python 3.12 install guide for your platform").action(()=>function(){const n=o();console.log(),console.log(chalk.bold.white(" Python 3.12 — Installation Guide")),console.log(chalk.gray(" ─────────────────────────────────────────────")),console.log();let t="",c="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 n=e(o,{encoding:"utf-8",timeout:3e3}).trim().replace("Python ",""),r=n.split(".").map(Number);if(3===r[0]&&12===r[1]){t=n,c="ok";break}t=n,c=3===r[0]&&r[1]>=10&&r[1]<12?"old":3===r[0]&&r[1]>12?"new":"missing"}catch{}if("ok"===c)return console.log(chalk.green(` ✓ Python ${t} — you're good!`)),console.log(chalk.gray(" Exam toolkit ready. Next: ")+chalk.bold.cyan("exam setup")),void console.log();if("old"===c?console.log(chalk.yellow(` ⚠ Python ${t} — works, but 3.12 recommended`)):"new"===c?(console.log(chalk.yellow(` ⚠ Python ${t} — 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"===n)console.log(chalk.bold.white(" macOS (Homebrew)")),console.log(),console.log(chalk.green(" brew install python@3.12"));else if("linux"===n){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-distutils && \\")),console.log(chalk.green(" sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.12 1"))):"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"===n?(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()}()),a.action(()=>h())}function h(){console.log();const r=o(),a="darwin"===r?"brew":"linux"===r?"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 (110) 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 n=o();try{if("darwin"===n)return`macOS ${e("sw_vers -productVersion",{encoding:"utf-8"}).trim()} (${e("uname -m",{encoding:"utf-8"}).trim()})`;if("linux"===n)try{const o=e("cat /etc/os-release | grep PRETTY_NAME",{encoding:"utf-8"}).match(/PRETTY_NAME="(.+)"/),n=e("uname -m",{encoding:"utf-8"}).trim();return o?`${o[1]} (${n})`:`Linux (${n})`}catch{return"Linux"}else if("win32"===n)return e("ver",{encoding:"utf-8"}).trim()||"Windows"}catch{}return n}())),console.log(chalk.gray(" Node: ")+chalk.white(`Node.js ${process.version}`)),console.log(chalk.gray(" Package: ")+chalk.white(a)),console.log(chalk.gray(" Target: ")+chalk.white(`Node ${t} | Python ${n}`)),"win32"===r&&(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 h=process.versions.node,y=h.split(".").map(Number);y[0]>22||22===y[0]&&y[1]>22||22===y[0]&&22===y[1]&&y[2]>=2?console.log(chalk.green(` ✓ Node.js ${h}`)+chalk.gray(` (>= ${t})`)):(console.log(chalk.red(` ✗ Node.js ${h}`)+chalk.gray(` (>= ${t} required)`)),console.log(chalk.gray(" Install: nvm install 22 or visit https://nodejs.org/")));const m=g(),d=p();d===n?console.log(chalk.green(` ✓ Python ${d}`)+chalk.gray(" (official)")):"3.12"===m?console.log(chalk.yellow(` ~ Python ${d}`)+chalk.gray(` (${n} recommended, run env setup)`)):m?console.log(chalk.yellow(` ~ Python ${d}`)+chalk.gray(` (${n} required, run env setup)`)):console.log(chalk.red(" ✗ Python 3 not found")),console.log();let u=0,w=0,k="";for(const e of s){e.category!==k&&(k=e.category,console.log(chalk.bold.gray(` ${k}`)));const o=i(e.check),n=o?l(e.name):"",t=n?chalk.gray(` (${n})`):"";o?(console.log(chalk.green(` ✓ ${e.name}`)+t),u++):(console.log(chalk.red(` ✗ ${e.name}`)),w++)}k="";const b="darwin"===r?"/opt/homebrew/opt/python@3.12/bin/pip3.12":"win32"===r?"pip":"pip3";for(const o of c)if(o.category!==k&&(k=o.category,console.log(chalk.bold.gray(` ${k}`))),i(o.check)){let n="";for(const t of[b,"pip3","pip"])try{const c=o.name.replace("python-magic","python_magic"),r=e(`${t} show ${c}`,{encoding:"utf-8",timeout:3e3,stdio:["pipe","pipe","ignore"]}).match(/Version:\s*(\S+)/);if(r){n=r[1];break}}catch{}console.log(chalk.green(` ✓ ${o.name}`)+chalk.gray(n?` (${n})`:"")),u++}else console.log(chalk.red(` ✗ ${o.name}`)+chalk.gray(` → ${o.install||"latest"}`)),w++;const f=u+w;console.log(),console.log(chalk.gray(" ─────────────────────────────────────────────")),console.log(` ${chalk.green(`✓ ${u}/${f}`)} ${w>0?chalk.red(`✗ ${w} missing`):chalk.green("All 110 ready!")}`),w>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()}
|