//! Common configuration options for the challenges. use std::fmt::Debug; use std::net::SocketAddr; use std::str::FromStr; use anyhow::Result; use clap::Parser; use libpt::cli::args::VerbosityLevel; use serde::Serialize; /// The environment variable that can hold the secret for a challenge pub const ENV_SECRET: &str = "WOOLY_SECRET"; /// Wooly Vault --- A few small hacking challenges /// /// # Configuration /// Each challenge requires some basic information to host: /// /// * secret - a string that if found signifies that the challenge was solved /// /// * addr - the network adress plus port the challenge should run on /// /// * verbosity - how verbose the logging should be /// /// * challenge - which challenge to host (there are a few) /// /// The secret cannot be inputted with a command line argument, because the arguments can often be /// seen in the process view. You may either specify a secret in the 'WOOLY_SECRET' environment /// variable or input it interactively on start. /// /// # Challenges /// /// There are a number of challenges: /// /// 1. Connect by TCP /// /// 2. Connect by TCP and send a special u16 /// /// 3. Connect by TCP, get sent dynamic math questions, solve them fast enough #[derive(Parser, Clone, PartialEq, Eq, Hash, Serialize)] #[command( author, version, about, long_about, help_template = libpt::cli::args::HELP_TEMPLATE)] pub struct Config { /// Index of the challenge pub challenge: u16, /// Network address to host the challenge on pub addr: SocketAddr, /// Network address to host the challenge on #[arg(short = 'a', long = "admin")] pub addr_admin: Option, #[command(flatten)] pub verbosity: VerbosityLevel, } impl Default for Config { fn default() -> Self { Self { challenge: 1, addr: SocketAddr::from_str("127.0.0.1:1337").unwrap(), verbosity: VerbosityLevel::default(), addr_admin: Option::default(), } } } impl Debug for Config { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("Config") .field("addr", &self.addr) .field("verbosity", &self.verbosity.level()) .field("admin", &self.addr_admin) .finish() } } impl Config { /// Load or input the secret /// /// This will try to get the secret from the [`ENV_SECRET`] environment variable. If that /// variable is not set, the user will be asked to input a secret manually. /// /// # Errors /// /// When the environment variable is not set and the reading from stdin fails. pub fn secret() -> Result { if let Ok(v) = std::env::var(ENV_SECRET) { return Ok(v); } println!("Input the secret and press enter"); let mut buf: String = String::new(); std::io::stdin().read_line(&mut buf)?; Ok(buf.trim().to_string()) } }