diff --git a/Cargo.lock b/Cargo.lock index d07f21e..12d2468 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -113,6 +113,12 @@ dependencies = [ "byte-tools", ] +[[package]] +name = "bs58" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" + [[package]] name = "buf_redux" version = "0.8.4" @@ -436,6 +442,7 @@ name = "gmarche" version = "0.1.0" dependencies = [ "bincode", + "bs58", "dirs", "handlebars", "hex", diff --git a/Cargo.toml b/Cargo.toml index cda7613..e981072 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ edition = "2018" [dependencies] bincode = "1.3.1" +bs58 = "0.4.0" dirs = "3.0.1" handlebars = "3.5.1" hex = "0.4.2" diff --git a/src/main.rs b/src/main.rs index db55574..026c989 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,7 @@ mod db; mod server; mod static_files; mod templates; +mod utils; use structopt::StructOpt; diff --git a/src/server.rs b/src/server.rs index 8763ae8..493b134 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1,4 +1,4 @@ -use super::{cli, config, db, static_files, templates}; +use super::{cli, config, db, static_files, templates, utils::*}; use handlebars::to_json; use serde::{Deserialize, Serialize}; @@ -118,21 +118,28 @@ pub async fn start_server( .and(warp::get()) .and(warp::fs::dir(opt.dir.0.join(static_files::STATIC_DIR))); - let handle_new_ad = { - let handle_index = handle_index.clone(); - let dbs = dbs.clone(); - let cache_ads = cache_ads.clone(); - move |query: NewAdQuery| { - let mut hasher = Sha512Trunc256::new(); - hasher.update(query.psw); - dbs.ads + let handle_new_ad = + { + let handle_index = handle_index.clone(); + let dbs = dbs.clone(); + let cache_ads = cache_ads.clone(); + move |query: NewAdQuery| { + let mut hasher = Sha512Trunc256::new(); + hasher.update(query.psw); + dbs.ads .insert( AdId::random(), bincode::serialize(&Ad { author: query.author, password: hasher.finalize()[..].try_into().unwrap(), price: query.price, - pubkey: (!query.pubkey.is_empty()).then_some(query.pubkey), + pubkey: (!query.pubkey.is_empty()).then_some(match format_pubkey(&query.pubkey) { + Ok(pubkey) => pubkey, + Err(e) => return handle_index(&[ErrorTemplate{text: match e { + PubkeyDecodeError::BadChecksum => "La somme de contrôle de la clé publique est incorrecte.", + PubkeyDecodeError::BadFormat => "Le format de la clé publique est incorrect.", + }}]) + }), quantity: query.quantity, time: 0, title: query.title, @@ -140,24 +147,24 @@ pub async fn start_server( .unwrap(), ) .unwrap(); - dbs.ads.flush().unwrap(); - let mut cache_ads = cache_ads.write().unwrap(); - *cache_ads = to_json( - dbs.ads - .iter() - .filter_map(|x| { - let (ad_id, ad) = x.ok()?; - Some(AdWithId { - id: hex::encode(ad_id.as_ref()), - ad: bincode::deserialize::(&ad).ok()?, + dbs.ads.flush().unwrap(); + let mut cache_ads = cache_ads.write().unwrap(); + *cache_ads = to_json( + dbs.ads + .iter() + .filter_map(|x| { + let (ad_id, ad) = x.ok()?; + Some(AdWithId { + id: hex::encode(ad_id.as_ref()), + ad: bincode::deserialize::(&ad).ok()?, + }) }) - }) - .collect::>(), - ); - drop(cache_ads); - handle_index(&[]) - } - }; + .collect::>(), + ); + drop(cache_ads); + handle_index(&[]) + } + }; let handle_rm_ad = { let handle_index = handle_index.clone(); @@ -259,14 +266,10 @@ pub async fn start_server( let handle_admin_login = handle_admin_login.clone(); let config = config.clone(); move |psw, query| { - dbg!(); if config.admin_passwords.contains(&psw) { - dbg!(); let AdminQuery::RmAdQuery(query) = query; - dbg!(); handle_admin_rm_ad(query) } else { - dbg!(); handle_admin_login(&[ErrorTemplate { text: "Mot de passe administrateur invalide", }]) @@ -278,12 +281,9 @@ pub async fn start_server( let handle_admin_login = handle_admin_login.clone(); let config = config.clone(); move |psw| { - dbg!(); if config.admin_passwords.contains(&psw) { - dbg!(); handle_admin(&[]) } else { - dbg!(); handle_admin_login(&[ErrorTemplate { text: "Mot de passe administrateur invalide", }]) @@ -292,10 +292,7 @@ pub async fn start_server( })) .or(warp::path::end().map({ let handle_admin_login = handle_admin_login.clone(); - move || { - dbg!(); - handle_admin_login(&[]) - } + move || handle_admin_login(&[]) })), ) .or(warp::path("login").and(warp::path::end()).and( @@ -304,9 +301,7 @@ pub async fn start_server( .or(warp::body::form::().map({ let config = config.clone(); move |query: AdminLoginQuery| { - dbg!(); if config.admin_passwords.contains(&query.psw) { - dbg!(); warp::reply::with_header( warp::redirect(warp::http::Uri::from_static("/admin")), "Set-Cookie", @@ -317,7 +312,6 @@ pub async fn start_server( ) .into_response() } else { - dbg!(); handle_admin_login(&[ErrorTemplate { text: "Mot de passe administrateur invalide", }]) diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..105c488 --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,37 @@ +use sha2::{Digest, Sha256}; + +pub enum PubkeyDecodeError { + BadChecksum, + BadFormat, +} + +/// Decode pubkey from base 58 +/// Verify checksum if provided +/// Accepts any checksum length >=3 +pub fn format_pubkey(raw: &str) -> Result { + let mut iter = raw.splitn(2, ':'); + let mut pubkey = [0u8; 32]; + bs58::decode(iter.next().ok_or(PubkeyDecodeError::BadFormat)?) + .into(&mut pubkey) + .map_err(|_| PubkeyDecodeError::BadFormat)?; + + let mut hasher1 = Sha256::new(); + hasher1.update(&pubkey.as_ref()[..32]); + let mut hasher2 = Sha256::new(); + hasher2.update(hasher1.finalize()); + let checksum = bs58::encode(hasher2.finalize()).into_string(); + + if let Some(given_checksum) = iter.next() { + if given_checksum.len() < 3 { + return Err(PubkeyDecodeError::BadFormat); + } + if !checksum.starts_with(given_checksum) { + return Err(PubkeyDecodeError::BadChecksum); + } + } + Ok(format!( + "{}:{}", + bs58::encode(pubkey).into_string(), + &checksum[..3] + )) +} diff --git a/static/style1.css b/static/style1.css index 2e71c2e..a0d6dbd 100644 --- a/static/style1.css +++ b/static/style1.css @@ -48,6 +48,10 @@ h1, h2, h3, h4 { width: 100%; } +fieldset { + border: 1px dashed grey; +} + .center { padding: 4px; }