UNPKG

@noemaresearch/ctf-cli

Version:

A CLI tool for navigating and playing cybersecurity challenges

173 lines (156 loc) 5.04 kB
#!/usr/bin/env node import { auth, removeAuthToken, saveAuthToken, withAuth, authenticate } from './firebase'; import { Auth } from 'firebase/auth'; import { program } from 'commander'; import login from './commands/login'; import signup from './commands/signup'; import ls from './commands/ls'; import ssh from './commands/ssh'; import hint from './commands/hint'; import leaderboard from './commands/leaderboard'; import logout from './commands/logout'; import feedback from './commands/feedback'; import deleteAccount from './commands/delete'; import reset from './commands/reset'; import topup from './commands/topup'; import token from './commands/token'; import skipChallengeState from './commands/skip'; program .version('1.0.0') .description('A CLI tool for navigating and playing cybersecurity challenges'); program .command('login') .description('Log in to the CTF platform using email and password') .option('--email <email>', 'Email for headless login') .option('--password <password>', 'Password for headless login') .action( async (options) => { await login(auth, options); if ( auth ) { const newToken = await auth.currentUser?.getIdToken(); if (newToken) saveAuthToken(newToken); } }); program .command('signup') .description('Sign up for a new account on the CTF platform') .action( async () => { await signup(auth); }); program .command('ls') .description('List available challenges') .option('--raw', 'Return raw JSON data') .action( async (options) => { const auth = await authenticate(); await withAuth(auth, async (auth: Auth) => { await ls(auth, options); }); }); program .command('ssh') .argument('<challenge-id>', 'ID of the challenge to SSH into') .description('SSH into a challenge environment') .option('--raw', 'Return raw output without formatting') .action( async (challengeId, options) => { const auth = await authenticate(); await withAuth(auth, async (auth: Auth) => { await ssh(auth, challengeId, options); }); }); program .command('hint') .argument('<challenge-id>', 'ID of the challenge to get a hint for') .description('Get a hint for a challenge') .action( async (options) => { const auth = await authenticate(); await withAuth(auth, async (auth: Auth) => { await hint(auth, options); }); }); program .command('leaderboard') .description('View the global leaderboard and your challenge history') .option('--raw', 'Return raw JSON data') .action( async (options) => { const auth = await authenticate(); await withAuth(auth, async (auth: Auth) => { await leaderboard(auth, options); }); }); program .command('skip-stage') .argument('<challenge-id>', 'ID of the challenge to skip stage for') .description('Skip current challenge stage') .option('--raw', 'Return raw JSON data') .action( async (challengeId, options) => { const auth = await authenticate(); await withAuth(auth, async (auth: Auth) => { await skipChallengeState(auth, challengeId, options); }); }); program .command('logout') .description('Log out from the CTF platform') .action( async () => { const auth = await authenticate(); await withAuth(auth, async(auth: Auth) => { await logout(auth); await removeAuthToken(); }); }); program .command('feedback') .description('Submit a feedback') .action( async () => { const auth = await authenticate(); await withAuth(auth, async (auth: Auth) => { await feedback(auth); }); }); program .command('delete') .description('Delete your account from the CTF Platform') .action( async () => { const auth = await authenticate(); await withAuth(auth, async (auth: Auth) => { await deleteAccount(auth); }); }); program .command('reset') .argument('<challenge-id>', 'ID of the challenge to reset') .description('Reset a challenge environment to its initial state') .option('--raw', 'Return raw output without formatting') .action( async (challengeId, options) => { const auth = await authenticate(); await withAuth(auth, async (auth: Auth) => { await reset(auth, challengeId, options); }); }); program .command('topup') .description('Top-up your challenge credits') .action( async () => { const auth = await authenticate(); await withAuth(auth, async (auth: Auth) => { await topup(auth); }); }); program .command('token') .argument('<action>', 'Action to perform: "show" or "reset"') .description('Manage your API token: "show" retrieves the token, "reset" generates a new token') .action(async (action, options) => { const auth = await authenticate(); await withAuth(auth, async (auth: Auth) => { await token(auth, action); }); }); async function main() { await program.parseAsync(process.argv); process.exit(0); } main().catch((error) => { console.error('An unexpected error occurred:', error); process.exit(1); });