summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMark Felder <feld@feld.me>2025-02-28 16:40:38 -0800
committerMark Felder <feld@feld.me>2025-02-28 16:43:28 -0800
commit2c9d071aadde88e8ab615be6654e237ae01decb7 (patch)
treec189e9325782f602fddd499a2ef0fe108dc7b17f /lib
parent63663ac88bae834621417a1084e507831a44e7e2 (diff)
downloadpleroma-2c9d071aadde88e8ab615be6654e237ae01decb7.tar.gz
pleroma-2c9d071aadde88e8ab615be6654e237ae01decb7.zip
Retire MRFs DNSRBL, FODirectReply, and QuietReply
DNSRBL was a neat experiment which should live out of tree. It works and could be used to coordinate rules across different servers, but Simple Policy will always be better FODirectReply and QuietReply have reliability issues as implemented in an MRF. If we want to expose this functionality to admins it should be a setting that overrides the chosen scope during CommonAPI.post instead of trying to rewrite the recipients with an MRF.
Diffstat (limited to 'lib')
-rw-r--r--lib/pleroma/web/activity_pub/mrf/dnsrbl_policy.ex146
-rw-r--r--lib/pleroma/web/activity_pub/mrf/fo_direct_reply.ex53
-rw-r--r--lib/pleroma/web/activity_pub/mrf/quiet_reply.ex60
3 files changed, 0 insertions, 259 deletions
diff --git a/lib/pleroma/web/activity_pub/mrf/dnsrbl_policy.ex b/lib/pleroma/web/activity_pub/mrf/dnsrbl_policy.ex
deleted file mode 100644
index ca41c464c..000000000
--- a/lib/pleroma/web/activity_pub/mrf/dnsrbl_policy.ex
+++ /dev/null
@@ -1,146 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2024 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Web.ActivityPub.MRF.DNSRBLPolicy do
- @moduledoc """
- Dynamic activity filtering based on an RBL database
-
- This MRF makes queries to a custom DNS server which will
- respond with values indicating the classification of the domain
- the activity originated from. This method has been widely used
- in the email anti-spam industry for very fast reputation checks.
-
- e.g., if the DNS response is 127.0.0.1 or empty, the domain is OK
- Other values such as 127.0.0.2 may be used for specific classifications.
-
- Information for why the host is blocked can be stored in a corresponding TXT record.
-
- This method is fail-open so if the queries fail the activites are accepted.
-
- An example of software meant for this purpsoe is rbldnsd which can be found
- at http://www.corpit.ru/mjt/rbldnsd.html or mirrored at
- https://git.pleroma.social/feld/rbldnsd
-
- It is highly recommended that you run your own copy of rbldnsd and use an
- external mechanism to sync/share the contents of the zone file. This is
- important to keep the latency on the queries as low as possible and prevent
- your DNS server from being attacked so it fails and content is permitted.
- """
-
- @behaviour Pleroma.Web.ActivityPub.MRF.Policy
-
- alias Pleroma.Config
-
- require Logger
-
- @query_retries 1
- @query_timeout 500
-
- @impl true
- def filter(%{"actor" => actor} = activity) do
- actor_info = URI.parse(actor)
-
- with {:ok, activity} <- check_rbl(actor_info, activity) do
- {:ok, activity}
- else
- _ -> {:reject, "[DNSRBLPolicy]"}
- end
- end
-
- @impl true
- def filter(activity), do: {:ok, activity}
-
- @impl true
- def describe do
- mrf_dnsrbl =
- Config.get(:mrf_dnsrbl)
- |> Enum.into(%{})
-
- {:ok, %{mrf_dnsrbl: mrf_dnsrbl}}
- end
-
- @impl true
- def config_description do
- %{
- key: :mrf_dnsrbl,
- related_policy: "Pleroma.Web.ActivityPub.MRF.DNSRBLPolicy",
- label: "MRF DNSRBL",
- description: "DNS RealTime Blackhole Policy",
- children: [
- %{
- key: :nameserver,
- type: {:string},
- description: "DNSRBL Nameserver to Query (IP or hostame)",
- suggestions: ["127.0.0.1"]
- },
- %{
- key: :port,
- type: {:string},
- description: "Nameserver port",
- suggestions: ["53"]
- },
- %{
- key: :zone,
- type: {:string},
- description: "Root zone for querying",
- suggestions: ["bl.pleroma.com"]
- }
- ]
- }
- end
-
- defp check_rbl(%{host: actor_host}, activity) do
- with false <- match?(^actor_host, Pleroma.Web.Endpoint.host()),
- zone when not is_nil(zone) <- Keyword.get(Config.get([:mrf_dnsrbl]), :zone) do
- query =
- Enum.join([actor_host, zone], ".")
- |> String.to_charlist()
-
- rbl_response = rblquery(query)
-
- if Enum.empty?(rbl_response) do
- {:ok, activity}
- else
- Task.start(fn ->
- reason =
- case rblquery(query, :txt) do
- [[result]] -> result
- _ -> "undefined"
- end
-
- Logger.warning(
- "DNSRBL Rejected activity from #{actor_host} for reason: #{inspect(reason)}"
- )
- end)
-
- :error
- end
- else
- _ -> {:ok, activity}
- end
- end
-
- defp get_rblhost_ip(rblhost) do
- case rblhost |> String.to_charlist() |> :inet_parse.address() do
- {:ok, _} -> rblhost |> String.to_charlist() |> :inet_parse.address()
- _ -> {:ok, rblhost |> String.to_charlist() |> :inet_res.lookup(:in, :a) |> Enum.random()}
- end
- end
-
- defp rblquery(query, type \\ :a) do
- config = Config.get([:mrf_dnsrbl])
-
- case get_rblhost_ip(config[:nameserver]) do
- {:ok, rblnsip} ->
- :inet_res.lookup(query, :in, type,
- nameservers: [{rblnsip, config[:port]}],
- timeout: @query_timeout,
- retry: @query_retries
- )
-
- _ ->
- []
- end
- end
-end
diff --git a/lib/pleroma/web/activity_pub/mrf/fo_direct_reply.ex b/lib/pleroma/web/activity_pub/mrf/fo_direct_reply.ex
deleted file mode 100644
index 2cf22745a..000000000
--- a/lib/pleroma/web/activity_pub/mrf/fo_direct_reply.ex
+++ /dev/null
@@ -1,53 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2024 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Web.ActivityPub.MRF.FODirectReply do
- @moduledoc """
- FODirectReply alters the scope of replies to activities which are Followers Only to be Direct. The purpose of this policy is to prevent broken threads for followers of the reply author because their response was to a user that they are not also following.
- """
-
- alias Pleroma.Object
- alias Pleroma.User
- alias Pleroma.Web.ActivityPub.Visibility
-
- @behaviour Pleroma.Web.ActivityPub.MRF.Policy
-
- @impl true
- def filter(
- %{
- "type" => "Create",
- "to" => to,
- "object" => %{
- "actor" => actor,
- "type" => "Note",
- "inReplyTo" => in_reply_to
- }
- } = activity
- ) do
- with true <- is_binary(in_reply_to),
- %User{follower_address: followers_collection, local: true} <- User.get_by_ap_id(actor),
- %Object{} = in_reply_to_object <- Object.get_by_ap_id(in_reply_to),
- "private" <- Visibility.get_visibility(in_reply_to_object) do
- direct_to = to -- [followers_collection]
-
- updated_activity =
- activity
- |> Map.put("cc", [])
- |> Map.put("to", direct_to)
- |> Map.put("directMessage", true)
- |> put_in(["object", "cc"], [])
- |> put_in(["object", "to"], direct_to)
-
- {:ok, updated_activity}
- else
- _ -> {:ok, activity}
- end
- end
-
- @impl true
- def filter(activity), do: {:ok, activity}
-
- @impl true
- def describe, do: {:ok, %{}}
-end
diff --git a/lib/pleroma/web/activity_pub/mrf/quiet_reply.ex b/lib/pleroma/web/activity_pub/mrf/quiet_reply.ex
deleted file mode 100644
index b07dc3b56..000000000
--- a/lib/pleroma/web/activity_pub/mrf/quiet_reply.ex
+++ /dev/null
@@ -1,60 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2023 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Web.ActivityPub.MRF.QuietReply do
- @moduledoc """
- QuietReply alters the scope of activities from local users when replying by enforcing them to be "Unlisted" or "Quiet Public". This delivers the activity to all the expected recipients and instances, but it will not be published in the Federated / The Whole Known Network timelines. It will still be published to the Home timelines of the user's followers and visible to anyone who opens the thread.
- """
- require Pleroma.Constants
-
- alias Pleroma.User
-
- @behaviour Pleroma.Web.ActivityPub.MRF.Policy
-
- @impl true
- def history_awareness, do: :auto
-
- @impl true
- def filter(
- %{
- "type" => "Create",
- "to" => to,
- "cc" => cc,
- "object" => %{
- "actor" => actor,
- "type" => "Note",
- "inReplyTo" => in_reply_to
- }
- } = activity
- ) do
- with true <- is_binary(in_reply_to),
- false <- match?([], cc),
- %User{follower_address: followers_collection, local: true} <-
- User.get_by_ap_id(actor) do
- updated_to =
- to
- |> Kernel.++([followers_collection])
- |> Kernel.--([Pleroma.Constants.as_public()])
-
- updated_cc = [Pleroma.Constants.as_public()]
-
- updated_activity =
- activity
- |> Map.put("to", updated_to)
- |> Map.put("cc", updated_cc)
- |> put_in(["object", "to"], updated_to)
- |> put_in(["object", "cc"], updated_cc)
-
- {:ok, updated_activity}
- else
- _ -> {:ok, activity}
- end
- end
-
- @impl true
- def filter(activity), do: {:ok, activity}
-
- @impl true
- def describe, do: {:ok, %{}}
-end