diff --git a/upub/core/src/server/mod.rs b/upub/core/src/server/mod.rs index 4df38565..8fcefffc 100644 --- a/upub/core/src/server/mod.rs +++ b/upub/core/src/server/mod.rs @@ -7,7 +7,6 @@ pub mod inbox; pub mod init; pub mod outbox; pub mod auth; -pub mod httpsign; pub mod normalizer; pub mod side_effects; diff --git a/utils/httpsign/Cargo.toml b/utils/httpsign/Cargo.toml new file mode 100644 index 00000000..dddd9f76 --- /dev/null +++ b/utils/httpsign/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "httpsign" +version = "0.1.0" +edition = "2021" +authors = [ "alemi " ] +description = "fediverse-friendly implementation of http signaures in rust" +license = "MIT" +#keywords = ["html", "markdown", "parser"] +repository = "https://git.alemi.dev/upub.git" +readme = "README.md" + +[lib] +path = "lib.rs" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +thiserror = "1" +tracing = "0.1" +base64 = "0.22" +openssl = "0.10" # TODO handle pubkeys with a smaller crate +axum = { version = "0.7", optional = true } + +[features] +default = [] +axum = ["dep:axum"] diff --git a/utils/httpsign/README.md b/utils/httpsign/README.md new file mode 100644 index 00000000..e69de29b diff --git a/upub/core/src/server/httpsign.rs b/utils/httpsign/lib.rs similarity index 85% rename from upub/core/src/server/httpsign.rs rename to utils/httpsign/lib.rs index 47a46788..849849ac 100644 --- a/upub/core/src/server/httpsign.rs +++ b/utils/httpsign/lib.rs @@ -1,9 +1,25 @@ use std::collections::BTreeMap; -use axum::http::request::Parts; use base64::Engine; use openssl::{hash::MessageDigest, pkey::PKey, sign::Verifier}; +#[derive(Debug, thiserror::Error)] +pub enum HttpSignatureError { + #[error("openssl error: {0:?}")] + OpenSSL(#[from] openssl::error::ErrorStack), + + #[error("invalid UTF8 in key: {0:?}")] + UTF8(#[from] std::str::Utf8Error), + + #[error("os I/O error: {0}")] + IO(#[from] std::io::Error), + + #[error("invalid base64: {0}")] + Base64(#[from] base64::DecodeError), +} + +type Result = std::result::Result; + #[derive(Debug, Clone, Default)] pub struct HttpSignature { pub key_id: String, @@ -60,7 +76,8 @@ impl HttpSignature { self } - pub fn build_from_parts(&mut self, parts: &Parts) -> &mut Self { + #[cfg(feature = "axum")] + pub fn build_from_parts(&mut self, parts: &axum::http::request::Parts) -> &mut Self { let mut out = Vec::new(); for header in self.headers.iter() { match header.as_str() { @@ -82,14 +99,14 @@ impl HttpSignature { self } - pub fn verify(&self, key: &str) -> crate::Result { + pub fn verify(&self, key: &str) -> Result { let pubkey = PKey::public_key_from_pem(key.as_bytes())?; let mut verifier = Verifier::new(MessageDigest::sha256(), &pubkey)?; let signature = base64::prelude::BASE64_STANDARD.decode(&self.signature)?; Ok(verifier.verify_oneshot(&signature, self.control.as_bytes())?) } - pub fn sign(&mut self, key: &str) -> crate::Result<&str> { + pub fn sign(&mut self, key: &str) -> Result<&str> { let privkey = PKey::private_key_from_pem(key.as_bytes())?; let mut signer = openssl::sign::Signer::new(MessageDigest::sha256(), &privkey)?; signer.update(self.control.as_bytes())?; @@ -100,6 +117,9 @@ impl HttpSignature { #[cfg(test)] mod test { + + // TODO more tests!!! + #[test] fn http_signature_signs_and_verifies() { let key = openssl::rsa::Rsa::generate(2048).unwrap();