UNPKG

@noemaresearch/ctf-cli

Version:

A CLI tool for navigating and playing cybersecurity challenges

131 lines (111 loc) 4.18 kB
import dotenv from 'dotenv'; import path from 'path'; import fs from 'fs'; import { httpsCallable } from 'firebase/functions'; import { FirebaseApp, getApps, getApp, initializeApp } from 'firebase/app'; import { Auth, initializeAuth, getAuth, setPersistence, inMemoryPersistence, signInWithCustomToken } from 'firebase/auth'; import { getFirestore } from 'firebase/firestore'; import { getFunctions } from 'firebase/functions'; import { resolve } from 'node:path'; import { cwd } from 'node:process'; import chalk from 'chalk'; import boxen from 'boxen'; import { getLocalStorage } from './local_storage'; // Path to store the current environment const ENV_STORE_PATH = path.join(__dirname, '..', '.current_env'); // Function to get the current environment function getCurrentEnv(): string { if (process.env.NODE_ENV) { // If NODE_ENV is set, use it and store it for future use fs.writeFileSync(ENV_STORE_PATH, process.env.NODE_ENV); return process.env.NODE_ENV; } else if (fs.existsSync(ENV_STORE_PATH)) { // If NODE_ENV is not set, try to read from the stored file return fs.readFileSync(ENV_STORE_PATH, 'utf8').trim(); } // Default to 'development' if no environment is set or stored return 'development'; } const currentEnv = getCurrentEnv(); // Determine the correct .env file and load envvars const envFile = currentEnv === 'production' ? '.env.production' : '.env.development'; const envPath = path.resolve(__dirname, '..', envFile); dotenv.config({ path: envPath }); // Load Firebase Config const firebaseConfig = { projectId: process.env.FIREBASE_PROJECT_ID, apiKey: process.env.FIREBASE_API_KEY, authDomain: process.env.FIREBASE_AUTH_DOMAIN, storageBucket: process.env.FIREBASE_STORAGE_BUCKET, messagingSenderId: process.env.FIREBASE_MESSAGING_SENDER_ID, appId: process.env.FIREBASE_APP_ID }; global.localStorage = getLocalStorage(); // Singleton Firebase App Initialization let app: FirebaseApp | null = null; let initialized: boolean = getApps().length > 0; app = initialized? getApp(): initializeApp(firebaseConfig); // Firebase Auth with inMemoryPersistence let auth: Auth; if ( initialized ) { auth = getAuth(); } else { auth = initializeAuth(app, { persistence: inMemoryPersistence }); } const db = getFirestore(app); const functions = getFunctions(app); // Utility functions for token persistence const TOKEN_KEY = 'firebase_id_token'; export async function saveAuthToken(token: string) { global.localStorage.setItem(TOKEN_KEY, token); } export async function loadAuthToken() { const token: string | null = global.localStorage.getItem(TOKEN_KEY); return token; } export async function removeAuthToken() { global.localStorage.removeItem(TOKEN_KEY); } async function authenticate() { app = getApps().length? getApp(): initializeApp(firebaseConfig); auth = getAuth(); const token = await loadAuthToken(); if (token) { // Reauthenticate using the saved token try { const getAuthToken = httpsCallable(functions, 'getAuthToken'); const result: any = await getAuthToken({ idToken: token }); await signInWithCustomToken(auth, result.data); } catch (error) { //console.error('Error on authentication:', error); } } else { // No saved token, initiate login // For example, you might sign in the user here or prompt for credentials // After login, save the token const newToken = await auth.currentUser?.getIdToken(); if (newToken) saveAuthToken(newToken); } return auth; } async function withAuth(auth: Auth, commandFn: (auth: Auth) => Promise<void>): Promise<void> { if (!auth.currentUser?.email) { console.log(); console.log( boxen( chalk.red(chalk.bold('Authentication Required')) + '\n\n' + chalk.white('You must be logged in to use this command.') + '\n' + chalk.white('Please run ') + chalk.cyan('`ctf login`') + chalk.white(' first.'), { padding: 1, borderColor: 'red', borderStyle: 'round', } ) ); console.log(); return; } await commandFn(auth); } export { db, functions, authenticate, withAuth, auth, app };