From 301cf8bc16d8845e250a07a965c030623f2cf170 Mon Sep 17 00:00:00 2001 From: aumetra Date: Thu, 7 Dec 2023 16:45:56 +0100 Subject: [PATCH] begin --- Cargo.lock | 23 ++++++++++++++++++++ Cargo.toml | 1 + lib/csurf/Cargo.toml | 13 ++++++++++++ lib/csurf/README.md | 5 +++++ lib/csurf/src/lib.rs | 50 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 92 insertions(+) create mode 100644 lib/csurf/Cargo.toml create mode 100644 lib/csurf/README.md create mode 100644 lib/csurf/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 099c9f322..b71d849fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1303,6 +1303,15 @@ dependencies = [ "syn 2.0.39", ] +[[package]] +name = "csurf" +version = "0.0.1-pre.4" +dependencies = [ + "http", + "tower", + "zeroize", +] + [[package]] name = "curl" version = "0.4.44" @@ -7358,6 +7367,20 @@ name = "zeroize" version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] [[package]] name = "zip" diff --git a/Cargo.toml b/Cargo.toml index 55e4410c3..5bcc50f56 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,6 +44,7 @@ members = [ "kitsune-cli", "kitsune-job-runner", "lib/athena", + "lib/csurf", "lib/masto-id-convert", "lib/post-process", "lib/speedy-uuid", diff --git a/lib/csurf/Cargo.toml b/lib/csurf/Cargo.toml new file mode 100644 index 000000000..b78123632 --- /dev/null +++ b/lib/csurf/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "csurf" +authors.workspace = true +edition.workspace = true +version.workspace = true + +[dependencies] +http = "0.2.11" +tower = { version = "0.4.13", default-features = false } +zeroize = { version = "1.7.0", features = ["derive"] } + +[lints] +workspace = true diff --git a/lib/csurf/README.md b/lib/csurf/README.md new file mode 100644 index 000000000..035641ce7 --- /dev/null +++ b/lib/csurf/README.md @@ -0,0 +1,5 @@ +# csurf + +Small stateless CSRF crate for tower-based frameworks + +Implements the [Signed Double-Submit Cookie](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#signed-double-submit-cookie-recommended) pattern, as recommended by OWASP. diff --git a/lib/csurf/src/lib.rs b/lib/csurf/src/lib.rs new file mode 100644 index 000000000..b00a34705 --- /dev/null +++ b/lib/csurf/src/lib.rs @@ -0,0 +1,50 @@ +use http::{Request, Response}; +use std::task::{self, Poll}; +use tower::{Layer, Service}; +use zeroize::{Zeroize, ZeroizeOnDrop}; + +#[derive(Zeroize, ZeroizeOnDrop)] +pub struct Signer {} + +#[derive(Clone, Zeroize, ZeroizeOnDrop)] +pub struct CsrfLayer { + key: Vec, +} + +impl Layer for CsrfLayer { + type Service = CsrfService; + + fn layer(&self, inner: S) -> Self::Service { + CsrfService::new(inner, self.key.clone()) + } +} + +#[derive(Clone, Zeroize, ZeroizeOnDrop)] +pub struct CsrfService { + #[zeroize(skip)] + inner: S, + key: Vec, +} + +impl CsrfService { + pub fn new(inner: S, key: Vec) -> Self { + Self { inner, key } + } +} + +impl Service> for CsrfService +where + S: Service, Response = Response>, +{ + type Error = S::Error; + type Future = S::Future; + type Response = S::Response; + + fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll> { + self.inner.poll_ready(cx) + } + + fn call(&mut self, req: Request) -> Self::Future { + self.inner.call(req) + } +}