2023-03-05 17:17:34 -08:00
|
|
|
//! Handles incoming activities, verifying HTTP signatures and other checks
|
|
|
|
|
//!
|
|
|
|
|
#![doc = include_str!("../../docs/08_receiving_activities.md")]
|
|
|
|
|
|
2022-11-28 13:19:56 -08:00
|
|
|
use crate::{
|
2023-03-15 18:11:48 -07:00
|
|
|
config::Data,
|
2023-03-01 15:19:10 -08:00
|
|
|
error::Error,
|
2023-12-12 02:30:21 -08:00
|
|
|
http_signatures::verify_signature,
|
|
|
|
|
parse_received_activity,
|
2023-03-16 13:41:29 -07:00
|
|
|
traits::{ActivityHandler, Actor, Object},
|
2022-11-28 13:19:56 -08:00
|
|
|
};
|
2023-03-05 17:17:34 -08:00
|
|
|
use axum::{
|
2024-09-11 05:47:13 -07:00
|
|
|
body::Body,
|
2023-03-05 17:17:34 -08:00
|
|
|
extract::FromRequest,
|
|
|
|
|
http::{Request, StatusCode},
|
|
|
|
|
response::{IntoResponse, Response},
|
|
|
|
|
};
|
|
|
|
|
use http::{HeaderMap, Method, Uri};
|
2022-11-28 13:19:56 -08:00
|
|
|
use serde::de::DeserializeOwned;
|
|
|
|
|
use tracing::debug;
|
|
|
|
|
|
2023-03-02 06:18:06 -08:00
|
|
|
/// Handles incoming activities, verifying HTTP signatures and other checks
|
2022-11-28 13:19:56 -08:00
|
|
|
pub async fn receive_activity<Activity, ActorT, Datatype>(
|
2023-02-19 04:26:01 -08:00
|
|
|
activity_data: ActivityData,
|
2023-03-15 18:11:48 -07:00
|
|
|
data: &Data<Datatype>,
|
2022-11-28 13:19:56 -08:00
|
|
|
) -> Result<(), <Activity as ActivityHandler>::Error>
|
|
|
|
|
where
|
|
|
|
|
Activity: ActivityHandler<DataType = Datatype> + DeserializeOwned + Send + 'static,
|
2023-03-16 13:41:29 -07:00
|
|
|
ActorT: Object<DataType = Datatype> + Actor + Send + 'static,
|
|
|
|
|
for<'de2> <ActorT as Object>::Kind: serde::Deserialize<'de2>,
|
2023-11-20 02:42:47 -08:00
|
|
|
<Activity as ActivityHandler>::Error: From<Error> + From<<ActorT as Object>::Error>,
|
|
|
|
|
<ActorT as Object>::Error: From<Error>,
|
2023-02-19 04:26:01 -08:00
|
|
|
Datatype: Clone,
|
2022-11-28 13:19:56 -08:00
|
|
|
{
|
2023-12-12 02:30:21 -08:00
|
|
|
let (activity, actor) =
|
|
|
|
|
parse_received_activity::<Activity, ActorT, _>(&activity_data.body, data).await?;
|
2022-11-28 13:19:56 -08:00
|
|
|
|
2023-02-19 04:26:01 -08:00
|
|
|
verify_signature(
|
|
|
|
|
&activity_data.headers,
|
|
|
|
|
&activity_data.method,
|
|
|
|
|
&activity_data.uri,
|
2023-03-09 13:09:44 -08:00
|
|
|
actor.public_key_pem(),
|
2023-02-19 04:26:01 -08:00
|
|
|
)?;
|
2022-11-28 13:19:56 -08:00
|
|
|
|
|
|
|
|
debug!("Receiving activity {}", activity.id().to_string());
|
2023-03-09 13:09:44 -08:00
|
|
|
activity.verify(data).await?;
|
2023-02-11 04:32:35 -08:00
|
|
|
activity.receive(data).await?;
|
2022-11-28 13:19:56 -08:00
|
|
|
Ok(())
|
|
|
|
|
}
|
2023-02-19 04:26:01 -08:00
|
|
|
|
2023-03-05 17:17:34 -08:00
|
|
|
/// 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<u8>,
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-11 05:47:13 -07:00
|
|
|
impl<S> FromRequest<S> for ActivityData
|
2023-03-05 17:17:34 -08:00
|
|
|
where
|
|
|
|
|
S: Send + Sync,
|
|
|
|
|
{
|
|
|
|
|
type Rejection = Response;
|
|
|
|
|
|
2024-09-11 05:47:13 -07:00
|
|
|
async fn from_request(req: Request<Body>, _state: &S) -> Result<Self, Self::Rejection> {
|
2023-03-05 17:17:34 -08:00
|
|
|
let (parts, body) = req.into_parts();
|
|
|
|
|
|
|
|
|
|
// this wont work if the body is an long running stream
|
2024-09-11 05:47:13 -07:00
|
|
|
let bytes = axum::body::to_bytes(body, usize::MAX)
|
2023-03-05 17:17:34 -08:00
|
|
|
.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(),
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-19 04:26:01 -08:00
|
|
|
// TODO: copy tests from actix-web inbox and implement for axum as well
|