1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2021 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 media_update_message = build_media_update_message()
30 local_message = build_local_message()
32 assert SimplePolicy.filter(media_message) == {:ok, media_message}
33 assert SimplePolicy.filter(media_update_message) == {:ok, media_update_message}
34 assert SimplePolicy.filter(local_message) == {:ok, local_message}
37 test "has a matching host" do
38 clear_config([:mrf_simple, :media_removal], [{"remote.instance", "Some reason"}])
39 media_message = build_media_message()
40 media_update_message = build_media_update_message()
41 local_message = build_local_message()
43 assert SimplePolicy.filter(media_message) ==
46 |> Map.put("object", Map.delete(media_message["object"], "attachment"))}
48 assert SimplePolicy.filter(media_update_message) ==
51 |> Map.put("object", Map.delete(media_update_message["object"], "attachment"))}
53 assert SimplePolicy.filter(local_message) == {:ok, local_message}
56 test "match with wildcard domain" do
57 clear_config([:mrf_simple, :media_removal], [{"*.remote.instance", "Whatever reason"}])
58 media_message = build_media_message()
59 media_update_message = build_media_update_message()
60 local_message = build_local_message()
62 assert SimplePolicy.filter(media_message) ==
65 |> Map.put("object", Map.delete(media_message["object"], "attachment"))}
67 assert SimplePolicy.filter(media_update_message) ==
70 |> Map.put("object", Map.delete(media_update_message["object"], "attachment"))}
72 assert SimplePolicy.filter(local_message) == {:ok, local_message}
76 describe "when :media_nsfw" do
78 clear_config([:mrf_simple, :media_nsfw], [])
79 media_message = build_media_message()
80 media_update_message = build_media_update_message()
81 local_message = build_local_message()
83 assert SimplePolicy.filter(media_message) == {:ok, media_message}
84 assert SimplePolicy.filter(media_update_message) == {:ok, media_update_message}
85 assert SimplePolicy.filter(local_message) == {:ok, local_message}
88 test "has a matching host" do
89 clear_config([:mrf_simple, :media_nsfw], [{"remote.instance", "Whetever"}])
90 media_message = build_media_message()
91 media_update_message = build_media_update_message()
92 local_message = build_local_message()
94 assert SimplePolicy.filter(media_message) ==
95 {:ok, put_in(media_message, ["object", "sensitive"], true)}
97 assert SimplePolicy.filter(media_update_message) ==
98 {:ok, put_in(media_update_message, ["object", "sensitive"], true)}
100 assert SimplePolicy.filter(local_message) == {:ok, local_message}
103 test "match with wildcard domain" do
104 clear_config([:mrf_simple, :media_nsfw], [{"*.remote.instance", "yeah yeah"}])
105 media_message = build_media_message()
106 media_update_message = build_media_update_message()
107 local_message = build_local_message()
109 assert SimplePolicy.filter(media_message) ==
110 {:ok, put_in(media_message, ["object", "sensitive"], true)}
112 assert SimplePolicy.filter(media_update_message) ==
113 {:ok, put_in(media_update_message, ["object", "sensitive"], true)}
115 assert SimplePolicy.filter(local_message) == {:ok, local_message}
119 defp build_media_message do
121 "actor" => "https://remote.instance/users/bob",
124 "attachment" => [%{}],
131 defp build_media_update_message do
133 "actor" => "https://remote.instance/users/bob",
136 "attachment" => [%{}],
143 describe "when :report_removal" do
145 clear_config([:mrf_simple, :report_removal], [])
146 report_message = build_report_message()
147 local_message = build_local_message()
149 assert SimplePolicy.filter(report_message) == {:ok, report_message}
150 assert SimplePolicy.filter(local_message) == {:ok, local_message}
153 test "has a matching host" do
154 clear_config([:mrf_simple, :report_removal], [{"remote.instance", "muh"}])
155 report_message = build_report_message()
156 local_message = build_local_message()
158 assert {:reject, _} = SimplePolicy.filter(report_message)
159 assert SimplePolicy.filter(local_message) == {:ok, local_message}
162 test "match with wildcard domain" do
163 clear_config([:mrf_simple, :report_removal], [{"*.remote.instance", "suya"}])
164 report_message = build_report_message()
165 local_message = build_local_message()
167 assert {:reject, _} = SimplePolicy.filter(report_message)
168 assert SimplePolicy.filter(local_message) == {:ok, local_message}
172 defp build_report_message do
174 "actor" => "https://remote.instance/users/bob",
179 describe "when :federated_timeline_removal" do
181 clear_config([:mrf_simple, :federated_timeline_removal], [])
182 {_, ftl_message} = build_ftl_actor_and_message()
183 local_message = build_local_message()
185 assert SimplePolicy.filter(ftl_message) == {:ok, ftl_message}
186 assert SimplePolicy.filter(local_message) == {:ok, local_message}
189 test "has a matching host" do
190 {actor, ftl_message} = build_ftl_actor_and_message()
192 ftl_message_actor_host =
194 |> Map.fetch!("actor")
198 clear_config([:mrf_simple, :federated_timeline_removal], [{ftl_message_actor_host, "uwu"}])
199 local_message = build_local_message()
201 assert {:ok, ftl_message} = SimplePolicy.filter(ftl_message)
202 assert actor.follower_address in ftl_message["to"]
203 refute actor.follower_address in ftl_message["cc"]
204 refute "https://www.w3.org/ns/activitystreams#Public" in ftl_message["to"]
205 assert "https://www.w3.org/ns/activitystreams#Public" in ftl_message["cc"]
207 assert SimplePolicy.filter(local_message) == {:ok, local_message}
210 test "match with wildcard domain" do
211 {actor, ftl_message} = build_ftl_actor_and_message()
213 ftl_message_actor_host =
215 |> Map.fetch!("actor")
219 clear_config([:mrf_simple, :federated_timeline_removal], [
220 {"*." <> ftl_message_actor_host, "owo"}
223 local_message = build_local_message()
225 assert {:ok, ftl_message} = SimplePolicy.filter(ftl_message)
226 assert actor.follower_address in ftl_message["to"]
227 refute actor.follower_address in ftl_message["cc"]
228 refute "https://www.w3.org/ns/activitystreams#Public" in ftl_message["to"]
229 assert "https://www.w3.org/ns/activitystreams#Public" in ftl_message["cc"]
231 assert SimplePolicy.filter(local_message) == {:ok, local_message}
234 test "has a matching host but only as:Public in to" do
235 {_actor, ftl_message} = build_ftl_actor_and_message()
237 ftl_message_actor_host =
239 |> Map.fetch!("actor")
243 ftl_message = Map.put(ftl_message, "cc", [])
245 clear_config([:mrf_simple, :federated_timeline_removal], [
246 {ftl_message_actor_host, "spiderwaifu goes 88w88"}
249 assert {:ok, ftl_message} = SimplePolicy.filter(ftl_message)
250 refute "https://www.w3.org/ns/activitystreams#Public" in ftl_message["to"]
251 assert "https://www.w3.org/ns/activitystreams#Public" in ftl_message["cc"]
255 describe "describe/1" do
256 test "returns a description of the policy" do
257 clear_config([:mrf_simple, :reject], [
258 {"remote.instance", "did not give my catboy a burg"}
261 assert {:ok, %{mrf_simple: %{reject: ["remote.instance"]}}} = SimplePolicy.describe()
264 test "excludes domains listed in :transparency_exclusions" do
265 clear_config([:mrf, :transparency_exclusions], [{"remote.instance", ":("}])
267 clear_config([:mrf_simple, :reject], [
268 {"remote.instance", "did not give my catboy a burg"}
271 {:ok, description} = SimplePolicy.describe()
272 assert %{mrf_simple: %{reject: []}} = description
273 assert description[:mrf_simple_info][:reject] == nil
276 test "obfuscates domains listed in :transparency_obfuscate_domains" do
277 clear_config([:mrf, :transparency_obfuscate_domains], ["remote.instance", "a.b"])
279 clear_config([:mrf_simple, :reject], [
280 {"remote.instance", "did not give my catboy a burg"},
281 {"a.b", "spam-poked me on facebook in 2006"}
286 mrf_simple: %{reject: ["rem***.*****nce", "a.b"]},
287 mrf_simple_info: %{reject: %{"rem***.*****nce" => %{}}}
288 }} = SimplePolicy.describe()
292 defp build_ftl_actor_and_message do
293 actor = insert(:user)
297 "actor" => actor.ap_id,
298 "to" => ["https://www.w3.org/ns/activitystreams#Public", "http://foo.bar/baz"],
299 "cc" => [actor.follower_address, "http://foo.bar/qux"]
303 describe "when :reject" do
305 clear_config([:mrf_simple, :reject], [])
307 remote_message = build_remote_message()
309 assert SimplePolicy.filter(remote_message) == {:ok, remote_message}
312 test "activity has a matching host" do
313 clear_config([:mrf_simple, :reject], [{"remote.instance", ""}])
315 remote_message = build_remote_message()
317 assert {:reject, _} = SimplePolicy.filter(remote_message)
320 test "activity matches with wildcard domain" do
321 clear_config([:mrf_simple, :reject], [{"*.remote.instance", ""}])
323 remote_message = build_remote_message()
325 assert {:reject, _} = SimplePolicy.filter(remote_message)
328 test "actor has a matching host" do
329 clear_config([:mrf_simple, :reject], [{"remote.instance", ""}])
331 remote_user = build_remote_user()
333 assert {:reject, _} = SimplePolicy.filter(remote_user)
336 test "reject Announce when object would be rejected" do
337 clear_config([:mrf_simple, :reject], [{"blocked.tld", ""}])
340 "type" => "Announce",
341 "actor" => "https://okay.tld/users/alice",
342 "object" => %{"type" => "Note", "actor" => "https://blocked.tld/users/bob"}
345 assert {:reject, _} = SimplePolicy.filter(announce)
348 test "reject by URI object" do
349 clear_config([:mrf_simple, :reject], [{"blocked.tld", ""}])
352 "type" => "Announce",
353 "actor" => "https://okay.tld/users/alice",
354 "object" => "https://blocked.tld/activities/1"
357 assert {:reject, _} = SimplePolicy.filter(announce)
361 describe "when :followers_only" do
363 clear_config([:mrf_simple, :followers_only], [])
364 {_, ftl_message} = build_ftl_actor_and_message()
365 local_message = build_local_message()
367 assert SimplePolicy.filter(ftl_message) == {:ok, ftl_message}
368 assert SimplePolicy.filter(local_message) == {:ok, local_message}
371 test "has a matching host" do
372 actor = insert(:user)
373 following_user = insert(:user)
374 non_following_user = insert(:user)
376 {:ok, _, _, _} = CommonAPI.follow(following_user, actor)
379 "actor" => actor.ap_id,
381 "https://www.w3.org/ns/activitystreams#Public",
382 following_user.ap_id,
383 non_following_user.ap_id
385 "cc" => [actor.follower_address, "http://foo.bar/qux"]
389 "actor" => actor.ap_id,
391 following_user.ap_id,
392 non_following_user.ap_id
399 |> Map.fetch!("actor")
403 clear_config([:mrf_simple, :followers_only], [{actor_domain, ""}])
405 assert {:ok, new_activity} = SimplePolicy.filter(activity)
406 assert actor.follower_address in new_activity["cc"]
407 assert following_user.ap_id in new_activity["to"]
408 refute "https://www.w3.org/ns/activitystreams#Public" in new_activity["to"]
409 refute "https://www.w3.org/ns/activitystreams#Public" in new_activity["cc"]
410 refute non_following_user.ap_id in new_activity["to"]
411 refute non_following_user.ap_id in new_activity["cc"]
413 assert {:ok, new_dm_activity} = SimplePolicy.filter(dm_activity)
414 assert new_dm_activity["to"] == [following_user.ap_id]
415 assert new_dm_activity["cc"] == []
419 describe "when :accept" do
421 clear_config([:mrf_simple, :accept], [])
423 local_message = build_local_message()
424 remote_message = build_remote_message()
426 assert SimplePolicy.filter(local_message) == {:ok, local_message}
427 assert SimplePolicy.filter(remote_message) == {:ok, remote_message}
430 test "is not empty but activity doesn't have a matching host" do
431 clear_config([:mrf_simple, :accept], [{"non.matching.remote", ""}])
433 local_message = build_local_message()
434 remote_message = build_remote_message()
436 assert SimplePolicy.filter(local_message) == {:ok, local_message}
437 assert {:reject, _} = SimplePolicy.filter(remote_message)
440 test "activity has a matching host" do
441 clear_config([:mrf_simple, :accept], [{"remote.instance", ""}])
443 local_message = build_local_message()
444 remote_message = build_remote_message()
446 assert SimplePolicy.filter(local_message) == {:ok, local_message}
447 assert SimplePolicy.filter(remote_message) == {:ok, remote_message}
450 test "activity matches with wildcard domain" do
451 clear_config([:mrf_simple, :accept], [{"*.remote.instance", ""}])
453 local_message = build_local_message()
454 remote_message = build_remote_message()
456 assert SimplePolicy.filter(local_message) == {:ok, local_message}
457 assert SimplePolicy.filter(remote_message) == {:ok, remote_message}
460 test "actor has a matching host" do
461 clear_config([:mrf_simple, :accept], [{"remote.instance", ""}])
463 remote_user = build_remote_user()
465 assert SimplePolicy.filter(remote_user) == {:ok, remote_user}
469 describe "when :avatar_removal" do
471 clear_config([:mrf_simple, :avatar_removal], [])
473 remote_user = build_remote_user()
475 assert SimplePolicy.filter(remote_user) == {:ok, remote_user}
478 test "is not empty but it doesn't have a matching host" do
479 clear_config([:mrf_simple, :avatar_removal], [{"non.matching.remote", ""}])
481 remote_user = build_remote_user()
483 assert SimplePolicy.filter(remote_user) == {:ok, remote_user}
486 test "has a matching host" do
487 clear_config([:mrf_simple, :avatar_removal], [{"remote.instance", ""}])
489 remote_user = build_remote_user()
490 {:ok, filtered} = SimplePolicy.filter(remote_user)
492 refute filtered["icon"]
495 test "match with wildcard domain" do
496 clear_config([:mrf_simple, :avatar_removal], [{"*.remote.instance", ""}])
498 remote_user = build_remote_user()
499 {:ok, filtered} = SimplePolicy.filter(remote_user)
501 refute filtered["icon"]
505 describe "when :banner_removal" do
507 clear_config([:mrf_simple, :banner_removal], [])
509 remote_user = build_remote_user()
511 assert SimplePolicy.filter(remote_user) == {:ok, remote_user}
514 test "is not empty but it doesn't have a matching host" do
515 clear_config([:mrf_simple, :banner_removal], [{"non.matching.remote", ""}])
517 remote_user = build_remote_user()
519 assert SimplePolicy.filter(remote_user) == {:ok, remote_user}
522 test "has a matching host" do
523 clear_config([:mrf_simple, :banner_removal], [{"remote.instance", ""}])
525 remote_user = build_remote_user()
526 {:ok, filtered} = SimplePolicy.filter(remote_user)
528 refute filtered["image"]
531 test "match with wildcard domain" do
532 clear_config([:mrf_simple, :banner_removal], [{"*.remote.instance", ""}])
534 remote_user = build_remote_user()
535 {:ok, filtered} = SimplePolicy.filter(remote_user)
537 refute filtered["image"]
541 describe "when :reject_deletes is empty" do
542 setup do: clear_config([:mrf_simple, :reject_deletes], [])
544 test "it accepts deletions even from rejected servers" do
545 clear_config([:mrf_simple, :reject], [{"remote.instance", ""}])
547 deletion_message = build_remote_deletion_message()
549 assert SimplePolicy.filter(deletion_message) == {:ok, deletion_message}
552 test "it accepts deletions even from non-whitelisted servers" do
553 clear_config([:mrf_simple, :accept], [{"non.matching.remote", ""}])
555 deletion_message = build_remote_deletion_message()
557 assert SimplePolicy.filter(deletion_message) == {:ok, deletion_message}
561 describe "when :reject_deletes is not empty but it doesn't have a matching host" do
562 setup do: clear_config([:mrf_simple, :reject_deletes], [{"non.matching.remote", ""}])
564 test "it accepts deletions even from rejected servers" do
565 clear_config([:mrf_simple, :reject], [{"remote.instance", ""}])
567 deletion_message = build_remote_deletion_message()
569 assert SimplePolicy.filter(deletion_message) == {:ok, deletion_message}
572 test "it accepts deletions even from non-whitelisted servers" do
573 clear_config([:mrf_simple, :accept], [{"non.matching.remote", ""}])
575 deletion_message = build_remote_deletion_message()
577 assert SimplePolicy.filter(deletion_message) == {:ok, deletion_message}
581 describe "when :reject_deletes has a matching host" do
582 setup do: clear_config([:mrf_simple, :reject_deletes], [{"remote.instance", ""}])
584 test "it rejects the deletion" do
585 deletion_message = build_remote_deletion_message()
587 assert {:reject, _} = SimplePolicy.filter(deletion_message)
591 describe "when :reject_deletes match with wildcard domain" do
592 setup do: clear_config([:mrf_simple, :reject_deletes], [{"*.remote.instance", ""}])
594 test "it rejects the deletion" do
595 deletion_message = build_remote_deletion_message()
597 assert {:reject, _} = SimplePolicy.filter(deletion_message)
601 defp build_local_message do
603 "actor" => "#{Pleroma.Web.Endpoint.url()}/users/alice",
609 defp build_remote_message do
610 %{"actor" => "https://remote.instance/users/bob"}
613 defp build_remote_user do
615 "id" => "https://remote.instance/users/bob",
617 "url" => "http://example.com/image.jpg",
621 "url" => "http://example.com/image.jpg",
628 defp build_remote_deletion_message do
631 "actor" => "https://remote.instance/users/bob"