import {
alpha,
beta,
+ gamma,
setupLogins,
resolveCommunity,
createCommunity,
removeCommunity,
getCommunity,
followCommunity,
+ banPersonFromCommunity,
+ resolvePerson,
+ getSite,
+ createPost,
+ getPost,
+ resolvePost,
} from './shared';
beforeAll(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);
+});
verify_mod_action(
&activity.actor,
activity.object.id(),
- &community,
+ community.id,
context,
request_counter,
)
) -> 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)?;
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;
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
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