@noemaresearch/ctf-cli
Version:
A CLI tool for navigating and playing cybersecurity challenges
173 lines (156 loc) • 5.04 kB
text/typescript
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);
});