commit: 19f3e2050eb77d9231bb3ca4c8bd056981e96018
parent 2c20b3fc046a7bfaf9e75d3add2383998282e033
Author: Lain Soykaf <lain@lain.com>
Date: Tue, 6 Jan 2026 15:12:49 +0400
Emoji: Handle more edge cases for local emoji with strange filenames.
Diffstat:
6 files changed, 50 insertions(+), 11 deletions(-)
diff --git a/lib/pleroma/emoji.ex b/lib/pleroma/emoji.ex
@@ -11,6 +11,8 @@ defmodule Pleroma.Emoji do
alias Pleroma.Emoji.Combinations
alias Pleroma.Emoji.Loader
+ alias Pleroma.Utils.URIEncoding
+ alias Pleroma.Web.Endpoint
require Logger
@@ -189,8 +191,23 @@ defmodule Pleroma.Emoji do
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
- url = URI.encode(url)
+ url = URIEncoding.encode_url(url)
%{
"icon" => %{"url" => "#{url}", "type" => "Image"},
diff --git a/lib/pleroma/emoji/formatter.ex b/lib/pleroma/emoji/formatter.ex
@@ -5,7 +5,6 @@
defmodule Pleroma.Emoji.Formatter do
alias Pleroma.Emoji
alias Pleroma.HTML
- alias Pleroma.Web.Endpoint
alias Pleroma.Web.MediaProxy
def emojify(text) do
@@ -44,7 +43,7 @@ defmodule Pleroma.Emoji.Formatter do
Emoji.get_all()
|> Enum.filter(fn {emoji, %Emoji{}} -> String.contains?(text, ":#{emoji}:") end)
|> 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
diff --git a/lib/pleroma/web/activity_pub/builder.ex b/lib/pleroma/web/activity_pub/builder.ex
@@ -17,7 +17,6 @@ defmodule Pleroma.Web.ActivityPub.Builder do
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.CommonAPI.ActivityDraft
- alias Pleroma.Web.Endpoint
require Pleroma.Constants
@@ -105,7 +104,7 @@ defmodule Pleroma.Web.ActivityPub.Builder do
defp local_custom_emoji_react(data, 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)
else
_ -> {:error, "Emoji does not exist"}
diff --git a/lib/pleroma/web/mastodon_api/views/custom_emoji_view.ex b/lib/pleroma/web/mastodon_api/views/custom_emoji_view.ex
@@ -6,14 +6,13 @@ defmodule Pleroma.Web.MastodonAPI.CustomEmojiView do
use Pleroma.Web, :view
alias Pleroma.Emoji
- alias Pleroma.Web.Endpoint
def render("index.json", %{custom_emojis: custom_emojis}) do
render_many(custom_emojis, __MODULE__, "show.json")
end
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,
diff --git a/lib/pleroma/web/pleroma_api/views/bookmark_folder_view.ex b/lib/pleroma/web/pleroma_api/views/bookmark_folder_view.ex
@@ -7,7 +7,6 @@ defmodule Pleroma.Web.PleromaAPI.BookmarkFolderView do
alias Pleroma.BookmarkFolder
alias Pleroma.Emoji
- alias Pleroma.Web.Endpoint
def render("show.json", %{folder: %BookmarkFolder{} = folder}) do
%{
@@ -33,7 +32,7 @@ defmodule Pleroma.Web.PleromaAPI.BookmarkFolderView do
emoji = Emoji.get(emoji)
if emoji != nil do
- Endpoint.url() |> URI.merge(emoji.file) |> to_string()
+ Emoji.local_url(emoji.file)
else
nil
end
diff --git a/test/pleroma/web/activity_pub/transmogrifier/emoji_tag_building_test.exs b/test/pleroma/web/activity_pub/transmogrifier/emoji_tag_building_test.exs
@@ -1,8 +1,6 @@
defmodule Pleroma.Web.ActivityPub.Transmogrifier.EmojiTagBuildingTest do
use Pleroma.DataCase, async: true
- alias Pleroma.Web.ActivityPub.Transmogrifier
-
test "it encodes the id to be a valid url" do
name = "hanapog"
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"
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