use crate::{data::ActorCache, error::MyError, requests::Requests}; use activitystreams::primitives::XsdAnyUri; use actix_web::web; use http_signature_normalization_actix::{prelude::*, verify::DeprecatedAlgorithm}; use log::error; use rsa::{hash::Hashes, padding::PaddingScheme, PublicKey, RSAPublicKey}; use rsa_pem::KeyExt; use sha2::{Digest, Sha256}; use std::{future::Future, pin::Pin}; #[derive(Clone)] pub struct MyVerify(pub Requests, pub ActorCache); impl MyVerify { async fn verify( &self, algorithm: Option, key_id: String, signature: String, signing_string: String, ) -> Result { let mut uri: XsdAnyUri = key_id.parse()?; uri.as_url_mut().set_fragment(None); let actor = self.1.get(&uri, &self.0).await?; let was_cached = actor.is_cached(); let actor = actor.into_inner(); match algorithm { Some(Algorithm::Hs2019) => (), Some(Algorithm::Deprecated(DeprecatedAlgorithm::RsaSha256)) => (), Some(other) => { return Err(MyError::Algorithm(other.to_string())); } None => (), }; let res = do_verify(&actor.public_key, signature.clone(), signing_string.clone()).await; if let Err(e) = res { if !was_cached { return Err(e); } } else { return Ok(true); } // Previously we verified the sig from an actor's local cache // // Now we make sure we fetch an updated actor let actor = self.1.get_no_cache(&uri, &self.0).await?; do_verify(&actor.public_key, signature, signing_string).await?; Ok(true) } } async fn do_verify( public_key: &str, signature: String, signing_string: String, ) -> Result<(), MyError> { let public_key = RSAPublicKey::from_pem_pkcs8(public_key)?; web::block(move || { let decoded = base64::decode(signature)?; let hashed = Sha256::digest(signing_string.as_bytes()); public_key.verify( PaddingScheme::PKCS1v15, Some(&Hashes::SHA2_256), &hashed, &decoded, )?; Ok(()) as Result<(), MyError> }) .await?; Ok(()) } impl SignatureVerify for MyVerify { type Error = MyError; type Future = Pin>>>; fn signature_verify( &mut self, algorithm: Option, key_id: String, signature: String, signing_string: String, ) -> Self::Future { let this = self.clone(); Box::pin(async move { this.verify(algorithm, key_id, signature, signing_string) .await .map_err(|e| { error!("Failed to verify, {}", e); e }) }) } }