Emoji: Handle more edge cases for local emoji with strange filenames.

This commit is contained in:
Lain Soykaf 2026-01-06 15:12:49 +04:00
commit 19f3e2050e
6 changed files with 50 additions and 11 deletions

View file

@ -11,6 +11,8 @@ defmodule Pleroma.Emoji do
alias Pleroma.Emoji.Combinations alias Pleroma.Emoji.Combinations
alias Pleroma.Emoji.Loader alias Pleroma.Emoji.Loader
alias Pleroma.Utils.URIEncoding
alias Pleroma.Web.Endpoint
require Logger require Logger
@ -189,8 +191,23 @@ defmodule Pleroma.Emoji do
def emoji_url(_), do: nil def emoji_url(_), do: nil
@spec local_url(String.t() | nil) :: String.t() | nil
def local_url(nil), do: nil
def local_url("http" <> _ = url) do
URIEncoding.encode_url(url)
end
def local_url("/" <> _ = path) do
URIEncoding.encode_url(Endpoint.url() <> path, bypass_decode: true)
end
def local_url(path) when is_binary(path) do
local_url("/" <> path)
end
def build_emoji_tag({name, url}) do def build_emoji_tag({name, url}) do
url = URI.encode(url) url = URIEncoding.encode_url(url)
%{ %{
"icon" => %{"url" => "#{url}", "type" => "Image"}, "icon" => %{"url" => "#{url}", "type" => "Image"},

View file

@ -5,7 +5,6 @@
defmodule Pleroma.Emoji.Formatter do defmodule Pleroma.Emoji.Formatter do
alias Pleroma.Emoji alias Pleroma.Emoji
alias Pleroma.HTML alias Pleroma.HTML
alias Pleroma.Web.Endpoint
alias Pleroma.Web.MediaProxy alias Pleroma.Web.MediaProxy
def emojify(text) do def emojify(text) do
@ -44,7 +43,7 @@ defmodule Pleroma.Emoji.Formatter do
Emoji.get_all() Emoji.get_all()
|> Enum.filter(fn {emoji, %Emoji{}} -> String.contains?(text, ":#{emoji}:") end) |> Enum.filter(fn {emoji, %Emoji{}} -> String.contains?(text, ":#{emoji}:") end)
|> Enum.reduce(%{}, fn {name, %Emoji{file: file}}, acc -> |> Enum.reduce(%{}, fn {name, %Emoji{file: file}}, acc ->
Map.put(acc, name, to_string(URI.merge(Endpoint.url(), file))) Map.put(acc, name, Emoji.local_url(file))
end) end)
end end

View file

@ -17,7 +17,6 @@ defmodule Pleroma.Web.ActivityPub.Builder do
alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.ActivityPub.Visibility alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.CommonAPI.ActivityDraft alias Pleroma.Web.CommonAPI.ActivityDraft
alias Pleroma.Web.Endpoint
require Pleroma.Constants require Pleroma.Constants
@ -105,7 +104,7 @@ defmodule Pleroma.Web.ActivityPub.Builder do
defp local_custom_emoji_react(data, emoji) do defp local_custom_emoji_react(data, emoji) do
with %{file: path} = emojo <- Emoji.get(emoji) do with %{file: path} = emojo <- Emoji.get(emoji) do
url = "#{Endpoint.url()}#{path}" url = Emoji.local_url(path)
add_emoji_content(data, emojo.code, url) add_emoji_content(data, emojo.code, url)
else else
_ -> {:error, "Emoji does not exist"} _ -> {:error, "Emoji does not exist"}

View file

@ -6,14 +6,13 @@ defmodule Pleroma.Web.MastodonAPI.CustomEmojiView do
use Pleroma.Web, :view use Pleroma.Web, :view
alias Pleroma.Emoji alias Pleroma.Emoji
alias Pleroma.Web.Endpoint
def render("index.json", %{custom_emojis: custom_emojis}) do def render("index.json", %{custom_emojis: custom_emojis}) do
render_many(custom_emojis, __MODULE__, "show.json") render_many(custom_emojis, __MODULE__, "show.json")
end end
def render("show.json", %{custom_emoji: {shortcode, %Emoji{file: relative_url, tags: tags}}}) do def render("show.json", %{custom_emoji: {shortcode, %Emoji{file: relative_url, tags: tags}}}) do
url = Endpoint.url() |> URI.merge(relative_url) |> to_string() url = Emoji.local_url(relative_url)
%{ %{
"shortcode" => shortcode, "shortcode" => shortcode,

View file

@ -7,7 +7,6 @@ defmodule Pleroma.Web.PleromaAPI.BookmarkFolderView do
alias Pleroma.BookmarkFolder alias Pleroma.BookmarkFolder
alias Pleroma.Emoji alias Pleroma.Emoji
alias Pleroma.Web.Endpoint
def render("show.json", %{folder: %BookmarkFolder{} = folder}) do def render("show.json", %{folder: %BookmarkFolder{} = folder}) do
%{ %{
@ -33,7 +32,7 @@ defmodule Pleroma.Web.PleromaAPI.BookmarkFolderView do
emoji = Emoji.get(emoji) emoji = Emoji.get(emoji)
if emoji != nil do if emoji != nil do
Endpoint.url() |> URI.merge(emoji.file) |> to_string() Emoji.local_url(emoji.file)
else else
nil nil
end end

View file

@ -1,8 +1,6 @@
defmodule Pleroma.Web.ActivityPub.Transmogrifier.EmojiTagBuildingTest do defmodule Pleroma.Web.ActivityPub.Transmogrifier.EmojiTagBuildingTest do
use Pleroma.DataCase, async: true use Pleroma.DataCase, async: true
alias Pleroma.Web.ActivityPub.Transmogrifier
test "it encodes the id to be a valid url" do test "it encodes the id to be a valid url" do
name = "hanapog" name = "hanapog"
url = "https://misskey.local.live/emojis/hana pog.png" url = "https://misskey.local.live/emojis/hana pog.png"
@ -11,4 +9,32 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.EmojiTagBuildingTest do
assert tag["id"] == "https://misskey.local.live/emojis/hana%20pog.png" assert tag["id"] == "https://misskey.local.live/emojis/hana%20pog.png"
end end
test "it does not double-encode already encoded urls" do
name = "hanapog"
url = "https://misskey.local.live/emojis/hana%20pog.png"
tag = Pleroma.Emoji.build_emoji_tag({name, url})
assert tag["id"] == url
end
test "it encodes disallowed path characters" do
name = "hanapog"
url = "https://example.com/emojis/hana[pog].png"
tag = Pleroma.Emoji.build_emoji_tag({name, url})
assert tag["id"] == "https://example.com/emojis/hana%5Bpog%5D.png"
end
test "local_url does not decode percent in filenames" do
url = Pleroma.Emoji.local_url("/emoji/hana%20pog.png")
assert url == Pleroma.Web.Endpoint.url() <> "/emoji/hana%2520pog.png"
tag = Pleroma.Emoji.build_emoji_tag({"hanapog", url})
assert tag["id"] == url
end
end end