From 3c90f7f7156889a1f74950ab976819faa281df43 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Tue, 28 Jul 2020 18:55:29 -0500 Subject: [PATCH] SimpleMRF: Let instances be silenced --- config/description.exs | 6 +++ docs/configuration/cheatsheet.md | 1 + .../web/activity_pub/mrf/simple_policy.ex | 28 +++++++++++ .../activity_pub/mrf/simple_policy_test.exs | 47 +++++++++++++++++++ 4 files changed, 82 insertions(+) diff --git a/config/description.exs b/config/description.exs index 91261c1e1..9ffe6f93d 100644 --- a/config/description.exs +++ b/config/description.exs @@ -1524,6 +1524,12 @@ description: "List of instances to only accept activities from (except deletes)", suggestions: ["example.com", "*.example.com"] }, + %{ + key: :silence, + type: {:list, :string}, + description: "Force posts from the given instances to be visible by followers only", + suggestions: ["example.com", "*.example.com"] + }, %{ key: :report_removal, type: {:list, :string}, diff --git a/docs/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md index 2a25a024a..9a7f4f369 100644 --- a/docs/configuration/cheatsheet.md +++ b/docs/configuration/cheatsheet.md @@ -122,6 +122,7 @@ To add configuration to your config file, you can copy it from the base config. * `federated_timeline_removal`: List of instances to remove from Federated (aka The Whole Known Network) Timeline. * `reject`: List of instances to reject any activities from. * `accept`: List of instances to accept any activities from. +* `silence`: List of instances to force posts as followers-only. * `report_removal`: List of instances to reject reports from. * `avatar_removal`: List of instances to strip avatars from. * `banner_removal`: List of instances to strip banners from. diff --git a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex index b77b8c7b4..e168a943e 100644 --- a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex @@ -7,6 +7,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do @behaviour Pleroma.Web.ActivityPub.MRF alias Pleroma.Config + alias Pleroma.FollowingRelationship alias Pleroma.User alias Pleroma.Web.ActivityPub.MRF @@ -108,6 +109,32 @@ defp check_ftl_removal(%{host: actor_host} = _actor_info, object) do {:ok, object} end + defp check_silence(%{host: actor_host} = _actor_info, object) do + silence = + Config.get([:mrf_simple, :silence]) + |> MRF.subdomains_regex() + + object = + with true <- MRF.subdomain_match?(silence, actor_host), + user <- User.get_cached_by_ap_id(object["actor"]) do + to = + FollowingRelationship.followers_ap_ids(user, Map.get(object, "to", [])) ++ + [user.follower_address] + + cc = FollowingRelationship.followers_ap_ids(user, Map.get(object, "cc", [])) + + object + |> Map.put("to", to) + |> Map.put("cc", cc) + else + _ -> object + end + + {:ok, object} + end + + defp check_silence(_actor_info, object), do: {:ok, object} + defp check_report_removal(%{host: actor_host} = _actor_info, %{"type" => "Flag"} = object) do report_removal = Config.get([:mrf_simple, :report_removal]) @@ -174,6 +201,7 @@ def filter(%{"actor" => actor} = object) do {:ok, object} <- check_media_removal(actor_info, object), {:ok, object} <- check_media_nsfw(actor_info, object), {:ok, object} <- check_ftl_removal(actor_info, object), + {:ok, object} <- check_silence(actor_info, object), {:ok, object} <- check_report_removal(actor_info, object) do {:ok, object} else diff --git a/test/web/activity_pub/mrf/simple_policy_test.exs b/test/web/activity_pub/mrf/simple_policy_test.exs index e842d8d8d..510a31d80 100644 --- a/test/web/activity_pub/mrf/simple_policy_test.exs +++ b/test/web/activity_pub/mrf/simple_policy_test.exs @@ -7,6 +7,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do import Pleroma.Factory alias Pleroma.Config alias Pleroma.Web.ActivityPub.MRF.SimplePolicy + alias Pleroma.Web.CommonAPI setup do: clear_config(:mrf_simple, @@ -15,6 +16,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do federated_timeline_removal: [], report_removal: [], reject: [], + silence: [], accept: [], avatar_removal: [], banner_removal: [], @@ -261,6 +263,51 @@ test "actor has a matching host" do end end + describe "when :silence" do + test "is empty" do + Config.put([:mrf_simple, :silence], []) + {_, ftl_message} = build_ftl_actor_and_message() + local_message = build_local_message() + + assert SimplePolicy.filter(ftl_message) == {:ok, ftl_message} + assert SimplePolicy.filter(local_message) == {:ok, local_message} + end + + test "has a matching host" do + actor = insert(:user) + following_user = insert(:user) + non_following_user = insert(:user) + + {:ok, _, _, _} = CommonAPI.follow(following_user, actor) + + activity = %{ + "actor" => actor.ap_id, + "to" => [ + "https://www.w3.org/ns/activitystreams#Public", + following_user.ap_id, + non_following_user.ap_id + ], + "cc" => [actor.follower_address, "http://foo.bar/qux"] + } + + actor_domain = + activity + |> Map.fetch!("actor") + |> URI.parse() + |> Map.fetch!(:host) + + Config.put([:mrf_simple, :silence], [actor_domain]) + + assert {:ok, new_activity} = SimplePolicy.filter(activity) + assert actor.follower_address in new_activity["to"] + assert following_user.ap_id in new_activity["to"] + refute "https://www.w3.org/ns/activitystreams#Public" in new_activity["to"] + refute "https://www.w3.org/ns/activitystreams#Public" in new_activity["cc"] + refute non_following_user.ap_id in new_activity["to"] + refute non_following_user.ap_id in new_activity["cc"] + end + end + describe "when :accept" do test "is empty" do Config.put([:mrf_simple, :accept], [])