diff --git a/Cargo.toml b/Cargo.toml index c3dd3bf..849f67b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,3 +12,7 @@ repository = "https://git.cscherr.de/PlexSheep/wooly-vault" [dependencies] +anyhow = "1.0.86" +async-trait = "0.1.82" +libpt = { version = "0.6.0", features = ["log"] } +tokio = { version = "1.40.0", features = ["macros", "net", "time", "io-util", "rt", "sync"] } diff --git a/src/challenge/c1.rs b/src/challenge/c1.rs new file mode 100644 index 0000000..e5ed0d8 --- /dev/null +++ b/src/challenge/c1.rs @@ -0,0 +1,49 @@ +use async_trait::async_trait; +use libpt::log::{info, warn}; +use tokio::io::AsyncWriteExt; +use tokio::net::TcpListener; + +use super::Challenge; +use crate::has_won; +use crate::vault::{Config, VaultRef}; + +pub struct C1 { + config: Config, + vault: VaultRef, +} + +impl C1 {} + +#[async_trait] +impl Challenge for C1 { + fn new(config: Config, vault: VaultRef) -> Self { + Self { config, vault } + } + fn hint() -> String { + String::from("TCP connect to 1337") + } + async fn serve(self) -> anyhow::Result<()> { + info!("serving challenge 1"); + 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; + } + }; + has_won(addr); + 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}"); + }; + }); + } + } +} diff --git a/src/challenge/mod.rs b/src/challenge/mod.rs new file mode 100644 index 0000000..039efa3 --- /dev/null +++ b/src/challenge/mod.rs @@ -0,0 +1,24 @@ +use anyhow::anyhow; +use async_trait::async_trait; + +use crate::vault::{Config, VaultRef}; + +use self::c1::C1; + +pub mod c1; + +#[async_trait] +pub trait Challenge +where + Self: Sized, +{ + fn new(config: Config, vault: VaultRef) -> Self; + fn hint() -> String; + async fn serve(self) -> anyhow::Result<()>; + fn get_challenge(idx: u16, config: Config, vault: VaultRef) -> anyhow::Result { + match idx { + 1 => Ok(C1::new(config, vault)), + _ => Err(anyhow!("no challenge with that index exists")), + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 8b13789..12acbd1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1 +1,7 @@ +pub mod challenge; +pub mod vault; +#[inline] +pub(crate) fn has_won(addr: std::net::SocketAddr) { + libpt::log::info!("Sending the secret to {addr}") +} diff --git a/src/main.rs b/src/main.rs index e7a11a9..f0de726 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,41 @@ -fn main() { - println!("Hello, world!"); +use anyhow::anyhow; +use libpt::log::{debug, error}; +use std::io::Read; + +use wooly_vault::challenge::c1::C1; +use wooly_vault::challenge::Challenge; +use wooly_vault::vault::{Config, Vault}; + +#[tokio::main(flavor = "current_thread")] +async fn main() -> anyhow::Result<()> { + let _logger = libpt::log::Logger::builder() + .set_level(libpt::log::Level::TRACE) + .display_time(false) + .build()?; + + println!("Input the secret and press enter"); + let mut buf: String = String::new(); + std::io::stdin().read_line(&mut buf)?; + let secret = buf.trim(); + + let conf = Config::default(); + + let v = Vault::new(secret); + + println!("What challenge to serve?"); + let i = select_challenge()?; + match i { + 1 => { + C1::new(conf, v).serve().await?; + } + _ => return Err(anyhow!("no challenge with index {i} does currently exist")), + } + + Ok(()) +} + +fn select_challenge() -> anyhow::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 new file mode 100644 index 0000000..8217adb --- /dev/null +++ b/src/vault.rs @@ -0,0 +1,35 @@ +use std::net::SocketAddr; +use std::str::FromStr; +use std::sync::Arc; + +pub type VaultRef = Arc; + +#[derive(Debug, Clone, PartialEq, Copy)] +pub struct Config { + pub addr: SocketAddr, +} + +impl Default for Config { + fn default() -> Self { + Self { + addr: SocketAddr::from_str("127.0.0.1:1337").unwrap(), + } + } +} + +#[derive(Debug, Clone, PartialEq)] +pub struct Vault { + secret: String, +} + +impl Vault { + pub fn new(secret: &str) -> VaultRef { + let v = Self { + secret: secret.to_string(), + }; + Arc::new(v) + } + pub fn secret(&self) -> &str { + &self.secret + } +}