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.
This commit is contained in:
Hélène 2022-06-28 20:33:50 +02:00
parent 75f912c63f
commit 11f9f2ef27
No known key found for this signature in database
GPG key ID: A215F2E9F1589D62
3 changed files with 71 additions and 0 deletions

View file

@ -49,6 +49,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
defp fix(data) do defp fix(data) do
data = data =
data data
|> fix_emoji_qualification()
|> CommonFixes.fix_actor() |> CommonFixes.fix_actor()
|> CommonFixes.fix_activity_addressing() |> CommonFixes.fix_activity_addressing()
@ -61,6 +62,20 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
end end
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 defp validate_emoji(cng) do
content = get_field(cng, :content) content = get_field(cng, :content)

View file

@ -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"
}
]
}

View file

@ -37,6 +37,32 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.EmojiReactHandlingTest do
assert match?([["👌", _]], object.data["reactions"]) assert match?([["👌", _]], object.data["reactions"])
end 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 test "it reject invalid emoji reactions" do
user = insert(:user) user = insert(:user)
other_user = insert(:user, local: false) other_user = insert(:user, local: false)