mirror of
https://github.com/LemmyNet/activitypub-federation-rust.git
synced 2024-06-03 05:49:28 +00:00
9332c81458
* feat: add actix feature flag * (WIP)feat: add axum feature * WIP: axum veridy digest + example Note: this does not compile yet * WIP * chore: clippy lints * Use actix rt for axum example * ci: run example in CI for both actix and axum * feat: add json wrapper type for axum * docs: update readme with actix and axum feature flags * fix: fix ci * chore: more clippy lints * refactor: update according to PR comment and factorize 'verify_digest'
81 lines
2.3 KiB
Rust
81 lines
2.3 KiB
Rust
use axum::{
|
|
async_trait,
|
|
body::{self, BoxBody, Bytes, Full},
|
|
extract::FromRequest,
|
|
http::{Request, StatusCode},
|
|
middleware::Next,
|
|
response::{IntoResponse, Response},
|
|
};
|
|
use digest::{verify_sha256, DigestPart};
|
|
|
|
mod digest;
|
|
pub mod inbox;
|
|
pub mod json;
|
|
|
|
/// A request guard to ensure digest has been verified request has been
|
|
/// see [`receive_activity`]
|
|
#[derive(Clone)]
|
|
pub struct DigestVerified;
|
|
|
|
pub struct BufferRequestBody(pub Bytes);
|
|
|
|
pub async fn verify_request_payload(
|
|
request: Request<BoxBody>,
|
|
next: Next<BoxBody>,
|
|
) -> Result<impl IntoResponse, Response> {
|
|
let mut request = verify_payload(request).await?;
|
|
request.extensions_mut().insert(DigestVerified);
|
|
Ok(next.run(request).await)
|
|
}
|
|
|
|
async fn verify_payload(request: Request<BoxBody>) -> Result<Request<BoxBody>, Response> {
|
|
let (parts, body) = request.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())?;
|
|
|
|
match parts.headers.get("Digest") {
|
|
None => Err((
|
|
StatusCode::UNAUTHORIZED,
|
|
"Missing digest header".to_string(),
|
|
)
|
|
.into_response()),
|
|
Some(digest) => match DigestPart::try_from_header(digest) {
|
|
None => Err((
|
|
StatusCode::UNAUTHORIZED,
|
|
"Malformed digest header".to_string(),
|
|
)
|
|
.into_response()),
|
|
Some(digests) => {
|
|
if !verify_sha256(&digests, bytes.as_ref()) {
|
|
Err((
|
|
StatusCode::INTERNAL_SERVER_ERROR,
|
|
"Digest does not match payload".to_string(),
|
|
)
|
|
.into_response())
|
|
} else {
|
|
Ok(Request::from_parts(parts, body::boxed(Full::from(bytes))))
|
|
}
|
|
}
|
|
},
|
|
}
|
|
}
|
|
|
|
#[async_trait]
|
|
impl<S> FromRequest<S, BoxBody> for BufferRequestBody
|
|
where
|
|
S: Send + Sync,
|
|
{
|
|
type Rejection = Response;
|
|
|
|
async fn from_request(req: Request<BoxBody>, state: &S) -> Result<Self, Self::Rejection> {
|
|
let body = Bytes::from_request(req, state)
|
|
.await
|
|
.map_err(IntoResponse::into_response)?;
|
|
|
|
Ok(Self(body))
|
|
}
|
|
}
|