diff --git a/crates/apub_lib/src/lib.rs b/crates/apub_lib/src/lib.rs index e3cfc0e12..349775cd7 100644 --- a/crates/apub_lib/src/lib.rs +++ b/crates/apub_lib/src/lib.rs @@ -81,6 +81,20 @@ pub fn verify_domains_match(a: &Url, b: &Url) -> Result<(), LemmyError> { Ok(()) } +pub fn verify_domains_match_opt(a: &Url, b: Option<&Url>) -> Result<(), LemmyError> { + if let Some(b2) = b { + return verify_domains_match(a, b2); + } + Ok(()) +} + +pub fn verify_urls_match(a: &Url, b: &Url) -> Result<(), LemmyError> { + if a != b { + return Err(DomainError.into()); + } + Ok(()) +} + // todo: instead of phantomdata, might use option to cache the fetched object (or just fetch on construction) pub struct ObjectId<'a, Kind>(Url, &'a PhantomData); diff --git a/crates/apub_receive/src/activities/private_message/create.rs b/crates/apub_receive/src/activities/private_message/create.rs index ac298b167..2cf732155 100644 --- a/crates/apub_receive/src/activities/private_message/create.rs +++ b/crates/apub_receive/src/activities/private_message/create.rs @@ -1,7 +1,7 @@ -use crate::activities::private_message::send_websocket_message; +use crate::activities::private_message::{send_websocket_message, verify_activity, verify_person}; use activitystreams::{activity::kind::CreateType, base::BaseExt}; -use lemmy_apub::{check_is_apub_id_valid, objects::FromApub, NoteExt}; -use lemmy_apub_lib::{verify_domains_match, ActivityCommonFields, ActivityHandlerNew}; +use lemmy_apub::{objects::FromApub, NoteExt}; +use lemmy_apub_lib::{verify_domains_match_opt, ActivityCommonFields, ActivityHandlerNew}; use lemmy_db_schema::source::private_message::PrivateMessage; use lemmy_utils::LemmyError; use lemmy_websocket::{LemmyContext, UserOperationCrud}; @@ -20,10 +20,15 @@ pub struct CreatePrivateMessage { #[async_trait::async_trait(?Send)] impl ActivityHandlerNew for CreatePrivateMessage { - async fn verify(&self, _context: &LemmyContext, _: &mut i32) -> Result<(), LemmyError> { - verify_domains_match(self.common.id_unchecked(), &self.common.actor)?; - self.object.id(self.common.actor.as_str())?; - check_is_apub_id_valid(&self.common.actor, false) + async fn verify( + &self, + context: &LemmyContext, + request_counter: &mut i32, + ) -> Result<(), LemmyError> { + verify_activity(self.common())?; + verify_person(&self.common.actor, context, request_counter).await?; + verify_domains_match_opt(&self.common.actor, self.object.id_unchecked())?; + Ok(()) } async fn receive( diff --git a/crates/apub_receive/src/activities/private_message/delete.rs b/crates/apub_receive/src/activities/private_message/delete.rs index cfb45db5b..db16a7a6a 100644 --- a/crates/apub_receive/src/activities/private_message/delete.rs +++ b/crates/apub_receive/src/activities/private_message/delete.rs @@ -1,7 +1,6 @@ -use crate::activities::private_message::send_websocket_message; +use crate::activities::private_message::{send_websocket_message, verify_activity, verify_person}; use activitystreams::activity::kind::DeleteType; use lemmy_api_common::blocking; -use lemmy_apub::check_is_apub_id_valid; use lemmy_apub_lib::{verify_domains_match, ActivityCommonFields, ActivityHandlerNew}; use lemmy_db_queries::{source::private_message::PrivateMessage_, ApubObject}; use lemmy_db_schema::source::private_message::PrivateMessage; @@ -22,10 +21,15 @@ pub struct DeletePrivateMessage { #[async_trait::async_trait(?Send)] impl ActivityHandlerNew for DeletePrivateMessage { - async fn verify(&self, _context: &LemmyContext, _: &mut i32) -> Result<(), LemmyError> { - verify_domains_match(&self.common.actor, self.common.id_unchecked())?; + async fn verify( + &self, + context: &LemmyContext, + request_counter: &mut i32, + ) -> Result<(), LemmyError> { + verify_activity(self.common())?; + verify_person(&self.common.actor, context, request_counter).await?; verify_domains_match(&self.common.actor, &self.object)?; - check_is_apub_id_valid(&self.common.actor, false) + Ok(()) } async fn receive( diff --git a/crates/apub_receive/src/activities/private_message/mod.rs b/crates/apub_receive/src/activities/private_message/mod.rs index beb28b299..12378b5e7 100644 --- a/crates/apub_receive/src/activities/private_message/mod.rs +++ b/crates/apub_receive/src/activities/private_message/mod.rs @@ -1,14 +1,38 @@ +use anyhow::anyhow; use lemmy_api_common::{blocking, person::PrivateMessageResponse}; +use lemmy_apub::{check_is_apub_id_valid, fetcher::person::get_or_fetch_and_upsert_person}; +use lemmy_apub_lib::{verify_domains_match, ActivityCommonFields}; use lemmy_db_schema::PrivateMessageId; use lemmy_db_views::{local_user_view::LocalUserView, private_message_view::PrivateMessageView}; use lemmy_utils::LemmyError; use lemmy_websocket::{messages::SendUserRoomMessage, LemmyContext, UserOperationCrud}; +use url::Url; pub mod create; pub mod delete; pub mod undo_delete; pub mod update; +/// Checks that the specified Url actually identifies a Person (by fetching it), and that the person +/// doesn't have a site ban. +async fn verify_person( + person_id: &Url, + context: &LemmyContext, + request_counter: &mut i32, +) -> Result<(), LemmyError> { + let person = get_or_fetch_and_upsert_person(person_id, context, request_counter).await?; + if person.banned { + return Err(anyhow!("Person {} is banned", person_id).into()); + } + Ok(()) +} + +fn verify_activity(common: &ActivityCommonFields) -> Result<(), LemmyError> { + check_is_apub_id_valid(&common.actor, false)?; + verify_domains_match(common.id_unchecked(), &common.actor)?; + Ok(()) +} + async fn send_websocket_message( private_message_id: PrivateMessageId, op: UserOperationCrud, diff --git a/crates/apub_receive/src/activities/private_message/undo_delete.rs b/crates/apub_receive/src/activities/private_message/undo_delete.rs index 440e79c70..3581233af 100644 --- a/crates/apub_receive/src/activities/private_message/undo_delete.rs +++ b/crates/apub_receive/src/activities/private_message/undo_delete.rs @@ -1,8 +1,17 @@ -use crate::activities::private_message::{delete::DeletePrivateMessage, send_websocket_message}; +use crate::activities::private_message::{ + delete::DeletePrivateMessage, + send_websocket_message, + verify_activity, + verify_person, +}; use activitystreams::activity::kind::UndoType; use lemmy_api_common::blocking; -use lemmy_apub::check_is_apub_id_valid; -use lemmy_apub_lib::{verify_domains_match, ActivityCommonFields, ActivityHandlerNew}; +use lemmy_apub_lib::{ + verify_domains_match, + verify_urls_match, + ActivityCommonFields, + ActivityHandlerNew, +}; use lemmy_db_queries::{source::private_message::PrivateMessage_, ApubObject}; use lemmy_db_schema::source::private_message::PrivateMessage; use lemmy_utils::LemmyError; @@ -27,10 +36,12 @@ impl ActivityHandlerNew for UndoDeletePrivateMessage { context: &LemmyContext, request_counter: &mut i32, ) -> Result<(), LemmyError> { - verify_domains_match(&self.common.actor, self.common.id_unchecked())?; - verify_domains_match(&self.common.actor, self.object.common.id_unchecked())?; - check_is_apub_id_valid(&self.common.actor, false)?; - self.object.verify(context, request_counter).await + verify_activity(self.common())?; + verify_person(&self.common.actor, context, request_counter).await?; + verify_urls_match(&self.common.actor, &self.object.common.actor)?; + verify_domains_match(&self.common.actor, &self.object.object)?; + self.object.verify(context, request_counter).await?; + Ok(()) } async fn receive( diff --git a/crates/apub_receive/src/activities/private_message/update.rs b/crates/apub_receive/src/activities/private_message/update.rs index 7c477eac6..19633ce60 100644 --- a/crates/apub_receive/src/activities/private_message/update.rs +++ b/crates/apub_receive/src/activities/private_message/update.rs @@ -1,7 +1,7 @@ -use crate::activities::private_message::send_websocket_message; +use crate::activities::private_message::{send_websocket_message, verify_activity, verify_person}; use activitystreams::{activity::kind::UpdateType, base::BaseExt}; -use lemmy_apub::{check_is_apub_id_valid, objects::FromApub, NoteExt}; -use lemmy_apub_lib::{verify_domains_match, ActivityCommonFields, ActivityHandlerNew}; +use lemmy_apub::{objects::FromApub, NoteExt}; +use lemmy_apub_lib::{verify_domains_match_opt, ActivityCommonFields, ActivityHandlerNew}; use lemmy_db_schema::source::private_message::PrivateMessage; use lemmy_utils::LemmyError; use lemmy_websocket::{LemmyContext, UserOperationCrud}; @@ -20,10 +20,15 @@ pub struct UpdatePrivateMessage { #[async_trait::async_trait(?Send)] impl ActivityHandlerNew for UpdatePrivateMessage { - async fn verify(&self, _context: &LemmyContext, _: &mut i32) -> Result<(), LemmyError> { - verify_domains_match(self.common.id_unchecked(), &self.common.actor)?; - self.object.id(self.common.actor.as_str())?; - check_is_apub_id_valid(&self.common.actor, false) + async fn verify( + &self, + context: &LemmyContext, + request_counter: &mut i32, + ) -> Result<(), LemmyError> { + verify_activity(self.common())?; + verify_person(&self.common.actor, context, request_counter).await?; + verify_domains_match_opt(&self.common.actor, self.object.id_unchecked())?; + Ok(()) } async fn receive( diff --git a/crates/apub_receive/src/http/community.rs b/crates/apub_receive/src/http/community.rs index beeb4cf0c..106eeff2f 100644 --- a/crates/apub_receive/src/http/community.rs +++ b/crates/apub_receive/src/http/community.rs @@ -56,11 +56,11 @@ pub(crate) async fn get_apub_community_http( pub async fn community_inbox( request: HttpRequest, payload: Payload, - path: web::Path, + _path: web::Path, context: web::Data, ) -> Result { let unparsed = payload_to_string(payload).await?; - receive_activity::(request, &unparsed, Some(path.0), context).await + receive_activity::(request, &unparsed, context).await } /// Returns an empty followers collection, only populating the size (for privacy). diff --git a/crates/apub_receive/src/http/mod.rs b/crates/apub_receive/src/http/mod.rs index 82700cbed..aeb8999db 100644 --- a/crates/apub_receive/src/http/mod.rs +++ b/crates/apub_receive/src/http/mod.rs @@ -50,7 +50,7 @@ pub async fn shared_inbox( context: web::Data, ) -> Result { let unparsed = payload_to_string(payload).await?; - receive_activity::(request, &unparsed, None, context).await + receive_activity::(request, &unparsed, context).await } async fn payload_to_string(mut payload: Payload) -> Result { @@ -65,7 +65,6 @@ async fn payload_to_string(mut payload: Payload) -> Result { async fn receive_activity<'a, T>( request: HttpRequest, activity: &'a str, - expected_name: Option, context: web::Data, ) -> Result where @@ -85,11 +84,6 @@ where let request_counter = &mut 0; let actor = get_or_fetch_and_upsert_actor(&activity_data.actor, &context, request_counter).await?; - if let Some(expected) = expected_name { - if expected != actor.name() { - return Ok(HttpResponse::BadRequest().finish()); - } - } verify_signature(&request, &actor.public_key().context(location_info!())?)?; activity.verify(&context, request_counter).await?; diff --git a/crates/apub_receive/src/http/person.rs b/crates/apub_receive/src/http/person.rs index b3a3b7386..59cc86970 100644 --- a/crates/apub_receive/src/http/person.rs +++ b/crates/apub_receive/src/http/person.rs @@ -48,11 +48,11 @@ pub(crate) async fn get_apub_person_http( pub async fn person_inbox( request: HttpRequest, payload: Payload, - path: web::Path, + _path: web::Path, context: web::Data, ) -> Result { let unparsed = payload_to_string(payload).await?; - receive_activity::(request, &unparsed, Some(path.0), context).await + receive_activity::(request, &unparsed, context).await } pub(crate) async fn get_apub_person_outbox(