commit: 4533f171ab5b73e5fc332c8f65fcf1e39e4d6003
parent d2eb4992e254c1cdc27033742de1958f02757df1
Author: Alex Gleason <alex@alexgleason.me>
Date: Sat, 5 Nov 2022 13:56:56 -0500
Add RemoteReportPolicy to reject reports without enough information
Diffstat:
3 files changed, 169 insertions(+), 0 deletions(-)
diff --git a/config/config.exs b/config/config.exs
@@ -434,6 +434,10 @@ config :pleroma, :mrf_follow_bot, follower_nickname: nil
config :pleroma, :mrf_inline_quote, template: "<bdi>RT:</bdi> {url}"
+config :pleroma, :mrf_remote_report,
+ reject_anonymous: true,
+ reject_empty_message: true
+
config :pleroma, :mrf_force_mention,
mention_parent: true,
mention_quoted: true
diff --git a/lib/pleroma/web/activity_pub/mrf/remote_report_policy.ex b/lib/pleroma/web/activity_pub/mrf/remote_report_policy.ex
@@ -0,0 +1,80 @@
+defmodule Pleroma.Web.ActivityPub.MRF.RemoteReportPolicy do
+ @moduledoc "Drop remote reports if they don't contain enough information."
+ @behaviour Pleroma.Web.ActivityPub.MRF.Policy
+
+ alias Pleroma.Config
+
+ @impl true
+ def filter(%{"type" => "Flag"} = object) do
+ with {_, false} <- {:local, local?(object)},
+ {:ok, _} <- maybe_reject_anonymous(object),
+ {:ok, _} <- maybe_reject_empty_message(object) do
+ {:ok, object}
+ else
+ {:local, true} -> {:ok, object}
+ {:reject, message} -> {:reject, message}
+ error -> {:reject, error}
+ end
+ end
+
+ def filter(object), do: {:ok, object}
+
+ defp maybe_reject_anonymous(%{"actor" => actor} = object) do
+ with true <- Config.get([:mrf_remote_report, :reject_anonymous]),
+ %URI{path: "/actor"} <- URI.parse(actor) do
+ {:reject, "[RemoteReportPolicy] Anonymous: #{actor}"}
+ else
+ _ -> {:ok, object}
+ end
+ end
+
+ defp maybe_reject_empty_message(%{"content" => content} = object)
+ when is_binary(content) and content != "" do
+ {:ok, object}
+ end
+
+ defp maybe_reject_empty_message(object) do
+ if Config.get([:mrf_remote_report, :reject_empty_message]) do
+ {:reject, ["RemoteReportPolicy] No content"]}
+ else
+ {:ok, object}
+ end
+ end
+
+ defp local?(%{"actor" => actor}) do
+ String.starts_with?(actor, Pleroma.Web.Endpoint.url())
+ end
+
+ @impl true
+ def describe do
+ mrf_remote_report =
+ Config.get(:mrf_remote_report)
+ |> Enum.into(%{})
+
+ {:ok, %{mrf_remote_report: mrf_remote_report}}
+ end
+
+ @impl true
+ def config_description do
+ %{
+ key: :mrf_remote_report,
+ related_policy: "Pleroma.Web.ActivityPub.MRF.RemoteReportPolicy",
+ label: "MRF Remote Report",
+ description: "Drop remote reports if they don't contain enough information.",
+ children: [
+ %{
+ key: :reject_anonymous,
+ type: :boolean,
+ description: "Reject anonymous remote reports?",
+ suggestions: [true]
+ },
+ %{
+ key: :reject_empty_message,
+ type: :boolean,
+ description: "Reject remote reports with no message?",
+ suggestions: [true]
+ }
+ ]
+ }
+ end
+end
diff --git a/test/pleroma/web/activity_pub/mrf/remote_report_policy_test.exs b/test/pleroma/web/activity_pub/mrf/remote_report_policy_test.exs
@@ -0,0 +1,85 @@
+defmodule Pleroma.Web.ActivityPub.MRF.RemoteReportPolicyTest do
+ use Pleroma.DataCase, async: true
+
+ alias Pleroma.Web.ActivityPub.MRF.RemoteReportPolicy
+
+ test "doesn't impact local report" do
+ clear_config([:mrf_remote_report, :reject_anonymous], true)
+ clear_config([:mrf_remote_report, :reject_empty_message], true)
+
+ activity = %{
+ "type" => "Flag",
+ "actor" => "http://localhost:4001/actor"
+ }
+
+ assert {:ok, _} = RemoteReportPolicy.filter(activity)
+ end
+
+ test "rejects anonymous report if `reject_anonymous: true`" do
+ clear_config([:mrf_remote_report, :reject_anonymous], true)
+
+ activity = %{
+ "type" => "Flag",
+ "actor" => "https://mastodon.social/actor"
+ }
+
+ assert {:reject, _} = RemoteReportPolicy.filter(activity)
+ end
+
+ test "preserves anonymous report if `reject_anonymous: false`" do
+ clear_config([:mrf_remote_report, :reject_anonymous], false)
+
+ activity = %{
+ "type" => "Flag",
+ "actor" => "https://mastodon.social/actor"
+ }
+
+ assert {:ok, _} = RemoteReportPolicy.filter(activity)
+ end
+
+ test "rejects empty message report if `reject_empty_message: true`" do
+ clear_config([:mrf_remote_report, :reject_empty_message], true)
+
+ activity = %{
+ "type" => "Flag",
+ "actor" => "https://mastodon.social/users/Gargron"
+ }
+
+ assert {:reject, _} = RemoteReportPolicy.filter(activity)
+ end
+
+ test "rejects empty message report (\"\") if `reject_empty_message: true`" do
+ clear_config([:mrf_remote_report, :reject_empty_message], true)
+
+ activity = %{
+ "type" => "Flag",
+ "actor" => "https://mastodon.social/users/Gargron",
+ "content" => ""
+ }
+
+ assert {:reject, _} = RemoteReportPolicy.filter(activity)
+ end
+
+ test "preserves empty message report if `reject_empty_message: false`" do
+ clear_config([:mrf_remote_report, :reject_empty_message], false)
+
+ activity = %{
+ "type" => "Flag",
+ "actor" => "https://mastodon.social/users/Gargron"
+ }
+
+ assert {:ok, _} = RemoteReportPolicy.filter(activity)
+ end
+
+ test "preserves anonymous, empty message report with all settings disabled" do
+ clear_config([:mrf_remote_report, :reject_empty_message], false)
+ clear_config([:mrf_remote_report, :reject_empty_message], false)
+
+ activity = %{
+ "type" => "Flag",
+ "actor" => "https://mastodon.social/actor"
+ }
+
+ assert {:ok, _} = RemoteReportPolicy.filter(activity)
+ end
+end