diff --git a/api_tests/src/post.spec.ts b/api_tests/src/post.spec.ts index 01befa60c..0d1788c62 100644 --- a/api_tests/src/post.spec.ts +++ b/api_tests/src/post.spec.ts @@ -23,6 +23,7 @@ import { banUserFromSite, searchPostLocal, banUserFromCommunity, + followCommunity, } from './shared'; import { PostView, CommunityView } from 'lemmy-js-client'; @@ -169,35 +170,38 @@ test('Sticky a post', async () => { }); test('Lock a post', async () => { + await followCommunity(alpha, true, betaCommunity.community.id); let postRes = await createPost(alpha, betaCommunity.community.id); // Lock the post - let lockedPostRes = await lockPost(alpha, true, postRes.post_view.post); + let searchBeta = await searchPost(beta, postRes.post_view.post); + let betaPost1 = searchBeta.posts[0]; + let lockedPostRes = await lockPost(beta, true, betaPost1.post); expect(lockedPostRes.post_view.post.locked).toBe(true); - // Make sure that post is locked on beta - let searchBeta = await searchPostLocal(beta, postRes.post_view.post); - let betaPost1 = searchBeta.posts[0]; - expect(betaPost1.post.locked).toBe(true); + // Make sure that post is locked on alpha + let searchAlpha = await searchPostLocal(alpha, postRes.post_view.post); + let alphaPost1 = searchAlpha.posts[0]; + expect(alphaPost1.post.locked).toBe(true); // Try to make a new comment there, on alpha - let comment: any = await createComment(alpha, postRes.post_view.post.id); + let comment: any = await createComment(alpha, alphaPost1.post.id); expect(comment['error']).toBe('locked'); // Unlock a post - let unlockedPost = await lockPost(alpha, false, postRes.post_view.post); + let unlockedPost = await lockPost(beta, false, betaPost1.post); expect(unlockedPost.post_view.post.locked).toBe(false); - // Make sure that post is unlocked on beta - let searchBeta2 = await searchPost(beta, postRes.post_view.post); - let betaPost2 = searchBeta2.posts[0]; - expect(betaPost2.community.local).toBe(true); - expect(betaPost2.creator.local).toBe(false); - expect(betaPost2.post.locked).toBe(false); + // Make sure that post is unlocked on alpha + let searchAlpha2 = await searchPostLocal(alpha, postRes.post_view.post); + let alphaPost2 = searchAlpha2.posts[0]; + expect(alphaPost2.community.local).toBe(false); + expect(alphaPost2.creator.local).toBe(true); + expect(alphaPost2.post.locked).toBe(false); - // Try to create a new comment, on beta - let commentBeta = await createComment(beta, betaPost2.post.id); - expect(commentBeta).toBeDefined(); + // Try to create a new comment, on alpha + let commentAlpha = await createComment(alpha, alphaPost1.post.id); + expect(commentAlpha).toBeDefined(); }); test('Delete a post', async () => { diff --git a/crates/apub/src/activities/receive/post.rs b/crates/apub/src/activities/receive/post.rs index b0582e60e..631f9933b 100644 --- a/crates/apub/src/activities/receive/post.rs +++ b/crates/apub/src/activities/receive/post.rs @@ -75,14 +75,17 @@ pub(crate) async fn receive_update_post( // If sticked or locked state was changed, make sure the actor is a mod let stickied = page.ext_one.stickied.context(location_info!())?; let locked = !page.ext_one.comments_enabled.context(location_info!())?; - let mut is_mod_action = false; + let mut mod_action_allowed = false; if stickied != old_post.stickied || locked != old_post.locked { let community = blocking(context.pool(), move |conn| { Community::read(conn, old_post.community_id) }) .await??; - verify_mod_activity(&update, announce, &community, context).await?; - is_mod_action = true; + // Only check mod status if the community is local, otherwise we trust that it was sent correctly. + if community.local { + verify_mod_activity(&update, announce, &community, context).await?; + } + mod_action_allowed = true; } let post = Post::from_apub( @@ -90,7 +93,7 @@ pub(crate) async fn receive_update_post( context, user.actor_id(), request_counter, - is_mod_action, + mod_action_allowed, ) .await?; diff --git a/crates/apub/src/activities/send/community.rs b/crates/apub/src/activities/send/community.rs index c6c90d502..84d2fcedd 100644 --- a/crates/apub/src/activities/send/community.rs +++ b/crates/apub/src/activities/send/community.rs @@ -165,7 +165,7 @@ impl CommunityType for Community { .set_many_contexts(lemmy_context()?) .set_id(generate_activity_id(AnnounceType::Announce)?) .set_to(public()) - .set_many_ccs(vec![self.actor_id()]); + .set_many_ccs(vec![self.followers_url.clone().into_inner()]); send_to_community_followers(announce, self, context).await?; diff --git a/crates/apub/src/inbox/user_inbox.rs b/crates/apub/src/inbox/user_inbox.rs index 3d16403bc..7ddb83368 100644 --- a/crates/apub/src/inbox/user_inbox.rs +++ b/crates/apub/src/inbox/user_inbox.rs @@ -1,5 +1,6 @@ use crate::{ activities::receive::{ + comment::{receive_create_comment, receive_update_comment}, community::{ receive_delete_community, receive_remove_community, @@ -326,6 +327,8 @@ pub async fn receive_announce( } } +/// Receive either a new private message, or a new comment mention. We distinguish them by checking +/// whether the activity is public. async fn receive_create( context: &LemmyContext, activity: AnyBase, @@ -334,9 +337,15 @@ async fn receive_create( ) -> Result<(), LemmyError> { let create = Create::from_any_base(activity)?.context(location_info!())?; verify_activity_domains_valid(&create, &expected_domain, true)?; - receive_create_private_message(&context, create, expected_domain, request_counter).await + if verify_is_addressed_to_public(&create).is_ok() { + receive_create_comment(create, context, request_counter).await + } else { + receive_create_private_message(&context, create, expected_domain, request_counter).await + } } +/// Receive either an updated private message, or an updated comment mention. We distinguish +/// them by checking whether the activity is public. async fn receive_update( context: &LemmyContext, activity: AnyBase, @@ -345,7 +354,11 @@ async fn receive_update( ) -> Result<(), LemmyError> { let update = Update::from_any_base(activity)?.context(location_info!())?; verify_activity_domains_valid(&update, &expected_domain, true)?; - receive_update_private_message(&context, update, expected_domain, request_counter).await + if verify_is_addressed_to_public(&update).is_ok() { + receive_update_comment(update, context, request_counter).await + } else { + receive_update_private_message(&context, update, expected_domain, request_counter).await + } } async fn receive_delete( diff --git a/crates/apub/src/objects/comment.rs b/crates/apub/src/objects/comment.rs index 43bd86595..63f5d9e2c 100644 --- a/crates/apub/src/objects/comment.rs +++ b/crates/apub/src/objects/comment.rs @@ -99,14 +99,14 @@ impl FromApub for Comment { context: &LemmyContext, expected_domain: Url, request_counter: &mut i32, - is_mod_action: bool, + mod_action_allowed: bool, ) -> Result { let comment: Comment = get_object_from_apub( note, context, expected_domain, request_counter, - is_mod_action, + mod_action_allowed, ) .await?; @@ -135,7 +135,7 @@ impl FromApubToForm for CommentForm { context: &LemmyContext, expected_domain: Url, request_counter: &mut i32, - _is_mod_action: bool, + _mod_action_allowed: bool, ) -> Result { let creator_actor_id = ¬e .attributed_to() diff --git a/crates/apub/src/objects/community.rs b/crates/apub/src/objects/community.rs index 9ae801b74..73cca5c71 100644 --- a/crates/apub/src/objects/community.rs +++ b/crates/apub/src/objects/community.rs @@ -107,14 +107,14 @@ impl FromApub for Community { context: &LemmyContext, expected_domain: Url, request_counter: &mut i32, - is_mod_action: bool, + mod_action_allowed: bool, ) -> Result { let community: Community = get_object_from_apub( group, context, expected_domain, request_counter, - is_mod_action, + mod_action_allowed, ) .await?; @@ -169,7 +169,7 @@ impl FromApubToForm for CommunityForm { context: &LemmyContext, expected_domain: Url, request_counter: &mut i32, - _is_mod_action: bool, + _mod_action_allowed: bool, ) -> Result { let moderator_uris = fetch_community_mods(context, group, request_counter).await?; let creator_uri = moderator_uris.first().context(location_info!())?; diff --git a/crates/apub/src/objects/mod.rs b/crates/apub/src/objects/mod.rs index 9f5007204..78095e747 100644 --- a/crates/apub/src/objects/mod.rs +++ b/crates/apub/src/objects/mod.rs @@ -46,13 +46,13 @@ pub(crate) trait FromApub { /// * `apub` The object to read from /// * `context` LemmyContext which holds DB pool, HTTP client etc /// * `expected_domain` Domain where the object was received from. None in case of mod action. - /// * `is_mod_action` True if the object was sent in a mod activity, ignore `expected_domain` in this case + /// * `mod_action_allowed` True if the object can be a mod activity, ignore `expected_domain` in this case async fn from_apub( apub: &Self::ApubType, context: &LemmyContext, expected_domain: Url, request_counter: &mut i32, - is_mod_action: bool, + mod_action_allowed: bool, ) -> Result where Self: Sized; @@ -65,7 +65,7 @@ pub(in crate::objects) trait FromApubToForm { context: &LemmyContext, expected_domain: Url, request_counter: &mut i32, - is_mod_action: bool, + mod_action_allowed: bool, ) -> Result where Self: Sized; diff --git a/crates/apub/src/objects/post.rs b/crates/apub/src/objects/post.rs index 92d542644..14b43c6cb 100644 --- a/crates/apub/src/objects/post.rs +++ b/crates/apub/src/objects/post.rs @@ -118,14 +118,14 @@ impl FromApub for Post { context: &LemmyContext, expected_domain: Url, request_counter: &mut i32, - is_mod_action: bool, + mod_action_allowed: bool, ) -> Result { let post: Post = get_object_from_apub( page, context, expected_domain, request_counter, - is_mod_action, + mod_action_allowed, ) .await?; check_object_for_community_or_site_ban(page, post.community_id, context, request_counter) @@ -141,9 +141,9 @@ impl FromApubToForm for PostForm { context: &LemmyContext, expected_domain: Url, request_counter: &mut i32, - is_mod_action: bool, + mod_action_allowed: bool, ) -> Result { - let ap_id = if is_mod_action { + let ap_id = if mod_action_allowed { let id = page.id_unchecked().context(location_info!())?; check_is_apub_id_valid(id)?; id.to_owned().into() diff --git a/crates/apub/src/objects/private_message.rs b/crates/apub/src/objects/private_message.rs index 93d13503a..ea9ae3f64 100644 --- a/crates/apub/src/objects/private_message.rs +++ b/crates/apub/src/objects/private_message.rs @@ -77,14 +77,14 @@ impl FromApub for PrivateMessage { context: &LemmyContext, expected_domain: Url, request_counter: &mut i32, - is_mod_action: bool, + mod_action_allowed: bool, ) -> Result { get_object_from_apub( note, context, expected_domain, request_counter, - is_mod_action, + mod_action_allowed, ) .await } @@ -97,7 +97,7 @@ impl FromApubToForm for PrivateMessageForm { context: &LemmyContext, expected_domain: Url, request_counter: &mut i32, - _is_mod_action: bool, + _mod_action_allowed: bool, ) -> Result { let creator_actor_id = note .attributed_to() diff --git a/crates/apub/src/objects/user.rs b/crates/apub/src/objects/user.rs index 5b33331b9..b6043d31d 100644 --- a/crates/apub/src/objects/user.rs +++ b/crates/apub/src/objects/user.rs @@ -93,7 +93,7 @@ impl FromApub for User_ { context: &LemmyContext, expected_domain: Url, request_counter: &mut i32, - is_mod_action: bool, + mod_action_allowed: bool, ) -> Result { let user_id = person.id_unchecked().context(location_info!())?.to_owned(); let domain = user_id.domain().context(location_info!())?; @@ -109,7 +109,7 @@ impl FromApub for User_ { context, expected_domain, request_counter, - is_mod_action, + mod_action_allowed, ) .await?; let user = blocking(context.pool(), move |conn| User_::upsert(conn, &user_form)).await??; @@ -125,7 +125,7 @@ impl FromApubToForm for UserForm { _context: &LemmyContext, expected_domain: Url, _request_counter: &mut i32, - _is_mod_action: bool, + _mod_action_allowed: bool, ) -> Result { let avatar = match person.icon() { Some(any_image) => Some(