From 11f9f2ef277937d5558a1cc0a92a60b872f17de0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9l=C3=A8ne?= Date: Tue, 28 Jun 2022 20:33:50 +0200 Subject: [PATCH] EmojiReactValidator: fix emoji qualification Tries fully-qualifying emoji when receiving them, by adding the emoji variation sequence to the received reaction emoji. This issue arises when other instance software, such as Misskey, tries reacting with emoji that have unqualified or minimally qualified variants, like a red heart. Pleroma only accepts fully qualified emoji in emoji reactions, and refused those emoji. Now, Pleroma will attempt to properly qualify them first, and reject them if checks still fail. --- .../emoji_react_validator.ex | 15 ++++++++++ test/fixtures/emoji-reaction-unqualified.json | 30 +++++++++++++++++++ .../emoji_react_handling_test.exs | 26 ++++++++++++++++ 3 files changed, 71 insertions(+) create mode 100644 test/fixtures/emoji-reaction-unqualified.json diff --git a/lib/pleroma/web/activity_pub/object_validators/emoji_react_validator.ex b/lib/pleroma/web/activity_pub/object_validators/emoji_react_validator.ex index ed072b888..bf5166633 100644 --- a/lib/pleroma/web/activity_pub/object_validators/emoji_react_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/emoji_react_validator.ex @@ -49,6 +49,7 @@ def changeset(struct, data) do defp fix(data) do data = data + |> fix_emoji_qualification() |> CommonFixes.fix_actor() |> CommonFixes.fix_activity_addressing() @@ -61,6 +62,20 @@ defp fix(data) do end end + defp fix_emoji_qualification(%{"content" => emoji} = data) do + # Emoji variation sequence + new_emoji = emoji <> "\uFE0F" + + if Pleroma.Emoji.is_unicode_emoji?(new_emoji) do + data + |> Map.put("content", new_emoji) + else + data + end + end + + defp fix_emoji_qualification(data), do: data + defp validate_emoji(cng) do content = get_field(cng, :content) diff --git a/test/fixtures/emoji-reaction-unqualified.json b/test/fixtures/emoji-reaction-unqualified.json new file mode 100644 index 000000000..722fd7092 --- /dev/null +++ b/test/fixtures/emoji-reaction-unqualified.json @@ -0,0 +1,30 @@ +{ + "type": "EmojiReact", + "signature": { + "type": "RsaSignature2017", + "signatureValue": "fdxMfQSMwbC6wP6sh6neS/vM5879K67yQkHTbiT5Npr5wAac0y6+o3Ij+41tN3rL6wfuGTosSBTHOtta6R4GCOOhCaCSLMZKypnp1VltCzLDoyrZELnYQIC8gpUXVmIycZbREk22qWUe/w7DAFaKK4UscBlHDzeDVcA0K3Se5Sluqi9/Zh+ldAnEzj/rSEPDjrtvf5wGNf3fHxbKSRKFt90JvKK6hS+vxKUhlRFDf6/SMETw+EhwJSNW4d10yMUakqUWsFv4Acq5LW7l+HpYMvlYY1FZhNde1+uonnCyuQDyvzkff8zwtEJmAXC4RivO/VVLa17SmqheJZfI8oluVg==", + "creator": "http://mastodon.example.org/users/admin#main-key", + "created": "2018-02-17T18:57:49Z" + }, + "object": "http://localtesting.pleroma.lol/objects/eb92579d-3417-42a8-8652-2492c2d4f454", + "content": "❤", + "nickname": "lain", + "id": "http://mastodon.example.org/users/admin#reactions/2", + "actor": "http://mastodon.example.org/users/admin", + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/v1", + { + "toot": "http://joinmastodon.org/ns#", + "sensitive": "as:sensitive", + "ostatus": "http://ostatus.org#", + "movedTo": "as:movedTo", + "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", + "inReplyToAtomUri": "ostatus:inReplyToAtomUri", + "conversation": "ostatus:conversation", + "atomUri": "ostatus:atomUri", + "Hashtag": "as:Hashtag", + "Emoji": "toot:Emoji" + } + ] +} diff --git a/test/pleroma/web/activity_pub/transmogrifier/emoji_react_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/emoji_react_handling_test.exs index ceedb185f..5edb6d56e 100644 --- a/test/pleroma/web/activity_pub/transmogrifier/emoji_react_handling_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier/emoji_react_handling_test.exs @@ -37,6 +37,32 @@ test "it works for incoming emoji reactions" do assert match?([["👌", _]], object.data["reactions"]) end + test "it works for incoming unqualified emoji reactions" do + user = insert(:user) + other_user = insert(:user, local: false) + {:ok, activity} = CommonAPI.post(user, %{status: "hello"}) + + data = + File.read!("test/fixtures/emoji-reaction-unqualified.json") + |> Jason.decode!() + |> Map.put("object", activity.data["object"]) + |> Map.put("actor", other_user.ap_id) + + {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) + + assert data["actor"] == other_user.ap_id + assert data["type"] == "EmojiReact" + assert data["id"] == "http://mastodon.example.org/users/admin#reactions/2" + assert data["object"] == activity.data["object"] + # heart emoji with added emoji variation sequence + assert data["content"] == "❤️" + + object = Object.get_by_ap_id(data["object"]) + + assert object.data["reaction_count"] == 1 + assert match?([["❤️", _]], object.data["reactions"]) + end + test "it reject invalid emoji reactions" do user = insert(:user) other_user = insert(:user, local: false)