In inbox, verify that http signature digest was verified (ref #1)

This commit is contained in:
Felix Ableitner 2022-11-14 14:06:40 +01:00
parent da32da5a67
commit 6bec924440
4 changed files with 44 additions and 28 deletions

28
Cargo.lock generated
View file

@ -631,9 +631,9 @@ dependencies = [
[[package]]
name = "futures-channel"
version = "0.3.24"
version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30bdd20c28fadd505d0fd6712cdfcb0d4b5648baf45faef7f852afb2399bb050"
checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed"
dependencies = [
"futures-core",
"futures-sink",
@ -641,9 +641,9 @@ dependencies = [
[[package]]
name = "futures-core"
version = "0.3.24"
version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e5aa3de05362c3fb88de6531e6296e85cde7739cccad4b9dfeeb7f6ebce56bf"
checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac"
[[package]]
name = "futures-executor"
@ -658,15 +658,15 @@ dependencies = [
[[package]]
name = "futures-io"
version = "0.3.24"
version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbf4d2a7a308fd4578637c0b17c7e1c7ba127b8f6ba00b29f717e9655d85eb68"
checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb"
[[package]]
name = "futures-macro"
version = "0.3.24"
version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42cd15d1c7456c04dbdf7e88bcd69760d74f3a798d6444e16974b505b0e62f17"
checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d"
dependencies = [
"proc-macro2",
"quote",
@ -675,21 +675,21 @@ dependencies = [
[[package]]
name = "futures-sink"
version = "0.3.24"
version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21b20ba5a92e727ba30e72834706623d94ac93a725410b6a6b6fbc1b07f7ba56"
checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9"
[[package]]
name = "futures-task"
version = "0.3.24"
version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6508c467c73851293f390476d4491cf4d227dbabcd4170f3bb6044959b294f1"
checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea"
[[package]]
name = "futures-util"
version = "0.3.24"
version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44fb6cb1be61cc1d2e43b262516aafcf63b241cffdb1d3fa115f91d9c7b09c90"
checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6"
dependencies = [
"futures-channel",
"futures-core",

View file

@ -16,7 +16,7 @@ use activitypub_federation::{
UrlVerifier,
APUB_JSON_CONTENT_TYPE,
};
use actix_web::{web, App, HttpRequest, HttpResponse, HttpServer};
use actix_web::{web, web::Payload, App, HttpRequest, HttpResponse, HttpServer};
use async_trait::async_trait;
use http_signature_normalization_actix::prelude::VerifyDigest;
use reqwest::Client;
@ -90,8 +90,6 @@ impl Instance {
web::scope("")
// Important: this ensures that the activity json matches the hashsum in signed
// HTTP header
// TODO: it would be possible to get rid of this by verifying hash in
// receive_activity()
.wrap(VerifyDigest::new(Sha256::new()))
// Just a single, global inbox for simplicity
.route("/inbox", web::post().to(http_post_user_inbox)),
@ -126,14 +124,13 @@ async fn http_get_user(
/// Handles messages received in user inbox
async fn http_post_user_inbox(
request: HttpRequest,
payload: String,
payload: Payload,
data: web::Data<InstanceHandle>,
) -> Result<HttpResponse, Error> {
let data: InstanceHandle = data.into_inner().deref().clone();
let activity = serde_json::from_str(&payload)?;
receive_activity::<WithContext<PersonAcceptedActivities>, MyUser, InstanceHandle>(
request,
activity,
payload,
&data.clone().local_instance,
&Data::new(data),
)

View file

@ -6,14 +6,21 @@ use crate::{
Error,
LocalInstance,
};
use actix_web::{HttpRequest, HttpResponse};
use actix_web::{
web::{Bytes, Payload},
FromRequest,
HttpRequest,
HttpResponse,
};
use anyhow::anyhow;
use http_signature_normalization_actix::prelude::DigestVerified;
use serde::de::DeserializeOwned;
use tracing::log::debug;
use tracing::{log::debug, warn};
/// Receive an activity and perform some basic checks, including HTTP signature verification.
pub async fn receive_activity<Activity, ActorT, Datatype>(
request: HttpRequest,
activity: Activity,
payload: Payload,
local_instance: &LocalInstance,
data: &Data<Datatype>,
) -> Result<HttpResponse, <Activity as ActivityHandler>::Error>
@ -21,10 +28,25 @@ where
Activity: ActivityHandler<DataType = Datatype> + DeserializeOwned + Send + 'static,
ActorT: ApubObject<DataType = Datatype> + Actor + Send + 'static,
for<'de2> <ActorT as ApubObject>::ApubType: serde::Deserialize<'de2>,
<Activity as ActivityHandler>::Error:
From<anyhow::Error> + From<Error> + From<<ActorT as ApubObject>::Error>,
<Activity as ActivityHandler>::Error: From<anyhow::Error>
+ From<Error>
+ From<<ActorT as ApubObject>::Error>
+ From<serde_json::Error>
+ From<http_signature_normalization_actix::digest::middleware::VerifyError>,
<ActorT as ApubObject>::Error: From<Error> + From<anyhow::Error>,
{
let mut payload = payload.into_inner();
// ensure that payload hash was checked against digest header by middleware
DigestVerified::from_request(&request, &mut payload).await?;
let bytes = Bytes::from_request(&request, &mut payload)
.await
.map_err(|e| {
warn!("{}", e);
anyhow!("Failed to parse request body")
})?;
let activity: Activity = serde_json::from_slice(&bytes)?;
verify_domains_match(activity.id(), activity.actor())?;
verify_url_valid(activity.id(), &local_instance.settings).await?;
if local_instance.is_local_url(activity.id()) {

View file

@ -1,3 +0,0 @@
fn main() {
println!("Hello, world!");
}