forked from alemi/upub
chore(httpsign): moved httpsign into standalone crate
This commit is contained in:
parent
5ea4940f58
commit
e7e9584783
4 changed files with 50 additions and 5 deletions
|
@ -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
26
utils/httpsign/Cargo.toml
Normal 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
0
utils/httpsign/README.md
Normal 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();
|
Loading…
Reference in a new issue