From 67b3a91a233b7bcc516e8f43b71c865b5b5c62c7 Mon Sep 17 00:00:00 2001 From: Pierre Berthe <42767265+MrTsunami4@users.noreply.github.com> Date: Thu, 25 Jul 2024 12:42:04 +0200 Subject: [PATCH 1/2] Fix browser console warning --- src/common.rs | 2 +- src/main.rs | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/common.rs b/src/common.rs index ef2114b..1934d39 100644 --- a/src/common.rs +++ b/src/common.rs @@ -88,5 +88,5 @@ pub async fn style() -> impl IntoResponse { .get_style_str() .to_string(); - ([("content-type", "style/css")], style) + ([("content-type", "text/css")], style) } diff --git a/src/main.rs b/src/main.rs index 81f58de..366c5a5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,7 +13,7 @@ use axum::{ }; use chrono::prelude::*; use common::{footer, head, header, style}; -use maud::{html, Escaper, Markup, PreEscaped}; +use maud::{html, Escaper, Markup, PreEscaped, DOCTYPE}; use serde::{Deserialize, Serialize}; use store::Store; use tokio::net::TcpListener; @@ -50,6 +50,7 @@ async fn main() -> Result<()> { async fn home() -> Markup { html!( + (DOCTYPE) (head("")) body { content { @@ -71,6 +72,7 @@ async fn home() -> Markup { async fn topics(State(state): State) -> impl IntoResponse { let topics = state.store.read().unwrap().list().unwrap(); html!( + (DOCTYPE) (head("sujets")) body { content { @@ -94,6 +96,7 @@ async fn topics(State(state): State) -> impl IntoResponse { async fn activity(State(state): State) -> impl IntoResponse { let topics = state.store.read().unwrap().activity().unwrap(); html!( + (DOCTYPE) (head("activité")) body { content { @@ -120,6 +123,7 @@ async fn topic(Path(name): Path, State(state): State) -> impl }; html!( + (DOCTYPE) (head(&name)) body { content { @@ -210,6 +214,7 @@ fn sanithize_identifier(input: &str) -> String { async fn create() -> impl IntoResponse { html!( + (DOCTYPE) (head("créer")) body { content { @@ -242,6 +247,7 @@ async fn create() -> impl IntoResponse { fn error(message: impl ToString) -> Markup { let message = message.to_string(); html!( + (DOCTYPE) (head("Failure")) body { content { -- 2.49.0 From 11ca3e3aae9676713d252359bb2d2043722a6f5e Mon Sep 17 00:00:00 2001 From: Pierre Berthe <42767265+MrTsunami4@users.noreply.github.com> Date: Thu, 25 Jul 2024 18:19:56 +0200 Subject: [PATCH 2/2] Add validator --- Cargo.lock | 167 ++++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + src/main.rs | 42 +++++++------ 3 files changed, 191 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 10e4723..e76c03c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,15 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + [[package]] name = "android-tzdata" version = "0.1.1" @@ -205,6 +214,41 @@ version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.72", +] + +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.72", +] + [[package]] name = "either" version = "1.13.0" @@ -399,6 +443,22 @@ dependencies = [ "cc", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "instant" version = "0.1.13" @@ -549,6 +609,7 @@ dependencies = [ "sled", "stylist", "tokio", + "validator", ] [[package]] @@ -699,6 +760,35 @@ dependencies = [ "bitflags", ] +[[package]] +name = "regex" +version = "1.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -819,6 +909,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "stylist" version = "0.13.0" @@ -924,6 +1020,21 @@ dependencies = [ "syn 2.0.72", ] +[[package]] +name = "tinyvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "tokio" version = "1.39.1" @@ -998,12 +1109,68 @@ dependencies = [ "once_cell", ] +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unicode-normalization" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "url" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "validator" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db79c75af171630a3148bd3e6d7c4f42b6a9a014c2945bc5ed0020cbb8d9478e" +dependencies = [ + "idna", + "once_cell", + "regex", + "serde", + "serde_derive", + "serde_json", + "url", + "validator_derive", +] + +[[package]] +name = "validator_derive" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55591299b7007f551ed1eb79a684af7672c19c3193fb9e0a31936987bb2438ec" +dependencies = [ + "darling", + "once_cell", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.72", +] + [[package]] name = "version_check" version = "0.9.4" diff --git a/Cargo.toml b/Cargo.toml index b2a9da0..f3136ff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,3 +14,4 @@ serde_json = "1.0.120" sled = "0.34.7" stylist = "0.13.0" tokio = { version = "1.39.1", features = ["net", "rt-multi-thread"] } +validator = { version = "0.18.1", features = ["derive"] } diff --git a/src/main.rs b/src/main.rs index 366c5a5..6d76178 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,6 +17,7 @@ use maud::{html, Escaper, Markup, PreEscaped, DOCTYPE}; use serde::{Deserialize, Serialize}; use store::Store; use tokio::net::TcpListener; +use validator::{Validate, ValidationError}; mod common; mod store; @@ -146,35 +147,38 @@ async fn topic(Path(name): Path, State(state): State) -> impl ) } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize, Validate)] struct PostContent { + #[validate(length(min = 1, max = 32), custom(function = "validate_topic"))] topic: String, + #[validate(length(min = 10, max = 10_000))] content: String, + #[validate(length(min = 2, max = 32))] author: String, } -async fn post( - State(state): State, - Form(PostContent { +fn validate_topic(topic: &str) -> Result<(), ValidationError> { + if topic.starts_with('_') || topic.ends_with('_') { + return Err(ValidationError::new("Bad topic format.")); + } + Ok(()) +} + +async fn post(State(state): State, Form(post_content): Form) -> Response { + let mut store = state.store.write().unwrap(); + let date = Utc::now().format("%d/%m/%Y"); + + if post_content.validate().is_err() { + return (StatusCode::BAD_REQUEST, "Bad input.").into_response(); + } + + let PostContent { topic, content, author, - }): Form, -) -> Response { - let mut store = state.store.write().unwrap(); - let date = Utc::now().format("%d/%m/%Y"); - let topic = sanithize_identifier(topic.trim()); - let content = content.trim(); + } = post_content; - if content.len() < 10 || content.len() > 10_000 { - return (StatusCode::BAD_REQUEST, "Bad content.").into_response(); - } - if author.len() > 2 || author.len() > 32 { - return (StatusCode::BAD_REQUEST, "Bad author.").into_response(); - } - if topic.len() > 32 || topic.is_empty() || topic.starts_with('_') || topic.ends_with('_') { - return (StatusCode::BAD_REQUEST, "Bad topic.").into_response(); - } + let topic = sanithize_identifier(&topic); let content = format!("{content}\n\t~{author}, {date}"); store.insert(&topic, content).unwrap(); -- 2.49.0