feat: proper cli
cargo devel CI / cargo CI (push) Successful in 2m16s Details

This commit is contained in:
Christoph J. Scherr 2024-09-06 17:59:04 +02:00
parent 19b81e2631
commit f00aa8b4e9
8 changed files with 129 additions and 37 deletions

View File

@ -14,5 +14,15 @@ repository = "https://git.cscherr.de/PlexSheep/wooly-vault"
[dependencies] [dependencies]
anyhow = "1.0.86" anyhow = "1.0.86"
async-trait = "0.1.82" async-trait = "0.1.82"
libpt = { version = "0.6.0", features = ["log"] } clap = { version = "4.5.17", features = ["derive"] }
tokio = { version = "1.40.0", features = ["macros", "net", "time", "io-util", "rt", "sync"] } libpt = { version = "0.7.1", features = ["cli", "log"] }
serde = { version = "1.0.209", features = ["derive"] }
serde_json = "1.0.128"
tokio = { version = "1.40.0", features = [
"macros",
"net",
"time",
"io-util",
"rt",
"sync",
] }

View File

@ -4,8 +4,9 @@ use tokio::io::AsyncWriteExt;
use tokio::net::TcpListener; use tokio::net::TcpListener;
use super::Challenge; use super::Challenge;
use crate::config::Config;
use crate::has_won; use crate::has_won;
use crate::vault::{Config, VaultRef}; use crate::vault::VaultRef;
pub struct C1 { pub struct C1 {
config: Config, config: Config,
@ -19,9 +20,15 @@ impl Challenge for C1 {
fn new(config: Config, vault: VaultRef) -> Self { fn new(config: Config, vault: VaultRef) -> Self {
Self { config, vault } Self { config, vault }
} }
fn hints() -> Vec<String> { fn hints() -> Vec<String> {
vec![String::from("TCP connect to 1337")] vec![String::from("TCP connect to 1337.")]
} }
fn solution() -> String {
String::from("Connect by TCP, then the secret will be sent to you.")
}
async fn serve(self) -> anyhow::Result<()> { async fn serve(self) -> anyhow::Result<()> {
info!("serving challenge 1"); info!("serving challenge 1");
let listener = TcpListener::bind(self.config.addr).await?; let listener = TcpListener::bind(self.config.addr).await?;

View File

@ -5,8 +5,9 @@ use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::{TcpListener, TcpStream}; use tokio::net::{TcpListener, TcpStream};
use super::Challenge; use super::Challenge;
use crate::config::Config;
use crate::has_won; use crate::has_won;
use crate::vault::{Config, VaultRef}; use crate::vault::VaultRef;
pub struct C2 { pub struct C2 {
config: Config, config: Config,
@ -37,11 +38,17 @@ impl Challenge for C2 {
fn new(config: Config, vault: VaultRef) -> Self { fn new(config: Config, vault: VaultRef) -> Self {
Self { config, vault } Self { config, vault }
} }
fn hints() -> Vec<String> { fn hints() -> Vec<String> {
vec![String::from( vec![String::from(
"TCP connect to 1337 and give me a special u16", "TCP connect to 1337 and give me a special u16",
)] )]
} }
fn solution() -> String {
String::from("Connect by TCP, send 1337 as bytes (not text).")
}
async fn serve(self) -> anyhow::Result<()> { async fn serve(self) -> anyhow::Result<()> {
info!("serving challenge 2"); info!("serving challenge 2");
let listener = TcpListener::bind(self.config.addr).await?; let listener = TcpListener::bind(self.config.addr).await?;

View File

@ -1,7 +1,8 @@
use anyhow::anyhow; use anyhow::anyhow;
use async_trait::async_trait; use async_trait::async_trait;
use crate::vault::{Config, VaultRef}; use crate::config::Config;
use crate::vault::VaultRef;
pub mod c1; pub mod c1;
pub mod c2; pub mod c2;
@ -13,6 +14,7 @@ where
{ {
fn new(config: Config, vault: VaultRef) -> Self; fn new(config: Config, vault: VaultRef) -> Self;
fn hints() -> Vec<String>; fn hints() -> Vec<String>;
fn solution() -> String;
async fn serve(self) -> anyhow::Result<()>; async fn serve(self) -> anyhow::Result<()>;
} }

69
src/config.rs Normal file
View File

@ -0,0 +1,69 @@
use std::fmt::{Debug, Display};
use std::net::SocketAddr;
use std::str::FromStr;
use clap::Parser;
use libpt::cli::args::VerbosityLevel;
use serde::Serialize;
pub const ENV_SECRET: &str = "WOOLY_SECRET";
/// Wooly Vault --- A few small hacking challenges
///
/// # Configuration
/// Each challenge requires some basic information to host:
///
/// * secret - a string that if found signifies that the challenge was solved
///
/// * addr - the network adress plus port the challenge should run on
///
/// * verbosity - how verbose the logging should be
///
/// * challenge - which challenge to host (there are a few)
///
/// The secret cannot be inputted with a command line argument, because the arguments can often be
/// seen in the process view. You may either specify a secret in the 'WOOLY_SECRET' environment
/// variable or input it interactively on start.
///
/// # Challenges
///
/// There are a number of challenges:
///
/// 1. Connect by TCP
///
/// 2. Connect by TCP and send a special u16
#[derive(Parser, Clone, PartialEq, Eq, Hash, Serialize)]
#[command(
author,
version,
about,
long_about,
help_template = libpt::cli::args::HELP_TEMPLATE)]
pub struct Config {
/// Index of the challenge
pub challenge: u16,
/// Network address to host the challenge on
pub addr: SocketAddr,
#[command(flatten)]
pub verbosity: VerbosityLevel,
}
impl Default for Config {
fn default() -> Self {
Self {
challenge: 1,
addr: SocketAddr::from_str("127.0.0.1:1337").unwrap(),
verbosity: VerbosityLevel::default(),
}
}
}
impl Debug for Config {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Config")
.field("addr", &self.addr)
.field("verbosity", &self.verbosity.level())
.finish()
}
}

View File

@ -1,4 +1,5 @@
pub mod challenge; pub mod challenge;
pub mod config;
pub mod vault; pub mod vault;
#[inline] #[inline]

View File

@ -1,30 +1,41 @@
use wooly_vault::challenge::select_and_start; use anyhow::Result;
use wooly_vault::vault::{Config, Vault}; use clap::Parser;
use libpt::log::{debug, info};
use wooly_vault::config::ENV_SECRET;
use wooly_vault::{challenge::select_and_start, config::Config, vault::Vault};
#[tokio::main(flavor = "current_thread")] #[tokio::main(flavor = "current_thread")]
async fn main() -> anyhow::Result<()> { async fn main() -> Result<()> {
let conf = Config::parse();
let _logger = libpt::log::Logger::builder() let _logger = libpt::log::Logger::builder()
.set_level(libpt::log::Level::TRACE) .set_level(conf.verbosity.level())
.display_time(false) .display_time(false)
.build()?; .build()?;
debug!("logger active");
info!("Configuration: {conf:?}");
println!("Input the secret and press enter"); let secret = get_secret()?;
let mut buf: String = String::new(); let v = Vault::new(&secret);
std::io::stdin().read_line(&mut buf)?;
let secret = buf.trim();
let conf = Config::default(); select_and_start(conf.challenge, conf, v).await?;
let v = Vault::new(secret);
println!("What challenge to serve?");
let i = select_challenge()?;
select_and_start(i, conf, v).await?;
Ok(()) Ok(())
} }
fn select_challenge() -> anyhow::Result<u16> { fn get_secret() -> Result<String> {
if let Ok(v) = std::env::var(ENV_SECRET) {
return Ok(v);
}
println!("Input the secret and press enter");
let mut buf: String = String::new();
std::io::stdin().read_line(&mut buf)?;
Ok(buf.trim().to_string())
}
fn select_challenge() -> Result<u16> {
let mut buf: String = String::new(); let mut buf: String = String::new();
std::io::stdin().read_line(&mut buf)?; std::io::stdin().read_line(&mut buf)?;
Ok(buf.trim().parse()?) Ok(buf.trim().parse()?)

View File

@ -1,22 +1,7 @@
use std::net::SocketAddr;
use std::str::FromStr;
use std::sync::Arc; use std::sync::Arc;
pub type VaultRef = Arc<Vault>; pub type VaultRef = Arc<Vault>;
#[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)] #[derive(Debug, Clone, PartialEq)]
pub struct Vault { pub struct Vault {
secret: String, secret: String,