forked from AkkomaGang/akkoma
[#2497] Made media preview proxy fall back to media proxy instead of to source url. Adjusted tests. Refactoring.
This commit is contained in:
parent
f25b0e87f3
commit
c3b02341bf
4 changed files with 51 additions and 42 deletions
|
@ -7,12 +7,14 @@ defmodule Pleroma.Helpers.MediaHelper do
|
||||||
Handles common media-related operations.
|
Handles common media-related operations.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
alias Pleroma.HTTP
|
||||||
|
|
||||||
@tmp_base "/tmp/pleroma-media_preview-pipe"
|
@tmp_base "/tmp/pleroma-media_preview-pipe"
|
||||||
|
|
||||||
def image_resize(url, options) do
|
def image_resize(url, options) do
|
||||||
with executable when is_binary(executable) <- System.find_executable("convert"),
|
with executable when is_binary(executable) <- System.find_executable("convert"),
|
||||||
{:ok, args} <- prepare_image_resize_args(options),
|
{:ok, args} <- prepare_image_resize_args(options),
|
||||||
{:ok, env} <- Pleroma.HTTP.get(url, [], [adapter: [pool: :preview]]),
|
{:ok, env} <- HTTP.get(url, [], adapter: [pool: :preview]),
|
||||||
{:ok, fifo_path} <- mkfifo() do
|
{:ok, fifo_path} <- mkfifo() do
|
||||||
args = List.flatten([fifo_path, args])
|
args = List.flatten([fifo_path, args])
|
||||||
run_fifo(fifo_path, env, executable, args)
|
run_fifo(fifo_path, env, executable, args)
|
||||||
|
@ -60,7 +62,7 @@ defp prepare_image_resize_args(_), do: {:error, :missing_options}
|
||||||
|
|
||||||
def video_framegrab(url) do
|
def video_framegrab(url) do
|
||||||
with executable when is_binary(executable) <- System.find_executable("ffmpeg"),
|
with executable when is_binary(executable) <- System.find_executable("ffmpeg"),
|
||||||
{:ok, env} <- Pleroma.HTTP.get(url, [], [adapter: [pool: :preview]]),
|
{:ok, env} <- HTTP.get(url, [], adapter: [pool: :preview]),
|
||||||
{:ok, fifo_path} <- mkfifo(),
|
{:ok, fifo_path} <- mkfifo(),
|
||||||
args = [
|
args = [
|
||||||
"-y",
|
"-y",
|
||||||
|
|
|
@ -57,13 +57,11 @@ def url_proxiable?(url) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Note: routing all URLs to preview handler (even local and whitelisted).
|
|
||||||
# Preview handler will call url/1 on decoded URLs, and applicable ones will detour media proxy.
|
|
||||||
def preview_url(url, preview_params \\ []) do
|
def preview_url(url, preview_params \\ []) do
|
||||||
if preview_enabled?() do
|
if preview_enabled?() do
|
||||||
encode_preview_url(url, preview_params)
|
encode_preview_url(url, preview_params)
|
||||||
else
|
else
|
||||||
url
|
url(url)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -48,10 +48,12 @@ def preview(conn, %{"sig" => sig64, "url" => url64}) do
|
||||||
end
|
end
|
||||||
|
|
||||||
defp handle_preview(conn, url) do
|
defp handle_preview(conn, url) do
|
||||||
|
media_proxy_url = MediaProxy.url(url)
|
||||||
|
|
||||||
with {:ok, %{status: status} = head_response} when status in 200..299 <-
|
with {:ok, %{status: status} = head_response} when status in 200..299 <-
|
||||||
Pleroma.HTTP.request("head", MediaProxy.url(url), [], [], [adapter: [pool: :preview]]) do
|
Pleroma.HTTP.request("head", media_proxy_url, [], [], adapter: [pool: :preview]) do
|
||||||
content_type = Tesla.get_header(head_response, "content-type")
|
content_type = Tesla.get_header(head_response, "content-type")
|
||||||
handle_preview(content_type, conn, url)
|
handle_preview(content_type, conn, media_proxy_url)
|
||||||
else
|
else
|
||||||
{_, %{status: status}} ->
|
{_, %{status: status}} ->
|
||||||
send_resp(conn, :failed_dependency, "Can't fetch HTTP headers (HTTP #{status}).")
|
send_resp(conn, :failed_dependency, "Can't fetch HTTP headers (HTTP #{status}).")
|
||||||
|
@ -67,40 +69,38 @@ defp handle_preview(conn, url) do
|
||||||
defp handle_preview(
|
defp handle_preview(
|
||||||
"image/" <> _ = _content_type,
|
"image/" <> _ = _content_type,
|
||||||
%{params: %{"output_format" => "jpeg"}} = conn,
|
%{params: %{"output_format" => "jpeg"}} = conn,
|
||||||
url
|
media_proxy_url
|
||||||
) do
|
) do
|
||||||
handle_jpeg_preview(conn, url)
|
handle_jpeg_preview(conn, media_proxy_url)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp handle_preview("image/gif" = _content_type, conn, url) do
|
defp handle_preview("image/gif" = _content_type, conn, media_proxy_url) do
|
||||||
mediaproxy_url = url |> MediaProxy.url()
|
redirect(conn, external: media_proxy_url)
|
||||||
|
|
||||||
redirect(conn, external: mediaproxy_url)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
defp handle_preview("image/png" <> _ = _content_type, conn, url) do
|
defp handle_preview("image/png" <> _ = _content_type, conn, media_proxy_url) do
|
||||||
handle_png_preview(conn, url)
|
handle_png_preview(conn, media_proxy_url)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp handle_preview("image/" <> _ = _content_type, conn, url) do
|
defp handle_preview("image/" <> _ = _content_type, conn, media_proxy_url) do
|
||||||
handle_jpeg_preview(conn, url)
|
handle_jpeg_preview(conn, media_proxy_url)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp handle_preview("video/" <> _ = _content_type, conn, url) do
|
defp handle_preview("video/" <> _ = _content_type, conn, media_proxy_url) do
|
||||||
handle_video_preview(conn, url)
|
handle_video_preview(conn, media_proxy_url)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp handle_preview(content_type, conn, _url) do
|
defp handle_preview(content_type, conn, _media_proxy_url) do
|
||||||
send_resp(conn, :unprocessable_entity, "Unsupported content type: #{content_type}.")
|
send_resp(conn, :unprocessable_entity, "Unsupported content type: #{content_type}.")
|
||||||
end
|
end
|
||||||
|
|
||||||
defp handle_png_preview(%{params: params} = conn, url) do
|
defp handle_png_preview(%{params: params} = conn, media_proxy_url) do
|
||||||
quality = Config.get!([:media_preview_proxy, :image_quality])
|
quality = Config.get!([:media_preview_proxy, :image_quality])
|
||||||
|
|
||||||
with {thumbnail_max_width, thumbnail_max_height} <- thumbnail_max_dimensions(params),
|
with {thumbnail_max_width, thumbnail_max_height} <- thumbnail_max_dimensions(params),
|
||||||
{:ok, thumbnail_binary} <-
|
{:ok, thumbnail_binary} <-
|
||||||
MediaHelper.image_resize(
|
MediaHelper.image_resize(
|
||||||
url,
|
media_proxy_url,
|
||||||
%{
|
%{
|
||||||
max_width: thumbnail_max_width,
|
max_width: thumbnail_max_width,
|
||||||
max_height: thumbnail_max_height,
|
max_height: thumbnail_max_height,
|
||||||
|
@ -109,7 +109,7 @@ defp handle_png_preview(%{params: params} = conn, url) do
|
||||||
}
|
}
|
||||||
) do
|
) do
|
||||||
conn
|
conn
|
||||||
|> put_preview_response_headers("image/png", "preview.png")
|
|> put_preview_response_headers(["image/png", "preview.png"])
|
||||||
|> send_resp(200, thumbnail_binary)
|
|> send_resp(200, thumbnail_binary)
|
||||||
else
|
else
|
||||||
_ ->
|
_ ->
|
||||||
|
@ -117,13 +117,13 @@ defp handle_png_preview(%{params: params} = conn, url) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp handle_jpeg_preview(%{params: params} = conn, url) do
|
defp handle_jpeg_preview(%{params: params} = conn, media_proxy_url) do
|
||||||
quality = Config.get!([:media_preview_proxy, :image_quality])
|
quality = Config.get!([:media_preview_proxy, :image_quality])
|
||||||
|
|
||||||
with {thumbnail_max_width, thumbnail_max_height} <- thumbnail_max_dimensions(params),
|
with {thumbnail_max_width, thumbnail_max_height} <- thumbnail_max_dimensions(params),
|
||||||
{:ok, thumbnail_binary} <-
|
{:ok, thumbnail_binary} <-
|
||||||
MediaHelper.image_resize(
|
MediaHelper.image_resize(
|
||||||
url,
|
media_proxy_url,
|
||||||
%{max_width: thumbnail_max_width, max_height: thumbnail_max_height, quality: quality}
|
%{max_width: thumbnail_max_width, max_height: thumbnail_max_height, quality: quality}
|
||||||
) do
|
) do
|
||||||
conn
|
conn
|
||||||
|
@ -135,9 +135,9 @@ defp handle_jpeg_preview(%{params: params} = conn, url) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp handle_video_preview(conn, url) do
|
defp handle_video_preview(conn, media_proxy_url) do
|
||||||
with {:ok, thumbnail_binary} <-
|
with {:ok, thumbnail_binary} <-
|
||||||
MediaHelper.video_framegrab(url) do
|
MediaHelper.video_framegrab(media_proxy_url) do
|
||||||
conn
|
conn
|
||||||
|> put_preview_response_headers()
|
|> put_preview_response_headers()
|
||||||
|> send_resp(200, thumbnail_binary)
|
|> send_resp(200, thumbnail_binary)
|
||||||
|
@ -147,10 +147,14 @@ defp handle_video_preview(conn, url) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp put_preview_response_headers(conn, content_type \\ "image/jpeg", filename \\ "preview.jpg") do
|
defp put_preview_response_headers(
|
||||||
|
conn,
|
||||||
|
[content_type, filename] = _content_info \\ ["image/jpeg", "preview.jpg"]
|
||||||
|
) do
|
||||||
conn
|
conn
|
||||||
|> put_resp_header("content-type", content_type)
|
|> put_resp_header("content-type", content_type)
|
||||||
|> put_resp_header("content-disposition", "inline; filename=\"#{filename}\"")
|
|> put_resp_header("content-disposition", "inline; filename=\"#{filename}\"")
|
||||||
|
# TODO: enable caching
|
||||||
|> put_resp_header("cache-control", "max-age=0, private, must-revalidate")
|
|> put_resp_header("cache-control", "max-age=0, private, must-revalidate")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -541,8 +541,9 @@ test "shows non-zero when historical unapproved requests are present" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
test "uses mediaproxy urls when it's enabled" do
|
test "uses mediaproxy urls when it's enabled (regardless of media preview proxy state)" do
|
||||||
clear_config([:media_proxy, :enabled], true)
|
clear_config([:media_proxy, :enabled], true)
|
||||||
|
clear_config([:media_preview_proxy, :enabled])
|
||||||
|
|
||||||
user =
|
user =
|
||||||
insert(:user,
|
insert(:user,
|
||||||
|
@ -551,20 +552,24 @@ test "uses mediaproxy urls when it's enabled" do
|
||||||
emoji: %{"joker_smile" => "https://evil.website/society.png"}
|
emoji: %{"joker_smile" => "https://evil.website/society.png"}
|
||||||
)
|
)
|
||||||
|
|
||||||
AccountView.render("show.json", %{user: user, skip_visibility_check: true})
|
with media_preview_enabled <- [false, true] do
|
||||||
|> Enum.all?(fn
|
Config.put([:media_preview_proxy, :enabled], media_preview_enabled)
|
||||||
{key, url} when key in [:avatar, :avatar_static, :header, :header_static] ->
|
|
||||||
String.starts_with?(url, Pleroma.Web.base_url())
|
|
||||||
|
|
||||||
{:emojis, emojis} ->
|
AccountView.render("show.json", %{user: user, skip_visibility_check: true})
|
||||||
Enum.all?(emojis, fn %{url: url, static_url: static_url} ->
|
|> Enum.all?(fn
|
||||||
String.starts_with?(url, Pleroma.Web.base_url()) &&
|
{key, url} when key in [:avatar, :avatar_static, :header, :header_static] ->
|
||||||
String.starts_with?(static_url, Pleroma.Web.base_url())
|
String.starts_with?(url, Pleroma.Web.base_url())
|
||||||
end)
|
|
||||||
|
|
||||||
_ ->
|
{:emojis, emojis} ->
|
||||||
true
|
Enum.all?(emojis, fn %{url: url, static_url: static_url} ->
|
||||||
end)
|
String.starts_with?(url, Pleroma.Web.base_url()) &&
|
||||||
|> assert()
|
String.starts_with?(static_url, Pleroma.Web.base_url())
|
||||||
|
end)
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
true
|
||||||
|
end)
|
||||||
|
|> assert()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue