icoa-cli 2.19.34 → 2.19.35
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 +59 -18
- package/package.json +1 -1
package/dist/commands/ai4ctf.js
CHANGED
|
@@ -17,6 +17,10 @@ function getChallengeContext() {
|
|
|
17
17
|
let chatActive = false;
|
|
18
18
|
let chatSession = null;
|
|
19
19
|
let chatTokensUsed = 0;
|
|
20
|
+
// Set true when the user burns through DEMO_TOKEN_CAP without solving. The
|
|
21
|
+
// chat session stays alive so `!<shell>` and `submit <flag>` still work, but
|
|
22
|
+
// further AI messages are blocked. See the reveal path in handleChatMessage.
|
|
23
|
+
let tokensLocked = false;
|
|
20
24
|
const DEMO_TOKEN_CAP = 5000;
|
|
21
25
|
export function isChatActive() {
|
|
22
26
|
return chatActive;
|
|
@@ -53,14 +57,46 @@ const DEMO_HINTS = {
|
|
|
53
57
|
'For simple challenges like this one, hint c adds nothing extra:',
|
|
54
58
|
'hint b already tells you everything you need.',
|
|
55
59
|
'',
|
|
56
|
-
'
|
|
57
|
-
'just type a question like: how do I decode Base64 on the command line?',
|
|
60
|
+
'Two ways forward from here:',
|
|
58
61
|
'',
|
|
59
|
-
'
|
|
62
|
+
' 1. Chat with your AI teammate in natural language. Examples:',
|
|
63
|
+
' what is the base64 command?',
|
|
64
|
+
' how do I decode Base64 on macOS?',
|
|
65
|
+
' Just type the question — anything without "!" goes to the AI.',
|
|
60
66
|
'',
|
|
61
|
-
'
|
|
67
|
+
' 2. Run a shell command directly. Shell commands inside ai4ctf',
|
|
68
|
+
' must start with "!", otherwise your text goes to the AI. Example:',
|
|
69
|
+
'',
|
|
70
|
+
' !echo aWNvYXt3M2xjMG1lXzJfYWk0Y3RmfQ== | base64 -d',
|
|
62
71
|
],
|
|
63
72
|
};
|
|
73
|
+
// Shown when the user hits the 5000-token demo cap without solving. Keeps
|
|
74
|
+
// the session alive (no chatActive=false) so they can still paste the shell
|
|
75
|
+
// command below and then `submit <flag>`.
|
|
76
|
+
function showTokenCapReveal() {
|
|
77
|
+
console.log();
|
|
78
|
+
console.log(chalk.yellow(' ─────────────────────────────────────────────'));
|
|
79
|
+
console.log(chalk.bold.yellow(' 💡 Out of AI tokens — here is the reveal'));
|
|
80
|
+
console.log(chalk.yellow(' ─────────────────────────────────────────────'));
|
|
81
|
+
console.log();
|
|
82
|
+
console.log(chalk.white(' Looks like you have not found the flag yet.'));
|
|
83
|
+
console.log(chalk.white(' No worries — for the demo we will just tell you.'));
|
|
84
|
+
console.log();
|
|
85
|
+
console.log(chalk.white(' Run this command to decode the Base64 string:'));
|
|
86
|
+
console.log();
|
|
87
|
+
console.log(chalk.cyan(' !echo aWNvYXt3M2xjMG1lXzJfYWk0Y3RmfQ== | base64 -d'));
|
|
88
|
+
console.log();
|
|
89
|
+
console.log(chalk.white(' You will see the flag:'));
|
|
90
|
+
console.log();
|
|
91
|
+
console.log(chalk.green(' icoa{w3lc0me_2_ai4ctf}'));
|
|
92
|
+
console.log();
|
|
93
|
+
console.log(chalk.white(' Then submit it:'));
|
|
94
|
+
console.log();
|
|
95
|
+
console.log(chalk.cyan(' submit icoa{w3lc0me_2_ai4ctf}'));
|
|
96
|
+
console.log();
|
|
97
|
+
console.log(chalk.gray(' (AI chat is locked — only shell commands and submit work now.)'));
|
|
98
|
+
console.log();
|
|
99
|
+
}
|
|
64
100
|
function showDemoHint(tier) {
|
|
65
101
|
const title = tier === 'a' ? t('ai4ctfHintA') : tier === 'b' ? t('ai4ctfHintB') : t('ai4ctfHintC');
|
|
66
102
|
const tierLabel = `Hint ${tier.toUpperCase()}`;
|
|
@@ -214,12 +250,14 @@ export async function handleChatMessage(input) {
|
|
|
214
250
|
console.log();
|
|
215
251
|
return 'exit';
|
|
216
252
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
//
|
|
253
|
+
// Token cap: first hit → reveal the answer, lock AI, but keep the session
|
|
254
|
+
// alive so the user can still paste the shell command and then submit.
|
|
255
|
+
// `tokensLocked` prevents any further sendMessage calls.
|
|
256
|
+
if (!tokensLocked && chatTokensUsed >= DEMO_TOKEN_CAP) {
|
|
257
|
+
tokensLocked = true;
|
|
258
|
+
// Report the token-cap session once (solved:false). If the user then
|
|
259
|
+
// submits the revealed flag, the submit-success path fires another POST
|
|
260
|
+
// with solved:true which is the canonical record.
|
|
223
261
|
fetch('https://practice.icoa2026.au/api/icoa/demo-stats', {
|
|
224
262
|
method: 'POST',
|
|
225
263
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -229,16 +267,18 @@ export async function handleChatMessage(input) {
|
|
|
229
267
|
console.log();
|
|
230
268
|
console.log(chalk.yellow(` ${t('tokenLimit')}`));
|
|
231
269
|
drawTokenBar();
|
|
270
|
+
showTokenCapReveal();
|
|
271
|
+
return 'continue';
|
|
272
|
+
}
|
|
273
|
+
// If AI is locked (post-reveal), bounce any non-shell, non-submit input
|
|
274
|
+
// back to the user with a reminder of what actually works now.
|
|
275
|
+
if (tokensLocked) {
|
|
232
276
|
console.log();
|
|
233
|
-
console.log(chalk.
|
|
234
|
-
console.log(chalk.
|
|
235
|
-
console.log(chalk.gray(
|
|
236
|
-
console.log(chalk.gray(` ${t('ai4ctfModel')}: Google Gemma 4 (gemma-4-31b-it)`));
|
|
237
|
-
console.log(chalk.gray(' ─────────────────────────────────────────'));
|
|
238
|
-
console.log();
|
|
239
|
-
console.log(chalk.white(` ${t('ai4ctfNext')}`));
|
|
277
|
+
console.log(chalk.yellow(' AI chat is locked — out of tokens.'));
|
|
278
|
+
console.log(chalk.gray(' Use: ') + chalk.cyan('!echo aWNvYXt3M2xjMG1lXzJfYWk0Y3RmfQ== | base64 -d'));
|
|
279
|
+
console.log(chalk.gray(' Then: ') + chalk.cyan('submit icoa{w3lc0me_2_ai4ctf}'));
|
|
240
280
|
console.log();
|
|
241
|
-
return '
|
|
281
|
+
return 'continue';
|
|
242
282
|
}
|
|
243
283
|
console.log(chalk.gray(` ${t('ai4ctfThinking')}`));
|
|
244
284
|
try {
|
|
@@ -280,6 +320,7 @@ export function registerAi4ctfCommand(program) {
|
|
|
280
320
|
}
|
|
281
321
|
chatActive = true;
|
|
282
322
|
chatTokensUsed = 0;
|
|
323
|
+
tokensLocked = false;
|
|
283
324
|
// Guided welcome
|
|
284
325
|
console.log();
|
|
285
326
|
console.log(chalk.green.bold(` ═══ ${t('ai4ctfTitle')} ═══`));
|