icoa-cli 1.5.0 → 1.5.1
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.d.ts +2 -0
- package/dist/commands/env.js +208 -0
- package/dist/index.js +3 -1
- package/dist/repl.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { execSync } from 'node:child_process';
|
|
3
|
+
import { platform } from 'node:os';
|
|
4
|
+
const PYTHON_LIBS = [
|
|
5
|
+
{ name: 'pwntools', check: 'python3 -c "import pwn"', install: 'pwntools==4.12.0', category: 'Python Libraries' },
|
|
6
|
+
{ name: 'pycryptodome', check: 'python3 -c "import Crypto"', install: 'pycryptodome==3.20.0', category: 'Python Libraries' },
|
|
7
|
+
{ name: 'requests', check: 'python3 -c "import requests"', install: 'requests==2.31.0', category: 'Python Libraries' },
|
|
8
|
+
{ name: 'beautifulsoup4', check: 'python3 -c "import bs4"', install: 'beautifulsoup4==4.12.3', category: 'Python Libraries' },
|
|
9
|
+
{ name: 'z3-solver', check: 'python3 -c "import z3"', install: 'z3-solver==4.12.6', category: 'Python Libraries' },
|
|
10
|
+
{ name: 'sympy', check: 'python3 -c "import sympy"', install: 'sympy==1.12', category: 'Python Libraries' },
|
|
11
|
+
{ name: 'scapy', check: 'python3 -c "import scapy"', install: 'scapy==2.5.0', category: 'Python Libraries' },
|
|
12
|
+
{ name: 'pillow', check: 'python3 -c "import PIL"', install: 'pillow==10.2.0', category: 'Python Libraries' },
|
|
13
|
+
{ name: 'numpy', check: 'python3 -c "import numpy"', install: 'numpy==1.26.4', category: 'Python Libraries' },
|
|
14
|
+
{ name: 'pefile', check: 'python3 -c "import pefile"', install: 'pefile==2023.2.7', category: 'Python Libraries' },
|
|
15
|
+
{ name: 'capstone', check: 'python3 -c "import capstone"', install: 'capstone==5.0.1', category: 'Python Libraries' },
|
|
16
|
+
{ name: 'ropper', check: 'python3 -c "import ropper"', install: 'ropper==1.13.8', category: 'Python Libraries' },
|
|
17
|
+
{ name: 'ROPgadget', check: 'which ROPgadget', install: 'ROPgadget==7.4', category: 'Python Libraries' },
|
|
18
|
+
{ name: 'flask', check: 'python3 -c "import flask"', install: 'flask==3.0.0', category: 'Python Libraries' },
|
|
19
|
+
{ name: 'cryptography', check: 'python3 -c "import cryptography"', install: 'cryptography==42.0.0', category: 'Python Libraries' },
|
|
20
|
+
{ name: 'paramiko', check: 'python3 -c "import paramiko"', install: 'paramiko==3.4.0', category: 'Python Libraries' },
|
|
21
|
+
{ name: 'python-magic', check: 'python3 -c "import magic"', install: 'python-magic==0.4.27', category: 'Python Libraries' },
|
|
22
|
+
{ name: 'ipython', check: 'which ipython3 || which ipython', install: 'ipython', category: 'Python Libraries' },
|
|
23
|
+
{ name: 'angr', check: 'python3 -c "import angr"', install: 'angr', category: 'Python Libraries' },
|
|
24
|
+
{ name: 'sqlmap', check: 'which sqlmap', install: 'sqlmap', category: 'Python Libraries' },
|
|
25
|
+
];
|
|
26
|
+
const SYSTEM_TOOLS = [
|
|
27
|
+
// Editors
|
|
28
|
+
{ name: 'vim', check: 'which vim', category: 'Editors' },
|
|
29
|
+
{ name: 'nano', check: 'which nano', category: 'Editors' },
|
|
30
|
+
{ name: 'tmux', check: 'which tmux', category: 'Editors' },
|
|
31
|
+
// Compilers
|
|
32
|
+
{ name: 'gcc', check: 'which gcc', category: 'Compilers' },
|
|
33
|
+
{ name: 'g++', check: 'which g++', category: 'Compilers' },
|
|
34
|
+
{ name: 'make', check: 'which make', category: 'Compilers' },
|
|
35
|
+
{ name: 'nasm', check: 'which nasm', category: 'Compilers' },
|
|
36
|
+
// Python
|
|
37
|
+
{ name: 'python3', check: 'python3 --version', category: 'Python' },
|
|
38
|
+
{ name: 'pip3', check: 'pip3 --version', category: 'Python' },
|
|
39
|
+
// Network
|
|
40
|
+
{ name: 'curl', check: 'which curl', category: 'Networking' },
|
|
41
|
+
{ name: 'wget', check: 'which wget', category: 'Networking' },
|
|
42
|
+
{ name: 'nc', check: 'which nc', category: 'Networking' },
|
|
43
|
+
{ name: 'nmap', check: 'which nmap', category: 'Networking' },
|
|
44
|
+
{ name: 'ssh', check: 'which ssh', category: 'Networking' },
|
|
45
|
+
{ name: 'socat', check: 'which socat', category: 'Networking' },
|
|
46
|
+
// Debuggers
|
|
47
|
+
{ name: 'gdb', check: 'which gdb', category: 'Debuggers' },
|
|
48
|
+
{ name: 'ltrace', check: 'which ltrace', category: 'Debuggers' },
|
|
49
|
+
{ name: 'strace', check: 'which strace', category: 'Debuggers' },
|
|
50
|
+
// RE
|
|
51
|
+
{ name: 'radare2', check: 'which r2', category: 'Reverse Engineering' },
|
|
52
|
+
{ name: 'objdump', check: 'which objdump', category: 'Reverse Engineering' },
|
|
53
|
+
// Forensics
|
|
54
|
+
{ name: 'binwalk', check: 'which binwalk', category: 'Forensics' },
|
|
55
|
+
{ name: 'exiftool', check: 'which exiftool', category: 'Forensics' },
|
|
56
|
+
{ name: 'steghide', check: 'which steghide', category: 'Forensics' },
|
|
57
|
+
{ name: 'strings', check: 'which strings', category: 'Forensics' },
|
|
58
|
+
{ name: 'file', check: 'which file', category: 'Forensics' },
|
|
59
|
+
{ name: 'xxd', check: 'which xxd', category: 'Forensics' },
|
|
60
|
+
// Crypto
|
|
61
|
+
{ name: 'john', check: 'which john', category: 'Crypto' },
|
|
62
|
+
{ name: 'hashcat', check: 'which hashcat', category: 'Crypto' },
|
|
63
|
+
{ name: 'openssl', check: 'which openssl', category: 'Crypto' },
|
|
64
|
+
// Data
|
|
65
|
+
{ name: 'jq', check: 'which jq', category: 'Data Processing' },
|
|
66
|
+
{ name: 'sqlite3', check: 'which sqlite3', category: 'Data Processing' },
|
|
67
|
+
// Core
|
|
68
|
+
{ name: 'git', check: 'which git', category: 'Version Control' },
|
|
69
|
+
{ name: 'docker', check: 'which docker', category: 'Container' },
|
|
70
|
+
];
|
|
71
|
+
function isInstalled(check) {
|
|
72
|
+
try {
|
|
73
|
+
execSync(check, { stdio: 'ignore' });
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function getVersion(name) {
|
|
81
|
+
try {
|
|
82
|
+
if (name === 'python3') {
|
|
83
|
+
return execSync('python3 --version', { encoding: 'utf-8' }).trim().replace('Python ', '');
|
|
84
|
+
}
|
|
85
|
+
if (name === 'gcc') {
|
|
86
|
+
const out = execSync('gcc --version', { encoding: 'utf-8' });
|
|
87
|
+
const match = out.match(/(\d+\.\d+\.\d+)/);
|
|
88
|
+
return match ? match[1] : '';
|
|
89
|
+
}
|
|
90
|
+
if (name === 'docker') {
|
|
91
|
+
const out = execSync('docker --version', { encoding: 'utf-8' });
|
|
92
|
+
const match = out.match(/(\d+\.\d+\.\d+)/);
|
|
93
|
+
return match ? match[1] : '';
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
catch { /* ignore */ }
|
|
97
|
+
return '';
|
|
98
|
+
}
|
|
99
|
+
export function registerEnvCommand(program) {
|
|
100
|
+
const envCmd = program.command('env').description('Manage competition environment');
|
|
101
|
+
// icoa env — show status
|
|
102
|
+
envCmd
|
|
103
|
+
.command('status')
|
|
104
|
+
.alias('check')
|
|
105
|
+
.description('Check installed tools and libraries')
|
|
106
|
+
.action(() => {
|
|
107
|
+
showStatus();
|
|
108
|
+
});
|
|
109
|
+
// icoa env setup — install everything
|
|
110
|
+
envCmd
|
|
111
|
+
.command('setup')
|
|
112
|
+
.description('Install all Python libraries (locked versions)')
|
|
113
|
+
.action(async () => {
|
|
114
|
+
await installAll();
|
|
115
|
+
});
|
|
116
|
+
// Default action: show status
|
|
117
|
+
envCmd.action(() => {
|
|
118
|
+
showStatus();
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
function showStatus() {
|
|
122
|
+
console.log();
|
|
123
|
+
console.log(chalk.bold.white(' ICOA Competition Environment'));
|
|
124
|
+
console.log(chalk.gray(' ─────────────────────────────────'));
|
|
125
|
+
console.log();
|
|
126
|
+
let installed = 0;
|
|
127
|
+
let missing = 0;
|
|
128
|
+
let currentCategory = '';
|
|
129
|
+
// System tools
|
|
130
|
+
for (const tool of SYSTEM_TOOLS) {
|
|
131
|
+
if (tool.category !== currentCategory) {
|
|
132
|
+
currentCategory = tool.category;
|
|
133
|
+
console.log(chalk.bold.gray(` ${currentCategory}`));
|
|
134
|
+
}
|
|
135
|
+
const ok = isInstalled(tool.check);
|
|
136
|
+
const ver = ok ? getVersion(tool.name) : '';
|
|
137
|
+
const verStr = ver ? chalk.gray(` (${ver})`) : '';
|
|
138
|
+
if (ok) {
|
|
139
|
+
console.log(chalk.green(` ✓ ${tool.name}`) + verStr);
|
|
140
|
+
installed++;
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
console.log(chalk.red(` ✗ ${tool.name}`));
|
|
144
|
+
missing++;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// Python libraries
|
|
148
|
+
currentCategory = '';
|
|
149
|
+
for (const lib of PYTHON_LIBS) {
|
|
150
|
+
if (lib.category !== currentCategory) {
|
|
151
|
+
currentCategory = lib.category;
|
|
152
|
+
console.log(chalk.bold.gray(` ${currentCategory}`));
|
|
153
|
+
}
|
|
154
|
+
const ok = isInstalled(lib.check);
|
|
155
|
+
const verStr = lib.install ? chalk.gray(` (${lib.install})`) : '';
|
|
156
|
+
if (ok) {
|
|
157
|
+
console.log(chalk.green(` ✓ ${lib.name}`) + verStr);
|
|
158
|
+
installed++;
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
console.log(chalk.red(` ✗ ${lib.name}`) + (lib.install ? chalk.gray(` → ${lib.install}`) : ''));
|
|
162
|
+
missing++;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
console.log();
|
|
166
|
+
console.log(chalk.gray(' ─────────────────────────────────'));
|
|
167
|
+
console.log(` ${chalk.green(`✓ ${installed} installed`)} ${missing > 0 ? chalk.red(`✗ ${missing} missing`) : chalk.green('All ready!')}`);
|
|
168
|
+
if (missing > 0) {
|
|
169
|
+
console.log();
|
|
170
|
+
console.log(chalk.gray(' Install missing Python libs: ') + chalk.white('env setup'));
|
|
171
|
+
}
|
|
172
|
+
console.log();
|
|
173
|
+
}
|
|
174
|
+
async function installAll() {
|
|
175
|
+
console.log();
|
|
176
|
+
console.log(chalk.bold.white(' Installing Python libraries (locked versions)...'));
|
|
177
|
+
console.log();
|
|
178
|
+
const os = platform();
|
|
179
|
+
const pipFlag = os === 'darwin' || os === 'linux' ? '--break-system-packages' : '';
|
|
180
|
+
let installed = 0;
|
|
181
|
+
let failed = 0;
|
|
182
|
+
for (const lib of PYTHON_LIBS) {
|
|
183
|
+
if (!lib.install)
|
|
184
|
+
continue;
|
|
185
|
+
const alreadyInstalled = isInstalled(lib.check);
|
|
186
|
+
if (alreadyInstalled) {
|
|
187
|
+
console.log(chalk.green(` ✓ ${lib.name}`) + chalk.gray(` (already installed)`));
|
|
188
|
+
installed++;
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
process.stdout.write(chalk.gray(` ⏳ Installing ${lib.name}...`));
|
|
192
|
+
try {
|
|
193
|
+
execSync(`pip3 install ${pipFlag} ${lib.install}`, { stdio: 'ignore' });
|
|
194
|
+
process.stdout.write('\r');
|
|
195
|
+
console.log(chalk.green(` ✓ ${lib.name}`) + chalk.gray(` (${lib.install})`));
|
|
196
|
+
installed++;
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
process.stdout.write('\r');
|
|
200
|
+
console.log(chalk.red(` ✗ ${lib.name}`) + chalk.gray(` (install failed)`));
|
|
201
|
+
failed++;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
console.log();
|
|
205
|
+
console.log(chalk.gray(' ─────────────────────────────────'));
|
|
206
|
+
console.log(` ${chalk.green(`✓ ${installed} installed`)} ${failed > 0 ? chalk.red(`✗ ${failed} failed`) : chalk.green('All ready!')}`);
|
|
207
|
+
console.log();
|
|
208
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -11,6 +11,7 @@ import { registerNoteCommand } from './commands/note.js';
|
|
|
11
11
|
import { registerLogCommand } from './commands/log.js';
|
|
12
12
|
import { registerLangCommand } from './commands/lang.js';
|
|
13
13
|
import { registerSetupCommand } from './commands/setup.js';
|
|
14
|
+
import { registerEnvCommand } from './commands/env.js';
|
|
14
15
|
import { getConfig, saveConfig } from './lib/config.js';
|
|
15
16
|
import { startRepl } from './repl.js';
|
|
16
17
|
import { checkTerminal } from './lib/terminal.js';
|
|
@@ -37,7 +38,7 @@ ${B} ${B}
|
|
|
37
38
|
${B} ${chalk.white('Sydney, Australia')} ${chalk.gray('Jun 27 - Jul 2, 2026')} ${B}
|
|
38
39
|
${B} ${chalk.cyan.underline('https://icoa2026.au')} ${B}
|
|
39
40
|
${B} ${B}
|
|
40
|
-
${B} ${chalk.gray('CLI-Native Competition Terminal v1.5.
|
|
41
|
+
${B} ${chalk.gray('CLI-Native Competition Terminal v1.5.1')} ${B}
|
|
41
42
|
${B} ${B}
|
|
42
43
|
${chalk.cyan('╚══════════════════════════════════════════════════════════╝')}
|
|
43
44
|
`;
|
|
@@ -82,6 +83,7 @@ registerNoteCommand(program);
|
|
|
82
83
|
registerLogCommand(program);
|
|
83
84
|
registerLangCommand(program);
|
|
84
85
|
registerSetupCommand(program);
|
|
86
|
+
registerEnvCommand(program);
|
|
85
87
|
// Hidden command: switch AI model
|
|
86
88
|
program
|
|
87
89
|
.command('model', { hidden: true })
|
package/dist/repl.js
CHANGED
|
@@ -125,7 +125,7 @@ export function startRepl(program, resumeMode) {
|
|
|
125
125
|
'join', 'activate', 'challenges', 'ch', 'open', 'submit', 'flag',
|
|
126
126
|
'scoreboard', 'sb', 'status', 'time', 'hint', 'hint-b', 'hint-c',
|
|
127
127
|
'hint-budget', 'ref', 'shell', 'files', 'connect', 'note', 'log',
|
|
128
|
-
'lang', 'setup', 'model', 'ctf',
|
|
128
|
+
'lang', 'setup', 'env', 'model', 'ctf',
|
|
129
129
|
];
|
|
130
130
|
if (!knownCommands.includes(cmd)) {
|
|
131
131
|
// Route to Docker sandbox if available, otherwise system shell
|