//! Handles incoming activities, verifying HTTP signatures and other checks //! #![doc = include_str!("../../docs/08_receiving_activities.md")] use crate::{ config::Data, error::Error, http_signatures::verify_signature, parse_received_activity, traits::{ActivityHandler, Actor, Object}, }; use axum::{ async_trait, body::{Bytes, HttpBody}, extract::FromRequest, http::{Request, StatusCode}, response::{IntoResponse, Response}, }; use http::{HeaderMap, Method, Uri}; use serde::de::DeserializeOwned; use tracing::debug; /// Handles incoming activities, verifying HTTP signatures and other checks pub async fn receive_activity( activity_data: ActivityData, data: &Data, ) -> Result<(), ::Error> where Activity: ActivityHandler + DeserializeOwned + Send + 'static, ActorT: Object + Actor + Send + 'static, for<'de2> ::Kind: serde::Deserialize<'de2>, ::Error: From + From<::Error>, ::Error: From, Datatype: Clone, { let (activity, actor) = parse_received_activity::(&activity_data.body, data).await?; verify_signature( &activity_data.headers, &activity_data.method, &activity_data.uri, actor.public_key_pem(), )?; debug!("Receiving activity {}", activity.id().to_string()); activity.verify(data).await?; activity.receive(data).await?; Ok(()) } /// Contains all data that is necessary to receive an activity from an HTTP request #[derive(Debug)] pub struct ActivityData { headers: HeaderMap, method: Method, uri: Uri, body: Vec, } #[async_trait] impl FromRequest for ActivityData where Bytes: FromRequest, B: HttpBody + Send + 'static, S: Send + Sync, ::Error: std::fmt::Display, ::Data: Send, { type Rejection = Response; async fn from_request(req: Request, _state: &S) -> Result { let (parts, body) = req.into_parts(); // this wont work if the body is an long running stream let bytes = hyper::body::to_bytes(body) .await .map_err(|err| (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()).into_response())?; Ok(Self { headers: parts.headers, method: parts.method, uri: parts.uri, body: bytes.to_vec(), }) } } // TODO: copy tests from actix-web inbox and implement for axum as well