1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
8 alias Pleroma.Web.ActivityPub.MRF.SimplePolicy
9 alias Pleroma.Web.CommonAPI
12 clear_config(:mrf_simple,
15 federated_timeline_removal: [],
25 describe "when :media_removal" do
27 clear_config([:mrf_simple, :media_removal], [])
28 media_message = build_media_message()
29 local_message = build_local_message()
31 assert SimplePolicy.filter(media_message) == {:ok, media_message}
32 assert SimplePolicy.filter(local_message) == {:ok, local_message}
35 test "has a matching host" do
36 clear_config([:mrf_simple, :media_removal], [{"remote.instance", "Some reason"}])
37 media_message = build_media_message()
38 local_message = build_local_message()
40 assert SimplePolicy.filter(media_message) ==
43 |> Map.put("object", Map.delete(media_message["object"], "attachment"))}
45 assert SimplePolicy.filter(local_message) == {:ok, local_message}
48 test "match with wildcard domain" do
49 clear_config([:mrf_simple, :media_removal], [{"*.remote.instance", "Whatever reason"}])
50 media_message = build_media_message()
51 local_message = build_local_message()
53 assert SimplePolicy.filter(media_message) ==
56 |> Map.put("object", Map.delete(media_message["object"], "attachment"))}
58 assert SimplePolicy.filter(local_message) == {:ok, local_message}
61 test "works with Updates" do
62 clear_config([:mrf_simple, :media_removal], [{"remote.instance", "Some reason"}])
63 media_message = build_media_message(type: "Update")
65 assert SimplePolicy.filter(media_message) ==
68 |> Map.put("object", Map.delete(media_message["object"], "attachment"))}
72 describe "when :media_nsfw" do
74 clear_config([:mrf_simple, :media_nsfw], [])
75 media_message = build_media_message()
76 local_message = build_local_message()
78 assert SimplePolicy.filter(media_message) == {:ok, media_message}
79 assert SimplePolicy.filter(local_message) == {:ok, local_message}
82 test "has a matching host" do
83 clear_config([:mrf_simple, :media_nsfw], [{"remote.instance", "Whetever"}])
84 media_message = build_media_message()
85 local_message = build_local_message()
87 assert SimplePolicy.filter(media_message) ==
88 {:ok, put_in(media_message, ["object", "sensitive"], true)}
90 assert SimplePolicy.filter(local_message) == {:ok, local_message}
93 test "match with wildcard domain" do
94 clear_config([:mrf_simple, :media_nsfw], [{"*.remote.instance", "yeah yeah"}])
95 media_message = build_media_message()
96 local_message = build_local_message()
98 assert SimplePolicy.filter(media_message) ==
99 {:ok, put_in(media_message, ["object", "sensitive"], true)}
101 assert SimplePolicy.filter(local_message) == {:ok, local_message}
104 test "works with Updates" do
105 clear_config([:mrf_simple, :media_nsfw], [{"remote.instance", "Whetever"}])
106 media_message = build_media_message(type: "Update")
108 assert SimplePolicy.filter(media_message) ==
109 {:ok, put_in(media_message, ["object", "sensitive"], true)}
113 defp build_media_message(opts \\ []) do
115 "actor" => "https://remote.instance/users/bob",
116 "type" => opts[:type] || "Create",
118 "attachment" => [%{}],
125 describe "when :report_removal" do
127 clear_config([:mrf_simple, :report_removal], [])
128 report_message = build_report_message()
129 local_message = build_local_message()
131 assert SimplePolicy.filter(report_message) == {:ok, report_message}
132 assert SimplePolicy.filter(local_message) == {:ok, local_message}
135 test "has a matching host" do
136 clear_config([:mrf_simple, :report_removal], [{"remote.instance", "muh"}])
137 report_message = build_report_message()
138 local_message = build_local_message()
140 assert {:reject, _} = SimplePolicy.filter(report_message)
141 assert SimplePolicy.filter(local_message) == {:ok, local_message}
144 test "match with wildcard domain" do
145 clear_config([:mrf_simple, :report_removal], [{"*.remote.instance", "suya"}])
146 report_message = build_report_message()
147 local_message = build_local_message()
149 assert {:reject, _} = SimplePolicy.filter(report_message)
150 assert SimplePolicy.filter(local_message) == {:ok, local_message}
154 defp build_report_message do
156 "actor" => "https://remote.instance/users/bob",
161 describe "when :federated_timeline_removal" do
163 clear_config([:mrf_simple, :federated_timeline_removal], [])
164 {_, ftl_message} = build_ftl_actor_and_message()
165 local_message = build_local_message()
167 assert SimplePolicy.filter(ftl_message) == {:ok, ftl_message}
168 assert SimplePolicy.filter(local_message) == {:ok, local_message}
171 test "has a matching host" do
172 {actor, ftl_message} = build_ftl_actor_and_message()
174 ftl_message_actor_host =
176 |> Map.fetch!("actor")
180 clear_config([:mrf_simple, :federated_timeline_removal], [{ftl_message_actor_host, "uwu"}])
181 local_message = build_local_message()
183 assert {:ok, ftl_message} = SimplePolicy.filter(ftl_message)
184 assert actor.follower_address in ftl_message["to"]
185 refute actor.follower_address in ftl_message["cc"]
186 refute "https://www.w3.org/ns/activitystreams#Public" in ftl_message["to"]
187 assert "https://www.w3.org/ns/activitystreams#Public" in ftl_message["cc"]
189 assert SimplePolicy.filter(local_message) == {:ok, local_message}
192 test "match with wildcard domain" do
193 {actor, ftl_message} = build_ftl_actor_and_message()
195 ftl_message_actor_host =
197 |> Map.fetch!("actor")
201 clear_config([:mrf_simple, :federated_timeline_removal], [
202 {"*." <> ftl_message_actor_host, "owo"}
205 local_message = build_local_message()
207 assert {:ok, ftl_message} = SimplePolicy.filter(ftl_message)
208 assert actor.follower_address in ftl_message["to"]
209 refute actor.follower_address in ftl_message["cc"]
210 refute "https://www.w3.org/ns/activitystreams#Public" in ftl_message["to"]
211 assert "https://www.w3.org/ns/activitystreams#Public" in ftl_message["cc"]
213 assert SimplePolicy.filter(local_message) == {:ok, local_message}
216 test "has a matching host but only as:Public in to" do
217 {_actor, ftl_message} = build_ftl_actor_and_message()
219 ftl_message_actor_host =
221 |> Map.fetch!("actor")
225 ftl_message = Map.put(ftl_message, "cc", [])
227 clear_config([:mrf_simple, :federated_timeline_removal], [
228 {ftl_message_actor_host, "spiderwaifu goes 88w88"}
231 assert {:ok, ftl_message} = SimplePolicy.filter(ftl_message)
232 refute "https://www.w3.org/ns/activitystreams#Public" in ftl_message["to"]
233 assert "https://www.w3.org/ns/activitystreams#Public" in ftl_message["cc"]
237 defp build_ftl_actor_and_message do
238 actor = insert(:user)
242 "actor" => actor.ap_id,
243 "to" => ["https://www.w3.org/ns/activitystreams#Public", "http://foo.bar/baz"],
244 "cc" => [actor.follower_address, "http://foo.bar/qux"]
248 describe "when :reject" do
250 clear_config([:mrf_simple, :reject], [])
252 remote_message = build_remote_message()
254 assert SimplePolicy.filter(remote_message) == {:ok, remote_message}
257 test "activity has a matching host" do
258 clear_config([:mrf_simple, :reject], [{"remote.instance", ""}])
260 remote_message = build_remote_message()
262 assert {:reject, _} = SimplePolicy.filter(remote_message)
265 test "activity matches with wildcard domain" do
266 clear_config([:mrf_simple, :reject], [{"*.remote.instance", ""}])
268 remote_message = build_remote_message()
270 assert {:reject, _} = SimplePolicy.filter(remote_message)
273 test "actor has a matching host" do
274 clear_config([:mrf_simple, :reject], [{"remote.instance", ""}])
276 remote_user = build_remote_user()
278 assert {:reject, _} = SimplePolicy.filter(remote_user)
281 test "reject Announce when object would be rejected" do
282 clear_config([:mrf_simple, :reject], [{"blocked.tld", ""}])
285 "type" => "Announce",
286 "actor" => "https://okay.tld/users/alice",
287 "object" => %{"type" => "Note", "actor" => "https://blocked.tld/users/bob"}
290 assert {:reject, _} = SimplePolicy.filter(announce)
293 test "reject by URI object" do
294 clear_config([:mrf_simple, :reject], [{"blocked.tld", ""}])
297 "type" => "Announce",
298 "actor" => "https://okay.tld/users/alice",
299 "object" => "https://blocked.tld/activities/1"
302 assert {:reject, _} = SimplePolicy.filter(announce)
306 describe "when :followers_only" do
308 clear_config([:mrf_simple, :followers_only], [])
309 {_, ftl_message} = build_ftl_actor_and_message()
310 local_message = build_local_message()
312 assert SimplePolicy.filter(ftl_message) == {:ok, ftl_message}
313 assert SimplePolicy.filter(local_message) == {:ok, local_message}
316 test "has a matching host" do
317 actor = insert(:user)
318 following_user = insert(:user)
319 non_following_user = insert(:user)
321 {:ok, _, _, _} = CommonAPI.follow(following_user, actor)
324 "actor" => actor.ap_id,
326 "https://www.w3.org/ns/activitystreams#Public",
327 following_user.ap_id,
328 non_following_user.ap_id
330 "cc" => [actor.follower_address, "http://foo.bar/qux"]
334 "actor" => actor.ap_id,
336 following_user.ap_id,
337 non_following_user.ap_id
344 |> Map.fetch!("actor")
348 clear_config([:mrf_simple, :followers_only], [{actor_domain, ""}])
350 assert {:ok, new_activity} = SimplePolicy.filter(activity)
351 assert actor.follower_address in new_activity["cc"]
352 assert following_user.ap_id in new_activity["to"]
353 refute "https://www.w3.org/ns/activitystreams#Public" in new_activity["to"]
354 refute "https://www.w3.org/ns/activitystreams#Public" in new_activity["cc"]
355 refute non_following_user.ap_id in new_activity["to"]
356 refute non_following_user.ap_id in new_activity["cc"]
358 assert {:ok, new_dm_activity} = SimplePolicy.filter(dm_activity)
359 assert new_dm_activity["to"] == [following_user.ap_id]
360 assert new_dm_activity["cc"] == []
364 describe "when :accept" do
366 clear_config([:mrf_simple, :accept], [])
368 local_message = build_local_message()
369 remote_message = build_remote_message()
371 assert SimplePolicy.filter(local_message) == {:ok, local_message}
372 assert SimplePolicy.filter(remote_message) == {:ok, remote_message}
375 test "is not empty but activity doesn't have a matching host" do
376 clear_config([:mrf_simple, :accept], [{"non.matching.remote", ""}])
378 local_message = build_local_message()
379 remote_message = build_remote_message()
381 assert SimplePolicy.filter(local_message) == {:ok, local_message}
382 assert {:reject, _} = SimplePolicy.filter(remote_message)
385 test "activity has a matching host" do
386 clear_config([:mrf_simple, :accept], [{"remote.instance", ""}])
388 local_message = build_local_message()
389 remote_message = build_remote_message()
391 assert SimplePolicy.filter(local_message) == {:ok, local_message}
392 assert SimplePolicy.filter(remote_message) == {:ok, remote_message}
395 test "activity matches with wildcard domain" do
396 clear_config([:mrf_simple, :accept], [{"*.remote.instance", ""}])
398 local_message = build_local_message()
399 remote_message = build_remote_message()
401 assert SimplePolicy.filter(local_message) == {:ok, local_message}
402 assert SimplePolicy.filter(remote_message) == {:ok, remote_message}
405 test "actor has a matching host" do
406 clear_config([:mrf_simple, :accept], [{"remote.instance", ""}])
408 remote_user = build_remote_user()
410 assert SimplePolicy.filter(remote_user) == {:ok, remote_user}
414 describe "when :avatar_removal" do
416 clear_config([:mrf_simple, :avatar_removal], [])
418 remote_user = build_remote_user()
420 assert SimplePolicy.filter(remote_user) == {:ok, remote_user}
423 test "is not empty but it doesn't have a matching host" do
424 clear_config([:mrf_simple, :avatar_removal], [{"non.matching.remote", ""}])
426 remote_user = build_remote_user()
428 assert SimplePolicy.filter(remote_user) == {:ok, remote_user}
431 test "has a matching host" do
432 clear_config([:mrf_simple, :avatar_removal], [{"remote.instance", ""}])
434 remote_user = build_remote_user()
435 {:ok, filtered} = SimplePolicy.filter(remote_user)
437 refute filtered["icon"]
440 test "match with wildcard domain" do
441 clear_config([:mrf_simple, :avatar_removal], [{"*.remote.instance", ""}])
443 remote_user = build_remote_user()
444 {:ok, filtered} = SimplePolicy.filter(remote_user)
446 refute filtered["icon"]
450 describe "when :banner_removal" do
452 clear_config([:mrf_simple, :banner_removal], [])
454 remote_user = build_remote_user()
456 assert SimplePolicy.filter(remote_user) == {:ok, remote_user}
459 test "is not empty but it doesn't have a matching host" do
460 clear_config([:mrf_simple, :banner_removal], [{"non.matching.remote", ""}])
462 remote_user = build_remote_user()
464 assert SimplePolicy.filter(remote_user) == {:ok, remote_user}
467 test "has a matching host" do
468 clear_config([:mrf_simple, :banner_removal], [{"remote.instance", ""}])
470 remote_user = build_remote_user()
471 {:ok, filtered} = SimplePolicy.filter(remote_user)
473 refute filtered["image"]
476 test "match with wildcard domain" do
477 clear_config([:mrf_simple, :banner_removal], [{"*.remote.instance", ""}])
479 remote_user = build_remote_user()
480 {:ok, filtered} = SimplePolicy.filter(remote_user)
482 refute filtered["image"]
486 describe "when :reject_deletes is empty" do
487 setup do: clear_config([:mrf_simple, :reject_deletes], [])
489 test "it accepts deletions even from rejected servers" do
490 clear_config([:mrf_simple, :reject], [{"remote.instance", ""}])
492 deletion_message = build_remote_deletion_message()
494 assert SimplePolicy.filter(deletion_message) == {:ok, deletion_message}
497 test "it accepts deletions even from non-whitelisted servers" do
498 clear_config([:mrf_simple, :accept], [{"non.matching.remote", ""}])
500 deletion_message = build_remote_deletion_message()
502 assert SimplePolicy.filter(deletion_message) == {:ok, deletion_message}
506 describe "when :reject_deletes is not empty but it doesn't have a matching host" do
507 setup do: clear_config([:mrf_simple, :reject_deletes], [{"non.matching.remote", ""}])
509 test "it accepts deletions even from rejected servers" do
510 clear_config([:mrf_simple, :reject], [{"remote.instance", ""}])
512 deletion_message = build_remote_deletion_message()
514 assert SimplePolicy.filter(deletion_message) == {:ok, deletion_message}
517 test "it accepts deletions even from non-whitelisted servers" do
518 clear_config([:mrf_simple, :accept], [{"non.matching.remote", ""}])
520 deletion_message = build_remote_deletion_message()
522 assert SimplePolicy.filter(deletion_message) == {:ok, deletion_message}
526 describe "when :reject_deletes has a matching host" do
527 setup do: clear_config([:mrf_simple, :reject_deletes], [{"remote.instance", ""}])
529 test "it rejects the deletion" do
530 deletion_message = build_remote_deletion_message()
532 assert {:reject, _} = SimplePolicy.filter(deletion_message)
536 describe "when :reject_deletes match with wildcard domain" do
537 setup do: clear_config([:mrf_simple, :reject_deletes], [{"*.remote.instance", ""}])
539 test "it rejects the deletion" do
540 deletion_message = build_remote_deletion_message()
542 assert {:reject, _} = SimplePolicy.filter(deletion_message)
546 defp build_local_message do
548 "actor" => "#{Pleroma.Web.Endpoint.url()}/users/alice",
554 defp build_remote_message do
555 %{"actor" => "https://remote.instance/users/bob"}
558 defp build_remote_user do
560 "id" => "https://remote.instance/users/bob",
562 "url" => "http://example.com/image.jpg",
566 "url" => "http://example.com/image.jpg",
573 defp build_remote_deletion_message do
576 "actor" => "https://remote.instance/users/bob"