refactor: change how ChallengeDesc works

This commit is contained in:
Christoph J. Scherr 2024-09-08 14:19:36 +02:00
parent fb4d028af6
commit 0db78399bd
5 changed files with 78 additions and 52 deletions

View File

@ -34,17 +34,18 @@ impl ChallengeLike for C1 {
Self { config, vault } Self { config, vault }
} }
fn text() -> ChallengeDesc { fn text(&self) -> ChallengeDesc {
ChallengeDesc { ChallengeDesc::new(
id: 1, 1,
title: "dumb TCP".to_string(), "dumb TCP",
hints: vec![String::from("TCP connect to 1337.")], &["TCP connect to 1337."],
solution: String::from("Connect by TCP, then the secret will be sent to you."), "Connect by TCP, then the secret will be sent to you.",
description: String::from("Do you know how to TCP?"), "Do you know how to TCP?",
} &self.config.addr,
)
} }
async fn serve(&self, addr: SocketAddr) -> anyhow::Result<()> { async fn serve(&self, addr: &SocketAddr) -> anyhow::Result<()> {
let listener = TcpListener::bind(addr).await?; let listener = TcpListener::bind(addr).await?;
loop { loop {

View File

@ -59,19 +59,18 @@ impl ChallengeLike for C2 {
fn new(config: Config, vault: VaultRef) -> Self { fn new(config: Config, vault: VaultRef) -> Self {
Self { config, vault } Self { config, vault }
} }
fn text() -> ChallengeDesc { fn text(&self) -> ChallengeDesc {
ChallengeDesc { ChallengeDesc::new(
id: 2, 2,
title: "TCP dialogue".to_string(), "TCP dialogue",
hints: vec![String::from( &["TCP connect to 1337 and give me a special u16"],
"TCP connect to 1337 and give me a special u16", "Connect by TCP, send 1337 as bytes (not text).",
)], "Do you know how to TCP, but slightly cooler than for C1?",
solution: String::from("Connect by TCP, send 1337 as bytes (not text)."), &self.config.addr,
description: String::from("Do you know how to TCP, but slightly cooler than for C1?"), )
}
} }
async fn serve(&self, addr: SocketAddr) -> anyhow::Result<()> { async fn serve(&self, addr: &SocketAddr) -> anyhow::Result<()> {
let listener = TcpListener::bind(addr).await?; let listener = TcpListener::bind(addr).await?;
loop { loop {

View File

@ -217,21 +217,22 @@ impl ChallengeLike for C3 {
fn new(config: Config, vault: VaultRef) -> Self { fn new(config: Config, vault: VaultRef) -> Self {
Self { config, vault } Self { config, vault }
} }
fn text() -> ChallengeDesc { fn text(&self) -> ChallengeDesc {
ChallengeDesc { ChallengeDesc::new(
id: 3, 3,
title: "TCP math exam".to_string(), "TCP math exam",
hints: vec![ &[
"TCP connect to 1337 and answer the questions.".to_string(), "TCP connect to 1337 and answer the questions.",
"The questions keep chaning.".to_string(), "The questions keep chaning.",
"You should try to solve the questions in an automated way.".to_string(), "You should try to solve the questions in an automated way.",
], ],
solution: String::from("Connect by TCP, programmatically answer the questions."), "Connect by TCP, programmatically answer the questions.",
description: String::from("How fast can you do arithmetics?"), "How fast can you do arithmetics?",
} &self.config.addr,
)
} }
async fn serve(&self, addr: SocketAddr) -> anyhow::Result<()> { async fn serve(&self, addr: &SocketAddr) -> anyhow::Result<()> {
let listener = TcpListener::bind(addr).await?; let listener = TcpListener::bind(addr).await?;
loop { loop {

View File

@ -23,9 +23,37 @@ pub struct ChallengeDesc {
hints: Vec<String>, hints: Vec<String>,
solution: String, solution: String,
description: String, description: String,
addr: SocketAddr,
} }
impl ChallengeDesc { impl ChallengeDesc {
pub fn new(
id: usize,
title: &str,
hints: &[&str],
solution: &str,
description: &str,
base_addr: &SocketAddr,
) -> Self {
Self {
id,
title: title.to_string(),
hints: hints.iter().map(|a| a.to_string()).collect(),
solution: solution.to_string(),
description: description.to_string(),
addr: SocketAddr::new(base_addr.ip(), base_addr.port() + id as u16),
}
}
/// Returns a [`SocketAddr`] for the challenge.
///
/// The challenge will be hosted on this [`SocketAddr`].
///
/// # Returns
///
/// The [`SocketAddr`] that the challenge is hosted on.
pub fn addr(&self) -> &SocketAddr {
&self.addr
}
/// Returns a list of hints for the challenge. /// Returns a list of hints for the challenge.
/// ///
/// A hint is a short text to be given to the contestants in case the admin thinks they need /// A hint is a short text to be given to the contestants in case the admin thinks they need
@ -98,7 +126,7 @@ where
/// Getter for the [Config]. /// Getter for the [Config].
fn config(&self) -> Config; fn config(&self) -> Config;
/// Get the various texts for this challenge. /// Get the various texts for this challenge.
fn text() -> ChallengeDesc; fn text(&self) -> ChallengeDesc;
/// Creates a new instance of the challenge with the given configuration and vault. /// Creates a new instance of the challenge with the given configuration and vault.
/// ///
/// # Arguments /// # Arguments
@ -122,7 +150,7 @@ where
/// # Errors /// # Errors
/// ///
/// Will error when the challenge errors, for example when the network adress cannot be bound. /// Will error when the challenge errors, for example when the network adress cannot be bound.
async fn serve(&self, addr: SocketAddr) -> anyhow::Result<()>; async fn serve(&self, addr: &SocketAddr) -> anyhow::Result<()>;
/// Serves a challenge and sets up the hint and monitoring service for the admin. /// Serves a challenge and sets up the hint and monitoring service for the admin.
/// ///
/// This method not only serves the challenge, but it also sets up a small webservice for the /// This method not only serves the challenge, but it also sets up a small webservice for the
@ -137,12 +165,14 @@ where
/// # Returns /// # Returns
/// ///
/// A result indicating whether the challenge and the admin interface were successfully served. /// A result indicating whether the challenge and the admin interface were successfully served.
async fn start(&self, addr: SocketAddr) -> anyhow::Result<()> { async fn start(&self, addr: &SocketAddr) -> anyhow::Result<()> {
let c = self.clone(); let c = self.clone();
let data = self.text();
let addr = addr.to_owned();
tokio::spawn(async move { tokio::spawn(async move {
info!("starting C{}", Self::text().id()); info!("starting C{}", data.id());
if let Err(e) = c.serve(addr).await { if let Err(e) = c.serve(&addr).await {
error!("challenge {} has crashed! {e:#?}", Self::text().title()); error!("challenge {} has crashed! {e:#?}", data.title());
}; };
}); });
Ok(()) Ok(())

View File

@ -14,8 +14,6 @@
//! Wooly Vault is programmed asynchronously with [tokio] to be able to handle many contestants at //! Wooly Vault is programmed asynchronously with [tokio] to be able to handle many contestants at
//! once if needed. //! once if needed.
use std::net::SocketAddr;
use anyhow::anyhow; use anyhow::anyhow;
use libpt::log::info; use libpt::log::info;
@ -64,17 +62,17 @@ pub async fn select_and_start_single(
match index { match index {
1 => { 1 => {
challenge::c1::C1::new(config.clone(), vault) challenge::c1::C1::new(config.clone(), vault)
.start(config.addr) .start(&config.addr)
.await? .await?
} }
2 => { 2 => {
challenge::c2::C2::new(config.clone(), vault) challenge::c2::C2::new(config.clone(), vault)
.start(config.addr) .start(&config.addr)
.await? .await?
} }
3 => { 3 => {
challenge::c3::C3::new(config.clone(), vault) challenge::c3::C3::new(config.clone(), vault)
.start(config.addr) .start(&config.addr)
.await? .await?
} }
_ => { _ => {
@ -88,22 +86,19 @@ pub async fn select_and_start_single(
// TODO: actually use different vaults for the challenges #7 // TODO: actually use different vaults for the challenges #7
pub async fn start_all(config: Config, vault: VaultRef) -> anyhow::Result<()> { pub async fn start_all(config: Config, vault: VaultRef) -> anyhow::Result<()> {
let ip = config.addr.ip();
let start_port = config.addr.port();
let c1 = challenge::c1::C1::new(config.clone(), vault.clone()); let c1 = challenge::c1::C1::new(config.clone(), vault.clone());
let c2 = challenge::c2::C2::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()); let c3 = challenge::c3::C3::new(config.clone(), vault.clone());
c1.start(SocketAddr::new(ip, start_port)).await?; c1.start(c1.text().addr()).await?;
c2.start(SocketAddr::new(ip, start_port + 1)).await?; c2.start(c2.text().addr()).await?;
c3.start(SocketAddr::new(ip, start_port + 2)).await?; c3.start(c3.text().addr()).await?;
meta::serve( meta::serve(
vec![ vec![
(challenge::c1::C1::text(), vault.clone()), (c1.text(), vault.clone()),
(challenge::c2::C2::text(), vault.clone()), (c2.text(), vault.clone()),
(challenge::c3::C3::text(), vault.clone()), (c3.text(), vault.clone()),
], ],
config.clone(), config.clone(),
) )