chore(httpsign): moved httpsign into standalone crate

This commit is contained in:
əlemi 2024-05-31 21:31:09 +02:00
parent 5ea4940f58
commit e7e9584783
Signed by: alemi
GPG key ID: A4895B84D311642C
4 changed files with 50 additions and 5 deletions

View file

@ -7,7 +7,6 @@ pub mod inbox;
pub mod init; pub mod init;
pub mod outbox; pub mod outbox;
pub mod auth; pub mod auth;
pub mod httpsign;
pub mod normalizer; pub mod normalizer;
pub mod side_effects; pub mod side_effects;

26
utils/httpsign/Cargo.toml Normal file
View file

@ -0,0 +1,26 @@
[package]
name = "httpsign"
version = "0.1.0"
edition = "2021"
authors = [ "alemi <me@alemi.dev>" ]
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"]

0
utils/httpsign/README.md Normal file
View file

View file

@ -1,9 +1,25 @@
use std::collections::BTreeMap; use std::collections::BTreeMap;
use axum::http::request::Parts;
use base64::Engine; use base64::Engine;
use openssl::{hash::MessageDigest, pkey::PKey, sign::Verifier}; 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<T> = std::result::Result<T, HttpSignatureError>;
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub struct HttpSignature { pub struct HttpSignature {
pub key_id: String, pub key_id: String,
@ -60,7 +76,8 @@ impl HttpSignature {
self 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(); let mut out = Vec::new();
for header in self.headers.iter() { for header in self.headers.iter() {
match header.as_str() { match header.as_str() {
@ -82,14 +99,14 @@ impl HttpSignature {
self self
} }
pub fn verify(&self, key: &str) -> crate::Result<bool> { pub fn verify(&self, key: &str) -> Result<bool> {
let pubkey = PKey::public_key_from_pem(key.as_bytes())?; let pubkey = PKey::public_key_from_pem(key.as_bytes())?;
let mut verifier = Verifier::new(MessageDigest::sha256(), &pubkey)?; let mut verifier = Verifier::new(MessageDigest::sha256(), &pubkey)?;
let signature = base64::prelude::BASE64_STANDARD.decode(&self.signature)?; let signature = base64::prelude::BASE64_STANDARD.decode(&self.signature)?;
Ok(verifier.verify_oneshot(&signature, self.control.as_bytes())?) 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 privkey = PKey::private_key_from_pem(key.as_bytes())?;
let mut signer = openssl::sign::Signer::new(MessageDigest::sha256(), &privkey)?; let mut signer = openssl::sign::Signer::new(MessageDigest::sha256(), &privkey)?;
signer.update(self.control.as_bytes())?; signer.update(self.control.as_bytes())?;
@ -100,6 +117,9 @@ impl HttpSignature {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
// TODO more tests!!!
#[test] #[test]
fn http_signature_signs_and_verifies() { fn http_signature_signs_and_verifies() {
let key = openssl::rsa::Rsa::generate(2048).unwrap(); let key = openssl::rsa::Rsa::generate(2048).unwrap();