]> Untitled Git - lemmy.git/commitdiff
Fix check for federated mod actions (#2489)
authorNutomic <me@nutomic.com>
Mon, 10 Oct 2022 15:20:36 +0000 (15:20 +0000)
committerGitHub <noreply@github.com>
Mon, 10 Oct 2022 15:20:36 +0000 (11:20 -0400)
api_tests/src/community.spec.ts
crates/apub/src/activities/block/block_user.rs
crates/apub/src/activities/community/add_mod.rs
crates/apub/src/activities/community/remove_mod.rs
crates/apub/src/activities/community/update.rs
crates/apub/src/activities/create_or_update/post.rs
crates/apub/src/activities/deletion/mod.rs
crates/apub/src/activities/mod.rs

index 723f3bb3f543e5699c83b71466f616d9d0fc5d34..381b546b306499dcf549ccb642b2ffec4c22d673 100644 (file)
@@ -4,6 +4,7 @@ import { CommunityView } from 'lemmy-js-client';
 import {
   alpha,
   beta,
+  gamma,
   setupLogins,
   resolveCommunity,
   createCommunity,
@@ -11,6 +12,12 @@ import {
   removeCommunity,
   getCommunity,
   followCommunity,
+  banPersonFromCommunity,
+  resolvePerson,
+  getSite,
+  createPost,
+  getPost,
+  resolvePost,
 } from './shared';
 
 beforeAll(async () => {
@@ -162,3 +169,33 @@ test('Search for beta community', async () => {
   let alphaCommunity = (await resolveCommunity(alpha, searchShort)).community.unwrap();
   assertCommunityFederation(alphaCommunity, communityRes.community_view);
 });
+
+test('Admin actions in remote community are not federated to origin', async () => {
+  // create a community on alpha
+  let communityRes = (await createCommunity(alpha)).community_view;
+  expect(communityRes.community.name).toBeDefined();
+
+  // gamma follows community and posts in it
+  let gammaCommunity = (await resolveCommunity(gamma, communityRes.community.actor_id)).community.unwrap();
+  let gammaFollow = (await followCommunity(gamma, true, gammaCommunity.community.id));
+  expect(gammaFollow.community_view.subscribed).toBe("Subscribed");
+  let gammaPost = (await createPost(gamma, gammaCommunity.community.id)).post_view;
+  expect(gammaPost.post.id).toBeDefined();
+  expect(gammaPost.creator_banned_from_community).toBe(false);
+
+  // admin of beta decides to ban gamma from community
+  let betaCommunity = (await resolveCommunity(beta, communityRes.community.actor_id)).community.unwrap();
+  let bannedUserInfo1 = (await getSite(gamma)).my_user.unwrap().local_user_view.person;
+  let bannedUserInfo2 = (await resolvePerson(beta, bannedUserInfo1.actor_id)).person.unwrap();
+  let banRes = (await banPersonFromCommunity(beta, bannedUserInfo2.person.id, betaCommunity.community.id, true, true));
+  console.log(banRes);
+  expect(banRes.banned).toBe(true);
+
+  // ban doesnt federate to community's origin instance alpha
+  let alphaPost = (await resolvePost(alpha, gammaPost.post)).post.unwrap();
+  expect(alphaPost.creator_banned_from_community).toBe(false);
+
+  // and neither to gamma
+  let gammaPost2 = (await getPost(gamma, gammaPost.post.id));
+  expect(gammaPost2.post_view.creator_banned_from_community).toBe(false);
+});
index 5297cda73af61c99edfc9b5d56b8af261cfa0712..72c4316373aa77706714f7ab93f5ffc8a5dc53e8 100644 (file)
@@ -145,7 +145,7 @@ impl ActivityHandler for BlockUser {
         verify_mod_action(
           &self.actor,
           self.object.inner(),
-          &community,
+          community.id,
           context,
           request_counter,
         )
index ada7afdf1dafc3ece6661430bf9f3e1c27d74035..4dbd463b70463596d6f7b5e2f55aaf33540d3f3f 100644 (file)
@@ -90,7 +90,7 @@ impl ActivityHandler for AddMod {
     verify_mod_action(
       &self.actor,
       self.object.inner(),
-      &community,
+      community.id,
       context,
       request_counter,
     )
index 7c5d817f90776d1746f02eca9407605328fc6c6a..ede6a0089cb9b22eca63714e2ab41d3d266b7536 100644 (file)
@@ -90,7 +90,7 @@ impl ActivityHandler for RemoveMod {
     verify_mod_action(
       &self.actor,
       self.object.inner(),
-      &community,
+      community.id,
       context,
       request_counter,
     )
index 51e2a6ea102bc8b416e7780ad4b17e373b1a504c..57a31221e45ad2da169f3710c21842b13fdb48be 100644 (file)
@@ -78,7 +78,7 @@ impl ActivityHandler for UpdateCommunity {
     verify_mod_action(
       &self.actor,
       self.object.id.inner(),
-      &community,
+      community.id,
       context,
       request_counter,
     )
index 5ac57fb00e7863815a59ee6e3c31ac7478186832..d9d7b854549ffd79d5f3ae5415f2f7c8879e7c71 100644 (file)
@@ -120,7 +120,7 @@ impl ActivityHandler for CreateOrUpdatePost {
           verify_mod_action(
             &self.actor,
             self.object.id.inner(),
-            &community,
+            community.id,
             context,
             request_counter,
           )
index 8bc67721ed1068c848605aed8f6b639989db2084..87dcd2d8f83a44db2ea268996e46688daf09ca93 100644 (file)
@@ -159,7 +159,7 @@ pub(in crate::activities) async fn verify_delete_activity(
       verify_mod_action(
         &activity.actor,
         activity.object.id(),
-        &community,
+        community.id,
         context,
         request_counter,
       )
@@ -208,7 +208,7 @@ async fn verify_delete_post_or_comment(
 ) -> Result<(), LemmyError> {
   verify_person_in_community(actor, community, context, request_counter).await?;
   if is_mod_action {
-    verify_mod_action(actor, object_id, community, context, request_counter).await?;
+    verify_mod_action(actor, object_id, community.id, context, request_counter).await?;
   } else {
     // domain of post ap_id and post.creator ap_id are identical, so we just check the former
     verify_domains_match(actor.inner(), object_id)?;
index bd928e72ca174ec0a8021e08411f147427d5342c..d3400705dff5fc439e422d0416ed1fbc709c7adb 100644 (file)
@@ -14,7 +14,7 @@ use activitypub_federation::{
 use activitystreams_kinds::public;
 use anyhow::anyhow;
 use lemmy_api_common::utils::blocking;
-use lemmy_db_schema::source::community::Community;
+use lemmy_db_schema::{newtypes::CommunityId, source::community::Community};
 use lemmy_db_views_actor::structs::{CommunityPersonBanView, CommunityView};
 use lemmy_utils::error::LemmyError;
 use lemmy_websocket::LemmyContext;
@@ -75,9 +75,7 @@ pub(crate) async fn verify_person_in_community(
   Ok(())
 }
 
-/// Verify that the actor is a community mod. This check is only run if the community is local,
-/// because in case of remote communities, admins can also perform mod actions. As admin status
-/// is not federated, we cant verify their actions remotely.
+/// Verify that mod action in community was performed by a moderator.
 ///
 /// * `mod_id` - Activitypub ID of the mod or admin who performed the action
 /// * `object_id` - Activitypub ID of the actor or object that is being moderated
@@ -86,40 +84,30 @@ pub(crate) async fn verify_person_in_community(
 pub(crate) async fn verify_mod_action(
   mod_id: &ObjectId<ApubPerson>,
   object_id: &Url,
-  community: &ApubCommunity,
+  community_id: CommunityId,
   context: &LemmyContext,
   request_counter: &mut i32,
 ) -> Result<(), LemmyError> {
-  if community.local {
-    let actor = mod_id
-      .dereference(context, local_instance(context), request_counter)
-      .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)
-    })
+  let mod_ = mod_id
+    .dereference(context, local_instance(context), request_counter)
     .await?;
 
-    // mod action was done either by a community mod or a local admin, so its allowed
-    if is_mod_or_admin {
-      return Ok(());
-    }
-
-    // mod action comes from the same instance as the moderated object, so it was presumably done
-    // by an instance admin and is legitimate (admin status is not federated).
-    if mod_id.inner().domain() == object_id.domain() {
-      return Ok(());
-    }
+  let is_mod_or_admin = blocking(context.pool(), move |conn| {
+    CommunityView::is_mod_or_admin(conn, mod_.id, community_id)
+  })
+  .await?;
+  if is_mod_or_admin {
+    return Ok(());
+  }
 
-    // the user is not a valid mod
-    return Err(LemmyError::from_message("Not a mod"));
+  // mod action comes from the same instance as the moderated object, so it was presumably done
+  // by an instance admin.
+  // TODO: federate instance admin status and check it here
+  if mod_id.inner().domain() == object_id.domain() {
+    return Ok(());
   }
-  Ok(())
+
+  Err(LemmyError::from_message("Not a mod"))
 }
 
 /// For Add/Remove community moderator activities, check that the target field actually contains