Merge pull request 'MediaProxy: proxy network-path URLs (//host/path)' (#8027) from lambadalambda/pleroma:fix/media-proxy-network-path into develop

Reviewed-on: https://git.pleroma.social/pleroma/pleroma/pulls/8027
This commit is contained in:
lain 2026-10-28 05:03:14 +00:00
commit 24738790c3
5 changed files with 64 additions and 1 deletions

View file

@ -0,0 +1 @@
Proxy media given as network-path URLs (//host/path), so remote HTML cannot load images directly

View file

@ -41,6 +41,7 @@ defmodule Pleroma.Web.MediaProxy do
end
def url(url) when is_nil(url) or url == "", do: nil
def url("//" <> _ = url), do: url("https:" <> url)
def url("/" <> _ = url), do: url
def url(url) do
@ -56,7 +57,10 @@ defmodule Pleroma.Web.MediaProxy do
not local?(url) and not whitelisted?(url)
end
def preview_url(url, preview_params \\ []) do
def preview_url(url, preview_params \\ [])
def preview_url("//" <> _ = url, pparams), do: preview_url("https:" <> url, pparams)
def preview_url(url, preview_params) do
if preview_enabled?() do
encode_preview_url(url, preview_params)
else

View file

@ -17,6 +17,10 @@ defmodule Pleroma.HTML.Transform.MediaProxy do
{"src", media_url}
end
def scrub_attribute(:img, {"src", "//" <> target}) do
scrub_attribute(:img, {"src", "https://" <> target})
end
def scrub_attribute(_tag, attribute), do: attribute
def scrub({:img, attributes, children}) do

View file

@ -559,6 +559,46 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
assert mention.url == recipient_ap_id
end
test "inlined images are media proxied" do
ConfigMock |> stub_with(Pleroma.Test.StaticConfig)
clear_config([:media_proxy, :enabled], true)
user = insert(:user)
{:ok, activity} =
CommonAPI.post(user, %{
content_type: "text/html",
status: "hii <img src=\"https://example.org/a.png\" />"
})
activity = Repo.get(Activity, activity.id)
status = StatusView.render("show.json", activity: activity)
assert_schema(status, "Status", Pleroma.Web.ApiSpec.spec())
assert status[:content] =~
~r/^hii <img src="https?:\/\/[^\/]+\/proxy\/[^\/]+\/aHR0cHM6Ly9leGFtcGxlLm9yZy9hLnBuZw\/a.png"/
end
test "inlined images using network-path ref are media proxied" do
ConfigMock |> stub_with(Pleroma.Test.StaticConfig)
clear_config([:media_proxy, :enabled], true)
user = insert(:user)
{:ok, activity} =
CommonAPI.post(user, %{
content_type: "text/html",
status: "hii <img src=\"//example.org/a.png\" />"
})
activity = Repo.get(Activity, activity.id)
status = StatusView.render("show.json", activity: activity)
assert_schema(status, "Status", Pleroma.Web.ApiSpec.spec())
assert status[:content] =~
~r/^hii <img src="https?:\/\/[^\/]+\/proxy\/[^\/]+\/aHR0cHM6Ly9leGFtcGxlLm9yZy9hLnBuZw\/a.png"/
end
test "create mentions from the 'tag' field" do
recipient = insert(:user)
cc = insert_pair(:user) |> Enum.map(& &1.ap_id)

View file

@ -59,6 +59,20 @@ defmodule Pleroma.Web.MediaProxyTest do
assert decode_result(encoded) == url
end
test "encodes and decodes a network-path reference URL as HTTPS" do
url = "//example.org/static/logo.png"
encoded = MediaProxy.url(url)
assert String.starts_with?(
encoded,
Config.get([:media_proxy, :base_url], Pleroma.Web.Endpoint.url())
)
assert String.ends_with?(encoded, "/logo.png")
assert decode_result(encoded) == "https:" <> url
end
test "encodes and decodes URL without a path" do
url = "https://pleroma.soykaf.com"
encoded = MediaProxy.url(url)