diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/pleroma/constants.ex | 5 | ||||
| -rw-r--r-- | lib/pleroma/web/activity_pub/mrf/remote_report_policy.ex | 118 | ||||
| -rw-r--r-- | lib/pleroma/web/activity_pub/object_validator.ex | 12 | 
3 files changed, 135 insertions, 0 deletions
diff --git a/lib/pleroma/constants.ex b/lib/pleroma/constants.ex index 5268ebe7a..2828c79a9 100644 --- a/lib/pleroma/constants.ex +++ b/lib/pleroma/constants.ex @@ -87,6 +87,7 @@ defmodule Pleroma.Constants do    const(activity_types,      do: [ +      "Block",        "Create",        "Update",        "Delete", @@ -115,6 +116,10 @@ defmodule Pleroma.Constants do      ]    ) +  const(object_types, +    do: ~w[Event Question Answer Audio Video Image Article Note Page ChatMessage] +  ) +    # basic regex, just there to weed out potential mistakes    # https://datatracker.ietf.org/doc/html/rfc2045#section-5.1    const(mime_regex, diff --git a/lib/pleroma/web/activity_pub/mrf/remote_report_policy.ex b/lib/pleroma/web/activity_pub/mrf/remote_report_policy.ex new file mode 100644 index 000000000..fa0610bf1 --- /dev/null +++ b/lib/pleroma/web/activity_pub/mrf/remote_report_policy.ex @@ -0,0 +1,118 @@ +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_all(object), +         {:ok, _} <- maybe_reject_anonymous(object), +         {:ok, _} <- maybe_reject_third_party(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_all(object) do +    if Config.get([:mrf_remote_report, :reject_all]) do +      {:reject, "[RemoteReportPolicy] Remote report"} +    else +      {:ok, object} +    end +  end + +  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_third_party(%{"object" => objects} = object) do +    {_, to} = +      case objects do +        [head | tail] when is_binary(head) -> {tail, head} +        s when is_binary(s) -> {[], s} +        _ -> {[], ""} +      end + +    with true <- Config.get([:mrf_remote_report, :reject_third_party]), +         false <- String.starts_with?(to, Pleroma.Web.Endpoint.url()) do +      {:reject, "[RemoteReportPolicy] Third-party: #{to}"} +    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_all, +          type: :boolean, +          description: "Reject all remote reports? (this option takes precedence)", +          suggestions: [false] +        }, +        %{ +          key: :reject_anonymous, +          type: :boolean, +          description: "Reject anonymous remote reports?", +          suggestions: [true] +        }, +        %{ +          key: :reject_third_party, +          type: :boolean, +          description: "Reject reports on users from third-party instances?", +          suggestions: [true] +        }, +        %{ +          key: :reject_empty_message, +          type: :boolean, +          description: "Reject remote reports with no message?", +          suggestions: [true] +        } +      ] +    } +  end +end diff --git a/lib/pleroma/web/activity_pub/object_validator.ex b/lib/pleroma/web/activity_pub/object_validator.ex index b3043b93a..35774d410 100644 --- a/lib/pleroma/web/activity_pub/object_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validator.ex @@ -11,6 +11,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do    @behaviour Pleroma.Web.ActivityPub.ObjectValidator.Validating +  import Pleroma.Constants, only: [activity_types: 0, object_types: 0] +    alias Pleroma.Activity    alias Pleroma.EctoType.ActivityPub.ObjectValidators    alias Pleroma.Object @@ -38,6 +40,16 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do    @impl true    def validate(object, meta) +  # This overload works together with the InboxGuardPlug +  # and ensures that we are not accepting any activity type +  # that cannot pass InboxGuardPlug. +  # If we want to support any more activity types, make sure to +  # add it in Pleroma.Constants's activity_types or object_types, +  # and, if applicable, allowed_activity_types_from_strangers. +  def validate(%{"type" => type}, _meta) +      when type not in activity_types() and type not in object_types(), +      do: {:error, :not_allowed_object_type} +    def validate(%{"type" => "Block"} = block_activity, meta) do      with {:ok, block_activity} <-             block_activity  | 
