summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
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
-rw-r--r--lib/pleroma/web/metadata/providers/open_graph.ex26
-rw-r--r--lib/pleroma/web/metadata/providers/twitter_card.ex54
-rw-r--r--lib/pleroma/web/rich_media/parsers/meta_tags_parser.ex2
-rw-r--r--lib/pleroma/web/rich_media/parsers/twitter_card.ex11
7 files changed, 52 insertions, 300 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
diff --git a/lib/pleroma/web/metadata/providers/open_graph.ex b/lib/pleroma/web/metadata/providers/open_graph.ex
index fa5fbe553..604434df2 100644
--- a/lib/pleroma/web/metadata/providers/open_graph.ex
+++ b/lib/pleroma/web/metadata/providers/open_graph.ex
@@ -78,10 +78,10 @@ defmodule Pleroma.Web.Metadata.Providers.OpenGraph do
# object when a Video or GIF is attached it will display that in Whatsapp Rich Preview.
case Utils.fetch_media_type(@media_types, url["mediaType"]) do
"audio" ->
- [
- {:meta, [property: "og:audio", content: MediaProxy.url(url["href"])], []}
- | acc
- ]
+ acc ++
+ [
+ {:meta, [property: "og:audio", content: MediaProxy.url(url["href"])], []}
+ ]
# Not using preview_url for this. It saves bandwidth, but the image dimensions will
# be wrong. We generate it on the fly and have no way to capture or analyze the
@@ -89,18 +89,18 @@ defmodule Pleroma.Web.Metadata.Providers.OpenGraph do
# in timelines too, but you can get clever with the aspect ratio metadata as a
# workaround.
"image" ->
- [
- {:meta, [property: "og:image", content: MediaProxy.url(url["href"])], []},
- {:meta, [property: "og:image:alt", content: attachment["name"]], []}
- | acc
- ]
+ (acc ++
+ [
+ {:meta, [property: "og:image", content: MediaProxy.url(url["href"])], []},
+ {:meta, [property: "og:image:alt", content: attachment["name"]], []}
+ ])
|> maybe_add_dimensions(url)
"video" ->
- [
- {:meta, [property: "og:video", content: MediaProxy.url(url["href"])], []}
- | acc
- ]
+ (acc ++
+ [
+ {:meta, [property: "og:video", content: MediaProxy.url(url["href"])], []}
+ ])
|> maybe_add_dimensions(url)
|> maybe_add_video_thumbnail(url)
diff --git a/lib/pleroma/web/metadata/providers/twitter_card.ex b/lib/pleroma/web/metadata/providers/twitter_card.ex
index 7f50877c3..212fa85ed 100644
--- a/lib/pleroma/web/metadata/providers/twitter_card.ex
+++ b/lib/pleroma/web/metadata/providers/twitter_card.ex
@@ -61,13 +61,13 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCard do
Enum.reduce(attachment["url"], [], fn url, acc ->
case Utils.fetch_media_type(@media_types, url["mediaType"]) do
"audio" ->
- [
- {:meta, [name: "twitter:card", content: "player"], []},
- {:meta, [name: "twitter:player:width", content: "480"], []},
- {:meta, [name: "twitter:player:height", content: "80"], []},
- {:meta, [name: "twitter:player", content: player_url(id)], []}
- | acc
- ]
+ acc ++
+ [
+ {:meta, [name: "twitter:card", content: "player"], []},
+ {:meta, [name: "twitter:player:width", content: "480"], []},
+ {:meta, [name: "twitter:player:height", content: "80"], []},
+ {:meta, [name: "twitter:player", content: player_url(id)], []}
+ ]
# Not using preview_url for this. It saves bandwidth, but the image dimensions will
# be wrong. We generate it on the fly and have no way to capture or analyze the
@@ -75,16 +75,16 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCard do
# in timelines too, but you can get clever with the aspect ratio metadata as a
# workaround.
"image" ->
- [
- {:meta, [name: "twitter:card", content: "summary_large_image"], []},
- {:meta,
+ (acc ++
[
- name: "twitter:image",
- content: MediaProxy.url(url["href"])
- ], []},
- {:meta, [name: "twitter:image:alt", content: truncate(attachment["name"])], []}
- | acc
- ]
+ {:meta, [name: "twitter:card", content: "summary_large_image"], []},
+ {:meta,
+ [
+ name: "twitter:image",
+ content: MediaProxy.url(url["href"])
+ ], []},
+ {:meta, [name: "twitter:image:alt", content: truncate(attachment["name"])], []}
+ ])
|> maybe_add_dimensions(url)
"video" ->
@@ -92,17 +92,17 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCard do
height = url["height"] || 480
width = url["width"] || 480
- [
- {:meta, [name: "twitter:card", content: "player"], []},
- {:meta, [name: "twitter:player", content: player_url(id)], []},
- {:meta, [name: "twitter:player:width", content: "#{width}"], []},
- {:meta, [name: "twitter:player:height", content: "#{height}"], []},
- {:meta, [name: "twitter:player:stream", content: MediaProxy.url(url["href"])],
- []},
- {:meta, [name: "twitter:player:stream:content_type", content: url["mediaType"]],
- []}
- | acc
- ]
+ acc ++
+ [
+ {:meta, [name: "twitter:card", content: "player"], []},
+ {:meta, [name: "twitter:player", content: player_url(id)], []},
+ {:meta, [name: "twitter:player:width", content: "#{width}"], []},
+ {:meta, [name: "twitter:player:height", content: "#{height}"], []},
+ {:meta, [name: "twitter:player:stream", content: MediaProxy.url(url["href"])],
+ []},
+ {:meta, [name: "twitter:player:stream:content_type", content: url["mediaType"]],
+ []}
+ ]
_ ->
acc
diff --git a/lib/pleroma/web/rich_media/parsers/meta_tags_parser.ex b/lib/pleroma/web/rich_media/parsers/meta_tags_parser.ex
index 320a5f515..c42e2c96b 100644
--- a/lib/pleroma/web/rich_media/parsers/meta_tags_parser.ex
+++ b/lib/pleroma/web/rich_media/parsers/meta_tags_parser.ex
@@ -9,7 +9,7 @@ defmodule Pleroma.Web.RichMedia.Parsers.MetaTagsParser do
|> Enum.reduce(data, fn el, acc ->
attributes = normalize_attributes(el, prefix, key_name, value_name)
- Map.merge(acc, attributes)
+ Map.merge(attributes, acc)
end)
|> maybe_put_title(html)
end
diff --git a/lib/pleroma/web/rich_media/parsers/twitter_card.ex b/lib/pleroma/web/rich_media/parsers/twitter_card.ex
index cc653729d..6f6f8b2ae 100644
--- a/lib/pleroma/web/rich_media/parsers/twitter_card.ex
+++ b/lib/pleroma/web/rich_media/parsers/twitter_card.ex
@@ -11,5 +11,16 @@ defmodule Pleroma.Web.RichMedia.Parsers.TwitterCard do
|> MetaTagsParser.parse(html, "og", "property")
|> MetaTagsParser.parse(html, "twitter", "name")
|> MetaTagsParser.parse(html, "twitter", "property")
+ |> filter_tags()
+ end
+
+ defp filter_tags(tags) do
+ Map.filter(tags, fn {k, _v} ->
+ cond do
+ k in ["card", "description", "image", "title", "ttl", "type", "url"] -> true
+ String.starts_with?(k, "image:") -> true
+ true -> false
+ end
+ end)
end
end