commit: 3ef98652f7b6613d543fa5b575e2f637cbb846c0
parent ee19d14b0619b04d75b980fa3235a397e372390d
Author: Lain Soykaf <lain@lain.com>
Date: Wed, 7 Jan 2026 10:40:45 +0400
Emoji, AccountView, UtilController: Handle encoding of emoji
Diffstat:
5 files changed, 52 insertions(+), 2 deletions(-)
diff --git a/lib/pleroma/emoji.ex b/lib/pleroma/emoji.ex
@@ -199,7 +199,8 @@ defmodule Pleroma.Emoji do
end
def local_url("/" <> _ = path) do
- URIEncoding.encode_url(Endpoint.url() <> path, bypass_decode: true)
+ path = URIEncoding.encode_url(path, bypass_parse: true, bypass_decode: true)
+ Endpoint.url() <> path
end
def local_url(path) when is_binary(path) do
diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex
@@ -9,6 +9,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
alias Pleroma.User
alias Pleroma.UserNote
alias Pleroma.UserRelationship
+ alias Pleroma.Utils.URIEncoding
alias Pleroma.Web.CommonAPI.Utils
alias Pleroma.Web.MastodonAPI.AccountView
alias Pleroma.Web.MediaProxy
@@ -238,7 +239,10 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
emojis =
Enum.map(user.emoji, fn {shortcode, raw_url} ->
- url = MediaProxy.url(raw_url)
+ url =
+ raw_url
+ |> encode_emoji_url()
+ |> MediaProxy.url()
%{
shortcode: shortcode,
@@ -511,4 +515,13 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
# See https://git.pleroma.social/pleroma/pleroma-meta/-/issues/14
user.actor_type == "Service" || user.actor_type == "Group"
end
+
+ defp encode_emoji_url(nil), do: nil
+ defp encode_emoji_url("http" <> _ = url), do: URIEncoding.encode_url(url)
+
+ defp encode_emoji_url("/" <> _ = path),
+ do: URIEncoding.encode_url(path, bypass_parse: true, bypass_decode: true)
+
+ defp encode_emoji_url(path) when is_binary(path),
+ do: URIEncoding.encode_url(path, bypass_parse: true, bypass_decode: true)
end
diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
@@ -11,6 +11,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
alias Pleroma.Config
alias Pleroma.Emoji
alias Pleroma.Healthcheck
+ alias Pleroma.Utils.URIEncoding
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.Auth.WrapperAuthenticator, as: Authenticator
@@ -180,12 +181,22 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
def emoji(conn, _params) do
emoji =
Enum.reduce(Emoji.get_all(), %{}, fn {code, %Emoji{file: file, tags: tags}}, acc ->
+ file = encode_emoji_url(file)
Map.put(acc, code, %{image_url: file, tags: tags})
end)
json(conn, emoji)
end
+ defp encode_emoji_url(nil), do: nil
+ defp encode_emoji_url("http" <> _ = url), do: URIEncoding.encode_url(url)
+
+ defp encode_emoji_url("/" <> _ = path),
+ do: URIEncoding.encode_url(path, bypass_parse: true, bypass_decode: true)
+
+ defp encode_emoji_url(path) when is_binary(path),
+ do: URIEncoding.encode_url(path, bypass_parse: true, bypass_decode: true)
+
def update_notification_settings(%{assigns: %{user: user}} = conn, params) do
with {:ok, _} <- User.update_notification_settings(user, params) do
json(conn, %{status: "success"})
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
@@ -37,4 +37,10 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.EmojiTagBuildingTest do
assert tag["id"] == url
end
+
+ test "local_url encodes question marks in filenames" do
+ url = Pleroma.Emoji.local_url("/emoji/file?name.png")
+
+ assert url == Pleroma.Web.Endpoint.url() <> "/emoji/file%3Fname.png"
+ end
end
diff --git a/test/pleroma/web/mastodon_api/views/account_view_test.exs b/test/pleroma/web/mastodon_api/views/account_view_test.exs
@@ -105,6 +105,25 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
assert expected == AccountView.render("show.json", %{user: user, skip_visibility_check: true})
end
+ test "encodes emoji urls in the emojis field" do
+ user =
+ insert(:user,
+ name: ":brackets: :percent:",
+ emoji: %{
+ "brackets" => "/emoji/hana[pog].png",
+ "percent" => "/emoji/hana%20pog.png"
+ }
+ )
+
+ %{emojis: emojis} =
+ AccountView.render("show.json", %{user: user, skip_visibility_check: true})
+
+ emoji_urls = Map.new(emojis, &{&1.shortcode, &1.url})
+
+ assert emoji_urls["brackets"] == "/emoji/hana%5Bpog%5D.png"
+ assert emoji_urls["percent"] == "/emoji/hana%2520pog.png"
+ end
+
describe "roles and privileges" do
setup do
clear_config([:instance, :moderator_privileges], [:cofe, :only_moderator])