diff --git a/lib/pleroma/web/activity_pub/mrf/inline_quote_policy.ex b/lib/pleroma/web/activity_pub/mrf/inline_quote_policy.ex index 20432410b..35682f994 100644 --- a/lib/pleroma/web/activity_pub/mrf/inline_quote_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/inline_quote_policy.ex @@ -6,14 +6,29 @@ defmodule Pleroma.Web.ActivityPub.MRF.InlineQuotePolicy do @moduledoc "Force a quote line into the message content." @behaviour Pleroma.Web.ActivityPub.MRF.Policy + alias Pleroma.Object + defp build_inline_quote(prefix, url) do "

#{prefix}: #{url}
" end - defp has_inline_quote?(content, quote_url) do + defp resolve_urls(quote_url) do + # Fetching here can cause infinite recursion as we run this logic on inbound objects too + # This is probably not a problem - its an exceptional corner case for a local user to quote + # a post which doesn't exist + with %Object{} = obj <- Object.normalize(quote_url, fetch: false) do + id = obj.data["id"] + url = Map.get(obj.data, "url", id) + {id, url, [id, url, quote_url]} + else + _ -> {quote_url, quote_url, [quote_url]} + end + end + + defp has_inline_quote?(content, urls) do cond do # Does the quote URL exist in the content? - content =~ quote_url -> true + Enum.any?(urls, fn url -> content =~ url end) -> true # Does the content already have a .quote-inline span? content =~ "" -> true # No inline quote found @@ -22,18 +37,22 @@ defmodule Pleroma.Web.ActivityPub.MRF.InlineQuotePolicy do end defp filter_object(%{"quoteUri" => quote_url} = object) do + {id, preferred_url, all_urls} = resolve_urls(quote_url) + object = Map.put(object, "quoteUri", id) + content = object["content"] || "" - if has_inline_quote?(content, quote_url) do + if has_inline_quote?(content, all_urls) do object else prefix = Pleroma.Config.get([:mrf_inline_quote, :prefix]) content = if String.ends_with?(content, "

") do - String.trim_trailing(content, "

") <> build_inline_quote(prefix, quote_url) <> "

" + String.trim_trailing(content, "

") <> + build_inline_quote(prefix, preferred_url) <> "

" else - content <> build_inline_quote(prefix, quote_url) + content <> build_inline_quote(prefix, preferred_url) end Map.put(object, "content", content) diff --git a/test/pleroma/web/activity_pub/mrf/inline_quote_policy_test.exs b/test/pleroma/web/activity_pub/mrf/inline_quote_policy_test.exs index 4e0910d3e..7671ad5a1 100644 --- a/test/pleroma/web/activity_pub/mrf/inline_quote_policy_test.exs +++ b/test/pleroma/web/activity_pub/mrf/inline_quote_policy_test.exs @@ -4,10 +4,16 @@ defmodule Pleroma.Web.ActivityPub.MRF.InlineQuotePolicyTest do alias Pleroma.Web.ActivityPub.MRF.InlineQuotePolicy + alias Pleroma.Object use Pleroma.DataCase + setup_all do + Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) + :ok + end + test "adds quote URL to post content" do - quote_url = "https://example.com/objects/1234" + quote_url = "https://mastodon.social/users/emelie/statuses/101849165031453009" activity = %{ "type" => "Create", @@ -19,10 +25,13 @@ defmodule Pleroma.Web.ActivityPub.MRF.InlineQuotePolicyTest do } } + # Prefetch the quoted post + %Object{} = Object.normalize(quote_url, fetch: true) + {:ok, %{"object" => %{"content" => filtered}}} = InlineQuotePolicy.filter(activity) assert filtered == - "

Nice post

RE: https://example.com/objects/1234

" + "

Nice post

RE: https://mastodon.social/@emelie/101849165031453009

" end test "ignores Misskey quote posts" do