Sanitise Content-Type of media proxy URLs

This commit is contained in:
Chizu 2024-04-02 04:38:10 +09:00
parent f56267280e
commit c101fa9a09
2 changed files with 57 additions and 2 deletions

View file

@ -17,6 +17,8 @@ defmodule Pleroma.ReverseProxy do
@failed_request_ttl :timer.seconds(60)
@methods ~w(GET HEAD)
@allowed_mime_types Pleroma.Config.get([Pleroma.Upload, :allowed_mime_types], [])
@cachex Pleroma.Config.get([:cachex, :provider], Cachex)
def max_read_duration_default, do: @max_read_duration
@ -250,6 +252,7 @@ defmodule Pleroma.ReverseProxy do
headers
|> Enum.filter(fn {k, _} -> k in @keep_resp_headers end)
|> build_resp_cache_headers(opts)
|> sanitise_content_type()
|> build_resp_content_disposition_header(opts)
|> build_csp_headers()
|> Keyword.merge(Keyword.get(opts, :resp_headers, []))
@ -279,6 +282,21 @@ defmodule Pleroma.ReverseProxy do
end
end
defp sanitise_content_type(headers) do
original_ct = get_content_type(headers)
safe_ct =
Pleroma.Web.Plugs.Utils.get_safe_mime_type(
%{allowed_mime_types: @allowed_mime_types},
original_ct
)
[
{"content-type", safe_ct}
| Enum.filter(headers, fn {k, _v} -> k != "content-type" end)
]
end
defp build_resp_content_disposition_header(headers, opts) do
opt = Keyword.get(opts, :inline_content_types, @inline_content_types)

View file

@ -75,13 +75,16 @@ defmodule Pleroma.ReverseProxyTest do
Tesla.Mock.mock(fn %{method: :head, url: "/head"} ->
%Tesla.Env{
status: 200,
headers: [{"content-type", "text/html; charset=utf-8"}],
headers: [{"content-type", "image/png"}],
body: ""
}
end)
conn = ReverseProxy.call(Map.put(conn, :method, "HEAD"), "/head")
assert html_response(conn, 200) == ""
assert conn.status == 200
assert Conn.get_resp_header(conn, "content-type") == ["image/png"]
assert conn.resp_body == ""
end
end
@ -252,4 +255,38 @@ defmodule Pleroma.ReverseProxyTest do
assert {"content-disposition", "attachment; filename=\"filename.jpg\""} in conn.resp_headers
end
end
describe "content-type sanitisation" do
test "preserves video type", %{conn: conn} do
Tesla.Mock.mock(fn %{method: :get, url: "/content"} ->
%Tesla.Env{
status: 200,
headers: [{"content-type", "video/mp4"}],
body: "test"
}
end)
conn = ReverseProxy.call(Map.put(conn, :method, "GET"), "/content")
assert conn.status == 200
assert Conn.get_resp_header(conn, "content-type") == ["video/mp4"]
assert conn.resp_body == "test"
end
test "replaces application type", %{conn: conn} do
Tesla.Mock.mock(fn %{method: :get, url: "/content"} ->
%Tesla.Env{
status: 200,
headers: [{"content-type", "application/activity+json"}],
body: "test"
}
end)
conn = ReverseProxy.call(Map.put(conn, :method, "GET"), "/content")
assert conn.status == 200
assert Conn.get_resp_header(conn, "content-type") == ["application/octet-stream"]
assert conn.resp_body == "test"
end
end
end