From 8a071b7b07000d581f28b09c11ba2f83a0e07e3a Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Tue, 29 Jun 2021 03:58:19 +0200 Subject: [PATCH] convert remaining activity receivers --- .../comment/create.rs | 4 +- .../comment/delete.rs | 8 +- .../comment/dislike.rs | 6 +- .../comment/like.rs | 6 +- .../comment/mod.rs | 0 .../comment/remove.rs | 6 +- .../comment/undo_delete.rs | 4 +- .../comment/undo_dislike.rs | 4 +- .../comment/undo_like.rs | 4 +- .../comment/undo_remove.rs | 4 +- .../comment/update.rs | 4 +- .../src/activities/community/add_mod.rs | 80 +++++++ .../src/activities/community/announce.rs | 134 +++++++++++ .../community/block_user.rs | 6 +- .../community/delete.rs | 6 +- .../community/mod.rs | 13 ++ .../community/remove.rs | 9 +- .../src/activities/community/remove_mod.rs | 69 ++++++ .../community/undo_block_user.rs | 4 +- .../community/undo_delete.rs | 4 +- .../community/undo_remove.rs | 4 +- .../community/update.rs | 4 +- .../follow/accept.rs | 4 +- .../follow/follow.rs | 4 +- .../follow/mod.rs | 0 .../follow/undo.rs | 4 +- crates/apub_receive/src/activities/mod.rs | 46 +++- .../post/create.rs | 4 +- .../post/delete.rs | 8 +- .../post/dislike.rs | 6 +- .../post/like.rs | 6 +- .../post/mod.rs | 0 .../post/remove.rs | 6 +- .../post/undo_delete.rs | 4 +- .../post/undo_dislike.rs | 4 +- .../post/undo_like.rs | 4 +- .../post/undo_remove.rs | 4 +- .../post/update.rs | 4 +- .../private_message/create.rs | 4 +- .../private_message/delete.rs | 6 +- .../private_message/mod.rs | 0 .../private_message/undo_delete.rs | 4 +- .../private_message/update.rs | 4 +- .../src/activities/receive/mod.rs | 57 ----- crates/apub_receive/src/activities_new/mod.rs | 45 ---- .../apub_receive/src/inbox/community_inbox.rs | 160 +------------ crates/apub_receive/src/inbox/mod.rs | 102 +------- .../src/inbox/new_inbox_routing.rs | 10 +- crates/apub_receive/src/inbox/person_inbox.rs | 218 +----------------- .../src/inbox/receive_for_community.rs | 214 ----------------- crates/apub_receive/src/inbox/shared_inbox.rs | 150 +----------- crates/apub_receive/src/lib.rs | 3 +- 52 files changed, 456 insertions(+), 1012 deletions(-) rename crates/apub_receive/src/{activities_new => activities}/comment/create.rs (91%) rename crates/apub_receive/src/{activities_new => activities}/comment/delete.rs (85%) rename crates/apub_receive/src/{activities_new => activities}/comment/dislike.rs (83%) rename crates/apub_receive/src/{activities_new => activities}/comment/like.rs (83%) rename crates/apub_receive/src/{activities_new => activities}/comment/mod.rs (100%) rename crates/apub_receive/src/{activities_new => activities}/comment/remove.rs (89%) rename crates/apub_receive/src/{activities_new => activities}/comment/undo_delete.rs (92%) rename crates/apub_receive/src/{activities_new => activities}/comment/undo_dislike.rs (89%) rename crates/apub_receive/src/{activities_new => activities}/comment/undo_like.rs (90%) rename crates/apub_receive/src/{activities_new => activities}/comment/undo_remove.rs (95%) rename crates/apub_receive/src/{activities_new => activities}/comment/update.rs (91%) create mode 100644 crates/apub_receive/src/activities/community/add_mod.rs create mode 100644 crates/apub_receive/src/activities/community/announce.rs rename crates/apub_receive/src/{activities_new => activities}/community/block_user.rs (91%) rename crates/apub_receive/src/{activities_new => activities}/community/delete.rs (93%) rename crates/apub_receive/src/{activities_new => activities}/community/mod.rs (77%) rename crates/apub_receive/src/{activities_new => activities}/community/remove.rs (88%) create mode 100644 crates/apub_receive/src/activities/community/remove_mod.rs rename crates/apub_receive/src/{activities_new => activities}/community/undo_block_user.rs (93%) rename crates/apub_receive/src/{activities_new => activities}/community/undo_delete.rs (97%) rename crates/apub_receive/src/{activities_new => activities}/community/undo_remove.rs (92%) rename crates/apub_receive/src/{activities_new => activities}/community/update.rs (94%) rename crates/apub_receive/src/{activities_new => activities}/follow/accept.rs (91%) rename crates/apub_receive/src/{activities_new => activities}/follow/follow.rs (95%) rename crates/apub_receive/src/{activities_new => activities}/follow/mod.rs (100%) rename crates/apub_receive/src/{activities_new => activities}/follow/undo.rs (92%) rename crates/apub_receive/src/{activities_new => activities}/post/create.rs (90%) rename crates/apub_receive/src/{activities_new => activities}/post/delete.rs (85%) rename crates/apub_receive/src/{activities_new => activities}/post/dislike.rs (83%) rename crates/apub_receive/src/{activities_new => activities}/post/like.rs (83%) rename crates/apub_receive/src/{activities_new => activities}/post/mod.rs (100%) rename crates/apub_receive/src/{activities_new => activities}/post/remove.rs (90%) rename crates/apub_receive/src/{activities_new => activities}/post/undo_delete.rs (92%) rename crates/apub_receive/src/{activities_new => activities}/post/undo_dislike.rs (90%) rename crates/apub_receive/src/{activities_new => activities}/post/undo_like.rs (90%) rename crates/apub_receive/src/{activities_new => activities}/post/undo_remove.rs (95%) rename crates/apub_receive/src/{activities_new => activities}/post/update.rs (94%) rename crates/apub_receive/src/{activities_new => activities}/private_message/create.rs (92%) rename crates/apub_receive/src/{activities_new => activities}/private_message/delete.rs (90%) rename crates/apub_receive/src/{activities_new => activities}/private_message/mod.rs (100%) rename crates/apub_receive/src/{activities_new => activities}/private_message/undo_delete.rs (92%) rename crates/apub_receive/src/{activities_new => activities}/private_message/update.rs (92%) delete mode 100644 crates/apub_receive/src/activities/receive/mod.rs delete mode 100644 crates/apub_receive/src/activities_new/mod.rs delete mode 100644 crates/apub_receive/src/inbox/receive_for_community.rs diff --git a/crates/apub_receive/src/activities_new/comment/create.rs b/crates/apub_receive/src/activities/comment/create.rs similarity index 91% rename from crates/apub_receive/src/activities_new/comment/create.rs rename to crates/apub_receive/src/activities/comment/create.rs index 1a1da075..569da807 100644 --- a/crates/apub_receive/src/activities_new/comment/create.rs +++ b/crates/apub_receive/src/activities/comment/create.rs @@ -1,5 +1,5 @@ use crate::{ - activities_new::comment::{get_notif_recipients, send_websocket_message}, + activities::comment::{get_notif_recipients, send_websocket_message}, inbox::new_inbox_routing::Activity, }; use activitystreams::{activity::kind::CreateType, base::BaseExt}; @@ -10,7 +10,7 @@ use lemmy_utils::LemmyError; use lemmy_websocket::{LemmyContext, UserOperationCrud}; use url::Url; -#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[derive(Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct CreateComment { actor: Url, diff --git a/crates/apub_receive/src/activities_new/comment/delete.rs b/crates/apub_receive/src/activities/comment/delete.rs similarity index 85% rename from crates/apub_receive/src/activities_new/comment/delete.rs rename to crates/apub_receive/src/activities/comment/delete.rs index 5c863dc3..75931d14 100644 --- a/crates/apub_receive/src/activities_new/comment/delete.rs +++ b/crates/apub_receive/src/activities/comment/delete.rs @@ -1,4 +1,4 @@ -use crate::{activities_new::comment::send_websocket_message, inbox::new_inbox_routing::Activity}; +use crate::{activities::comment::send_websocket_message, inbox::new_inbox_routing::Activity}; use activitystreams::activity::kind::DeleteType; use lemmy_api_common::blocking; use lemmy_apub::{check_is_apub_id_valid, fetcher::objects::get_or_fetch_and_insert_comment}; @@ -9,12 +9,12 @@ use lemmy_utils::LemmyError; use lemmy_websocket::{LemmyContext, UserOperationCrud}; use url::Url; -#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[derive(Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct DeleteComment { - pub(in crate::activities_new::comment) actor: Url, + pub(in crate::activities::comment) actor: Url, to: PublicUrl, - pub(in crate::activities_new::comment) object: Url, + pub(in crate::activities::comment) object: Url, cc: [Url; 1], #[serde(rename = "type")] kind: DeleteType, diff --git a/crates/apub_receive/src/activities_new/comment/dislike.rs b/crates/apub_receive/src/activities/comment/dislike.rs similarity index 83% rename from crates/apub_receive/src/activities_new/comment/dislike.rs rename to crates/apub_receive/src/activities/comment/dislike.rs index 2442105d..50aaaf66 100644 --- a/crates/apub_receive/src/activities_new/comment/dislike.rs +++ b/crates/apub_receive/src/activities/comment/dislike.rs @@ -1,4 +1,4 @@ -use crate::{activities_new::comment::like_or_dislike_comment, inbox::new_inbox_routing::Activity}; +use crate::{activities::comment::like_or_dislike_comment, inbox::new_inbox_routing::Activity}; use activitystreams::activity::kind::DislikeType; use lemmy_apub::check_is_apub_id_valid; use lemmy_apub_lib::{verify_domains_match, PublicUrl, ReceiveActivity, VerifyActivity}; @@ -6,12 +6,12 @@ use lemmy_utils::LemmyError; use lemmy_websocket::LemmyContext; use url::Url; -#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[derive(Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct DislikeComment { actor: Url, to: PublicUrl, - pub(in crate::activities_new::comment) object: Url, + pub(in crate::activities::comment) object: Url, cc: [Url; 1], #[serde(rename = "type")] kind: DislikeType, diff --git a/crates/apub_receive/src/activities_new/comment/like.rs b/crates/apub_receive/src/activities/comment/like.rs similarity index 83% rename from crates/apub_receive/src/activities_new/comment/like.rs rename to crates/apub_receive/src/activities/comment/like.rs index e90cee51..bfb1867d 100644 --- a/crates/apub_receive/src/activities_new/comment/like.rs +++ b/crates/apub_receive/src/activities/comment/like.rs @@ -1,4 +1,4 @@ -use crate::{activities_new::comment::like_or_dislike_comment, inbox::new_inbox_routing::Activity}; +use crate::{activities::comment::like_or_dislike_comment, inbox::new_inbox_routing::Activity}; use activitystreams::activity::kind::LikeType; use lemmy_apub::check_is_apub_id_valid; use lemmy_apub_lib::{verify_domains_match, PublicUrl, ReceiveActivity, VerifyActivity}; @@ -6,12 +6,12 @@ use lemmy_utils::LemmyError; use lemmy_websocket::LemmyContext; use url::Url; -#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[derive(Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct LikeComment { actor: Url, to: PublicUrl, - pub(in crate::activities_new::comment) object: Url, + pub(in crate::activities::comment) object: Url, cc: [Url; 1], #[serde(rename = "type")] kind: LikeType, diff --git a/crates/apub_receive/src/activities_new/comment/mod.rs b/crates/apub_receive/src/activities/comment/mod.rs similarity index 100% rename from crates/apub_receive/src/activities_new/comment/mod.rs rename to crates/apub_receive/src/activities/comment/mod.rs diff --git a/crates/apub_receive/src/activities_new/comment/remove.rs b/crates/apub_receive/src/activities/comment/remove.rs similarity index 89% rename from crates/apub_receive/src/activities_new/comment/remove.rs rename to crates/apub_receive/src/activities/comment/remove.rs index 38b85df0..172694eb 100644 --- a/crates/apub_receive/src/activities_new/comment/remove.rs +++ b/crates/apub_receive/src/activities/comment/remove.rs @@ -1,5 +1,5 @@ use crate::{ - activities_new::{comment::send_websocket_message, verify_mod_action}, + activities::{comment::send_websocket_message, verify_mod_action}, inbox::new_inbox_routing::Activity, }; use activitystreams::activity::kind::RemoveType; @@ -12,12 +12,12 @@ use lemmy_utils::LemmyError; use lemmy_websocket::{LemmyContext, UserOperationCrud}; use url::Url; -#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[derive(Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct RemoveComment { actor: Url, to: PublicUrl, - pub(in crate::activities_new::comment) object: Url, + pub(in crate::activities::comment) object: Url, cc: [Url; 1], #[serde(rename = "type")] kind: RemoveType, diff --git a/crates/apub_receive/src/activities_new/comment/undo_delete.rs b/crates/apub_receive/src/activities/comment/undo_delete.rs similarity index 92% rename from crates/apub_receive/src/activities_new/comment/undo_delete.rs rename to crates/apub_receive/src/activities/comment/undo_delete.rs index be233bbd..35f0ce58 100644 --- a/crates/apub_receive/src/activities_new/comment/undo_delete.rs +++ b/crates/apub_receive/src/activities/comment/undo_delete.rs @@ -1,5 +1,5 @@ use crate::{ - activities_new::comment::{delete::DeleteComment, send_websocket_message}, + activities::comment::{delete::DeleteComment, send_websocket_message}, inbox::new_inbox_routing::Activity, }; use activitystreams::activity::kind::UndoType; @@ -12,7 +12,7 @@ use lemmy_utils::LemmyError; use lemmy_websocket::{LemmyContext, UserOperationCrud}; use url::Url; -#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[derive(Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct UndoDeleteComment { actor: Url, diff --git a/crates/apub_receive/src/activities_new/comment/undo_dislike.rs b/crates/apub_receive/src/activities/comment/undo_dislike.rs similarity index 89% rename from crates/apub_receive/src/activities_new/comment/undo_dislike.rs rename to crates/apub_receive/src/activities/comment/undo_dislike.rs index 428ab663..4262e255 100644 --- a/crates/apub_receive/src/activities_new/comment/undo_dislike.rs +++ b/crates/apub_receive/src/activities/comment/undo_dislike.rs @@ -1,5 +1,5 @@ use crate::{ - activities_new::comment::{dislike::DislikeComment, undo_like_or_dislike_comment}, + activities::comment::{dislike::DislikeComment, undo_like_or_dislike_comment}, inbox::new_inbox_routing::Activity, }; use activitystreams::activity::kind::UndoType; @@ -9,7 +9,7 @@ use lemmy_utils::LemmyError; use lemmy_websocket::LemmyContext; use url::Url; -#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[derive(Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct UndoDislikeComment { actor: Url, diff --git a/crates/apub_receive/src/activities_new/comment/undo_like.rs b/crates/apub_receive/src/activities/comment/undo_like.rs similarity index 90% rename from crates/apub_receive/src/activities_new/comment/undo_like.rs rename to crates/apub_receive/src/activities/comment/undo_like.rs index c09365f6..cefa73e4 100644 --- a/crates/apub_receive/src/activities_new/comment/undo_like.rs +++ b/crates/apub_receive/src/activities/comment/undo_like.rs @@ -1,5 +1,5 @@ use crate::{ - activities_new::comment::{like::LikeComment, undo_like_or_dislike_comment}, + activities::comment::{like::LikeComment, undo_like_or_dislike_comment}, inbox::new_inbox_routing::Activity, }; use activitystreams::activity::kind::UndoType; @@ -9,7 +9,7 @@ use lemmy_utils::LemmyError; use lemmy_websocket::LemmyContext; use url::Url; -#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[derive(Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct UndoLikeComment { actor: Url, diff --git a/crates/apub_receive/src/activities_new/comment/undo_remove.rs b/crates/apub_receive/src/activities/comment/undo_remove.rs similarity index 95% rename from crates/apub_receive/src/activities_new/comment/undo_remove.rs rename to crates/apub_receive/src/activities/comment/undo_remove.rs index 63587a96..28d17f11 100644 --- a/crates/apub_receive/src/activities_new/comment/undo_remove.rs +++ b/crates/apub_receive/src/activities/comment/undo_remove.rs @@ -1,5 +1,5 @@ use crate::{ - activities_new::{ + activities::{ comment::{remove::RemoveComment, send_websocket_message}, verify_mod_action, }, @@ -15,7 +15,7 @@ use lemmy_utils::LemmyError; use lemmy_websocket::{LemmyContext, UserOperationCrud}; use url::Url; -#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[derive(Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct UndoRemoveComment { actor: Url, diff --git a/crates/apub_receive/src/activities_new/comment/update.rs b/crates/apub_receive/src/activities/comment/update.rs similarity index 91% rename from crates/apub_receive/src/activities_new/comment/update.rs rename to crates/apub_receive/src/activities/comment/update.rs index 34332192..258457f3 100644 --- a/crates/apub_receive/src/activities_new/comment/update.rs +++ b/crates/apub_receive/src/activities/comment/update.rs @@ -1,5 +1,5 @@ use crate::{ - activities_new::comment::{get_notif_recipients, send_websocket_message}, + activities::comment::{get_notif_recipients, send_websocket_message}, inbox::new_inbox_routing::Activity, }; use activitystreams::{activity::kind::UpdateType, base::BaseExt}; @@ -10,7 +10,7 @@ use lemmy_utils::LemmyError; use lemmy_websocket::{LemmyContext, UserOperationCrud}; use url::Url; -#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[derive(Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct UpdateComment { actor: Url, diff --git a/crates/apub_receive/src/activities/community/add_mod.rs b/crates/apub_receive/src/activities/community/add_mod.rs new file mode 100644 index 00000000..b260f987 --- /dev/null +++ b/crates/apub_receive/src/activities/community/add_mod.rs @@ -0,0 +1,80 @@ +use crate::{ + activities::{community::verify_add_remove_moderator_target, verify_mod_action}, + inbox::new_inbox_routing::Activity, +}; +use activitystreams::{activity::kind::AddType, base::AnyBase}; +use lemmy_api_common::blocking; +use lemmy_apub::{ + check_is_apub_id_valid, + fetcher::{community::get_or_fetch_and_upsert_community, person::get_or_fetch_and_upsert_person}, + CommunityType, +}; +use lemmy_apub_lib::{verify_domains_match, PublicUrl, ReceiveActivity, VerifyActivity}; +use lemmy_db_queries::{source::community::CommunityModerator_, Joinable}; +use lemmy_db_schema::source::community::{CommunityModerator, CommunityModeratorForm}; +use lemmy_utils::LemmyError; +use lemmy_websocket::LemmyContext; +use url::Url; + +#[derive(Debug, serde::Deserialize, serde::Serialize)] +#[serde(rename_all = "camelCase")] +pub struct AddModToCommunity { + actor: Url, + to: PublicUrl, + object: Url, + target: Url, + cc: [Url; 1], + #[serde(rename = "type")] + kind: AddType, +} + +#[async_trait::async_trait(?Send)] +impl VerifyActivity for Activity { + async fn verify(&self, context: &LemmyContext) -> Result<(), LemmyError> { + verify_domains_match(&self.inner.actor, self.id_unchecked())?; + verify_domains_match(&self.inner.target, &self.inner.cc[0])?; + check_is_apub_id_valid(&self.inner.actor, false)?; + verify_mod_action(self.inner.actor.clone(), self.inner.cc[0].clone(), context).await?; + verify_add_remove_moderator_target(&self.inner.target, self.inner.cc[0].clone()) + } +} + +#[async_trait::async_trait(?Send)] +impl ReceiveActivity for Activity { + async fn receive( + &self, + context: &LemmyContext, + request_counter: &mut i32, + ) -> Result<(), LemmyError> { + let community = + get_or_fetch_and_upsert_community(&self.inner.cc[0], context, request_counter).await?; + let new_mod = + get_or_fetch_and_upsert_person(&self.inner.object, context, request_counter).await?; + + // If we had to refetch the community while parsing the activity, then the new mod has already + // been added. Skip it here as it would result in a duplicate key error. + let new_mod_id = new_mod.id; + let moderated_communities = blocking(context.pool(), move |conn| { + CommunityModerator::get_person_moderated_communities(conn, new_mod_id) + }) + .await??; + if !moderated_communities.contains(&community.id) { + let form = CommunityModeratorForm { + community_id: community.id, + person_id: new_mod.id, + }; + blocking(context.pool(), move |conn| { + CommunityModerator::join(conn, &form) + }) + .await??; + } + if community.local { + let anybase = AnyBase::from_arbitrary_json(serde_json::to_string(self)?)?; + community + .send_announce(anybase, Some(self.inner.object.clone()), context) + .await?; + } + // TODO: send websocket notification about added mod + Ok(()) + } +} diff --git a/crates/apub_receive/src/activities/community/announce.rs b/crates/apub_receive/src/activities/community/announce.rs new file mode 100644 index 00000000..f189c011 --- /dev/null +++ b/crates/apub_receive/src/activities/community/announce.rs @@ -0,0 +1,134 @@ +use crate::{ + activities::{ + comment::{ + create::CreateComment, + delete::DeleteComment, + dislike::DislikeComment, + like::LikeComment, + remove::RemoveComment, + undo_delete::UndoDeleteComment, + undo_dislike::UndoDislikeComment, + undo_like::UndoLikeComment, + undo_remove::UndoRemoveComment, + update::UpdateComment, + }, + community::{ + block_user::BlockUserFromCommunity, + delete::DeleteCommunity, + remove::RemoveCommunity, + undo_block_user::UndoBlockUserFromCommunity, + undo_delete::UndoDeleteCommunity, + undo_remove::UndoRemoveCommunity, + update::UpdateCommunity, + }, + post::{ + create::CreatePost, + delete::DeletePost, + dislike::DislikePost, + like::LikePost, + remove::RemovePost, + undo_delete::UndoDeletePost, + undo_dislike::UndoDislikePost, + undo_like::UndoLikePost, + undo_remove::UndoRemovePost, + update::UpdatePost, + }, + }, + inbox::{is_activity_already_known, new_inbox_routing::Activity}, +}; +use activitystreams::activity::kind::RemoveType; +use lemmy_apub::check_is_apub_id_valid; +use lemmy_apub_lib::{verify_domains_match, PublicUrl, ReceiveActivity, VerifyActivity}; +use lemmy_utils::LemmyError; +use lemmy_websocket::LemmyContext; +use url::Url; + +#[derive(Debug, serde::Deserialize, serde::Serialize)] +pub enum AnnouncableActivities { + CreateComment(CreateComment), + UpdateComment(UpdateComment), + LikeComment(LikeComment), + DislikeComment(DislikeComment), + UndoLikeComment(UndoLikeComment), + UndoDislikeComment(UndoDislikeComment), + DeleteComment(DeleteComment), + UndoDeleteComment(UndoDeleteComment), + RemoveComment(RemoveComment), + UndoRemoveComment(UndoRemoveComment), + CreatePost(CreatePost), + UpdatePost(UpdatePost), + LikePost(LikePost), + DislikePost(DislikePost), + DeletePost(DeletePost), + UndoDeletePost(UndoDeletePost), + RemovePost(RemovePost), + UndoRemovePost(UndoRemovePost), + UndoLikePost(UndoLikePost), + UndoDislikePost(UndoDislikePost), + // TODO: which of these get announced? + UpdateCommunity(UpdateCommunity), + DeleteCommunity(DeleteCommunity), + RemoveCommunity(RemoveCommunity), + UndoDeleteCommunity(UndoDeleteCommunity), + UndoRemoveCommunity(UndoRemoveCommunity), + BlockUserFromCommunity(BlockUserFromCommunity), + UndoBlockUserFromCommunity(UndoBlockUserFromCommunity), +} + +#[async_trait::async_trait(?Send)] +impl VerifyActivity for AnnouncableActivities { + async fn verify(&self, context: &LemmyContext) -> Result<(), LemmyError> { + self.verify(context).await + } +} + +#[async_trait::async_trait(?Send)] +impl ReceiveActivity for AnnouncableActivities { + async fn receive( + &self, + context: &LemmyContext, + request_counter: &mut i32, + ) -> Result<(), LemmyError> { + self.receive(context, request_counter).await + } +} + +#[derive(Debug, serde::Deserialize, serde::Serialize)] +#[serde(rename_all = "camelCase")] +pub struct AnnounceActivity { + actor: Url, + to: PublicUrl, + object: Activity, + cc: [Url; 1], + #[serde(rename = "type")] + kind: RemoveType, +} + +#[async_trait::async_trait(?Send)] +impl VerifyActivity for Activity { + async fn verify(&self, context: &LemmyContext) -> Result<(), LemmyError> { + verify_domains_match(&self.inner.actor, self.id_unchecked())?; + verify_domains_match(&self.inner.actor, &self.inner.cc[0])?; + check_is_apub_id_valid(&self.inner.actor, false)?; + self.inner.object.inner.verify(context).await + } +} + +#[async_trait::async_trait(?Send)] +impl ReceiveActivity for Activity { + async fn receive( + &self, + context: &LemmyContext, + request_counter: &mut i32, + ) -> Result<(), LemmyError> { + if is_activity_already_known(context.pool(), &self.inner.object.id_unchecked()).await? { + return Ok(()); + } + self + .inner + .object + .inner + .receive(context, request_counter) + .await + } +} diff --git a/crates/apub_receive/src/activities_new/community/block_user.rs b/crates/apub_receive/src/activities/community/block_user.rs similarity index 91% rename from crates/apub_receive/src/activities_new/community/block_user.rs rename to crates/apub_receive/src/activities/community/block_user.rs index 60943219..6a2b5a40 100644 --- a/crates/apub_receive/src/activities_new/community/block_user.rs +++ b/crates/apub_receive/src/activities/community/block_user.rs @@ -1,4 +1,4 @@ -use crate::{activities_new::verify_mod_action, inbox::new_inbox_routing::Activity}; +use crate::{activities::verify_mod_action, inbox::new_inbox_routing::Activity}; use activitystreams::activity::kind::BlockType; use lemmy_api_common::blocking; use lemmy_apub::{ @@ -17,12 +17,12 @@ use lemmy_utils::LemmyError; use lemmy_websocket::LemmyContext; use url::Url; -#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[derive(Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct BlockUserFromCommunity { actor: Url, to: PublicUrl, - pub(in crate::activities_new::community) object: Url, + pub(in crate::activities::community) object: Url, cc: [Url; 1], #[serde(rename = "type")] kind: BlockType, diff --git a/crates/apub_receive/src/activities_new/community/delete.rs b/crates/apub_receive/src/activities/community/delete.rs similarity index 93% rename from crates/apub_receive/src/activities_new/community/delete.rs rename to crates/apub_receive/src/activities/community/delete.rs index 1d95f298..96757c79 100644 --- a/crates/apub_receive/src/activities_new/community/delete.rs +++ b/crates/apub_receive/src/activities/community/delete.rs @@ -1,5 +1,5 @@ use crate::{ - activities_new::community::{send_websocket_message, verify_is_community_mod}, + activities::community::{send_websocket_message, verify_is_community_mod}, inbox::new_inbox_routing::Activity, }; use activitystreams::activity::kind::DeleteType; @@ -20,12 +20,12 @@ use url::Url; // We have two possibilities which need to be handled: // 1. actor is remote mod, community id in object // 2. actor is community, cc is followers collection -#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[derive(Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct DeleteCommunity { actor: Url, to: PublicUrl, - pub(in crate::activities_new::community) object: Url, + pub(in crate::activities::community) object: Url, cc: [Url; 1], #[serde(rename = "type")] kind: DeleteType, diff --git a/crates/apub_receive/src/activities_new/community/mod.rs b/crates/apub_receive/src/activities/community/mod.rs similarity index 77% rename from crates/apub_receive/src/activities_new/community/mod.rs rename to crates/apub_receive/src/activities/community/mod.rs index 7950cde9..b8707726 100644 --- a/crates/apub_receive/src/activities_new/community/mod.rs +++ b/crates/apub_receive/src/activities/community/mod.rs @@ -1,5 +1,6 @@ use anyhow::anyhow; use lemmy_api_common::{blocking, community::CommunityResponse}; +use lemmy_apub::generate_moderators_url; use lemmy_db_queries::ApubObject; use lemmy_db_schema::{ source::{community::Community, person::Person}, @@ -10,9 +11,12 @@ use lemmy_utils::LemmyError; use lemmy_websocket::{messages::SendCommunityRoomMessage, LemmyContext}; use url::Url; +pub mod add_mod; +pub mod announce; pub mod block_user; pub mod delete; pub mod remove; +pub mod remove_mod; pub mod undo_block_user; pub mod undo_delete; pub mod undo_remove; @@ -63,3 +67,12 @@ async fn verify_is_community_mod( } Ok(()) } + +/// For Add/Remove community moderator activities, check that the target field actually contains +/// /c/community/moderators. Any different values are unsupported. +fn verify_add_remove_moderator_target(target: &Url, community: Url) -> Result<(), LemmyError> { + if target != &generate_moderators_url(&community.into())?.into_inner() { + return Err(anyhow!("Unkown target url").into()); + } + Ok(()) +} diff --git a/crates/apub_receive/src/activities_new/community/remove.rs b/crates/apub_receive/src/activities/community/remove.rs similarity index 88% rename from crates/apub_receive/src/activities_new/community/remove.rs rename to crates/apub_receive/src/activities/community/remove.rs index cc973e4b..fcc83836 100644 --- a/crates/apub_receive/src/activities_new/community/remove.rs +++ b/crates/apub_receive/src/activities/community/remove.rs @@ -1,7 +1,4 @@ -use crate::{ - activities_new::community::send_websocket_message, - inbox::new_inbox_routing::Activity, -}; +use crate::{activities::community::send_websocket_message, inbox::new_inbox_routing::Activity}; use activitystreams::activity::kind::RemoveType; use lemmy_api_common::blocking; use lemmy_apub::check_is_apub_id_valid; @@ -12,12 +9,12 @@ use lemmy_utils::LemmyError; use lemmy_websocket::{LemmyContext, UserOperationCrud}; use url::Url; -#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[derive(Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct RemoveCommunity { actor: Url, to: PublicUrl, - pub(in crate::activities_new::community) object: Url, + pub(in crate::activities::community) object: Url, cc: [Url; 1], #[serde(rename = "type")] kind: RemoveType, diff --git a/crates/apub_receive/src/activities/community/remove_mod.rs b/crates/apub_receive/src/activities/community/remove_mod.rs new file mode 100644 index 00000000..b9a5468e --- /dev/null +++ b/crates/apub_receive/src/activities/community/remove_mod.rs @@ -0,0 +1,69 @@ +use crate::{ + activities::{community::verify_add_remove_moderator_target, verify_mod_action}, + inbox::new_inbox_routing::Activity, +}; +use activitystreams::{activity::kind::RemoveType, base::AnyBase}; +use lemmy_api_common::blocking; +use lemmy_apub::{ + check_is_apub_id_valid, + fetcher::{community::get_or_fetch_and_upsert_community, person::get_or_fetch_and_upsert_person}, + CommunityType, +}; +use lemmy_apub_lib::{verify_domains_match, PublicUrl, ReceiveActivity, VerifyActivity}; +use lemmy_db_queries::Joinable; +use lemmy_db_schema::source::community::{CommunityModerator, CommunityModeratorForm}; +use lemmy_utils::LemmyError; +use lemmy_websocket::LemmyContext; +use url::Url; + +#[derive(Debug, serde::Deserialize, serde::Serialize)] +#[serde(rename_all = "camelCase")] +pub struct RemoveModToCommunity { + actor: Url, + to: PublicUrl, + object: Url, + target: Url, + cc: [Url; 1], + #[serde(rename = "type")] + kind: RemoveType, +} + +#[async_trait::async_trait(?Send)] +impl VerifyActivity for Activity { + async fn verify(&self, context: &LemmyContext) -> Result<(), LemmyError> { + verify_domains_match(&self.inner.actor, self.id_unchecked())?; + verify_domains_match(&self.inner.target, &self.inner.cc[0])?; + check_is_apub_id_valid(&self.inner.actor, false)?; + verify_mod_action(self.inner.actor.clone(), self.inner.cc[0].clone(), context).await?; + verify_add_remove_moderator_target(&self.inner.target, self.inner.cc[0].clone()) + } +} + +#[async_trait::async_trait(?Send)] +impl ReceiveActivity for Activity { + async fn receive( + &self, + context: &LemmyContext, + request_counter: &mut i32, + ) -> Result<(), LemmyError> { + let community = + get_or_fetch_and_upsert_community(&self.inner.cc[0], context, request_counter).await?; + let add_mod = + get_or_fetch_and_upsert_person(&self.inner.object, context, request_counter).await?; + + let form = CommunityModeratorForm { + community_id: community.id, + person_id: add_mod.id, + }; + blocking(context.pool(), move |conn| { + CommunityModerator::leave(conn, &form) + }) + .await??; + let anybase = AnyBase::from_arbitrary_json(serde_json::to_string(self)?)?; + community + .send_announce(anybase, Some(self.inner.object.clone()), context) + .await?; + // TODO: send websocket notification about removed mod + Ok(()) + } +} diff --git a/crates/apub_receive/src/activities_new/community/undo_block_user.rs b/crates/apub_receive/src/activities/community/undo_block_user.rs similarity index 93% rename from crates/apub_receive/src/activities_new/community/undo_block_user.rs rename to crates/apub_receive/src/activities/community/undo_block_user.rs index 14ce9089..5701474f 100644 --- a/crates/apub_receive/src/activities_new/community/undo_block_user.rs +++ b/crates/apub_receive/src/activities/community/undo_block_user.rs @@ -1,5 +1,5 @@ use crate::{ - activities_new::{community::block_user::BlockUserFromCommunity, verify_mod_action}, + activities::{community::block_user::BlockUserFromCommunity, verify_mod_action}, inbox::new_inbox_routing::Activity, }; use activitystreams::activity::kind::BlockType; @@ -15,7 +15,7 @@ use lemmy_utils::LemmyError; use lemmy_websocket::LemmyContext; use url::Url; -#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[derive(Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct UndoBlockUserFromCommunity { actor: Url, diff --git a/crates/apub_receive/src/activities_new/community/undo_delete.rs b/crates/apub_receive/src/activities/community/undo_delete.rs similarity index 97% rename from crates/apub_receive/src/activities_new/community/undo_delete.rs rename to crates/apub_receive/src/activities/community/undo_delete.rs index c4f4382e..5549f1a2 100644 --- a/crates/apub_receive/src/activities_new/community/undo_delete.rs +++ b/crates/apub_receive/src/activities/community/undo_delete.rs @@ -1,5 +1,5 @@ use crate::{ - activities_new::community::{ + activities::community::{ delete::DeleteCommunity, send_websocket_message, verify_is_community_mod, @@ -24,7 +24,7 @@ use url::Url; // We have two possibilities which need to be handled: // 1. actor is remote mod, community id in object // 2. actor is community, cc is followers collection -#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[derive(Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct UndoDeleteCommunity { actor: Url, diff --git a/crates/apub_receive/src/activities_new/community/undo_remove.rs b/crates/apub_receive/src/activities/community/undo_remove.rs similarity index 92% rename from crates/apub_receive/src/activities_new/community/undo_remove.rs rename to crates/apub_receive/src/activities/community/undo_remove.rs index 6566ae9a..0686e792 100644 --- a/crates/apub_receive/src/activities_new/community/undo_remove.rs +++ b/crates/apub_receive/src/activities/community/undo_remove.rs @@ -1,5 +1,5 @@ use crate::{ - activities_new::community::{remove::RemoveCommunity, send_websocket_message}, + activities::community::{remove::RemoveCommunity, send_websocket_message}, inbox::new_inbox_routing::Activity, }; use activitystreams::activity::kind::RemoveType; @@ -12,7 +12,7 @@ use lemmy_utils::LemmyError; use lemmy_websocket::{LemmyContext, UserOperationCrud}; use url::Url; -#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[derive(Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct UndoRemoveCommunity { actor: Url, diff --git a/crates/apub_receive/src/activities_new/community/update.rs b/crates/apub_receive/src/activities/community/update.rs similarity index 94% rename from crates/apub_receive/src/activities_new/community/update.rs rename to crates/apub_receive/src/activities/community/update.rs index 4533bde2..b938c6cd 100644 --- a/crates/apub_receive/src/activities_new/community/update.rs +++ b/crates/apub_receive/src/activities/community/update.rs @@ -1,5 +1,5 @@ use crate::{ - activities_new::community::{send_websocket_message, verify_is_community_mod}, + activities::community::{send_websocket_message, verify_is_community_mod}, inbox::new_inbox_routing::Activity, }; use activitystreams::{activity::kind::UpdateType, base::BaseExt}; @@ -14,7 +14,7 @@ use url::Url; /// This activity is received from a remote community mod, and updates the description or other /// fields of a local community. -#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[derive(Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct UpdateCommunity { actor: Url, diff --git a/crates/apub_receive/src/activities_new/follow/accept.rs b/crates/apub_receive/src/activities/follow/accept.rs similarity index 91% rename from crates/apub_receive/src/activities_new/follow/accept.rs rename to crates/apub_receive/src/activities/follow/accept.rs index f1daa37f..a077ff2b 100644 --- a/crates/apub_receive/src/activities_new/follow/accept.rs +++ b/crates/apub_receive/src/activities/follow/accept.rs @@ -1,4 +1,4 @@ -use crate::{activities_new::follow::follow::FollowCommunity, inbox::new_inbox_routing::Activity}; +use crate::{activities::follow::follow::FollowCommunity, inbox::new_inbox_routing::Activity}; use activitystreams::activity::kind::AcceptType; use lemmy_api_common::blocking; use lemmy_apub::{ @@ -12,7 +12,7 @@ use lemmy_utils::LemmyError; use lemmy_websocket::LemmyContext; use url::Url; -#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[derive(Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct AcceptFollowCommunity { actor: Url, diff --git a/crates/apub_receive/src/activities_new/follow/follow.rs b/crates/apub_receive/src/activities/follow/follow.rs similarity index 95% rename from crates/apub_receive/src/activities_new/follow/follow.rs rename to crates/apub_receive/src/activities/follow/follow.rs index 3d3664d5..92158c77 100644 --- a/crates/apub_receive/src/activities_new/follow/follow.rs +++ b/crates/apub_receive/src/activities/follow/follow.rs @@ -17,12 +17,12 @@ use lemmy_utils::{location_info, LemmyError}; use lemmy_websocket::LemmyContext; use url::Url; -#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[derive(Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct FollowCommunity { actor: Url, to: Url, - pub(in crate::activities_new::follow) object: Url, + pub(in crate::activities::follow) object: Url, #[serde(rename = "type")] kind: FollowType, } diff --git a/crates/apub_receive/src/activities_new/follow/mod.rs b/crates/apub_receive/src/activities/follow/mod.rs similarity index 100% rename from crates/apub_receive/src/activities_new/follow/mod.rs rename to crates/apub_receive/src/activities/follow/mod.rs diff --git a/crates/apub_receive/src/activities_new/follow/undo.rs b/crates/apub_receive/src/activities/follow/undo.rs similarity index 92% rename from crates/apub_receive/src/activities_new/follow/undo.rs rename to crates/apub_receive/src/activities/follow/undo.rs index 2bb93ec7..680e6b55 100644 --- a/crates/apub_receive/src/activities_new/follow/undo.rs +++ b/crates/apub_receive/src/activities/follow/undo.rs @@ -1,4 +1,4 @@ -use crate::{activities_new::follow::follow::FollowCommunity, inbox::new_inbox_routing::Activity}; +use crate::{activities::follow::follow::FollowCommunity, inbox::new_inbox_routing::Activity}; use activitystreams::activity::kind::UndoType; use lemmy_api_common::blocking; use lemmy_apub::{ @@ -12,7 +12,7 @@ use lemmy_utils::LemmyError; use lemmy_websocket::LemmyContext; use url::Url; -#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[derive(Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct UndoFollowCommunity { actor: Url, diff --git a/crates/apub_receive/src/activities/mod.rs b/crates/apub_receive/src/activities/mod.rs index cbdeafaf..daae5341 100644 --- a/crates/apub_receive/src/activities/mod.rs +++ b/crates/apub_receive/src/activities/mod.rs @@ -1 +1,45 @@ -pub(crate) mod receive; +use anyhow::anyhow; +use lemmy_api_common::blocking; +use lemmy_db_queries::ApubObject; +use lemmy_db_schema::source::{community::Community, person::Person}; +use lemmy_db_views_actor::community_view::CommunityView; +use lemmy_utils::LemmyError; +use lemmy_websocket::LemmyContext; +use url::Url; + +pub mod comment; +pub mod community; +pub mod follow; +pub mod post; +pub mod private_message; + +async fn verify_mod_action( + actor_id: Url, + activity_cc: Url, + context: &LemmyContext, +) -> Result<(), LemmyError> { + let community = blocking(context.pool(), move |conn| { + Community::read_from_apub_id(conn, &activity_cc.into()) + }) + .await??; + + if community.local { + let actor = blocking(&context.pool(), move |conn| { + Person::read_from_apub_id(&conn, &actor_id.clone().into()) + }) + .await??; + + // Note: this will also return true for admins in addition to mods, but as we dont know about + // remote admins, it doesnt make any difference. + let community_id = community.id; + let actor_id = actor.id; + let is_mod_or_admin = blocking(context.pool(), move |conn| { + CommunityView::is_mod_or_admin(conn, actor_id, community_id) + }) + .await?; + if !is_mod_or_admin { + return Err(anyhow!("Not a mod").into()); + } + } + Ok(()) +} diff --git a/crates/apub_receive/src/activities_new/post/create.rs b/crates/apub_receive/src/activities/post/create.rs similarity index 90% rename from crates/apub_receive/src/activities_new/post/create.rs rename to crates/apub_receive/src/activities/post/create.rs index ea23fae9..8fddd177 100644 --- a/crates/apub_receive/src/activities_new/post/create.rs +++ b/crates/apub_receive/src/activities/post/create.rs @@ -1,4 +1,4 @@ -use crate::{activities_new::post::send_websocket_message, inbox::new_inbox_routing::Activity}; +use crate::{activities::post::send_websocket_message, inbox::new_inbox_routing::Activity}; use activitystreams::{activity::kind::CreateType, base::BaseExt}; use lemmy_apub::{ check_is_apub_id_valid, @@ -13,7 +13,7 @@ use lemmy_utils::LemmyError; use lemmy_websocket::{LemmyContext, UserOperationCrud}; use url::Url; -#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[derive(Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct CreatePost { actor: Url, diff --git a/crates/apub_receive/src/activities_new/post/delete.rs b/crates/apub_receive/src/activities/post/delete.rs similarity index 85% rename from crates/apub_receive/src/activities_new/post/delete.rs rename to crates/apub_receive/src/activities/post/delete.rs index 8d98be31..84baa112 100644 --- a/crates/apub_receive/src/activities_new/post/delete.rs +++ b/crates/apub_receive/src/activities/post/delete.rs @@ -1,4 +1,4 @@ -use crate::{activities_new::post::send_websocket_message, inbox::new_inbox_routing::Activity}; +use crate::{activities::post::send_websocket_message, inbox::new_inbox_routing::Activity}; use activitystreams::activity::kind::DeleteType; use lemmy_api_common::blocking; use lemmy_apub::{check_is_apub_id_valid, fetcher::objects::get_or_fetch_and_insert_post}; @@ -9,12 +9,12 @@ use lemmy_utils::LemmyError; use lemmy_websocket::{LemmyContext, UserOperationCrud}; use url::Url; -#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[derive(Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct DeletePost { - pub(in crate::activities_new::post) actor: Url, + pub(in crate::activities::post) actor: Url, to: PublicUrl, - pub(in crate::activities_new::post) object: Url, + pub(in crate::activities::post) object: Url, cc: [Url; 1], #[serde(rename = "type")] kind: DeleteType, diff --git a/crates/apub_receive/src/activities_new/post/dislike.rs b/crates/apub_receive/src/activities/post/dislike.rs similarity index 83% rename from crates/apub_receive/src/activities_new/post/dislike.rs rename to crates/apub_receive/src/activities/post/dislike.rs index 272b699b..4c06aabd 100644 --- a/crates/apub_receive/src/activities_new/post/dislike.rs +++ b/crates/apub_receive/src/activities/post/dislike.rs @@ -1,4 +1,4 @@ -use crate::{activities_new::post::like_or_dislike_post, inbox::new_inbox_routing::Activity}; +use crate::{activities::post::like_or_dislike_post, inbox::new_inbox_routing::Activity}; use activitystreams::activity::kind::DislikeType; use lemmy_apub::check_is_apub_id_valid; use lemmy_apub_lib::{verify_domains_match, PublicUrl, ReceiveActivity, VerifyActivity}; @@ -6,12 +6,12 @@ use lemmy_utils::LemmyError; use lemmy_websocket::LemmyContext; use url::Url; -#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[derive(Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct DislikePost { actor: Url, to: PublicUrl, - pub(in crate::activities_new::post) object: Url, + pub(in crate::activities::post) object: Url, cc: [Url; 1], #[serde(rename = "type")] kind: DislikeType, diff --git a/crates/apub_receive/src/activities_new/post/like.rs b/crates/apub_receive/src/activities/post/like.rs similarity index 83% rename from crates/apub_receive/src/activities_new/post/like.rs rename to crates/apub_receive/src/activities/post/like.rs index 678b3e13..4a815a2f 100644 --- a/crates/apub_receive/src/activities_new/post/like.rs +++ b/crates/apub_receive/src/activities/post/like.rs @@ -1,4 +1,4 @@ -use crate::{activities_new::post::like_or_dislike_post, inbox::new_inbox_routing::Activity}; +use crate::{activities::post::like_or_dislike_post, inbox::new_inbox_routing::Activity}; use activitystreams::activity::kind::LikeType; use lemmy_apub::check_is_apub_id_valid; use lemmy_apub_lib::{verify_domains_match, PublicUrl, ReceiveActivity, VerifyActivity}; @@ -6,12 +6,12 @@ use lemmy_utils::LemmyError; use lemmy_websocket::LemmyContext; use url::Url; -#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[derive(Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct LikePost { actor: Url, to: PublicUrl, - pub(in crate::activities_new::post) object: Url, + pub(in crate::activities::post) object: Url, cc: [Url; 1], #[serde(rename = "type")] kind: LikeType, diff --git a/crates/apub_receive/src/activities_new/post/mod.rs b/crates/apub_receive/src/activities/post/mod.rs similarity index 100% rename from crates/apub_receive/src/activities_new/post/mod.rs rename to crates/apub_receive/src/activities/post/mod.rs diff --git a/crates/apub_receive/src/activities_new/post/remove.rs b/crates/apub_receive/src/activities/post/remove.rs similarity index 90% rename from crates/apub_receive/src/activities_new/post/remove.rs rename to crates/apub_receive/src/activities/post/remove.rs index 7daafe88..4bf6b708 100644 --- a/crates/apub_receive/src/activities_new/post/remove.rs +++ b/crates/apub_receive/src/activities/post/remove.rs @@ -1,5 +1,5 @@ use crate::{ - activities_new::{post::send_websocket_message, verify_mod_action}, + activities::{post::send_websocket_message, verify_mod_action}, inbox::new_inbox_routing::Activity, }; use activitystreams::activity::kind::RemoveType; @@ -12,12 +12,12 @@ use lemmy_utils::LemmyError; use lemmy_websocket::{LemmyContext, UserOperationCrud}; use url::Url; -#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[derive(Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct RemovePost { actor: Url, to: PublicUrl, - pub(in crate::activities_new::post) object: Url, + pub(in crate::activities::post) object: Url, cc: [Url; 1], #[serde(rename = "type")] kind: RemoveType, diff --git a/crates/apub_receive/src/activities_new/post/undo_delete.rs b/crates/apub_receive/src/activities/post/undo_delete.rs similarity index 92% rename from crates/apub_receive/src/activities_new/post/undo_delete.rs rename to crates/apub_receive/src/activities/post/undo_delete.rs index e57c419b..c71c6927 100644 --- a/crates/apub_receive/src/activities_new/post/undo_delete.rs +++ b/crates/apub_receive/src/activities/post/undo_delete.rs @@ -1,5 +1,5 @@ use crate::{ - activities_new::post::{delete::DeletePost, send_websocket_message}, + activities::post::{delete::DeletePost, send_websocket_message}, inbox::new_inbox_routing::Activity, }; use activitystreams::activity::kind::UndoType; @@ -12,7 +12,7 @@ use lemmy_utils::LemmyError; use lemmy_websocket::{LemmyContext, UserOperationCrud}; use url::Url; -#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[derive(Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct UndoDeletePost { actor: Url, diff --git a/crates/apub_receive/src/activities_new/post/undo_dislike.rs b/crates/apub_receive/src/activities/post/undo_dislike.rs similarity index 90% rename from crates/apub_receive/src/activities_new/post/undo_dislike.rs rename to crates/apub_receive/src/activities/post/undo_dislike.rs index 4277e2ca..e01223a6 100644 --- a/crates/apub_receive/src/activities_new/post/undo_dislike.rs +++ b/crates/apub_receive/src/activities/post/undo_dislike.rs @@ -1,5 +1,5 @@ use crate::{ - activities_new::post::{dislike::DislikePost, undo_like_or_dislike_post}, + activities::post::{dislike::DislikePost, undo_like_or_dislike_post}, inbox::new_inbox_routing::Activity, }; use activitystreams::activity::kind::UndoType; @@ -9,7 +9,7 @@ use lemmy_utils::LemmyError; use lemmy_websocket::LemmyContext; use url::Url; -#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[derive(Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct UndoDislikePost { actor: Url, diff --git a/crates/apub_receive/src/activities_new/post/undo_like.rs b/crates/apub_receive/src/activities/post/undo_like.rs similarity index 90% rename from crates/apub_receive/src/activities_new/post/undo_like.rs rename to crates/apub_receive/src/activities/post/undo_like.rs index 04a71f8b..7079b1f1 100644 --- a/crates/apub_receive/src/activities_new/post/undo_like.rs +++ b/crates/apub_receive/src/activities/post/undo_like.rs @@ -1,5 +1,5 @@ use crate::{ - activities_new::post::{like::LikePost, undo_like_or_dislike_post}, + activities::post::{like::LikePost, undo_like_or_dislike_post}, inbox::new_inbox_routing::Activity, }; use activitystreams::activity::kind::UndoType; @@ -9,7 +9,7 @@ use lemmy_utils::LemmyError; use lemmy_websocket::LemmyContext; use url::Url; -#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[derive(Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct UndoLikePost { actor: Url, diff --git a/crates/apub_receive/src/activities_new/post/undo_remove.rs b/crates/apub_receive/src/activities/post/undo_remove.rs similarity index 95% rename from crates/apub_receive/src/activities_new/post/undo_remove.rs rename to crates/apub_receive/src/activities/post/undo_remove.rs index 891c32d6..d22a7248 100644 --- a/crates/apub_receive/src/activities_new/post/undo_remove.rs +++ b/crates/apub_receive/src/activities/post/undo_remove.rs @@ -1,5 +1,5 @@ use crate::{ - activities_new::{ + activities::{ post::{remove::RemovePost, send_websocket_message}, verify_mod_action, }, @@ -15,7 +15,7 @@ use lemmy_utils::LemmyError; use lemmy_websocket::{LemmyContext, UserOperationCrud}; use url::Url; -#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[derive(Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct UndoRemovePost { actor: Url, diff --git a/crates/apub_receive/src/activities_new/post/update.rs b/crates/apub_receive/src/activities/post/update.rs similarity index 94% rename from crates/apub_receive/src/activities_new/post/update.rs rename to crates/apub_receive/src/activities/post/update.rs index 5ccbce19..9bd2fa73 100644 --- a/crates/apub_receive/src/activities_new/post/update.rs +++ b/crates/apub_receive/src/activities/post/update.rs @@ -1,4 +1,4 @@ -use crate::{activities_new::post::send_websocket_message, inbox::new_inbox_routing::Activity}; +use crate::{activities::post::send_websocket_message, inbox::new_inbox_routing::Activity}; use activitystreams::{activity::kind::UpdateType, base::BaseExt}; use anyhow::Context; use lemmy_api_common::blocking; @@ -22,7 +22,7 @@ use lemmy_utils::{location_info, LemmyError}; use lemmy_websocket::{LemmyContext, UserOperationCrud}; use url::Url; -#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[derive(Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct UpdatePost { actor: Url, diff --git a/crates/apub_receive/src/activities_new/private_message/create.rs b/crates/apub_receive/src/activities/private_message/create.rs similarity index 92% rename from crates/apub_receive/src/activities_new/private_message/create.rs rename to crates/apub_receive/src/activities/private_message/create.rs index 3a87472e..5f973e15 100644 --- a/crates/apub_receive/src/activities_new/private_message/create.rs +++ b/crates/apub_receive/src/activities/private_message/create.rs @@ -1,5 +1,5 @@ use crate::{ - activities_new::private_message::send_websocket_message, + activities::private_message::send_websocket_message, inbox::new_inbox_routing::Activity, }; use activitystreams::{activity::kind::CreateType, base::BaseExt}; @@ -10,7 +10,7 @@ use lemmy_utils::LemmyError; use lemmy_websocket::{LemmyContext, UserOperationCrud}; use url::Url; -#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[derive(Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct CreatePrivateMessage { actor: Url, diff --git a/crates/apub_receive/src/activities_new/private_message/delete.rs b/crates/apub_receive/src/activities/private_message/delete.rs similarity index 90% rename from crates/apub_receive/src/activities_new/private_message/delete.rs rename to crates/apub_receive/src/activities/private_message/delete.rs index 1e8cc352..68654bd4 100644 --- a/crates/apub_receive/src/activities_new/private_message/delete.rs +++ b/crates/apub_receive/src/activities/private_message/delete.rs @@ -1,5 +1,5 @@ use crate::{ - activities_new::private_message::send_websocket_message, + activities::private_message::send_websocket_message, inbox::new_inbox_routing::Activity, }; use activitystreams::activity::kind::DeleteType; @@ -12,12 +12,12 @@ use lemmy_utils::LemmyError; use lemmy_websocket::{LemmyContext, UserOperationCrud}; use url::Url; -#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[derive(Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct DeletePrivateMessage { actor: Url, to: Url, - pub(in crate::activities_new::private_message) object: Url, + pub(in crate::activities::private_message) object: Url, #[serde(rename = "type")] kind: DeleteType, } diff --git a/crates/apub_receive/src/activities_new/private_message/mod.rs b/crates/apub_receive/src/activities/private_message/mod.rs similarity index 100% rename from crates/apub_receive/src/activities_new/private_message/mod.rs rename to crates/apub_receive/src/activities/private_message/mod.rs diff --git a/crates/apub_receive/src/activities_new/private_message/undo_delete.rs b/crates/apub_receive/src/activities/private_message/undo_delete.rs similarity index 92% rename from crates/apub_receive/src/activities_new/private_message/undo_delete.rs rename to crates/apub_receive/src/activities/private_message/undo_delete.rs index 3fde4914..63a0ee5c 100644 --- a/crates/apub_receive/src/activities_new/private_message/undo_delete.rs +++ b/crates/apub_receive/src/activities/private_message/undo_delete.rs @@ -1,5 +1,5 @@ use crate::{ - activities_new::private_message::{delete::DeletePrivateMessage, send_websocket_message}, + activities::private_message::{delete::DeletePrivateMessage, send_websocket_message}, inbox::new_inbox_routing::Activity, }; use activitystreams::activity::kind::UndoType; @@ -12,7 +12,7 @@ use lemmy_utils::LemmyError; use lemmy_websocket::{LemmyContext, UserOperationCrud}; use url::Url; -#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[derive(Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct UndoDeletePrivateMessage { actor: Url, diff --git a/crates/apub_receive/src/activities_new/private_message/update.rs b/crates/apub_receive/src/activities/private_message/update.rs similarity index 92% rename from crates/apub_receive/src/activities_new/private_message/update.rs rename to crates/apub_receive/src/activities/private_message/update.rs index e28e1d81..398ed070 100644 --- a/crates/apub_receive/src/activities_new/private_message/update.rs +++ b/crates/apub_receive/src/activities/private_message/update.rs @@ -1,5 +1,5 @@ use crate::{ - activities_new::private_message::send_websocket_message, + activities::private_message::send_websocket_message, inbox::new_inbox_routing::Activity, }; use activitystreams::{activity::kind::UpdateType, base::BaseExt}; @@ -10,7 +10,7 @@ use lemmy_utils::LemmyError; use lemmy_websocket::{LemmyContext, UserOperationCrud}; use url::Url; -#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[derive(Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct UpdatePrivateMessage { actor: Url, diff --git a/crates/apub_receive/src/activities/receive/mod.rs b/crates/apub_receive/src/activities/receive/mod.rs deleted file mode 100644 index 8b085cda..00000000 --- a/crates/apub_receive/src/activities/receive/mod.rs +++ /dev/null @@ -1,57 +0,0 @@ -use activitystreams::{ - activity::{ActorAndObjectRef, ActorAndObjectRefExt}, - base::{AsBase, BaseExt}, - error::DomainError, -}; -use anyhow::{anyhow, Context}; -use lemmy_utils::{location_info, LemmyError}; -use log::debug; -use std::fmt::Debug; -use url::Url; - -/// Return HTTP 501 for unsupported activities in inbox. -pub(crate) fn receive_unhandled_activity(activity: A) -> Result<(), LemmyError> -where - A: Debug, -{ - debug!("received unhandled activity type: {:?}", activity); - Err(anyhow!("Activity not supported").into()) -} - -/// Ensure that the ID of an incoming activity comes from the same domain as the actor. Optionally -/// also checks the ID of the inner object. -/// -/// The reason that this starts with the actor ID is that it was already confirmed as correct by the -/// HTTP signature. -pub(crate) fn verify_activity_domains_valid( - activity: &T, - actor_id: &Url, - object_domain_must_match: bool, -) -> Result<(), LemmyError> -where - T: AsBase + ActorAndObjectRef, -{ - let expected_domain = actor_id.domain().context(location_info!())?; - - activity.id(expected_domain)?; - - let object_id = match activity.object().to_owned().single_xsd_any_uri() { - // object is just an ID - Some(id) => id, - // object is something like an activity, a comment or a post - None => activity - .object() - .to_owned() - .one() - .context(location_info!())? - .id() - .context(location_info!())? - .to_owned(), - }; - - if object_domain_must_match && object_id.domain() != Some(expected_domain) { - return Err(DomainError.into()); - } - - Ok(()) -} diff --git a/crates/apub_receive/src/activities_new/mod.rs b/crates/apub_receive/src/activities_new/mod.rs deleted file mode 100644 index daae5341..00000000 --- a/crates/apub_receive/src/activities_new/mod.rs +++ /dev/null @@ -1,45 +0,0 @@ -use anyhow::anyhow; -use lemmy_api_common::blocking; -use lemmy_db_queries::ApubObject; -use lemmy_db_schema::source::{community::Community, person::Person}; -use lemmy_db_views_actor::community_view::CommunityView; -use lemmy_utils::LemmyError; -use lemmy_websocket::LemmyContext; -use url::Url; - -pub mod comment; -pub mod community; -pub mod follow; -pub mod post; -pub mod private_message; - -async fn verify_mod_action( - actor_id: Url, - activity_cc: Url, - context: &LemmyContext, -) -> Result<(), LemmyError> { - let community = blocking(context.pool(), move |conn| { - Community::read_from_apub_id(conn, &activity_cc.into()) - }) - .await??; - - if community.local { - let actor = blocking(&context.pool(), move |conn| { - Person::read_from_apub_id(&conn, &actor_id.clone().into()) - }) - .await??; - - // Note: this will also return true for admins in addition to mods, but as we dont know about - // remote admins, it doesnt make any difference. - let community_id = community.id; - let actor_id = actor.id; - let is_mod_or_admin = blocking(context.pool(), move |conn| { - CommunityView::is_mod_or_admin(conn, actor_id, community_id) - }) - .await?; - if !is_mod_or_admin { - return Err(anyhow!("Not a mod").into()); - } - } - Ok(()) -} diff --git a/crates/apub_receive/src/inbox/community_inbox.rs b/crates/apub_receive/src/inbox/community_inbox.rs index 3996cb8f..310b0809 100644 --- a/crates/apub_receive/src/inbox/community_inbox.rs +++ b/crates/apub_receive/src/inbox/community_inbox.rs @@ -1,160 +1,14 @@ -use crate::inbox::{ - assert_activity_not_local, - get_activity_id, - inbox_verify_http_signature, - is_activity_already_known, - receive_for_community::receive_add_for_community, - verify_is_addressed_to_public, -}; -use activitystreams::{activity::ActorAndObject, prelude::*}; +use crate::inbox::new_inbox_routing::{Activity, SharedInboxActivities}; use actix_web::{web, HttpRequest, HttpResponse}; -use anyhow::{anyhow, Context}; -use lemmy_api_common::blocking; -use lemmy_apub::{ - check_community_or_site_ban, - get_activity_to_and_cc, - insert_activity, - ActorType, - CommunityType, -}; -use lemmy_db_queries::{source::community::Community_, ApubObject}; -use lemmy_db_schema::source::{community::Community, person::Person}; -use lemmy_utils::{location_info, LemmyError}; +use lemmy_utils::LemmyError; use lemmy_websocket::LemmyContext; -use log::info; -use serde::{Deserialize, Serialize}; -use std::fmt::Debug; - -/// Allowed activities for community inbox. -#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Deserialize, Serialize)] -#[serde(rename_all = "PascalCase")] -pub enum CommunityValidTypes { - Follow, // follow request from a person - Undo, // unfollow from a person - Create, // create post or comment - Update, // update post or comment - Like, // upvote post or comment - Dislike, // downvote post or comment - Delete, // post or comment deleted by creator - Remove, // post or comment removed by mod or admin, or mod removed from community - Add, // mod added to community - Block, // user blocked by community -} - -pub type CommunityAcceptedActivities = ActorAndObject; /// Handler for all incoming receive to community inboxes. pub async fn community_inbox( - request: HttpRequest, - input: web::Json, - path: web::Path, - context: web::Data, + _request: HttpRequest, + _input: web::Json>>, + _path: web::Path, + _context: web::Data, ) -> Result { - let activity = input.into_inner(); - // First of all check the http signature - let request_counter = &mut 0; - let actor = inbox_verify_http_signature(&activity, &context, request, request_counter).await?; - - // Do nothing if we received the same activity before - let activity_id = get_activity_id(&activity, &actor.actor_id())?; - if is_activity_already_known(context.pool(), &activity_id).await? { - return Ok(HttpResponse::Ok().finish()); - } - - // Check if the activity is actually meant for us - let path = path.into_inner(); - let community = blocking(&context.pool(), move |conn| { - Community::read_from_name(&conn, &path) - }) - .await??; - let to_and_cc = get_activity_to_and_cc(&activity); - if !to_and_cc.contains(&&community.actor_id()) { - return Err(anyhow!("Activity delivered to wrong community").into()); - } - - assert_activity_not_local(&activity)?; - insert_activity(&activity_id, activity.clone(), false, true, context.pool()).await?; - - community_receive_message( - activity.clone(), - community.clone(), - actor.as_ref(), - &context, - request_counter, - ) - .await -} - -/// Receives Follow, Undo/Follow, post actions, comment actions (including votes) -pub(crate) async fn community_receive_message( - activity: CommunityAcceptedActivities, - to_community: Community, - actor: &dyn ActorType, - context: &LemmyContext, - request_counter: &mut i32, -) -> Result { - // Only persons can send activities to the community, so we can get the actor as person - // unconditionally. - let actor_id = actor.actor_id(); - let person = blocking(&context.pool(), move |conn| { - Person::read_from_apub_id(&conn, &actor_id.into()) - }) - .await??; - check_community_or_site_ban(&person, to_community.id, context.pool()).await?; - - info!( - "Community {} received activity {} from {}", - to_community.name, - &activity - .id_unchecked() - .context(location_info!())? - .to_string(), - &person.actor_id().to_string() - ); - - let any_base = activity.clone().into_any_base()?; - let activity_kind = activity.kind().context(location_info!())?; - let do_announce = match activity_kind { - CommunityValidTypes::Follow => todo!(), - CommunityValidTypes::Undo => todo!(), - CommunityValidTypes::Create => todo!(), - CommunityValidTypes::Update => todo!(), - CommunityValidTypes::Like => todo!(), - CommunityValidTypes::Dislike => todo!(), - CommunityValidTypes::Delete => todo!(), - CommunityValidTypes::Add => { - Box::pin(receive_add_for_community( - context, - any_base.clone(), - None, - request_counter, - )) - .await?; - true - } - CommunityValidTypes::Remove => todo!(), - CommunityValidTypes::Block => todo!(), - }; - - if do_announce { - // Check again that the activity is public, just to be sure - verify_is_addressed_to_public(&activity)?; - let mut object_actor = activity.object().clone().single_xsd_any_uri(); - // If activity is something like Undo/Block, we need to access activity.object.object - if object_actor.is_none() { - object_actor = activity - .object() - .as_one() - .map(|a| ActorAndObject::from_any_base(a.to_owned()).ok()) - .flatten() - .flatten() - .map(|a: ActorAndObject| a.object().to_owned().single_xsd_any_uri()) - .flatten(); - } - to_community - .send_announce(activity.into_any_base()?, object_actor, context) - .await?; - } - - Ok(HttpResponse::Ok().finish()) + todo!() } diff --git a/crates/apub_receive/src/inbox/mod.rs b/crates/apub_receive/src/inbox/mod.rs index 3a940bfe..0e541b2f 100644 --- a/crates/apub_receive/src/inbox/mod.rs +++ b/crates/apub_receive/src/inbox/mod.rs @@ -1,48 +1,29 @@ use activitystreams::{ activity::ActorAndObjectRefExt, - base::{AsBase, BaseExt, Extends}, + base::{AsBase, Extends}, object::AsObject, - public, }; use actix_web::HttpRequest; -use anyhow::{anyhow, Context}; +use anyhow::Context; use lemmy_api_common::blocking; use lemmy_apub::{ check_is_apub_id_valid, extensions::signatures::verify_signature, fetcher::get_or_fetch_and_upsert_actor, - get_activity_to_and_cc, ActorType, }; -use lemmy_db_queries::{ - source::{activity::Activity_, community::Community_}, - ApubObject, - DbPool, -}; -use lemmy_db_schema::source::{activity::Activity, community::Community, person::Person}; -use lemmy_utils::{location_info, settings::structs::Settings, LemmyError}; +use lemmy_db_queries::{source::activity::Activity_, DbPool}; +use lemmy_db_schema::source::activity::Activity; +use lemmy_utils::{location_info, LemmyError}; use lemmy_websocket::LemmyContext; use serde::Serialize; -use std::fmt::Debug; use url::Url; pub mod community_inbox; pub mod new_inbox_routing; pub mod person_inbox; -pub(crate) mod receive_for_community; pub mod shared_inbox; -pub(crate) fn get_activity_id(activity: &T, creator_uri: &Url) -> Result -where - T: BaseExt + Extends + Debug, - Kind: Serialize, - >::Error: From + Send + Sync + 'static, -{ - let creator_domain = creator_uri.host_str().context(location_info!())?; - let activity_id = activity.id(creator_domain)?; - Ok(activity_id.context(location_info!())?.to_owned()) -} - pub(crate) async fn is_activity_already_known( pool: &DbPool, activity_id: &Url, @@ -58,18 +39,6 @@ pub(crate) async fn is_activity_already_known( } } -pub(crate) fn verify_is_addressed_to_public(activity: &T) -> Result<(), LemmyError> -where - T: AsBase + AsObject + ActorAndObjectRefExt, -{ - let to_and_cc = get_activity_to_and_cc(activity); - if to_and_cc.contains(&public()) { - Ok(()) - } else { - Err(anyhow!("Activity is not addressed to public").into()) - } -} - pub(crate) async fn inbox_verify_http_signature( activity: &T, context: &LemmyContext, @@ -91,64 +60,3 @@ where verify_signature(&request, actor.as_ref())?; Ok(actor) } - -/// Returns true if `to_and_cc` contains at least one local user. -pub(crate) async fn is_addressed_to_local_person( - to_and_cc: &[Url], - pool: &DbPool, -) -> Result { - for url in to_and_cc { - let url = url.to_owned(); - let person = blocking(&pool, move |conn| { - Person::read_from_apub_id(&conn, &url.into()) - }) - .await?; - if let Ok(u) = person { - if u.local { - return Ok(true); - } - } - } - Ok(false) -} - -/// If `to_and_cc` contains the followers collection of a remote community, returns this community -/// (like `https://example.com/c/main/followers`) -pub(crate) async fn is_addressed_to_community_followers( - to_and_cc: &[Url], - pool: &DbPool, -) -> Result, LemmyError> { - for url in to_and_cc { - let url = url.to_owned().into(); - let community = blocking(&pool, move |conn| { - // ignore errors here, because the current url might not actually be a followers url - Community::read_from_followers_url(&conn, &url).ok() - }) - .await?; - if let Some(c) = community { - if !c.local { - return Ok(Some(c)); - } - } - } - Ok(None) -} - -pub(in crate::inbox) fn assert_activity_not_local(activity: &T) -> Result<(), LemmyError> -where - T: BaseExt + Debug, -{ - let id = activity.id_unchecked().context(location_info!())?; - let activity_domain = id.domain().context(location_info!())?; - - if activity_domain == Settings::get().hostname() { - return Err( - anyhow!( - "Error: received activity which was sent by local instance: {:?}", - activity - ) - .into(), - ); - } - Ok(()) -} diff --git a/crates/apub_receive/src/inbox/new_inbox_routing.rs b/crates/apub_receive/src/inbox/new_inbox_routing.rs index 83bfec1f..615d54a1 100644 --- a/crates/apub_receive/src/inbox/new_inbox_routing.rs +++ b/crates/apub_receive/src/inbox/new_inbox_routing.rs @@ -1,4 +1,4 @@ -use crate::activities_new::{ +use crate::activities::{ comment::{ create::CreateComment, delete::DeleteComment, @@ -12,8 +12,11 @@ use crate::activities_new::{ update::UpdateComment, }, community::{ + announce::AnnounceActivity, + block_user::BlockUserFromCommunity, delete::DeleteCommunity, remove::RemoveCommunity, + undo_block_user::UndoBlockUserFromCommunity, undo_delete::UndoDeleteCommunity, undo_remove::UndoRemoveCommunity, update::UpdateCommunity, @@ -68,7 +71,7 @@ impl Activity { } } -#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[derive(Debug, serde::Deserialize, serde::Serialize)] pub enum SharedInboxActivities { FollowCommunity(FollowCommunity), AcceptFollowCommunity(AcceptFollowCommunity), @@ -97,11 +100,14 @@ pub enum SharedInboxActivities { UndoRemovePost(UndoRemovePost), UndoLikePost(UndoLikePost), UndoDislikePost(UndoDislikePost), + AnnounceActivity(AnnounceActivity), UpdateCommunity(UpdateCommunity), DeleteCommunity(DeleteCommunity), RemoveCommunity(RemoveCommunity), UndoDeleteCommunity(UndoDeleteCommunity), UndoRemoveCommunity(UndoRemoveCommunity), + BlockUserFromCommunity(BlockUserFromCommunity), + UndoBlockUserFromCommunity(UndoBlockUserFromCommunity), } // todo: can probably get rid of these? diff --git a/crates/apub_receive/src/inbox/person_inbox.rs b/crates/apub_receive/src/inbox/person_inbox.rs index e8111156..e53b6f02 100644 --- a/crates/apub_receive/src/inbox/person_inbox.rs +++ b/crates/apub_receive/src/inbox/person_inbox.rs @@ -1,223 +1,13 @@ -use crate::{ - activities::receive::{receive_unhandled_activity, verify_activity_domains_valid}, - inbox::{ - is_activity_already_known, - is_addressed_to_community_followers, - is_addressed_to_local_person, - new_inbox_routing::{Activity, SharedInboxActivities}, - receive_for_community::receive_add_for_community, - verify_is_addressed_to_public, - }, -}; -use activitystreams::{ - activity::{ActorAndObject, Announce}, - base::AnyBase, - prelude::*, -}; +use crate::inbox::new_inbox_routing::{Activity, SharedInboxActivities}; use actix_web::{web, HttpRequest, HttpResponse}; -use anyhow::{anyhow, Context}; -use lemmy_api_common::blocking; -use lemmy_apub::{check_is_apub_id_valid, get_activity_to_and_cc, ActorType}; -use lemmy_apub_lib::{ReceiveActivity, VerifyActivity}; -use lemmy_db_queries::Followable; -use lemmy_db_schema::source::{community::CommunityFollower, person::Person}; -use lemmy_utils::{location_info, LemmyError}; +use lemmy_utils::LemmyError; use lemmy_websocket::LemmyContext; -use log::info; -use serde::{Deserialize, Serialize}; -use std::fmt::Debug; -use strum_macros::EnumString; -/// Allowed activities for person inbox. -#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Deserialize, Serialize)] -#[serde(rename_all = "PascalCase")] -pub enum PersonValidTypes { - Accept, // community accepted our follow request - Create, // create private message - Update, // edit private message - Delete, // private message or community deleted by creator - Undo, // private message or community restored - Remove, // community removed by admin - Announce, // post, comment or vote in community -} - -pub type PersonAcceptedActivities = ActorAndObject; - -/// Handler for all incoming activities to person inboxes. pub async fn person_inbox( _request: HttpRequest, - input: web::Json>, + _input: web::Json>>, _path: web::Path, - context: web::Data, + _context: web::Data, ) -> Result { - let activity = input.into_inner(); - activity.inner.verify(&context).await?; - let request_counter = &mut 0; - activity.inner.receive(&context, request_counter).await?; todo!() - /* - // First of all check the http signature - let request_counter = &mut 0; - let actor = inbox_verify_http_signature(&activity, &context, request, request_counter).await?; - - // Do nothing if we received the same activity before - let activity_id = get_activity_id(&activity, &actor.actor_id())?; - if is_activity_already_known(context.pool(), &activity_id).await? { - return Ok(HttpResponse::Ok().finish()); - } - - // Check if the activity is actually meant for us - let username = path.into_inner(); - let person = blocking(&context.pool(), move |conn| { - Person::find_by_name(&conn, &username) - }) - .await??; - let to_and_cc = get_activity_to_and_cc(&activity); - // TODO: we should also accept activities that are sent to community followers - if !to_and_cc.contains(&&person.actor_id()) { - return Err(anyhow!("Activity delivered to wrong person").into()); - } - - assert_activity_not_local(&activity)?; - insert_activity(&activity_id, activity.clone(), false, true, context.pool()).await?; - - person_receive_message( - activity.clone(), - Some(person.clone()), - actor.as_ref(), - &context, - request_counter, - ) - .await - */ -} - -/// Receives Accept/Follow, Announce, private messages and community (undo) remove, (undo) delete -pub(crate) async fn person_receive_message( - activity: PersonAcceptedActivities, - _to_person: Option, - actor: &dyn ActorType, - context: &LemmyContext, - request_counter: &mut i32, -) -> Result { - is_for_person_inbox(context, &activity).await?; - - info!( - "User received activity {:?} from {}", - &activity - .id_unchecked() - .context(location_info!())? - .to_string(), - &actor.actor_id().to_string() - ); - - let any_base = activity.clone().into_any_base()?; - let kind = activity.kind().context(location_info!())?; - match kind { - PersonValidTypes::Accept => {} - PersonValidTypes::Announce => { - Box::pin(receive_announce(&context, any_base, actor, request_counter)).await? - } - PersonValidTypes::Create => {} - PersonValidTypes::Update => {} - PersonValidTypes::Delete => todo!(), - PersonValidTypes::Undo => todo!(), - PersonValidTypes::Remove => todo!(), - }; - - // TODO: would be logical to move websocket notification code here - - Ok(HttpResponse::Ok().finish()) -} - -/// Returns true if the activity is addressed directly to one or more local persons, or if it is -/// addressed to the followers collection of a remote community, and at least one local person follows -/// it. -async fn is_for_person_inbox( - context: &LemmyContext, - activity: &PersonAcceptedActivities, -) -> Result<(), LemmyError> { - let to_and_cc = get_activity_to_and_cc(activity); - // Check if it is addressed directly to any local person - if is_addressed_to_local_person(&to_and_cc, context.pool()).await? { - return Ok(()); - } - - // Check if it is addressed to any followers collection of a remote community, and that the - // community has local followers. - let community = is_addressed_to_community_followers(&to_and_cc, context.pool()).await?; - if let Some(c) = community { - let community_id = c.id; - let has_local_followers = blocking(&context.pool(), move |conn| { - CommunityFollower::has_local_followers(conn, community_id) - }) - .await??; - if c.local { - return Err( - anyhow!("Remote activity cant be addressed to followers of local community").into(), - ); - } - if has_local_followers { - return Ok(()); - } - } - - Err(anyhow!("Not addressed for any local person").into()) -} - -#[derive(EnumString)] -enum AnnouncableActivities { - Create, - Update, - Like, - Dislike, - Delete, - Remove, - Undo, - Add, - Block, -} - -/// Takes an announce and passes the inner activity to the appropriate handler. -pub async fn receive_announce( - context: &LemmyContext, - activity: AnyBase, - actor: &dyn ActorType, - request_counter: &mut i32, -) -> Result<(), LemmyError> { - let announce = Announce::from_any_base(activity)?.context(location_info!())?; - verify_activity_domains_valid(&announce, &actor.actor_id(), false)?; - verify_is_addressed_to_public(&announce)?; - - let kind = announce - .object() - .as_single_kind_str() - .and_then(|s| s.parse().ok()); - let inner_activity = announce - .object() - .to_owned() - .one() - .context(location_info!())?; - - let inner_id = inner_activity.id().context(location_info!())?.to_owned(); - check_is_apub_id_valid(&inner_id, false)?; - if is_activity_already_known(context.pool(), &inner_id).await? { - return Ok(()); - } - - use AnnouncableActivities::*; - match kind { - Some(Create) => todo!(), - Some(Update) => todo!(), - Some(Like) => todo!(), - Some(Dislike) => todo!(), - Some(Delete) => todo!(), - Some(Remove) => todo!(), - Some(Undo) => todo!(), - Some(Add) => { - receive_add_for_community(context, inner_activity, Some(announce), request_counter).await - } - Some(Block) => todo!(), - _ => receive_unhandled_activity(inner_activity), - } } diff --git a/crates/apub_receive/src/inbox/receive_for_community.rs b/crates/apub_receive/src/inbox/receive_for_community.rs deleted file mode 100644 index c635e235..00000000 --- a/crates/apub_receive/src/inbox/receive_for_community.rs +++ /dev/null @@ -1,214 +0,0 @@ -use crate::{ - activities::receive::verify_activity_domains_valid, - inbox::verify_is_addressed_to_public, -}; -use activitystreams::{ - activity::{ActorAndObjectRef, Add, Announce, OptTargetRef}, - base::AnyBase, - object::AsObject, - prelude::*, -}; -use anyhow::{anyhow, Context}; -use lemmy_api_common::blocking; -use lemmy_apub::{ - fetcher::person::get_or_fetch_and_upsert_person, - generate_moderators_url, - CommunityType, -}; -use lemmy_db_queries::{source::community::CommunityModerator_, ApubObject, Joinable}; -use lemmy_db_schema::{ - source::{ - community::{Community, CommunityModerator, CommunityModeratorForm}, - person::Person, - }, - DbUrl, -}; -use lemmy_db_views_actor::community_view::CommunityView; -use lemmy_utils::{location_info, LemmyError}; -use lemmy_websocket::LemmyContext; -use strum_macros::EnumString; - -#[derive(EnumString)] -enum PageOrNote { - Page, - Note, -} - -#[derive(EnumString)] -enum ObjectTypes { - Page, - Note, - Group, - Person, -} - -#[derive(EnumString)] -enum UndoableActivities { - Delete, - Remove, - Like, - Dislike, - Block, -} - -/// Add a new mod to the community (can only be done by an existing mod). -pub(in crate::inbox) async fn receive_add_for_community( - context: &LemmyContext, - add_any_base: AnyBase, - announce: Option, - request_counter: &mut i32, -) -> Result<(), LemmyError> { - let add = Add::from_any_base(add_any_base.to_owned())?.context(location_info!())?; - let community = extract_community_from_cc(&add, context).await?; - - verify_mod_activity(&add, announce, &community, context).await?; - verify_is_addressed_to_public(&add)?; - verify_add_remove_moderator_target(&add, &community)?; - - let new_mod = add - .object() - .as_single_xsd_any_uri() - .context(location_info!())?; - let new_mod = get_or_fetch_and_upsert_person(&new_mod, context, request_counter).await?; - - // If we had to refetch the community while parsing the activity, then the new mod has already - // been added. Skip it here as it would result in a duplicate key error. - let new_mod_id = new_mod.id; - let moderated_communities = blocking(context.pool(), move |conn| { - CommunityModerator::get_person_moderated_communities(conn, new_mod_id) - }) - .await??; - if !moderated_communities.contains(&community.id) { - let form = CommunityModeratorForm { - community_id: community.id, - person_id: new_mod.id, - }; - blocking(context.pool(), move |conn| { - CommunityModerator::join(conn, &form) - }) - .await??; - } - if community.local { - community - .send_announce( - add_any_base, - add.object().clone().single_xsd_any_uri(), - context, - ) - .await?; - } - // TODO: send websocket notification about added mod - Ok(()) -} - -/// Searches the activity's cc field for a Community ID, and returns the community. -async fn extract_community_from_cc( - activity: &T, - context: &LemmyContext, -) -> Result -where - T: AsObject, -{ - let cc = activity - .cc() - .map(|c| c.as_many()) - .flatten() - .context(location_info!())?; - let community_id = cc - .first() - .map(|c| c.as_xsd_any_uri()) - .flatten() - .context(location_info!())?; - let community_id: DbUrl = community_id.to_owned().into(); - let community = blocking(&context.pool(), move |conn| { - Community::read_from_apub_id(&conn, &community_id) - }) - .await??; - Ok(community) -} - -/// Checks that a moderation activity was sent by a user who is listed as mod for the community. -/// This is only used in the case of remote mods, as local mod actions don't go through the -/// community inbox. -/// -/// This method should only be used for activities received by the community, not for activities -/// used by community followers. -pub(crate) async fn verify_actor_is_community_mod( - activity: &T, - community: &Community, - context: &LemmyContext, -) -> Result<(), LemmyError> -where - T: ActorAndObjectRef + BaseExt, -{ - let actor = activity - .actor()? - .as_single_xsd_any_uri() - .context(location_info!())? - .to_owned(); - let actor = blocking(&context.pool(), move |conn| { - Person::read_from_apub_id(&conn, &actor.into()) - }) - .await??; - - // Note: this will also return true for admins in addition to mods, but as we dont know about - // remote admins, it doesnt make any difference. - let community_id = community.id; - let actor_id = actor.id; - let is_mod_or_admin = blocking(context.pool(), move |conn| { - CommunityView::is_mod_or_admin(conn, actor_id, community_id) - }) - .await?; - if !is_mod_or_admin { - return Err(anyhow!("Not a mod").into()); - } - - Ok(()) -} - -/// This method behaves differently, depending if it is called via community inbox (activity -/// received by community from a remote user), or via user inbox (activity received by user from -/// community). We distinguish the cases by checking if the activity is wrapper in an announce -/// (only true when sent from user to community). -/// -/// In the first case, we check that the actor is listed as community mod. In the second case, we -/// only check that the announce comes from the same domain as the activity. We trust the -/// community's instance to have validated the inner activity correctly. We can't do this validation -/// here, because we don't know who the instance admins are. Plus this allows for compatibility with -/// software that uses different rules for mod actions. -pub(crate) async fn verify_mod_activity( - mod_action: &T, - announce: Option, - community: &Community, - context: &LemmyContext, -) -> Result<(), LemmyError> -where - T: ActorAndObjectRef + BaseExt, -{ - match announce { - None => verify_actor_is_community_mod(mod_action, community, context).await?, - Some(a) => verify_activity_domains_valid(&a, &community.actor_id.to_owned().into(), false)?, - } - - Ok(()) -} - -/// For Add/Remove community moderator activities, check that the target field actually contains -/// /c/community/moderators. Any different values are unsupported. -fn verify_add_remove_moderator_target( - activity: &T, - community: &Community, -) -> Result<(), LemmyError> -where - T: ActorAndObjectRef + BaseExt + OptTargetRef, -{ - let target = activity - .target() - .map(|t| t.as_single_xsd_any_uri()) - .flatten() - .context(location_info!())?; - if target != &generate_moderators_url(&community.actor_id)?.into_inner() { - return Err(anyhow!("Unkown target url").into()); - } - Ok(()) -} diff --git a/crates/apub_receive/src/inbox/shared_inbox.rs b/crates/apub_receive/src/inbox/shared_inbox.rs index db060247..26297977 100644 --- a/crates/apub_receive/src/inbox/shared_inbox.rs +++ b/crates/apub_receive/src/inbox/shared_inbox.rs @@ -1,151 +1,17 @@ -use crate::inbox::{ - assert_activity_not_local, - community_inbox::{community_receive_message, CommunityAcceptedActivities}, - get_activity_id, - inbox_verify_http_signature, - is_activity_already_known, - is_addressed_to_community_followers, - is_addressed_to_local_person, - person_inbox::{person_receive_message, PersonAcceptedActivities}, -}; -use activitystreams::{activity::ActorAndObject, prelude::*}; +use crate::inbox::new_inbox_routing::{Activity, SharedInboxActivities}; use actix_web::{web, HttpRequest, HttpResponse}; -use anyhow::Context; -use lemmy_api_common::blocking; -use lemmy_apub::{get_activity_to_and_cc, insert_activity}; -use lemmy_db_queries::{ApubObject, DbPool}; -use lemmy_db_schema::source::community::Community; -use lemmy_utils::{location_info, LemmyError}; +use lemmy_apub_lib::{ReceiveActivity, VerifyActivity}; +use lemmy_utils::LemmyError; use lemmy_websocket::LemmyContext; -use serde::{Deserialize, Serialize}; -use std::fmt::Debug; -use url::Url; -/// Allowed activity types for shared inbox. -#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Deserialize, Serialize)] -#[serde(rename_all = "PascalCase")] -pub enum ValidTypes { - Create, - Update, - Like, - Dislike, - Delete, - Undo, - Remove, - Announce, - Add, - Block, -} - -// TODO: this isnt entirely correct, cause some of these receive are not ActorAndObject, -// but it still works due to the anybase conversion -pub type AcceptedActivities = ActorAndObject; - -/// Handler for all incoming requests to shared inbox. pub async fn shared_inbox( - request: HttpRequest, - input: web::Json, + _request: HttpRequest, + input: web::Json>, context: web::Data, ) -> Result { let activity = input.into_inner(); - // First of all check the http signature + activity.inner.verify(&context).await?; let request_counter = &mut 0; - let actor = inbox_verify_http_signature(&activity, &context, request, request_counter).await?; - - // Do nothing if we received the same activity before - let actor_id = actor.actor_id(); - let activity_id = get_activity_id(&activity, &actor_id)?; - if is_activity_already_known(context.pool(), &activity_id).await? { - return Ok(HttpResponse::Ok().finish()); - } - - assert_activity_not_local(&activity)?; - // Log the activity, so we avoid receiving and parsing it twice. Note that this could still happen - // if we receive the same activity twice in very quick succession. - insert_activity(&activity_id, activity.clone(), false, true, context.pool()).await?; - - let activity_any_base = activity.clone().into_any_base()?; - let mut res: Option = None; - let to_and_cc = get_activity_to_and_cc(&activity); - // Handle community first, so in case the sender is banned by the community, it will error out. - // If we handled the person receive first, the activity would be inserted to the database before the - // community could check for bans. - // Note that an activity can be addressed to a community and to a person (or multiple persons) at the - // same time. In this case we still only handle it once, to avoid duplicate websocket - // notifications. - let community = extract_local_community_from_destinations(&to_and_cc, context.pool()).await?; - if let Some(community) = community { - let community_activity = CommunityAcceptedActivities::from_any_base(activity_any_base.clone())? - .context(location_info!())?; - res = Some( - Box::pin(community_receive_message( - community_activity, - community, - actor.as_ref(), - &context, - request_counter, - )) - .await?, - ); - } else if is_addressed_to_local_person(&to_and_cc, context.pool()).await? { - let person_activity = PersonAcceptedActivities::from_any_base(activity_any_base.clone())? - .context(location_info!())?; - // `to_person` is only used for follow activities (which we dont receive here), so no need to pass - // it in - Box::pin(person_receive_message( - person_activity, - None, - actor.as_ref(), - &context, - request_counter, - )) - .await?; - } else if is_addressed_to_community_followers(&to_and_cc, context.pool()) - .await? - .is_some() - { - let person_activity = PersonAcceptedActivities::from_any_base(activity_any_base.clone())? - .context(location_info!())?; - res = Some( - Box::pin(person_receive_message( - person_activity, - None, - actor.as_ref(), - &context, - request_counter, - )) - .await?, - ); - } - - // If none of those, throw an error - if let Some(r) = res { - Ok(r) - } else { - Ok(HttpResponse::NotImplemented().finish()) - } -} - -/// If `to_and_cc` contains the ID of a local community, return that community, otherwise return -/// None. -/// -/// This doesnt handle the case where an activity is addressed to multiple communities (because -/// Lemmy doesnt generate such activities). -async fn extract_local_community_from_destinations( - to_and_cc: &[Url], - pool: &DbPool, -) -> Result, LemmyError> { - for url in to_and_cc { - let url = url.to_owned(); - let community = blocking(&pool, move |conn| { - Community::read_from_apub_id(&conn, &url.into()) - }) - .await?; - if let Ok(c) = community { - if c.local { - return Ok(Some(c)); - } - } - } - Ok(None) + activity.inner.receive(&context, request_counter).await?; + todo!() } diff --git a/crates/apub_receive/src/lib.rs b/crates/apub_receive/src/lib.rs index 36f3ed67..849369e7 100644 --- a/crates/apub_receive/src/lib.rs +++ b/crates/apub_receive/src/lib.rs @@ -1,5 +1,4 @@ -mod activities; -pub mod activities_new; +pub mod activities; mod http; mod inbox; pub mod routes;