diff --git a/src/challenge/mod.rs b/src/challenge/mod.rs index 49ac589..18d2184 100644 --- a/src/challenge/mod.rs +++ b/src/challenge/mod.rs @@ -1,3 +1,8 @@ +//! Challenges and their common interface. +//! +//! This module is the core of the Wooly Vault application, as it defines the interface that all +//! challenges must implement, and contains the challenge modules themselves. + use anyhow::anyhow; use async_trait::async_trait; @@ -8,17 +13,70 @@ pub mod c1; pub mod c2; pub mod c3; +/// Defines the behavior of a challenge. +/// +/// Any type that implements this trait can be served as a challenge in the Wooly Vault application. #[async_trait] pub trait Challenge where Self: Sized, { + /// Creates a new instance of the challenge with the given configuration and vault. + /// + /// # Arguments + /// + /// * `config` - The configuration for the challenge. + /// * `vault` - The vault that holds the secret for the challenge. + /// + /// # Returns + /// + /// A new instance of the challenge. fn new(config: Config, vault: VaultRef) -> Self; + /// Returns a list of hints for the challenge. + /// + /// A hint is a short text to be given to the contestants in case the host thinks they need + /// it. The first hint is the most vague, afterwards the hints become more and more helpful. + /// + /// # Returns + /// + /// A vector of strings containing hints for the challenge. fn hints() -> Vec; + /// Returns the solution to the challenge. + /// + /// A solution is a short description of what has to be done to solve the challenge and get the + /// secret of the vault. + /// + /// # Returns + /// + /// A string containing the solution to the challenge. fn solution() -> String; + /// Starts the challenge and serves it to the contestants. + /// + /// This method is asynchronous and returns a result indicating whether the challenge was + /// successful only after the challenge has ended. + /// + /// # Returns + /// + /// A result indicating whether the challenge was successful ended. async fn serve(self) -> anyhow::Result<()>; } +/// Selects a challenge by index and serves it with the given configuration and vault. +/// +/// # Arguments +/// +/// * `index` - The index of the challenge to select. +/// * `config` - The configuration for the challenge. +/// * `vault` - The vault that holds the secret for the challenge. +/// +/// # Returns +/// +/// A result indicating whether the challenge has successfully ended. +/// +/// # Errors +/// +/// Returns an error if no challenge with the given index exists, or if the challenge that is being +/// served errors. pub async fn select_and_start(index: u16, config: Config, vault: VaultRef) -> anyhow::Result<()> { match index { 1 => c1::C1::new(config, vault).serve().await?, diff --git a/src/config.rs b/src/config.rs index 80684eb..d2aad68 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,11 +1,15 @@ +//! 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 @@ -41,7 +45,6 @@ pub const ENV_SECRET: &str = "WOOLY_SECRET"; about, long_about, help_template = libpt::cli::args::HELP_TEMPLATE)] - pub struct Config { /// Index of the challenge pub challenge: u16, @@ -69,3 +72,24 @@ impl Debug for Config { .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()) + } +} diff --git a/src/lib.rs b/src/lib.rs index 143f2b8..8e4fa85 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,19 @@ +//! # Wooly Vault +//! +//! Wooly Vault is a set of smaller challenges for Rust hackers. +//! +//! A host may choose to open a challenge, set a secret and ask a contestant to try and solve the +//! challenge to get the secret. The contestant can then prove with the secret to the host that +//! they absolved the challenge. +//! +//! Wooly Vault has multiple challenges, and only one can be hosted per instance of this +//! application. The challenges all bind to a pre-set [Network Adress](crate::config::Config::addr). +//! The contestants can then connect to that adress with TCP. The first few challenges use raw TCP, +//! but some of the later ones are small HTTP webservices. +//! +//! Wooly Vault is programmed asynchronously with [tokio] to be able to handle many contestants at +//! once if needed. + pub mod challenge; pub mod config; pub mod vault; diff --git a/src/main.rs b/src/main.rs index c38aff0..5942211 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,6 @@ use anyhow::Result; use clap::Parser; use libpt::log::{debug, info}; -use wooly_vault::config::ENV_SECRET; use wooly_vault::{challenge::select_and_start, config::Config, vault::Vault}; #[tokio::main(flavor = "current_thread")] @@ -16,27 +15,10 @@ async fn main() -> Result<()> { debug!("logger active"); info!("Configuration: {conf:?}"); - let secret = get_secret()?; + let secret = Config::secret()?; let v = Vault::new(&secret); select_and_start(conf.challenge, conf, v).await?; Ok(()) } - -fn get_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()) -} - -fn select_challenge() -> Result { - let mut buf: String = String::new(); - std::io::stdin().read_line(&mut buf)?; - Ok(buf.trim().parse()?) -} diff --git a/src/vault.rs b/src/vault.rs index 44d786a..bf22d31 100644 --- a/src/vault.rs +++ b/src/vault.rs @@ -1,19 +1,44 @@ +//! A module for managing and sharing secrets in the Wooly Vault application. +//! +//! This module provides a [`Vault`] struct that holds a secret and allows it to be shared safely +//! across the application using an [`Arc`] (Atomic Reference Counted) pointer. + use std::sync::Arc; +/// A type alias for an [`Arc`] pointer to a [`Vault`] instance. +/// +/// This type is used to share a [`Vault`] instance across multiple parts of the application. pub type VaultRef = Arc; +/// A struct that holds a secret and provides methods for accessing it. +/// +/// The [`Vault`] struct is designed to be shared safely across the application using an [`Arc`] pointer. #[derive(Debug, Clone, PartialEq)] pub struct Vault { + /// The secret stored in the vault secret: String, } impl Vault { + /// Creates a new [`Vault`] instance with the given secret. + /// + /// Returns an [`Arc`] pointer to the new [`Vault`] instance. + /// + /// # Returns + /// + /// A new [`Vault`] instance with the given secret. pub fn new(secret: &str) -> VaultRef { let v = Self { secret: secret.to_string(), }; Arc::new(v) } + + /// Returns a reference to the secret stored in the vault. + /// + /// # Returns + /// + /// A reference to the secret stored in the vault. pub fn secret(&self) -> &str { &self.secret }