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 }
}
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."),
description: String::from("Do you know how to TCP?"),
}
fn text(&self) -> ChallengeDesc {
ChallengeDesc::new(
1,
"dumb TCP",
&["TCP connect to 1337."],
"Connect by TCP, then the secret will be sent to you.",
"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?;
loop {

View File

@ -59,19 +59,18 @@ impl ChallengeLike for C2 {
fn new(config: Config, vault: VaultRef) -> Self {
Self { config, vault }
}
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",
)],
solution: String::from("Connect by TCP, send 1337 as bytes (not text)."),
description: String::from("Do you know how to TCP, but slightly cooler than for C1?"),
}
fn text(&self) -> ChallengeDesc {
ChallengeDesc::new(
2,
"TCP dialogue",
&["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?",
&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?;
loop {

View File

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

View File

@ -23,9 +23,37 @@ pub struct ChallengeDesc {
hints: Vec<String>,
solution: String,
description: String,
addr: SocketAddr,
}
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.
///
/// 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].
fn config(&self) -> Config;
/// 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.
///
/// # Arguments
@ -122,7 +150,7 @@ where
/// # Errors
///
/// 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.
///
/// This method not only serves the challenge, but it also sets up a small webservice for the
@ -137,12 +165,14 @@ where
/// # Returns
///
/// 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 data = self.text();
let addr = addr.to_owned();
tokio::spawn(async move {
info!("starting C{}", Self::text().id());
if let Err(e) = c.serve(addr).await {
error!("challenge {} has crashed! {e:#?}", Self::text().title());
info!("starting C{}", data.id());
if let Err(e) = c.serve(&addr).await {
error!("challenge {} has crashed! {e:#?}", data.title());
};
});
Ok(())

View File

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