From ea23e93ec96e3559e7dba0ee7d950c45319737e8 Mon Sep 17 00:00:00 2001 From: PlexSheep Date: Sun, 8 Sep 2024 02:59:58 +0200 Subject: [PATCH] feat: launch many services somewhat at once --- src/challenge/c1.rs | 5 ++-- src/challenge/c2.rs | 5 ++-- src/challenge/c3.rs | 5 ++-- src/challenge/mod.rs | 53 ++++++++++++------------------------ src/lib.rs | 64 ++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 5 ++-- src/meta/mod.rs | 18 +++++-------- 7 files changed, 99 insertions(+), 56 deletions(-) diff --git a/src/challenge/c1.rs b/src/challenge/c1.rs index 9bb0164..3d78558 100644 --- a/src/challenge/c1.rs +++ b/src/challenge/c1.rs @@ -8,7 +8,7 @@ use libpt::log::warn; use tokio::io::AsyncWriteExt; use tokio::net::TcpListener; -use super::{Challenge, ChallengeDesc}; +use super::{ChallengeDesc, ChallengeLike}; use crate::config::Config; use crate::has_won; use crate::vault::VaultRef; @@ -21,7 +21,7 @@ pub struct C1 { } #[async_trait] -impl Challenge for C1 { +impl ChallengeLike for C1 { fn config(&self) -> Config { self.config.clone() } @@ -34,6 +34,7 @@ impl Challenge for C1 { fn text() -> ChallengeDesc { ChallengeDesc { + id: 1, title: "dumb TCP".to_string(), hints: vec![String::from("TCP connect to 1337.")], solution: String::from("Connect by TCP, then the secret will be sent to you."), diff --git a/src/challenge/c2.rs b/src/challenge/c2.rs index 3c86456..b10c0e8 100644 --- a/src/challenge/c2.rs +++ b/src/challenge/c2.rs @@ -10,7 +10,7 @@ use libpt::log::{info, warn}; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::net::{TcpListener, TcpStream}; -use super::{Challenge, ChallengeDesc}; +use super::{ChallengeDesc, ChallengeLike}; use crate::config::Config; use crate::has_won; use crate::vault::VaultRef; @@ -47,7 +47,7 @@ impl C2 { } #[async_trait] -impl Challenge for C2 { +impl ChallengeLike for C2 { fn config(&self) -> Config { self.config.clone() } @@ -59,6 +59,7 @@ impl Challenge for C2 { } fn text() -> ChallengeDesc { ChallengeDesc { + id: 2, title: "TCP dialogue".to_string(), hints: vec![String::from( "TCP connect to 1337 and give me a special u16", diff --git a/src/challenge/c3.rs b/src/challenge/c3.rs index 3ae95e0..f159cf7 100644 --- a/src/challenge/c3.rs +++ b/src/challenge/c3.rs @@ -29,7 +29,7 @@ use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader}; use tokio::net::{TcpListener, TcpStream}; use tokio::time::Instant; -use super::{Challenge, ChallengeDesc}; +use super::{ChallengeDesc, ChallengeLike}; use crate::config::Config; use crate::has_won; use crate::vault::VaultRef; @@ -207,7 +207,7 @@ impl C3 { } #[async_trait] -impl Challenge for C3 { +impl ChallengeLike for C3 { fn config(&self) -> Config { self.config.clone() } @@ -219,6 +219,7 @@ impl Challenge for C3 { } fn text() -> ChallengeDesc { ChallengeDesc { + id: 3, title: "TCP math exam".to_string(), hints: vec![ "TCP connect to 1337 and answer the questions.".to_string(), diff --git a/src/challenge/mod.rs b/src/challenge/mod.rs index 2c1dfe6..554f0a5 100644 --- a/src/challenge/mod.rs +++ b/src/challenge/mod.rs @@ -16,6 +16,7 @@ pub mod c3; #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub struct ChallengeDesc { + id: usize, title: String, hints: Vec, solution: String, @@ -30,7 +31,7 @@ impl ChallengeDesc { /// /// # Returns /// - /// A vector of strings containing hints for the challenge. + /// A [`Vec`] containing hints for the challenge. pub fn hints(&self) -> Vec<&str> { self.hints.iter().map(|a| a.as_ref()).collect() } @@ -41,7 +42,7 @@ impl ChallengeDesc { /// /// # Returns /// - /// A string containing the solution to the challenge. + /// A [`String`] containing the solution to the challenge. pub fn solution(&self) -> &str { &self.solution } @@ -52,7 +53,7 @@ impl ChallengeDesc { /// /// # Returns /// - /// A string containing the description to the challenge. + /// A [`String`] containing the description to the challenge. pub fn description(&self) -> &str { &self.description } @@ -62,17 +63,27 @@ impl ChallengeDesc { /// /// # Returns /// - /// A string containing the title to the challenge. + /// A [`String`] containing the title to the challenge. pub fn title(&self) -> &str { &self.title } + /// Returns the id to the challenge. + /// + /// The id is just the index of the challenge to distinguish them easily + /// + /// # Returns + /// + /// A [`usize`] containing the title to the challenge. + pub fn id(&self) -> usize { + self.id + } } /// 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 +pub trait ChallengeLike where Self: Sized + 'static, Self: Send, @@ -127,6 +138,7 @@ where async fn start(&self) -> anyhow::Result<()> { let c = self.clone(); tokio::spawn(async move { + info!("starting C{}", Self::text().id()); if let Err(e) = c.serve().await { error!("challenge {} has crashed! {e:#?}", Self::text().title()); }; @@ -134,34 +146,3 @@ where Ok(()) } } - -/// 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<()> { - info!("select+start"); - match index { - 1 => c1::C1::new(config, vault).start().await?, - 2 => c2::C2::new(config, vault).start().await?, - 3 => c3::C3::new(config, vault).start().await?, - _ => { - return Err(anyhow!( - "no challenge with index {index} does currently exist" - )) - } - } - Ok(()) -} diff --git a/src/lib.rs b/src/lib.rs index c25518b..6656693 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,6 +14,12 @@ //! Wooly Vault is programmed asynchronously with [tokio] to be able to handle many contestants at //! once if needed. +use anyhow::anyhow; +use libpt::log::info; + +use self::challenge::ChallengeLike; +use self::config::Config; +use self::meta::Service; use self::vault::VaultRef; pub mod challenge; @@ -31,3 +37,61 @@ pub(crate) async fn has_won( vault.add_winner(contestant.clone()).await; libpt::log::info!("Sending the secret to {addr}") } + +/// Selects a single 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_single( + index: u16, + config: Config, + vault: VaultRef, +) -> anyhow::Result<()> { + info!("select+start"); + match index { + 1 => challenge::c1::C1::new(config, vault).start().await?, + 2 => challenge::c2::C2::new(config, vault).start().await?, + 3 => challenge::c3::C3::new(config, vault).start().await?, + _ => { + return Err(anyhow!( + "no challenge with index {index} does currently exist" + )) + } + } + Ok(()) +} + +pub async fn start_all(config: Config, vault: VaultRef) -> anyhow::Result<()> { + let c1 = challenge::c1::C1::new(config.clone(), vault.clone()); + let c2 = challenge::c2::C2::new(config.clone(), vault.clone()); + let c3 = challenge::c3::C3::new(config.clone(), vault.clone()); + + c1.start().await?; + c2.start().await?; + c3.start().await?; + + meta::serve( + vec![ + challenge::c1::C1::text(), + challenge::c2::C2::text(), + challenge::c3::C3::text(), + ], + vault.clone(), + config.clone(), + ) + .await?; + + Ok(()) +} diff --git a/src/main.rs b/src/main.rs index 7544f90..211f7fe 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,8 @@ use anyhow::Result; use clap::Parser; use libpt::log::{debug, info}; -use wooly_vault::{challenge::select_and_start, config::Config, vault::Vault}; +use wooly_vault::{config::Config, vault::Vault}; +use wooly_vault::{select_and_start_single, start_all}; #[tokio::main(flavor = "current_thread")] async fn main() -> Result<()> { @@ -21,7 +22,7 @@ async fn main() -> Result<()> { let secret = Config::secret()?; let v = Vault::new(&secret); - select_and_start(conf.challenge, conf, v).await?; + start_all(conf, v).await?; loop { tokio::time::sleep(tokio::time::Duration::from_secs(5)).await diff --git a/src/meta/mod.rs b/src/meta/mod.rs index 1102c57..bbdb244 100644 --- a/src/meta/mod.rs +++ b/src/meta/mod.rs @@ -26,27 +26,21 @@ pub struct Service<'tp> { challenges: Vec, } impl<'tp> Service<'tp> { - fn new( - vault: VaultRef, - config: Config, - env: Environment<'tp>, - challenges: Vec, - ) -> Arc { - Self { + fn build(vault: VaultRef, config: Config, challenges: Vec) -> Result> { + let mut env = Environment::new(); + env.add_template("index", include_str!("../../data/www/admin.html"))?; + Ok(Self { vault, config, env, challenges, } - .into() + .into()) } } pub async fn serve(challenges: Vec, vault: VaultRef, config: Config) -> Result<()> { - let mut env = Environment::new(); - env.add_template("index", include_str!("../../data/www/admin.html"))?; - - let service = Service::new(vault, config, env, challenges); + let service = Service::build(vault, config, challenges)?; let routes = Service::admin_routes(service.clone()) .or(Service::ressources_routes())