//! The first challenge, in which the contestant only needs to connect by TCP to be sent the secret. //! //! This challenge is designed to be simple and straightforward, requiring the contestant to only //! establish a TCP connection to the server to receive the secret. use async_trait::async_trait; use libpt::log::warn; use tokio::io::AsyncWriteExt; use tokio::net::TcpListener; use super::{Challenge, Descriptions}; use crate::config::Config; use crate::has_won; use crate::vault::VaultRef; /// This struct holds the configuration and vault for the challenge. pub struct C1 { config: Config, vault: VaultRef, } #[async_trait] impl Challenge for C1 { fn config(&self) -> Config { self.config.clone() } fn vault(&self) -> VaultRef { self.vault.clone() } fn new(config: Config, vault: VaultRef) -> Self { Self { config, vault } } fn text() -> Descriptions { Descriptions { 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?"), } } async fn serve(&self) -> anyhow::Result<()> { let listener = TcpListener::bind(self.config.addr).await?; loop { let vault = self.vault.clone(); let (mut stream, addr) = match listener.accept().await { Ok(s) => s, Err(err) => { warn!("could not accept tcp stream: {err:?}"); continue; } }; self.vault.add_contestant(addr.into()).await; has_won(&addr, &self.vault, &addr.into()).await; tokio::spawn(async move { if let Err(e) = stream.write_all(vault.secret().as_bytes()).await { warn!("could not write to peer {addr}: {e}"); }; if let Err(e) = stream.shutdown().await { warn!("could end connection to peer {addr}: {e}"); }; }); } } }