commit: 2330c506668e8365868ea0126aedd7eb17404e5d
parent e74b6ed348e36ac99bdb1983412ad44c45abdc51
Author: nicole mikołajczyk <me@mkljczk.pl>
Date: Sat, 29 Nov 2025 18:12:33 +0100
Merge branch 'inlinequotes-mastodon' into 'develop'
MRF InlineQuotePolicy: Don't inline quoted post URL in Mastodon quotes
See merge request pleroma/pleroma!4371
Diffstat:
4 files changed, 114 insertions(+), 0 deletions(-)
diff --git a/changelog.d/mrf-inlinequotes-mastodon.fix b/changelog.d/mrf-inlinequotes-mastodon.fix
@@ -0,0 +1 @@
+MRF InlineQuotePolicy: Don't inline quoted post URL in Mastodon quote posts
diff --git a/lib/pleroma/web/activity_pub/mrf/inline_quote_policy.ex b/lib/pleroma/web/activity_pub/mrf/inline_quote_policy.ex
@@ -18,6 +18,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.InlineQuotePolicy do
content =~ quote_url -> true
# Does the content already have a .quote-inline span?
content =~ "<span class=\"quote-inline\">" -> true
+ # Does the content already have a .quote-inline p? (Mastodon)
+ content =~ "<p class=\"quote-inline\">" -> true
# No inline quote found
true -> false
end
diff --git a/test/fixtures/quote_post/mastodon_quote_post.json b/test/fixtures/quote_post/mastodon_quote_post.json
@@ -0,0 +1,93 @@
+{
+ "@context": [
+ "https://www.w3.org/ns/activitystreams",
+ {
+ "ostatus": "http://ostatus.org#",
+ "atomUri": "ostatus:atomUri",
+ "inReplyToAtomUri": "ostatus:inReplyToAtomUri",
+ "conversation": "ostatus:conversation",
+ "sensitive": "as:sensitive",
+ "toot": "http://joinmastodon.org/ns#",
+ "votersCount": "toot:votersCount",
+ "quote": "https://w3id.org/fep/044f#quote",
+ "quoteUri": "http://fedibird.com/ns#quoteUri",
+ "_misskey_quote": "https://misskey-hub.net/ns#_misskey_quote",
+ "quoteAuthorization": {
+ "@id": "https://w3id.org/fep/044f#quoteAuthorization",
+ "@type": "@id"
+ },
+ "gts": "https://gotosocial.org/ns#",
+ "interactionPolicy": {
+ "@id": "gts:interactionPolicy",
+ "@type": "@id"
+ },
+ "canQuote": {
+ "@id": "gts:canQuote",
+ "@type": "@id"
+ },
+ "automaticApproval": {
+ "@id": "gts:automaticApproval",
+ "@type": "@id"
+ },
+ "manualApproval": {
+ "@id": "gts:manualApproval",
+ "@type": "@id"
+ }
+ }
+ ],
+ "id": "https://mastodon.social/users/gwynnion/statuses/115345489087257171",
+ "type": "Note",
+ "summary": null,
+ "inReplyTo": null,
+ "published": "2025-10-09T17:54:47Z",
+ "url": "https://mastodon.social/@gwynnion/115345489087257171",
+ "attributedTo": "https://mastodon.social/users/gwynnion",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "cc": [
+ "https://mastodon.social/users/gwynnion/followers"
+ ],
+ "sensitive": false,
+ "atomUri": "https://mastodon.social/users/gwynnion/statuses/115345489087257171",
+ "inReplyToAtomUri": null,
+ "conversation": "https://mastodon.social/contexts/109836797527169643-115345489087257171",
+ "context": "https://mastodon.social/contexts/109836797527169643-115345489087257171",
+ "content": "<p class=\"quote-inline\">RE: <a href=\"https://mastodon.social/@404mediaco/115344945575874225\" target=\"_blank\" rel=\"nofollow noopener\" translate=\"no\"><span class=\"invisible\">https://</span><span class=\"ellipsis\">mastodon.social/@404mediaco/11</span><span class=\"invisible\">5344945575874225</span></a></p><p>Every age verification system is just a scheme for companies and hackers to steal your identity.</p>",
+ "contentMap": {
+ "en": "<p class=\"quote-inline\">RE: <a href=\"https://mastodon.social/@404mediaco/115344945575874225\" target=\"_blank\" rel=\"nofollow noopener\" translate=\"no\"><span class=\"invisible\">https://</span><span class=\"ellipsis\">mastodon.social/@404mediaco/11</span><span class=\"invisible\">5344945575874225</span></a></p><p>Every age verification system is just a scheme for companies and hackers to steal your identity.</p>"
+ },
+ "quote": "https://mastodon.social/users/404mediaco/statuses/115344945575874225",
+ "_misskey_quote": "https://mastodon.social/users/404mediaco/statuses/115344945575874225",
+ "quoteUri": "https://mastodon.social/users/404mediaco/statuses/115344945575874225",
+ "quoteAuthorization": "https://mastodon.social/users/404mediaco/quote_authorizations/115345489087269783",
+ "interactionPolicy": {
+ "canQuote": {
+ "automaticApproval": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ]
+ }
+ },
+ "attachment": [],
+ "tag": [],
+ "replies": {
+ "id": "https://mastodon.social/users/gwynnion/statuses/115345489087257171/replies",
+ "type": "Collection",
+ "first": {
+ "type": "CollectionPage",
+ "next": "https://mastodon.social/users/gwynnion/statuses/115345489087257171/replies?only_other_accounts=true&page=true",
+ "partOf": "https://mastodon.social/users/gwynnion/statuses/115345489087257171/replies",
+ "items": []
+ }
+ },
+ "likes": {
+ "id": "https://mastodon.social/users/gwynnion/statuses/115345489087257171/likes",
+ "type": "Collection",
+ "totalItems": 26
+ },
+ "shares": {
+ "id": "https://mastodon.social/users/gwynnion/statuses/115345489087257171/shares",
+ "type": "Collection",
+ "totalItems": 28
+ }
+}
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
@@ -109,4 +109,22 @@ defmodule Pleroma.Web.ActivityPub.MRF.InlineQuotePolicyTest do
{:ok, filtered} = InlineQuotePolicy.filter(activity)
assert filtered == activity
end
+
+ # Mastodon uses p tags instead of span in their quote posts
+ # URLs in quoteUri and post content are already mismatched
+ test "skips objects which already have an .inline-quote p" do
+ object = File.read!("test/fixtures/quote_post/mastodon_quote_post.json") |> Jason.decode!()
+
+ # Normally the ObjectValidator will fix this before it reaches MRF
+ object = Map.put(object, "quoteUrl", object["quoteUri"])
+
+ activity = %{
+ "type" => "Create",
+ "actor" => "https://mastodon.social/users/gwynnion",
+ "object" => object
+ }
+
+ {:ok, filtered} = InlineQuotePolicy.filter(activity)
+ assert filtered == activity
+ end
end