icoa-cli 2.10.0 → 2.12.0
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/ctf.js +19 -2
- package/dist/commands/exam.js +3 -1
- package/dist/lib/demo-exam.d.ts +10 -0
- package/dist/lib/demo-exam.js +54 -0
- package/dist/lib/translation.js +21 -7
- package/dist/repl.js +106 -15
- package/package.json +3 -2
- package/translations/ar/1.json +9 -0
- package/translations/ar/10.json +9 -0
- package/translations/ar/11.json +9 -0
- package/translations/ar/12.json +9 -0
- package/translations/ar/13.json +9 -0
- package/translations/ar/14.json +9 -0
- package/translations/ar/15.json +9 -0
- package/translations/ar/16.json +9 -0
- package/translations/ar/17.json +9 -0
- package/translations/ar/18.json +9 -0
- package/translations/ar/19.json +9 -0
- package/translations/ar/20.json +9 -0
- package/translations/ar/21.json +9 -0
- package/translations/ar/22.json +9 -0
- package/translations/ar/23.json +9 -0
- package/translations/ar/24.json +9 -0
- package/translations/ar/25.json +9 -0
- package/translations/ar/26.json +9 -0
- package/translations/ar/27.json +9 -0
- package/translations/ar/28.json +9 -0
- package/translations/ar/29.json +9 -0
- package/translations/ar/30.json +9 -0
- package/translations/ar/31.json +9 -0
- package/translations/ar/32.json +9 -0
- package/translations/ar/33.json +9 -0
- package/translations/ar/34.json +9 -0
- package/translations/ar/35.json +9 -0
- package/translations/ar/36.json +9 -0
- package/translations/ar/37.json +9 -0
- package/translations/ar/38.json +9 -0
- package/translations/ar/39.json +9 -0
- package/translations/ar/4.json +9 -0
- package/translations/ar/40.json +9 -0
- package/translations/ar/41.json +9 -0
- package/translations/ar/42.json +9 -0
- package/translations/ar/43.json +9 -0
- package/translations/ar/44.json +9 -0
- package/translations/ar/45.json +9 -0
- package/translations/ar/46.json +9 -0
- package/translations/ar/47.json +9 -0
- package/translations/ar/48.json +9 -0
- package/translations/ar/49.json +9 -0
- package/translations/ar/5.json +9 -0
- package/translations/ar/6.json +9 -0
- package/translations/ar/7.json +9 -0
- package/translations/ar/8.json +9 -0
- package/translations/ar/9.json +9 -0
- package/translations/ar/demo.json +332 -0
- package/translations/de/1.json +9 -0
- package/translations/de/demo.json +332 -0
- package/translations/es/1.json +9 -0
- package/translations/es/10.json +9 -0
- package/translations/es/11.json +9 -0
- package/translations/es/12.json +9 -0
- package/translations/es/13.json +9 -0
- package/translations/es/14.json +9 -0
- package/translations/es/15.json +9 -0
- package/translations/es/16.json +9 -0
- package/translations/es/17.json +9 -0
- package/translations/es/18.json +9 -0
- package/translations/es/19.json +9 -0
- package/translations/es/20.json +9 -0
- package/translations/es/21.json +9 -0
- package/translations/es/22.json +9 -0
- package/translations/es/23.json +9 -0
- package/translations/es/24.json +9 -0
- package/translations/es/25.json +9 -0
- package/translations/es/26.json +9 -0
- package/translations/es/27.json +9 -0
- package/translations/es/28.json +9 -0
- package/translations/es/29.json +9 -0
- package/translations/es/30.json +9 -0
- package/translations/es/31.json +9 -0
- package/translations/es/32.json +9 -0
- package/translations/es/33.json +9 -0
- package/translations/es/34.json +9 -0
- package/translations/es/35.json +9 -0
- package/translations/es/36.json +9 -0
- package/translations/es/37.json +9 -0
- package/translations/es/38.json +9 -0
- package/translations/es/39.json +9 -0
- package/translations/es/4.json +9 -0
- package/translations/es/40.json +9 -0
- package/translations/es/41.json +9 -0
- package/translations/es/42.json +9 -0
- package/translations/es/43.json +9 -0
- package/translations/es/44.json +9 -0
- package/translations/es/45.json +9 -0
- package/translations/es/46.json +9 -0
- package/translations/es/47.json +9 -0
- package/translations/es/48.json +9 -0
- package/translations/es/49.json +9 -0
- package/translations/es/5.json +9 -0
- package/translations/es/6.json +9 -0
- package/translations/es/7.json +9 -0
- package/translations/es/8.json +9 -0
- package/translations/es/9.json +9 -0
- package/translations/es/demo.json +332 -0
- package/translations/fr/1.json +9 -0
- package/translations/fr/10.json +9 -0
- package/translations/fr/11.json +9 -0
- package/translations/fr/12.json +9 -0
- package/translations/fr/13.json +9 -0
- package/translations/fr/14.json +9 -0
- package/translations/fr/15.json +9 -0
- package/translations/fr/16.json +9 -0
- package/translations/fr/17.json +9 -0
- package/translations/fr/18.json +9 -0
- package/translations/fr/19.json +9 -0
- package/translations/fr/20.json +9 -0
- package/translations/fr/21.json +9 -0
- package/translations/fr/22.json +9 -0
- package/translations/fr/23.json +9 -0
- package/translations/fr/24.json +9 -0
- package/translations/fr/25.json +9 -0
- package/translations/fr/26.json +9 -0
- package/translations/fr/27.json +9 -0
- package/translations/fr/28.json +9 -0
- package/translations/fr/29.json +9 -0
- package/translations/fr/30.json +9 -0
- package/translations/fr/31.json +9 -0
- package/translations/fr/32.json +9 -0
- package/translations/fr/33.json +9 -0
- package/translations/fr/34.json +9 -0
- package/translations/fr/35.json +9 -0
- package/translations/fr/36.json +9 -0
- package/translations/fr/37.json +9 -0
- package/translations/fr/38.json +9 -0
- package/translations/fr/39.json +9 -0
- package/translations/fr/4.json +9 -0
- package/translations/fr/40.json +9 -0
- package/translations/fr/41.json +9 -0
- package/translations/fr/42.json +9 -0
- package/translations/fr/43.json +9 -0
- package/translations/fr/44.json +9 -0
- package/translations/fr/45.json +9 -0
- package/translations/fr/46.json +9 -0
- package/translations/fr/47.json +9 -0
- package/translations/fr/48.json +9 -0
- package/translations/fr/49.json +9 -0
- package/translations/fr/5.json +9 -0
- package/translations/fr/6.json +9 -0
- package/translations/fr/7.json +9 -0
- package/translations/fr/8.json +9 -0
- package/translations/fr/9.json +9 -0
- package/translations/fr/demo.json +332 -0
- package/translations/hi/1.json +9 -0
- package/translations/hi/10.json +9 -0
- package/translations/hi/11.json +9 -0
- package/translations/hi/12.json +9 -0
- package/translations/hi/13.json +9 -0
- package/translations/hi/14.json +9 -0
- package/translations/hi/15.json +9 -0
- package/translations/hi/16.json +9 -0
- package/translations/hi/17.json +9 -0
- package/translations/hi/18.json +9 -0
- package/translations/hi/19.json +9 -0
- package/translations/hi/20.json +9 -0
- package/translations/hi/21.json +9 -0
- package/translations/hi/22.json +9 -0
- package/translations/hi/23.json +9 -0
- package/translations/hi/24.json +9 -0
- package/translations/hi/25.json +9 -0
- package/translations/hi/26.json +9 -0
- package/translations/hi/27.json +9 -0
- package/translations/hi/28.json +9 -0
- package/translations/hi/29.json +9 -0
- package/translations/hi/30.json +9 -0
- package/translations/hi/31.json +9 -0
- package/translations/hi/32.json +9 -0
- package/translations/hi/33.json +9 -0
- package/translations/hi/34.json +9 -0
- package/translations/hi/35.json +9 -0
- package/translations/hi/36.json +9 -0
- package/translations/hi/37.json +9 -0
- package/translations/hi/38.json +9 -0
- package/translations/hi/39.json +9 -0
- package/translations/hi/4.json +9 -0
- package/translations/hi/40.json +9 -0
- package/translations/hi/41.json +9 -0
- package/translations/hi/42.json +9 -0
- package/translations/hi/43.json +9 -0
- package/translations/hi/44.json +9 -0
- package/translations/hi/45.json +9 -0
- package/translations/hi/46.json +9 -0
- package/translations/hi/47.json +9 -0
- package/translations/hi/48.json +9 -0
- package/translations/hi/49.json +9 -0
- package/translations/hi/5.json +9 -0
- package/translations/hi/6.json +9 -0
- package/translations/hi/7.json +9 -0
- package/translations/hi/8.json +9 -0
- package/translations/hi/9.json +9 -0
- package/translations/hi/demo.json +332 -0
- package/translations/id/demo.json +332 -0
- package/translations/ja/1.json +9 -0
- package/translations/ja/10.json +9 -0
- package/translations/ja/11.json +9 -0
- package/translations/ja/12.json +9 -0
- package/translations/ja/13.json +9 -0
- package/translations/ja/14.json +9 -0
- package/translations/ja/15.json +9 -0
- package/translations/ja/16.json +9 -0
- package/translations/ja/17.json +9 -0
- package/translations/ja/18.json +9 -0
- package/translations/ja/19.json +9 -0
- package/translations/ja/20.json +9 -0
- package/translations/ja/21.json +9 -0
- package/translations/ja/22.json +9 -0
- package/translations/ja/23.json +9 -0
- package/translations/ja/24.json +9 -0
- package/translations/ja/25.json +9 -0
- package/translations/ja/26.json +9 -0
- package/translations/ja/27.json +9 -0
- package/translations/ja/28.json +9 -0
- package/translations/ja/29.json +9 -0
- package/translations/ja/30.json +9 -0
- package/translations/ja/31.json +9 -0
- package/translations/ja/32.json +9 -0
- package/translations/ja/33.json +9 -0
- package/translations/ja/34.json +9 -0
- package/translations/ja/35.json +9 -0
- package/translations/ja/36.json +9 -0
- package/translations/ja/37.json +9 -0
- package/translations/ja/38.json +9 -0
- package/translations/ja/39.json +9 -0
- package/translations/ja/4.json +9 -0
- package/translations/ja/40.json +9 -0
- package/translations/ja/41.json +9 -0
- package/translations/ja/42.json +9 -0
- package/translations/ja/43.json +9 -0
- package/translations/ja/44.json +9 -0
- package/translations/ja/45.json +9 -0
- package/translations/ja/46.json +9 -0
- package/translations/ja/47.json +9 -0
- package/translations/ja/48.json +9 -0
- package/translations/ja/49.json +9 -0
- package/translations/ja/5.json +9 -0
- package/translations/ja/6.json +9 -0
- package/translations/ja/7.json +9 -0
- package/translations/ja/8.json +9 -0
- package/translations/ja/9.json +9 -0
- package/translations/ja/demo.json +332 -0
- package/translations/ko/1.json +9 -0
- package/translations/ko/10.json +9 -0
- package/translations/ko/11.json +9 -0
- package/translations/ko/12.json +9 -0
- package/translations/ko/13.json +9 -0
- package/translations/ko/14.json +9 -0
- package/translations/ko/15.json +9 -0
- package/translations/ko/16.json +9 -0
- package/translations/ko/17.json +9 -0
- package/translations/ko/18.json +9 -0
- package/translations/ko/19.json +9 -0
- package/translations/ko/20.json +9 -0
- package/translations/ko/21.json +9 -0
- package/translations/ko/22.json +9 -0
- package/translations/ko/23.json +9 -0
- package/translations/ko/24.json +9 -0
- package/translations/ko/25.json +9 -0
- package/translations/ko/26.json +9 -0
- package/translations/ko/27.json +9 -0
- package/translations/ko/28.json +9 -0
- package/translations/ko/29.json +9 -0
- package/translations/ko/30.json +9 -0
- package/translations/ko/31.json +9 -0
- package/translations/ko/32.json +9 -0
- package/translations/ko/33.json +9 -0
- package/translations/ko/34.json +9 -0
- package/translations/ko/35.json +9 -0
- package/translations/ko/36.json +9 -0
- package/translations/ko/37.json +9 -0
- package/translations/ko/38.json +9 -0
- package/translations/ko/39.json +9 -0
- package/translations/ko/4.json +9 -0
- package/translations/ko/40.json +9 -0
- package/translations/ko/41.json +9 -0
- package/translations/ko/42.json +9 -0
- package/translations/ko/43.json +9 -0
- package/translations/ko/44.json +9 -0
- package/translations/ko/45.json +9 -0
- package/translations/ko/46.json +9 -0
- package/translations/ko/47.json +9 -0
- package/translations/ko/48.json +9 -0
- package/translations/ko/49.json +9 -0
- package/translations/ko/5.json +9 -0
- package/translations/ko/6.json +9 -0
- package/translations/ko/7.json +9 -0
- package/translations/ko/8.json +9 -0
- package/translations/ko/9.json +9 -0
- package/translations/ko/demo.json +332 -0
- package/translations/pt/1.json +9 -0
- package/translations/pt/10.json +9 -0
- package/translations/pt/11.json +9 -0
- package/translations/pt/12.json +9 -0
- package/translations/pt/13.json +9 -0
- package/translations/pt/14.json +9 -0
- package/translations/pt/15.json +9 -0
- package/translations/pt/16.json +9 -0
- package/translations/pt/17.json +9 -0
- package/translations/pt/18.json +9 -0
- package/translations/pt/19.json +9 -0
- package/translations/pt/20.json +9 -0
- package/translations/pt/21.json +9 -0
- package/translations/pt/22.json +9 -0
- package/translations/pt/23.json +9 -0
- package/translations/pt/24.json +9 -0
- package/translations/pt/25.json +9 -0
- package/translations/pt/26.json +9 -0
- package/translations/pt/27.json +9 -0
- package/translations/pt/28.json +9 -0
- package/translations/pt/29.json +9 -0
- package/translations/pt/30.json +9 -0
- package/translations/pt/31.json +9 -0
- package/translations/pt/32.json +9 -0
- package/translations/pt/33.json +9 -0
- package/translations/pt/34.json +9 -0
- package/translations/pt/35.json +9 -0
- package/translations/pt/36.json +9 -0
- package/translations/pt/37.json +9 -0
- package/translations/pt/38.json +9 -0
- package/translations/pt/39.json +9 -0
- package/translations/pt/4.json +9 -0
- package/translations/pt/40.json +9 -0
- package/translations/pt/41.json +9 -0
- package/translations/pt/42.json +9 -0
- package/translations/pt/43.json +9 -0
- package/translations/pt/44.json +9 -0
- package/translations/pt/45.json +9 -0
- package/translations/pt/46.json +9 -0
- package/translations/pt/47.json +9 -0
- package/translations/pt/48.json +9 -0
- package/translations/pt/49.json +9 -0
- package/translations/pt/5.json +9 -0
- package/translations/pt/6.json +9 -0
- package/translations/pt/7.json +9 -0
- package/translations/pt/8.json +9 -0
- package/translations/pt/9.json +9 -0
- package/translations/pt/demo.json +332 -0
- package/translations/ru/1.json +9 -0
- package/translations/ru/10.json +9 -0
- package/translations/ru/11.json +9 -0
- package/translations/ru/12.json +9 -0
- package/translations/ru/13.json +9 -0
- package/translations/ru/14.json +9 -0
- package/translations/ru/15.json +9 -0
- package/translations/ru/16.json +9 -0
- package/translations/ru/17.json +9 -0
- package/translations/ru/18.json +9 -0
- package/translations/ru/19.json +9 -0
- package/translations/ru/20.json +9 -0
- package/translations/ru/21.json +9 -0
- package/translations/ru/22.json +9 -0
- package/translations/ru/23.json +9 -0
- package/translations/ru/24.json +9 -0
- package/translations/ru/25.json +9 -0
- package/translations/ru/26.json +9 -0
- package/translations/ru/27.json +9 -0
- package/translations/ru/28.json +9 -0
- package/translations/ru/29.json +9 -0
- package/translations/ru/30.json +9 -0
- package/translations/ru/31.json +9 -0
- package/translations/ru/32.json +9 -0
- package/translations/ru/33.json +9 -0
- package/translations/ru/34.json +9 -0
- package/translations/ru/35.json +9 -0
- package/translations/ru/36.json +9 -0
- package/translations/ru/37.json +9 -0
- package/translations/ru/38.json +9 -0
- package/translations/ru/39.json +9 -0
- package/translations/ru/4.json +9 -0
- package/translations/ru/40.json +9 -0
- package/translations/ru/41.json +9 -0
- package/translations/ru/42.json +9 -0
- package/translations/ru/43.json +9 -0
- package/translations/ru/44.json +9 -0
- package/translations/ru/45.json +9 -0
- package/translations/ru/46.json +9 -0
- package/translations/ru/47.json +9 -0
- package/translations/ru/48.json +9 -0
- package/translations/ru/49.json +9 -0
- package/translations/ru/5.json +9 -0
- package/translations/ru/6.json +9 -0
- package/translations/ru/7.json +9 -0
- package/translations/ru/8.json +9 -0
- package/translations/ru/9.json +9 -0
- package/translations/ru/demo.json +332 -0
- package/translations/th/demo.json +332 -0
- package/translations/tr/demo.json +332 -0
- package/translations/vi/demo.json +332 -0
- package/translations/zh/1.json +9 -0
- package/translations/zh/10.json +9 -0
- package/translations/zh/11.json +9 -0
- package/translations/zh/12.json +9 -0
- package/translations/zh/13.json +9 -0
- package/translations/zh/14.json +9 -0
- package/translations/zh/15.json +9 -0
- package/translations/zh/16.json +9 -0
- package/translations/zh/17.json +9 -0
- package/translations/zh/18.json +9 -0
- package/translations/zh/19.json +9 -0
- package/translations/zh/20.json +9 -0
- package/translations/zh/21.json +9 -0
- package/translations/zh/22.json +9 -0
- package/translations/zh/23.json +9 -0
- package/translations/zh/24.json +9 -0
- package/translations/zh/25.json +9 -0
- package/translations/zh/26.json +9 -0
- package/translations/zh/27.json +9 -0
- package/translations/zh/28.json +9 -0
- package/translations/zh/29.json +9 -0
- package/translations/zh/30.json +9 -0
- package/translations/zh/31.json +9 -0
- package/translations/zh/32.json +9 -0
- package/translations/zh/33.json +9 -0
- package/translations/zh/34.json +9 -0
- package/translations/zh/35.json +9 -0
- package/translations/zh/36.json +9 -0
- package/translations/zh/37.json +9 -0
- package/translations/zh/38.json +9 -0
- package/translations/zh/39.json +9 -0
- package/translations/zh/4.json +9 -0
- package/translations/zh/40.json +9 -0
- package/translations/zh/41.json +9 -0
- package/translations/zh/42.json +9 -0
- package/translations/zh/43.json +9 -0
- package/translations/zh/44.json +9 -0
- package/translations/zh/45.json +9 -0
- package/translations/zh/46.json +9 -0
- package/translations/zh/47.json +9 -0
- package/translations/zh/48.json +9 -0
- package/translations/zh/49.json +9 -0
- package/translations/zh/5.json +9 -0
- package/translations/zh/6.json +9 -0
- package/translations/zh/7.json +9 -0
- package/translations/zh/8.json +9 -0
- package/translations/zh/9.json +9 -0
- package/translations/zh/demo.json +332 -0
package/dist/commands/ctf.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
-
import { input } from '@inquirer/prompts';
|
|
2
|
+
import { input, password as passwordPrompt } from '@inquirer/prompts';
|
|
3
3
|
import { CTFdClient } from '../lib/ctfd-client.js';
|
|
4
4
|
import { getConfig, saveConfig, getBudget } from '../lib/config.js';
|
|
5
5
|
import { logCommand, logSubmission } from '../lib/logger.js';
|
|
@@ -31,7 +31,7 @@ export function registerCtfCommands(program) {
|
|
|
31
31
|
console.log();
|
|
32
32
|
printInfo(`Connecting to ${chalk.bold(url)}`);
|
|
33
33
|
const username = await input({ message: 'Username:' });
|
|
34
|
-
const password = await
|
|
34
|
+
const password = await passwordPrompt({ message: 'Password:', mask: '*' });
|
|
35
35
|
let token = '';
|
|
36
36
|
let sessionCookie = '';
|
|
37
37
|
let csrfNonce = '';
|
|
@@ -125,6 +125,23 @@ export function registerCtfCommands(program) {
|
|
|
125
125
|
printError(err.message);
|
|
126
126
|
}
|
|
127
127
|
});
|
|
128
|
+
// ─── icoa ctf logout ───
|
|
129
|
+
ctf
|
|
130
|
+
.command('logout')
|
|
131
|
+
.description('Disconnect and clear credentials')
|
|
132
|
+
.action(() => {
|
|
133
|
+
logCommand('ctf logout');
|
|
134
|
+
saveConfig({
|
|
135
|
+
ctfdUrl: '',
|
|
136
|
+
token: '',
|
|
137
|
+
sessionCookie: '',
|
|
138
|
+
userId: null,
|
|
139
|
+
userName: '',
|
|
140
|
+
teamId: null,
|
|
141
|
+
country: '',
|
|
142
|
+
});
|
|
143
|
+
printSuccess('Logged out. Credentials cleared.');
|
|
144
|
+
});
|
|
128
145
|
// ─── icoa ctf activate <code> ───
|
|
129
146
|
ctf
|
|
130
147
|
.command('activate <code>')
|
package/dist/commands/exam.js
CHANGED
|
@@ -648,7 +648,9 @@ export function registerExamCommand(program) {
|
|
|
648
648
|
.description('Try a free practice exam (no account needed)')
|
|
649
649
|
.action(async () => {
|
|
650
650
|
logCommand('exam demo');
|
|
651
|
-
const {
|
|
651
|
+
const { getLocalizedDemoQuestions, getLocalizedDemoSession } = await import('../lib/demo-exam.js');
|
|
652
|
+
const DEMO_QUESTIONS = getLocalizedDemoQuestions();
|
|
653
|
+
const DEMO_SESSION = getLocalizedDemoSession();
|
|
652
654
|
const existing = getExamState();
|
|
653
655
|
if (existing) {
|
|
654
656
|
if (existing.session.examId === 'demo-free') {
|
package/dist/lib/demo-exam.d.ts
CHANGED
|
@@ -2,3 +2,13 @@ import type { ExamQuestion, ExamSession } from '../types/index.js';
|
|
|
2
2
|
export declare const DEMO_SESSION: ExamSession;
|
|
3
3
|
export declare const DEMO_ANSWERS: Record<number, string>;
|
|
4
4
|
export declare const DEMO_QUESTIONS: ExamQuestion[];
|
|
5
|
+
/**
|
|
6
|
+
* Get demo questions translated to user's language.
|
|
7
|
+
* Reads from translations/<lang>/demo.json (bundled static file).
|
|
8
|
+
* Falls back to English if not available.
|
|
9
|
+
*/
|
|
10
|
+
export declare function getLocalizedDemoQuestions(): ExamQuestion[];
|
|
11
|
+
/**
|
|
12
|
+
* Get localized demo session name.
|
|
13
|
+
*/
|
|
14
|
+
export declare function getLocalizedDemoSession(): ExamSession;
|
package/dist/lib/demo-exam.js
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { join, dirname } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { getConfig } from './config.js';
|
|
5
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
1
6
|
export const DEMO_SESSION = {
|
|
2
7
|
examId: 'demo-free',
|
|
3
8
|
examName: 'ICOA Demo Exam — Free Practice',
|
|
@@ -73,3 +78,52 @@ export const DEMO_QUESTIONS = [
|
|
|
73
78
|
{ number: 30, text: 'What is the best practice for storing passwords in a database?', category: 'Security',
|
|
74
79
|
options: { A: 'Plain text', B: 'Encrypted with AES', C: 'Hashed with salt', D: 'Encoded in Base64' } },
|
|
75
80
|
];
|
|
81
|
+
/**
|
|
82
|
+
* Get demo questions translated to user's language.
|
|
83
|
+
* Reads from translations/<lang>/demo.json (bundled static file).
|
|
84
|
+
* Falls back to English if not available.
|
|
85
|
+
*/
|
|
86
|
+
export function getLocalizedDemoQuestions() {
|
|
87
|
+
const lang = getConfig().language;
|
|
88
|
+
if (!lang || lang === 'en')
|
|
89
|
+
return DEMO_QUESTIONS;
|
|
90
|
+
const path = join(__dirname, '..', '..', 'translations', lang, 'demo.json');
|
|
91
|
+
if (!existsSync(path))
|
|
92
|
+
return DEMO_QUESTIONS;
|
|
93
|
+
try {
|
|
94
|
+
const data = JSON.parse(readFileSync(path, 'utf-8'));
|
|
95
|
+
if (Array.isArray(data) && data.length === 30)
|
|
96
|
+
return data;
|
|
97
|
+
}
|
|
98
|
+
catch { }
|
|
99
|
+
return DEMO_QUESTIONS;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Get localized demo session name.
|
|
103
|
+
*/
|
|
104
|
+
export function getLocalizedDemoSession() {
|
|
105
|
+
const lang = getConfig().language;
|
|
106
|
+
if (!lang || lang === 'en')
|
|
107
|
+
return { ...DEMO_SESSION, startedAt: '' };
|
|
108
|
+
const names = {
|
|
109
|
+
zh: 'ICOA 模拟考试 — 免费练习',
|
|
110
|
+
ja: 'ICOA デモ試験 — 無料練習',
|
|
111
|
+
ko: 'ICOA 데모 시험 — 무료 연습',
|
|
112
|
+
es: 'ICOA Examen Demo — Práctica Gratis',
|
|
113
|
+
ar: 'اختبار ICOA التجريبي — تدريب مجاني',
|
|
114
|
+
fr: 'ICOA Examen Démo — Pratique Gratuite',
|
|
115
|
+
pt: 'ICOA Exame Demo — Prática Gratuita',
|
|
116
|
+
ru: 'ICOA Демо Экзамен — Бесплатная Практика',
|
|
117
|
+
hi: 'ICOA डेमो परीक्षा — निःशुल्क अभ्यास',
|
|
118
|
+
de: 'ICOA Demo-Prüfung — Kostenlose Übung',
|
|
119
|
+
id: 'ICOA Ujian Demo — Latihan Gratis',
|
|
120
|
+
th: 'ICOA สอบทดลอง — ฝึกฟรี',
|
|
121
|
+
vi: 'ICOA Thi Thử — Luyện Tập Miễn Phí',
|
|
122
|
+
tr: 'ICOA Demo Sınav — Ücretsiz Uygulama',
|
|
123
|
+
};
|
|
124
|
+
return {
|
|
125
|
+
...DEMO_SESSION,
|
|
126
|
+
examName: names[lang] || DEMO_SESSION.examName,
|
|
127
|
+
startedAt: '',
|
|
128
|
+
};
|
|
129
|
+
}
|
package/dist/lib/translation.js
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
-
import { join } from 'node:path';
|
|
2
|
+
import { join, dirname } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
3
4
|
import { getIcoaDir } from './config.js';
|
|
4
5
|
import { translateText } from './gemini.js';
|
|
6
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
// Bundled translations shipped with the package (translations/<lang>/<id>.json)
|
|
8
|
+
function getBundledPath(lang, challengeId) {
|
|
9
|
+
return join(__dirname, '..', '..', 'translations', lang, `${challengeId}.json`);
|
|
10
|
+
}
|
|
11
|
+
// User-local cache (~/.icoa/translations/)
|
|
5
12
|
function getCachePath(lang, challengeId) {
|
|
6
13
|
const dir = join(getIcoaDir(), 'translations', lang);
|
|
7
14
|
mkdirSync(dir, { recursive: true });
|
|
@@ -10,21 +17,28 @@ function getCachePath(lang, challengeId) {
|
|
|
10
17
|
export async function getTranslation(text, challengeId, targetLang) {
|
|
11
18
|
if (targetLang === 'en')
|
|
12
19
|
return text;
|
|
20
|
+
// 1. Check bundled static translations (fastest, no API call)
|
|
21
|
+
const bundledPath = getBundledPath(targetLang, challengeId);
|
|
22
|
+
if (existsSync(bundledPath)) {
|
|
23
|
+
try {
|
|
24
|
+
const bundled = JSON.parse(readFileSync(bundledPath, 'utf-8'));
|
|
25
|
+
if (bundled.translation)
|
|
26
|
+
return bundled.translation;
|
|
27
|
+
}
|
|
28
|
+
catch { /* corrupt, fall through */ }
|
|
29
|
+
}
|
|
30
|
+
// 2. Check user-local cache
|
|
13
31
|
const cachePath = getCachePath(targetLang, challengeId);
|
|
14
|
-
// Check cache
|
|
15
32
|
if (existsSync(cachePath)) {
|
|
16
33
|
try {
|
|
17
34
|
const cached = JSON.parse(readFileSync(cachePath, 'utf-8'));
|
|
18
35
|
if (cached.translation)
|
|
19
36
|
return cached.translation;
|
|
20
37
|
}
|
|
21
|
-
catch {
|
|
22
|
-
// Cache corrupt, regenerate
|
|
23
|
-
}
|
|
38
|
+
catch { /* corrupt, fall through */ }
|
|
24
39
|
}
|
|
25
|
-
// Translate via Gemini
|
|
40
|
+
// 3. Translate via Gemini API (last resort)
|
|
26
41
|
const translation = await translateText(text, getLangName(targetLang));
|
|
27
|
-
// Cache result
|
|
28
42
|
writeFileSync(cachePath, JSON.stringify({ original: text, translation, timestamp: new Date().toISOString() }));
|
|
29
43
|
return translation;
|
|
30
44
|
}
|
package/dist/repl.js
CHANGED
|
@@ -38,19 +38,71 @@ export async function startRepl(program, resumeMode) {
|
|
|
38
38
|
// ─── Mode selection (every launch) ───
|
|
39
39
|
const { select: selectMode, confirm: confirmMode } = await import('@inquirer/prompts');
|
|
40
40
|
const savedMode = config.mode || '';
|
|
41
|
-
const
|
|
41
|
+
const modeChoices = [
|
|
42
42
|
{ name: ` ${chalk.bold('National Selection')} ${chalk.gray('·')} ${chalk.gray('Exam only, lightweight')}`, value: 'selection' },
|
|
43
43
|
{ name: ` ${chalk.bold('International Olympiad')} ${chalk.gray('·')} ${chalk.gray('CTF x AI (~500MB)')}`, value: 'olympiad' },
|
|
44
44
|
{ name: ` ${chalk.bold('National/Regional Partner')} ${chalk.gray('·')} ${chalk.gray('Organizer management')}`, value: 'organizer' },
|
|
45
|
+
{ name: ` ${chalk.gray('About ICOA')} ${chalk.gray('·')} ${chalk.gray('Info & contact')}`, value: 'about' },
|
|
45
46
|
];
|
|
46
|
-
const defaultIndex = savedMode ? choices.findIndex((c) => c.value === savedMode) : 0;
|
|
47
47
|
console.log(chalk.gray(' Use ') + chalk.yellow('↑') + chalk.gray(' or ') + chalk.yellow('↓') + chalk.gray(' to select, ') + chalk.yellow('Enter') + chalk.gray(' to confirm.'));
|
|
48
48
|
console.log();
|
|
49
|
-
let mode =
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
49
|
+
let mode = '';
|
|
50
|
+
while (!mode) {
|
|
51
|
+
const selected = await selectMode({
|
|
52
|
+
message: 'Mode',
|
|
53
|
+
choices: modeChoices,
|
|
54
|
+
default: savedMode || 'selection',
|
|
55
|
+
});
|
|
56
|
+
if (selected === 'about') {
|
|
57
|
+
console.log();
|
|
58
|
+
console.log(chalk.cyan(' ═══════════════════════════════════════════════════'));
|
|
59
|
+
console.log();
|
|
60
|
+
console.log(chalk.bold.white(' ██╗ ██████╗ ██████╗ █████╗'));
|
|
61
|
+
console.log(chalk.bold.white(' ██║██╔════╝██╔═══██╗██╔══██╗'));
|
|
62
|
+
console.log(chalk.bold.white(' ██║██║ ██║ ██║███████║'));
|
|
63
|
+
console.log(chalk.bold.white(' ██║██║ ██║ ██║██╔══██║'));
|
|
64
|
+
console.log(chalk.bold.white(' ██║╚██████╗╚██████╔╝██║ ██║'));
|
|
65
|
+
console.log(chalk.bold.white(' ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝'));
|
|
66
|
+
console.log();
|
|
67
|
+
console.log(chalk.bold.yellow(' The World\'s First'));
|
|
68
|
+
console.log(chalk.bold.white(' AI-Native CLI Platform for Global'));
|
|
69
|
+
console.log(chalk.bold.white(' Cybersecurity Education & Competition'));
|
|
70
|
+
console.log();
|
|
71
|
+
console.log(chalk.white(' One terminal. 15 languages. 15,000 concurrent participants.'));
|
|
72
|
+
console.log();
|
|
73
|
+
console.log(chalk.cyan(' ─────────────────────────────────────────────────'));
|
|
74
|
+
console.log();
|
|
75
|
+
console.log(chalk.bold.white(' What Makes ICOA Different'));
|
|
76
|
+
console.log(chalk.gray(' · AI-powered Gemini 3.1 translation, AI teammate, smart hints'));
|
|
77
|
+
console.log(chalk.gray(' · CLI-native Zero browser, 100x less bandwidth'));
|
|
78
|
+
console.log(chalk.gray(' · Global scale 15,000+ concurrent exams, single server'));
|
|
79
|
+
console.log(chalk.gray(' · 15 languages Real-time AI translation for all challenges'));
|
|
80
|
+
console.log();
|
|
81
|
+
console.log(chalk.bold.white(' Competition Format'));
|
|
82
|
+
console.log(chalk.green.bold(' AI4CTF') + chalk.gray(' [Day 1] AI as your teammate — 5hr jeopardy CTF'));
|
|
83
|
+
console.log(chalk.red.bold(' CTF4AI') + chalk.gray(' [Day 2] Hack & evaluate AI — adversarial ML, red-teaming'));
|
|
84
|
+
console.log();
|
|
85
|
+
console.log(chalk.white(' Sydney, Australia') + chalk.gray(' · Jun 27 - Jul 2, 2026'));
|
|
86
|
+
console.log(chalk.gray(' 40+ accredited nations and regions'));
|
|
87
|
+
console.log();
|
|
88
|
+
console.log(chalk.cyan(' ─────────────────────────────────────────────────'));
|
|
89
|
+
console.log();
|
|
90
|
+
console.log(chalk.bold.white(' Organized by'));
|
|
91
|
+
console.log(chalk.gray(' ASRA — Australia STEM and Robotics Advancement Association Inc'));
|
|
92
|
+
console.log(chalk.gray(' ICO Foundation Inc (Australia)'));
|
|
93
|
+
console.log();
|
|
94
|
+
console.log(chalk.bold.white(' Contact & Accreditation'));
|
|
95
|
+
console.log(chalk.cyan(' australia@icoa2026.au'));
|
|
96
|
+
console.log(chalk.cyan(' accreditation@icoa2026.au'));
|
|
97
|
+
console.log(chalk.cyan.underline(' https://icoa2026.au'));
|
|
98
|
+
console.log();
|
|
99
|
+
console.log(chalk.cyan(' ═══════════════════════════════════════════════════'));
|
|
100
|
+
console.log();
|
|
101
|
+
// Loop back to mode selection
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
mode = selected;
|
|
105
|
+
}
|
|
54
106
|
if (mode === 'olympiad' && savedMode !== 'olympiad') {
|
|
55
107
|
console.log();
|
|
56
108
|
console.log(chalk.yellow(' This mode will download ~500MB of CTF tools and AI models.'));
|
|
@@ -121,11 +173,8 @@ export async function startRepl(program, resumeMode) {
|
|
|
121
173
|
}
|
|
122
174
|
}
|
|
123
175
|
// ─── Mode-specific welcome ───
|
|
124
|
-
if (mode === 'selection'
|
|
125
|
-
|
|
126
|
-
const modeLabel = mode === 'selection'
|
|
127
|
-
? chalk.cyan.bold('[Selection Mode]')
|
|
128
|
-
: chalk.yellow.bold('[Organizer Mode]');
|
|
176
|
+
if (mode === 'selection') {
|
|
177
|
+
const modeLabel = chalk.cyan.bold('[Selection Mode]');
|
|
129
178
|
if (connected) {
|
|
130
179
|
console.log(chalk.green(` Welcome back, ${config.userName}!`) + ' ' + modeLabel);
|
|
131
180
|
console.log(chalk.gray(` Connected to ${config.ctfdUrl}`));
|
|
@@ -133,6 +182,7 @@ export async function startRepl(program, resumeMode) {
|
|
|
133
182
|
console.log(chalk.gray(' ─────────────────────────────────────────────'));
|
|
134
183
|
console.log(chalk.bold.cyan(' demo') + chalk.gray(' Free practice exam'));
|
|
135
184
|
console.log(chalk.white(' exam list') + chalk.gray(' Your available exams'));
|
|
185
|
+
console.log(chalk.white(' logout') + chalk.gray(' Disconnect'));
|
|
136
186
|
console.log(chalk.gray(' ─────────────────────────────────────────────'));
|
|
137
187
|
console.log();
|
|
138
188
|
}
|
|
@@ -151,6 +201,46 @@ export async function startRepl(program, resumeMode) {
|
|
|
151
201
|
console.log();
|
|
152
202
|
}
|
|
153
203
|
}
|
|
204
|
+
else if (mode === 'organizer') {
|
|
205
|
+
console.log(chalk.yellow.bold(' [National/Regional Partner]'));
|
|
206
|
+
console.log();
|
|
207
|
+
console.log(chalk.bold.white(' ██╗ ██████╗ ██████╗ █████╗'));
|
|
208
|
+
console.log(chalk.bold.white(' ██║██╔════╝██╔═══██╗██╔══██╗'));
|
|
209
|
+
console.log(chalk.bold.white(' ██║██║ ██║ ██║███████║'));
|
|
210
|
+
console.log(chalk.bold.white(' ██║██║ ██║ ██║██╔══██║'));
|
|
211
|
+
console.log(chalk.bold.white(' ██║╚██████╗╚██████╔╝██║ ██║'));
|
|
212
|
+
console.log(chalk.bold.white(' ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝'));
|
|
213
|
+
console.log();
|
|
214
|
+
console.log(chalk.yellow(' International Cyber Olympiad in AI 2026'));
|
|
215
|
+
console.log(chalk.gray(' Sydney, Australia · Jun 27 - Jul 2, 2026'));
|
|
216
|
+
console.log();
|
|
217
|
+
console.log(chalk.white(' Vision'));
|
|
218
|
+
console.log(chalk.gray(' Building a global pipeline for youth cyber & AI'));
|
|
219
|
+
console.log(chalk.gray(' security talent through education and competition.'));
|
|
220
|
+
console.log();
|
|
221
|
+
console.log(chalk.white(' Capacity'));
|
|
222
|
+
console.log(chalk.gray(' 15,000+ concurrent online examinations'));
|
|
223
|
+
console.log(chalk.gray(' National selection, training, and education support'));
|
|
224
|
+
console.log();
|
|
225
|
+
console.log(chalk.white(' Olympic Spirit'));
|
|
226
|
+
console.log(chalk.gray(' Excellence · Friendship · Respect'));
|
|
227
|
+
console.log();
|
|
228
|
+
console.log(chalk.gray(' ─────────────────────────────────────────────'));
|
|
229
|
+
console.log(chalk.white(' New country accreditation & support:'));
|
|
230
|
+
console.log(chalk.cyan(' australia@icoa2026.au'));
|
|
231
|
+
console.log(chalk.cyan(' accreditation@icoa2026.au'));
|
|
232
|
+
console.log(chalk.gray(' ─────────────────────────────────────────────'));
|
|
233
|
+
console.log();
|
|
234
|
+
if (connected) {
|
|
235
|
+
console.log(chalk.green(` Logged in as ${config.userName}`));
|
|
236
|
+
console.log(chalk.white(' exam list') + chalk.gray(' Manage exams'));
|
|
237
|
+
console.log(chalk.white(' logout') + chalk.gray(' Disconnect'));
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
console.log(chalk.white(' join <url>') + chalk.gray(' Connect to manage exams'));
|
|
241
|
+
}
|
|
242
|
+
console.log();
|
|
243
|
+
}
|
|
154
244
|
else {
|
|
155
245
|
// Olympiad mode: full flow with activate/device checks
|
|
156
246
|
if (activated && !isDeviceMatch()) {
|
|
@@ -327,8 +417,8 @@ export async function startRepl(program, resumeMode) {
|
|
|
327
417
|
}
|
|
328
418
|
const cmd = input.split(/\s+/)[0].toLowerCase();
|
|
329
419
|
// ─── Mode-based command filtering ───
|
|
330
|
-
const selectionCommands = ['join', 'exam', 'demo', 'next', 'prev', 'setup', 'lang', 'ref', 'ctf'];
|
|
331
|
-
const organizerCommands = ['join', 'exam', 'demo', 'next', 'prev', 'setup', 'lang', 'ref', 'ctf'];
|
|
420
|
+
const selectionCommands = ['join', 'exam', 'demo', 'next', 'prev', 'logout', 'setup', 'lang', 'ref', 'ctf'];
|
|
421
|
+
const organizerCommands = ['join', 'exam', 'demo', 'next', 'prev', 'logout', 'setup', 'lang', 'ref', 'ctf'];
|
|
332
422
|
if (mode === 'selection' && !selectionCommands.includes(cmd)) {
|
|
333
423
|
console.log(chalk.gray(' Not available in Selection mode. Switch via: setup'));
|
|
334
424
|
console.log();
|
|
@@ -357,7 +447,7 @@ export async function startRepl(program, resumeMode) {
|
|
|
357
447
|
'scoreboard', 'sb', 'status', 'time', 'hint', 'hint-b', 'hint-c',
|
|
358
448
|
'hint-budget', 'ref', 'shell', 'files', 'connect', 'note',
|
|
359
449
|
'log', 'lang', 'setup', 'env', 'ai4ctf', 'model', 'ctf',
|
|
360
|
-
'exam', 'demo', 'next', 'prev',
|
|
450
|
+
'exam', 'demo', 'next', 'prev', 'logout',
|
|
361
451
|
];
|
|
362
452
|
if (!knownCommands.includes(cmd)) {
|
|
363
453
|
// Block dangerous commands
|
|
@@ -494,6 +584,7 @@ function mapCommand(input) {
|
|
|
494
584
|
'demo': ['exam', 'demo'],
|
|
495
585
|
'next': ['exam', 'next'],
|
|
496
586
|
'prev': ['exam', 'prev'],
|
|
587
|
+
'logout': ['ctf', 'logout'],
|
|
497
588
|
'join': ['ctf', 'join', ...rest],
|
|
498
589
|
'activate': ['ctf', 'activate', ...rest],
|
|
499
590
|
'challenges': ['ctf', 'challenges'],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "icoa-cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.12.0",
|
|
4
4
|
"description": "ICOA CLI — The world's first CLI-native CTF competition terminal",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
},
|
|
9
9
|
"files": [
|
|
10
10
|
"dist",
|
|
11
|
-
"refs"
|
|
11
|
+
"refs",
|
|
12
|
+
"translations"
|
|
12
13
|
],
|
|
13
14
|
"scripts": {
|
|
14
15
|
"build": "tsc",
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": 1,
|
|
3
|
+
"name": "Incorrect Implementation of RSA",
|
|
4
|
+
"category": "crypto",
|
|
5
|
+
"translation": "لقد تعلمت للتو عن Rivest-Shamir-Aldeman، ولذلك قمت بإنشاء تطبيق خاص بي. إليكم الرسالة:\n\n```\nn: 16537241065399537261146800802060451995107796665337288928060948677362154976656429797729550619497788311160926523026781503470362013597201944839389519773564618679827061417896265475971561610333659217333638238386907603525565178455941971399130722191602944445714002268747028340120907894781607422707823554701443768586256913491149809410232167277063066105859165079765281480076330718726350243973636606134346374770537701812923215229226027759112780757449828410180237267791126609342382918352166823253106960191346933601235547281\ne: 5\nciphertext: [17623416832, 10510100501, 9509900499, 8587340257, 16105100000, 28153056843, 16850581551, 12166529024, 7737809375, 12762815625, 7737809375, 19254145824, 10510100501, 8587340257, 14693280768, 14693280768, 25937424601, 7737809375, 21003416576, 12166529024, 16850581551, 21924480357, 11592740743, 12166529024, 21003416576, 7737809375, 12762815625, 7737809375, 12166529024, 8587340257, 10000000000, 7737809375, 21003416576, 12166529024, 8587340257, 21003416576, 7737809375, 10000000000, 16850581551, 16105100000, 10510100501, 7737809375, 9509900499, 254803968, 19254145824, 19254145824, 345025251, 9509900499, 21003416576, 14693280768, 25937424601, 7737809375, 282475249, 282475249, 459165024, 312500000, 601692057, 30517578125]\n```",
|
|
6
|
+
"lang": "ar",
|
|
7
|
+
"model": "gemini-3.1-pro-preview",
|
|
8
|
+
"timestamp": "2026-04-08T03:45:44.709Z"
|
|
9
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": 10,
|
|
3
|
+
"name": "The Perfect Breakfast",
|
|
4
|
+
"category": "crypto",
|
|
5
|
+
"translation": "آه، الفطور. لحظة بزوغ الشمس من الأفق، لا شيء يضاهي رائحة شيء يتشوح على الموقد. لا أفوته أبدًا، ليس لأنني شخص صباحي، بل لأن الفطور هو المكان الذي أجد فيه دعوتي الحقيقية. البعض يفضل حبوب الإفطار، والبعض الآخر الخبز المحمص، أما أنا؟ أحب أن أبقي الأشياء مقرمشة.\n\nهناك فن في روتيني الصباحي. بيضتان، سائلتان قليلاً. كوب من القهوة، سوداء. والجوهرة التاجية: ذلك الكمال المدخن والمالح الذي لا يفشل أبدًا في رسم ابتسامة على وجهي. مفضلتي المطلقة. إنه إسراف بسيط، بالتأكيد، لكنه يستحق كل قضمة.\n\nيقولون إن الفطور هو أهم وجبة في اليوم… ربما لهذا السبب أخفيت الرسالة هناك. عليك فقط أن تعرف أين تبحث تحت الطبقات.",
|
|
6
|
+
"lang": "ar",
|
|
7
|
+
"model": "gemini-3.1-pro-preview",
|
|
8
|
+
"timestamp": "2026-04-08T03:46:38.220Z"
|
|
9
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": 11,
|
|
3
|
+
"name": "Wise Words",
|
|
4
|
+
"category": "crypto",
|
|
5
|
+
"translation": "لقد قابلت أغسطس ذات مرة، الابن بالتبني والوريث لجنرال عظيم. عندما سألته عن أعظم استراتيجياته، اكتفى بالهمس ببساطة: Fwfo_Djqifsaa_Fwpmwf",
|
|
6
|
+
"lang": "ar",
|
|
7
|
+
"model": "gemini-3.1-pro-preview",
|
|
8
|
+
"timestamp": "2026-04-08T03:46:43.627Z"
|
|
9
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": 13,
|
|
3
|
+
"name": "Keylogger",
|
|
4
|
+
"category": "forensics",
|
|
5
|
+
"translation": "بعد أن شعر بأن هناك شيئًا غير صحيح، أبلغ Ole فريق الأمن بالأمر. قرر الفريق التحقيق في الشبكة ولاحظ شيئًا مريبًا.",
|
|
6
|
+
"lang": "ar",
|
|
7
|
+
"model": "gemini-3.1-pro-preview",
|
|
8
|
+
"timestamp": "2026-04-08T03:46:50.263Z"
|
|
9
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": 14,
|
|
3
|
+
"name": "obfuscated script",
|
|
4
|
+
"category": "forensics",
|
|
5
|
+
"translation": "عثر أحد الموظفين على ملفين غريبين في مجلد Downloads folder الخاص بهم: a script وملف لم يتمكنوا من قراءته. هل يمكنك معرفة ما هي؟",
|
|
6
|
+
"lang": "ar",
|
|
7
|
+
"model": "gemini-3.1-pro-preview",
|
|
8
|
+
"timestamp": "2026-04-08T03:46:56.791Z"
|
|
9
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": 15,
|
|
3
|
+
"name": "Ping",
|
|
4
|
+
"category": "forensics",
|
|
5
|
+
"translation": "المهاجمون يزدادون ذكاءً هذه الأيام، فهم يجدون جميع أنواع الطرق لـ exfiltrate البيانات!\nماذا سرقوا هذه المرة؟",
|
|
6
|
+
"lang": "ar",
|
|
7
|
+
"model": "gemini-3.1-pro-preview",
|
|
8
|
+
"timestamp": "2026-04-08T03:47:03.643Z"
|
|
9
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": 16,
|
|
3
|
+
"name": "Sound Inversion",
|
|
4
|
+
"category": "forensics",
|
|
5
|
+
"translation": "أيها الجندي، نعتقد أن العدو قد أخفى رسالة صوتية منطوقة في مكان ما داخل هذا الملف. اعثر عليها، وأبلغنا فورًا.",
|
|
6
|
+
"lang": "ar",
|
|
7
|
+
"model": "gemini-3.1-pro-preview",
|
|
8
|
+
"timestamp": "2026-04-08T03:47:07.250Z"
|
|
9
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": 17,
|
|
3
|
+
"name": "There is always a trace",
|
|
4
|
+
"category": "forensics",
|
|
5
|
+
"translation": "لقد تم توظيفك من قبل الـ NSA وهذا يومك الأول في العمل. لمهمتك الأولى، أعطوك ملفًا مشبوهًا مع القليل جدًا من السياق، باستثناء أنه تم استرداده من كمبيوتر محمول لشخص كان يُشتبه في أنه قام بـ compromising لـ government server عن بُعد.",
|
|
6
|
+
"lang": "ar",
|
|
7
|
+
"model": "gemini-3.1-pro-preview",
|
|
8
|
+
"timestamp": "2026-04-08T03:47:19.009Z"
|
|
9
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": 18,
|
|
3
|
+
"name": "Electric Debugger",
|
|
4
|
+
"category": "misc",
|
|
5
|
+
"translation": "أصدرت الجهة المنافسة لبرامج تصحيح الأخطاء الشائعة الأخرى للتو نسخة جديدة من Electric debugger الخاص بها هذا الصباح. لسوء الحظ، لم يعد مجانيًا أو مفتوح المصدر. ومع ذلك، تشير الشائعات إلى توفر bounties إذا تمكن شخص ما من hackه.",
|
|
6
|
+
"lang": "ar",
|
|
7
|
+
"model": "gemini-3.1-pro-preview",
|
|
8
|
+
"timestamp": "2026-04-08T03:47:38.736Z"
|
|
9
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": 19,
|
|
3
|
+
"name": "Old is gold",
|
|
4
|
+
"category": "misc",
|
|
5
|
+
"translation": "كان مسؤول النظام السابق يعمل هنا لمدة 47 عامًا تقريبًا. تكتشف هذا الملف على جهاز الكمبيوتر القديم الخاص به...",
|
|
6
|
+
"lang": "ar",
|
|
7
|
+
"model": "gemini-3.1-pro-preview",
|
|
8
|
+
"timestamp": "2026-04-08T03:47:43.341Z"
|
|
9
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": 20,
|
|
3
|
+
"name": "Perceptions",
|
|
4
|
+
"category": "misc",
|
|
5
|
+
"translation": "تفقّد هذه المدونة التي صنعتها! إنها تحتوي على backend رائع، ويبدو أنها تستخدم عددًا أقل من ports.",
|
|
6
|
+
"lang": "ar",
|
|
7
|
+
"model": "gemini-3.1-pro-preview",
|
|
8
|
+
"timestamp": "2026-04-08T03:47:47.551Z"
|
|
9
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": 21,
|
|
3
|
+
"name": "Rules",
|
|
4
|
+
"category": "misc",
|
|
5
|
+
"translation": "أنا جاهز لترجمة وصف تحدي CTF. يرجى تزويدي بالوصف.\n\nسأقوم بالترجمة مع الالتزام بالقواعد التالية:\n* سيتم ترجمة **النص السردي/الوصفي** إلى اللغة العربية.\n* سيتم الاحتفاظ بجميع **المصطلحات التقنية** (مثل SQL injection, buffer overflow, crypto, reverse engineering, pwn, web, forensics) باللغة الإنجليزية كما هي.\n* سيتم الاحتفاظ بجميع **الأكواد البرمجية** (code) باللغة الإنجليزية كما هي.\n* سيتم الاحتفاظ بجميع **الأوامر** (commands) باللغة الإنجليزية كما هي.\n* سيتم الاحتفاظ بجميع **روابط URL** باللغة الإنجليزية كما هي.\n* سيتم الاحتفاظ بجميع **صيغ الأعلام** (flag formats) باللغة الإنجليزية كما هي.",
|
|
6
|
+
"lang": "ar",
|
|
7
|
+
"model": "gemini-3.1-pro-preview",
|
|
8
|
+
"timestamp": "2026-04-08T03:47:55.831Z"
|
|
9
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": 22,
|
|
3
|
+
"name": "Survey",
|
|
4
|
+
"category": "misc",
|
|
5
|
+
"translation": "أخبرنا برأيك حول PECAN+ CTF 2025. كل جزء من الملاحظات يساعد!\n\n<https://forms.cloud.microsoft/r/q5ESPCft24>",
|
|
6
|
+
"lang": "ar",
|
|
7
|
+
"model": "gemini-3.1-pro-preview",
|
|
8
|
+
"timestamp": "2026-04-08T03:48:00.873Z"
|
|
9
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": 23,
|
|
3
|
+
"name": "The Job Interview",
|
|
4
|
+
"category": "misc",
|
|
5
|
+
"translation": "كنت منحنياً فوق لوحة مفاتيحك، تتصارع ذهنياً مع أسئلة مقابلة عمل لمدة ساعتين متواصلتين لا هوادة فيهما. قهوتك باردة. وصبرك بدأ ينفد.\nولكن بينما أنت على وشك إرسال إجابتك النهائية، تظهر رسالة غامضة على شاشتك:\n\n\"لقد أثبتّ قدرتك على التحمل. الآن لنختبر قدرتك على حل المشكلات والمعرفة المتقدمة بـ the code الذي يبدو أنك تتقنه جيداً.\"\n\nيتم عرض URL واحد:\n\nhttps://docs.google.com/document/d/e/2PACX-1vRW7X8yMO9cM-b6Ao3FbiZysF3MIjARoeO73z0PlG8O_yeM8xxWAWzt9hdoavlh3HR1IOEwWtJFpczI/pub\n\nفي الداخل؟ شبكة من البيانات الغامضة، بسيطة بشكل مخادع، ولكنها تخفي شيئاً حاسماً.",
|
|
6
|
+
"lang": "ar",
|
|
7
|
+
"model": "gemini-3.1-pro-preview",
|
|
8
|
+
"timestamp": "2026-04-08T03:48:09.295Z"
|
|
9
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": 24,
|
|
3
|
+
"name": "Class Above Par",
|
|
4
|
+
"category": "osint",
|
|
5
|
+
"translation": "كل يوم، يسير Jamie في الشوارع التي تصطف على جانبيها الأشجار في ضواحي ملبورن الجنوبية للوصول إلى المدرسة الثانوية التي يرتادونها — مكانًا غالبًا ما يتقاطع فيه نداء الحضور الصباحي مع الرعد البعيد للطائرات في الأجواء.\n\nفي إحدى الأمسيات، أثناء رسم Jamie لخرائط المعالم المحلية لمشروع صفي، اكتشف شيئًا مثيرًا للفضول: قد تكون المدرسة التي يرتادونها هي أقرب مدرسة ثانوية إلى مطار رئيسي. والأغرب من ذلك، أنها تقع على بعد رمية حجر فقط من ملاعب الغولف الشاسعة، حيث تتناقض التأرجحات الهادئة مع هدير محركات الطائرات النفاثة.\n\nهل يمكنك الكشف عن المدرسة التي يسميها Jamie وطنه؟ Flag format: `pecan{my_high_school}`",
|
|
6
|
+
"lang": "ar",
|
|
7
|
+
"model": "gemini-3.1-pro-preview",
|
|
8
|
+
"timestamp": "2026-04-08T03:48:32.471Z"
|
|
9
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": 25,
|
|
3
|
+
"name": "Travelling Around",
|
|
4
|
+
"category": "osint",
|
|
5
|
+
"translation": "هممم… يبدو أن Corn Man قد زار بعض الأماكن المثيرة للاهتمام، في مسار غريب جدًا. هل يمكن أن يعني ذلك شيئًا؟ ربما تحتوي الضواحي على دليل... قد تحتوي المنشورات على \"pointer\" في الاتجاه الصحيح...\nRemember to wrap the flag in pecan{}, use uppercase letters, and separate the words with an underscore. E.g. `pecan{I_LOVE_PECAN}`",
|
|
6
|
+
"lang": "ar",
|
|
7
|
+
"model": "gemini-3.1-pro-preview",
|
|
8
|
+
"timestamp": "2026-04-08T03:48:37.588Z"
|
|
9
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": 26,
|
|
3
|
+
"name": "Online Presence",
|
|
4
|
+
"category": "osint",
|
|
5
|
+
"translation": "من خلال تحقيق مكثف، يبدو أن Corn Man لديه social media presence. هل يمكنك مساعدتنا في العثور على الحساب الذي يستخدمه؟",
|
|
6
|
+
"lang": "ar",
|
|
7
|
+
"model": "gemini-3.1-pro-preview",
|
|
8
|
+
"timestamp": "2026-04-08T03:48:47.450Z"
|
|
9
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": 27,
|
|
3
|
+
"name": "Happy Birthday Corn Man!",
|
|
4
|
+
"category": "osint",
|
|
5
|
+
"translation": "أنا أتعقب رجل الذرة منذ فترة الآن، لكنني واجهت طريقًا مسدودًا. لقد عثرت على بريده الإلكتروني مؤخرًا عبر الإنترنت وهو: <cornman25944@gmail.com>. يبدو أن لديه حضورًا كبيرًا على الإنترنت. هل يمكنك العثور على تاريخ ميلاده والمساعدة في هذا التحقيق؟",
|
|
6
|
+
"lang": "ar",
|
|
7
|
+
"model": "gemini-3.1-pro-preview",
|
|
8
|
+
"timestamp": "2026-04-08T03:48:54.552Z"
|
|
9
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": 28,
|
|
3
|
+
"name": "Ego is the weakness",
|
|
4
|
+
"category": "osint",
|
|
5
|
+
"translation": "تم اكتشاف عملية ransomware مؤخرًا، مما أدى إلى خسارة ملايين الدولارات في ثوانٍ.\nبعد بعض التحقيقات المشتركة مع الحكومة، تتبعنا أنشطتها إلى Instagram account يُعتقد أنها تخص الجاني.\nهل يمكنك مساعدتنا في تحديد عنوان مكان يتردد عليه هذا cybercriminal كثيرًا؟\nيشير intel الخاص بنا إلى أن هناك احتمالًا كبيرًا أن هذا الشخص لا يزال صغيرًا في السن، لذا لم يتخرج بعد.\n\nFlag format: `pecan{Paste in the address from Google Maps}`",
|
|
6
|
+
"lang": "ar",
|
|
7
|
+
"model": "gemini-3.1-pro-preview",
|
|
8
|
+
"timestamp": "2026-04-08T03:49:04.015Z"
|
|
9
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": 29,
|
|
3
|
+
"name": "Go git the door",
|
|
4
|
+
"category": "osint",
|
|
5
|
+
"translation": "مجرم إلكتروني سيئ السمعة، نفذ بنجاح العديد من `large-scale ransomware operations` في الماضي، يعمل حاليًا على واحدة جديدة. لحسن حظنا، لقد جعل `GitHub repository` الخاص به `public` عن طريق الخطأ. هل يمكنك الفحص لمعرفة ما إذا كان قد كشف عن أي معلومات سرية عن طريق الخطأ؟\n\n`Flag format: pecan{secret1_secret2}`",
|
|
6
|
+
"lang": "ar",
|
|
7
|
+
"model": "gemini-3.1-pro-preview",
|
|
8
|
+
"timestamp": "2026-04-08T03:49:11.137Z"
|
|
9
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": 30,
|
|
3
|
+
"name": "Echo Chamber",
|
|
4
|
+
"category": "pwn",
|
|
5
|
+
"translation": "وجدت خدمة غريبة ترد فقط بما ترسله إليها، إنها مثل مرآة غريبة أو انعكاس أو شيء من هذا القبيل.",
|
|
6
|
+
"lang": "ar",
|
|
7
|
+
"model": "gemini-3.1-pro-preview",
|
|
8
|
+
"timestamp": "2026-04-08T03:49:15.161Z"
|
|
9
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": 31,
|
|
3
|
+
"name": "Flag Fish",
|
|
4
|
+
"category": "pwn",
|
|
5
|
+
"translation": "Bjarne يبحث عن سمكة الـ flag المنشودة. أول `try` له لم ينجح، هل يمكنك مساعدته في `catch`ها هذه المرة؟",
|
|
6
|
+
"lang": "ar",
|
|
7
|
+
"model": "gemini-3.1-pro-preview",
|
|
8
|
+
"timestamp": "2026-04-08T03:49:22.438Z"
|
|
9
|
+
}
|