Skip to content

Commit aa79c51

Browse files
authored
Implement federated bans (fixes #1298) (#1553)
* Implement federated bans (fixes #1298) * mod actions should always be federated to affected user, in addition to followers * Make Undo/Block work for remote mods * clippy fix * fix federation test * vscodium doesnt auto-save changes...
1 parent 89dd0f2 commit aa79c51

12 files changed

Lines changed: 335 additions & 113 deletions

File tree

api_tests/src/post.spec.ts

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -340,17 +340,9 @@ test('Enforce community ban for federated user', async () => {
340340
let banAlpha = await banPersonFromCommunity(beta, alphaUser.person.id, 2, true);
341341
expect(banAlpha.banned).toBe(true);
342342

343-
// Alpha makes post on beta
343+
// Alpha tries to make post on beta, but it fails because of ban
344344
let postRes = await createPost(alpha, betaCommunity.community.id);
345-
expect(postRes.post_view.post).toBeDefined();
346-
expect(postRes.post_view.community.local).toBe(false);
347-
expect(postRes.post_view.creator.local).toBe(true);
348-
expect(postRes.post_view.counts.score).toBe(1);
349-
350-
// Make sure that post doesn't make it to beta community
351-
let searchBeta = await searchPostLocal(beta, postRes.post_view.post);
352-
let betaPost = searchBeta.posts[0];
353-
expect(betaPost).toBeUndefined();
345+
expect(postRes.post_view).toBeUndefined();
354346

355347
// Unban alpha
356348
let unBanAlpha = await banPersonFromCommunity(
@@ -360,4 +352,14 @@ test('Enforce community ban for federated user', async () => {
360352
false
361353
);
362354
expect(unBanAlpha.banned).toBe(false);
355+
let postRes2 = await createPost(alpha, betaCommunity.community.id);
356+
expect(postRes2.post_view.post).toBeDefined();
357+
expect(postRes2.post_view.community.local).toBe(false);
358+
expect(postRes2.post_view.creator.local).toBe(true);
359+
expect(postRes2.post_view.counts.score).toBe(1);
360+
361+
// Make sure that post makes it to beta community
362+
let searchBeta = await searchPostLocal(beta, postRes2.post_view.post);
363+
let betaPost = searchBeta.posts[0];
364+
expect(betaPost).toBeDefined();
363365
});

crates/api/src/community.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,15 @@ impl Perform for BanFromCommunity {
130130
person_id: data.person_id,
131131
};
132132

133+
let community = blocking(context.pool(), move |conn: &'_ _| {
134+
Community::read(conn, community_id)
135+
})
136+
.await??;
137+
let banned_person = blocking(context.pool(), move |conn: &'_ _| {
138+
Person::read(conn, banned_person_id)
139+
})
140+
.await??;
141+
133142
if data.ban {
134143
let ban = move |conn: &'_ _| CommunityPersonBan::ban(conn, &community_user_ban_form);
135144
if blocking(context.pool(), ban).await?.is_err() {
@@ -147,11 +156,18 @@ impl Perform for BanFromCommunity {
147156
})
148157
.await?
149158
.ok();
159+
160+
community
161+
.send_block_user(&local_user_view.person, banned_person, context)
162+
.await?;
150163
} else {
151164
let unban = move |conn: &'_ _| CommunityPersonBan::unban(conn, &community_user_ban_form);
152165
if blocking(context.pool(), unban).await?.is_err() {
153166
return Err(ApiError::err("community_user_already_banned").into());
154167
}
168+
community
169+
.send_undo_block_user(&local_user_view.person, banned_person, context)
170+
.await?;
155171
}
156172

157173
// Remove/Restore their data if that's desired

crates/apub/src/activities/send/comment.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ impl ApubObjectType for Comment {
7171
// Set the mention tags
7272
.set_many_tags(maa.get_tags()?);
7373

74-
send_to_community(create.clone(), &creator, &community, context).await?;
74+
send_to_community(create.clone(), &creator, &community, None, context).await?;
7575
send_comment_mentions(&creator, maa.inboxes, create, context).await?;
7676
Ok(())
7777
}
@@ -104,7 +104,7 @@ impl ApubObjectType for Comment {
104104
// Set the mention tags
105105
.set_many_tags(maa.get_tags()?);
106106

107-
send_to_community(update.clone(), &creator, &community, context).await?;
107+
send_to_community(update.clone(), &creator, &community, None, context).await?;
108108
send_comment_mentions(&creator, maa.inboxes, update, context).await?;
109109
Ok(())
110110
}
@@ -129,7 +129,7 @@ impl ApubObjectType for Comment {
129129
.set_to(public())
130130
.set_many_ccs(vec![community.actor_id()]);
131131

132-
send_to_community(delete, &creator, &community, context).await?;
132+
send_to_community(delete, &creator, &community, None, context).await?;
133133
Ok(())
134134
}
135135

@@ -169,7 +169,7 @@ impl ApubObjectType for Comment {
169169
.set_to(public())
170170
.set_many_ccs(vec![community.actor_id()]);
171171

172-
send_to_community(undo, &creator, &community, context).await?;
172+
send_to_community(undo, &creator, &community, None, context).await?;
173173
Ok(())
174174
}
175175

@@ -193,7 +193,7 @@ impl ApubObjectType for Comment {
193193
.set_to(public())
194194
.set_many_ccs(vec![community.actor_id()]);
195195

196-
send_to_community(remove, &mod_, &community, context).await?;
196+
send_to_community(remove, &mod_, &community, None, context).await?;
197197
Ok(())
198198
}
199199

@@ -233,7 +233,7 @@ impl ApubObjectType for Comment {
233233
.set_to(public())
234234
.set_many_ccs(vec![community.actor_id()]);
235235

236-
send_to_community(undo, &mod_, &community, context).await?;
236+
send_to_community(undo, &mod_, &community, None, context).await?;
237237
Ok(())
238238
}
239239
}
@@ -260,7 +260,7 @@ impl ApubLikeableType for Comment {
260260
.set_to(public())
261261
.set_many_ccs(vec![community.actor_id()]);
262262

263-
send_to_community(like, &creator, &community, context).await?;
263+
send_to_community(like, &creator, &community, None, context).await?;
264264
Ok(())
265265
}
266266

@@ -284,7 +284,7 @@ impl ApubLikeableType for Comment {
284284
.set_to(public())
285285
.set_many_ccs(vec![community.actor_id()]);
286286

287-
send_to_community(dislike, &creator, &community, context).await?;
287+
send_to_community(dislike, &creator, &community, None, context).await?;
288288
Ok(())
289289
}
290290

@@ -323,7 +323,7 @@ impl ApubLikeableType for Comment {
323323
.set_to(public())
324324
.set_many_ccs(vec![community.actor_id()]);
325325

326-
send_to_community(undo, &creator, &community, context).await?;
326+
send_to_community(undo, &creator, &community, None, context).await?;
327327
Ok(())
328328
}
329329
}

crates/apub/src/activities/send/community.rs

Lines changed: 92 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,29 @@ use crate::{
33
activity_queue::{send_activity_single_dest, send_to_community, send_to_community_followers},
44
check_is_apub_id_valid,
55
extensions::context::lemmy_context,
6-
fetcher::person::get_or_fetch_and_upsert_person,
6+
fetcher::{get_or_fetch_and_upsert_actor, person::get_or_fetch_and_upsert_person},
77
generate_moderators_url,
88
insert_activity,
99
ActorType,
1010
CommunityType,
1111
};
1212
use activitystreams::{
1313
activity::{
14-
kind::{AcceptType, AddType, AnnounceType, DeleteType, LikeType, RemoveType, UndoType},
14+
kind::{
15+
AcceptType,
16+
AddType,
17+
AnnounceType,
18+
BlockType,
19+
DeleteType,
20+
LikeType,
21+
RemoveType,
22+
UndoType,
23+
},
1524
Accept,
1625
ActorAndObjectRefExt,
1726
Add,
1827
Announce,
28+
Block,
1929
Delete,
2030
Follow,
2131
OptTargetRefExt,
@@ -62,6 +72,10 @@ impl ActorType for Community {
6272

6373
#[async_trait::async_trait(?Send)]
6474
impl CommunityType for Community {
75+
fn followers_url(&self) -> Url {
76+
self.followers_url.clone().into_inner()
77+
}
78+
6579
/// As a local community, accept the follow request from a remote person.
6680
async fn send_accept_follow(
6781
&self,
@@ -94,9 +108,9 @@ impl CommunityType for Community {
94108
.set_many_contexts(lemmy_context()?)
95109
.set_id(generate_activity_id(DeleteType::Delete)?)
96110
.set_to(public())
97-
.set_many_ccs(vec![self.followers_url.clone().into_inner()]);
111+
.set_many_ccs(vec![self.followers_url()]);
98112

99-
send_to_community_followers(delete, self, context).await?;
113+
send_to_community_followers(delete, self, None, context).await?;
100114
Ok(())
101115
}
102116

@@ -107,16 +121,16 @@ impl CommunityType for Community {
107121
.set_many_contexts(lemmy_context()?)
108122
.set_id(generate_activity_id(DeleteType::Delete)?)
109123
.set_to(public())
110-
.set_many_ccs(vec![self.followers_url.clone().into_inner()]);
124+
.set_many_ccs(vec![self.followers_url()]);
111125

112126
let mut undo = Undo::new(self.actor_id(), delete.into_any_base()?);
113127
undo
114128
.set_many_contexts(lemmy_context()?)
115129
.set_id(generate_activity_id(UndoType::Undo)?)
116130
.set_to(public())
117-
.set_many_ccs(vec![self.followers_url.clone().into_inner()]);
131+
.set_many_ccs(vec![self.followers_url()]);
118132

119-
send_to_community_followers(undo, self, context).await?;
133+
send_to_community_followers(undo, self, None, context).await?;
120134
Ok(())
121135
}
122136

@@ -127,9 +141,9 @@ impl CommunityType for Community {
127141
.set_many_contexts(lemmy_context()?)
128142
.set_id(generate_activity_id(RemoveType::Remove)?)
129143
.set_to(public())
130-
.set_many_ccs(vec![self.followers_url.clone().into_inner()]);
144+
.set_many_ccs(vec![self.followers_url()]);
131145

132-
send_to_community_followers(remove, self, context).await?;
146+
send_to_community_followers(remove, self, None, context).await?;
133147
Ok(())
134148
}
135149

@@ -140,17 +154,17 @@ impl CommunityType for Community {
140154
.set_many_contexts(lemmy_context()?)
141155
.set_id(generate_activity_id(RemoveType::Remove)?)
142156
.set_to(public())
143-
.set_many_ccs(vec![self.followers_url.clone().into_inner()]);
157+
.set_many_ccs(vec![self.followers_url()]);
144158

145159
// Undo that fake activity
146160
let mut undo = Undo::new(self.actor_id(), remove.into_any_base()?);
147161
undo
148162
.set_many_contexts(lemmy_context()?)
149163
.set_id(generate_activity_id(LikeType::Like)?)
150164
.set_to(public())
151-
.set_many_ccs(vec![self.followers_url.clone().into_inner()]);
165+
.set_many_ccs(vec![self.followers_url()]);
152166

153-
send_to_community_followers(undo, self, context).await?;
167+
send_to_community_followers(undo, self, None, context).await?;
154168
Ok(())
155169
}
156170

@@ -160,24 +174,41 @@ impl CommunityType for Community {
160174
/// If we are announcing a local activity, it hasn't been stored in the database yet, and we need
161175
/// to do it here, so that it can be fetched by ID. Remote activities are inserted into DB in the
162176
/// inbox.
177+
///
178+
/// If the `object` of the announced activity is an actor, the actor ID needs to be passed as
179+
/// `object_actor`, so that the announce can be delivered to that user.
163180
async fn send_announce(
164181
&self,
165182
activity: AnyBase,
183+
object_actor: Option<Url>,
166184
context: &LemmyContext,
167185
) -> Result<(), LemmyError> {
168186
let inner_id = activity.id().context(location_info!())?;
169187
if inner_id.domain() == Some(&Settings::get().get_hostname_without_port()?) {
170188
insert_activity(inner_id, activity.clone(), true, false, context.pool()).await?;
171189
}
172190

173-
let mut announce = Announce::new(self.actor_id.to_owned().into_inner(), activity);
191+
let mut ccs = vec![self.followers_url()];
192+
let mut object_actor_inbox: Option<Url> = None;
193+
if let Some(actor_id) = object_actor {
194+
// Ignore errors, maybe its not actually an actor
195+
// TODO: should pass the actual request counter in, but that seems complicated
196+
let actor = get_or_fetch_and_upsert_actor(&actor_id, context, &mut 0)
197+
.await
198+
.ok();
199+
if let Some(actor) = actor {
200+
ccs.push(actor_id);
201+
object_actor_inbox = Some(actor.get_shared_inbox_or_inbox_url());
202+
}
203+
}
204+
let mut announce = Announce::new(self.actor_id(), activity);
174205
announce
175206
.set_many_contexts(lemmy_context()?)
176207
.set_id(generate_activity_id(AnnounceType::Announce)?)
177208
.set_to(public())
178-
.set_many_ccs(vec![self.followers_url.clone().into_inner()]);
209+
.set_many_ccs(ccs);
179210

180-
send_to_community_followers(announce, self, context).await?;
211+
send_to_community_followers(announce, self, object_actor_inbox, context).await?;
181212

182213
Ok(())
183214
}
@@ -209,18 +240,15 @@ impl CommunityType for Community {
209240
added_mod: Person,
210241
context: &LemmyContext,
211242
) -> Result<(), LemmyError> {
212-
let mut add = Add::new(
213-
actor.actor_id.clone().into_inner(),
214-
added_mod.actor_id.into_inner(),
215-
);
243+
let mut add = Add::new(actor.actor_id(), added_mod.actor_id());
216244
add
217245
.set_many_contexts(lemmy_context()?)
218246
.set_id(generate_activity_id(AddType::Add)?)
219247
.set_to(public())
220248
.set_many_ccs(vec![self.actor_id()])
221249
.set_target(generate_moderators_url(&self.actor_id)?.into_inner());
222250

223-
send_to_community(add, actor, self, context).await?;
251+
send_to_community(add, actor, self, Some(added_mod.actor_id()), context).await?;
224252
Ok(())
225253
}
226254

@@ -230,18 +258,57 @@ impl CommunityType for Community {
230258
removed_mod: Person,
231259
context: &LemmyContext,
232260
) -> Result<(), LemmyError> {
233-
let mut remove = Remove::new(
234-
actor.actor_id.clone().into_inner(),
235-
removed_mod.actor_id.into_inner(),
236-
);
261+
let mut remove = Remove::new(actor.actor_id(), removed_mod.actor_id());
237262
remove
238263
.set_many_contexts(lemmy_context()?)
239264
.set_id(generate_activity_id(RemoveType::Remove)?)
240265
.set_to(public())
241266
.set_many_ccs(vec![self.actor_id()])
242267
.set_target(generate_moderators_url(&self.actor_id)?.into_inner());
243268

244-
send_to_community(remove, &actor, self, context).await?;
269+
send_to_community(remove, &actor, self, Some(removed_mod.actor_id()), context).await?;
270+
Ok(())
271+
}
272+
273+
async fn send_block_user(
274+
&self,
275+
actor: &Person,
276+
blocked_user: Person,
277+
context: &LemmyContext,
278+
) -> Result<(), LemmyError> {
279+
let mut block = Block::new(actor.actor_id(), blocked_user.actor_id());
280+
block
281+
.set_many_contexts(lemmy_context()?)
282+
.set_id(generate_activity_id(BlockType::Block)?)
283+
.set_to(public())
284+
.set_many_ccs(vec![self.actor_id()]);
285+
286+
send_to_community(block, &actor, self, Some(blocked_user.actor_id()), context).await?;
287+
Ok(())
288+
}
289+
290+
async fn send_undo_block_user(
291+
&self,
292+
actor: &Person,
293+
unblocked_user: Person,
294+
context: &LemmyContext,
295+
) -> Result<(), LemmyError> {
296+
let mut block = Block::new(actor.actor_id(), unblocked_user.actor_id());
297+
block
298+
.set_many_contexts(lemmy_context()?)
299+
.set_id(generate_activity_id(BlockType::Block)?)
300+
.set_to(public())
301+
.set_many_ccs(vec![self.actor_id()]);
302+
303+
// Undo that fake activity
304+
let mut undo = Undo::new(actor.actor_id(), block.into_any_base()?);
305+
undo
306+
.set_many_contexts(lemmy_context()?)
307+
.set_id(generate_activity_id(UndoType::Undo)?)
308+
.set_to(public())
309+
.set_many_ccs(vec![self.actor_id()]);
310+
311+
send_to_community(undo, &actor, self, Some(unblocked_user.actor_id()), context).await?;
245312
Ok(())
246313
}
247314
}

0 commit comments

Comments
 (0)