1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Pleroma.Web.MediaProxy.MediaProxyControllerTest do
6 use Pleroma.Web.ConnCase
10 alias Pleroma.Web.MediaProxy
13 describe "Media Proxy" do
15 clear_config([:media_proxy, :enabled], true)
16 clear_config([Pleroma.Web.Endpoint, :secret_key_base], "00000000000")
18 [url: MediaProxy.encode_url("https://google.fn/test.png")]
21 test "it returns 404 when disabled", %{conn: conn} do
22 clear_config([:media_proxy, :enabled], false)
26 resp_body: "Not Found"
27 } = get(conn, "/proxy/hhgfh/eeeee")
31 resp_body: "Not Found"
32 } = get(conn, "/proxy/hhgfh/eeee/fff")
35 test "it returns 403 for invalid signature", %{conn: conn, url: url} do
36 clear_config([Pleroma.Web.Endpoint, :secret_key_base], "000")
37 %{path: path} = URI.parse(url)
41 resp_body: "Forbidden"
46 resp_body: "Forbidden"
47 } = get(conn, "/proxy/hhgfh/eeee")
51 resp_body: "Forbidden"
52 } = get(conn, "/proxy/hhgfh/eeee/fff")
55 test "redirects to valid url when filename is invalidated", %{conn: conn, url: url} do
56 invalid_url = String.replace(url, "test.png", "test-file.png")
57 response = get(conn, invalid_url)
58 assert response.status == 302
59 assert redirected_to(response) == url
62 test "it performs ReverseProxy.call with valid signature", %{conn: conn, url: url} do
63 with_mock Pleroma.ReverseProxy,
64 call: fn _conn, _url, _opts -> %Conn{status: :success} end do
65 assert %Conn{status: :success} = get(conn, url)
69 test "it returns 404 when url is in banned_urls cache", %{conn: conn, url: url} do
70 MediaProxy.put_in_banned_urls("https://google.fn/test.png")
72 with_mock Pleroma.ReverseProxy,
73 call: fn _conn, _url, _opts -> %Conn{status: :success} end do
74 assert %Conn{status: 404, resp_body: "Not Found"} = get(conn, url)
79 describe "Media Preview Proxy" do
80 def assert_dependencies_installed do
81 missing_dependencies = Pleroma.Helpers.MediaHelper.missing_dependencies()
83 assert missing_dependencies == [],
84 "Error: missing dependencies (please refer to `docs/installation`): #{inspect(missing_dependencies)}"
88 clear_config([:media_proxy, :enabled], true)
89 clear_config([:media_preview_proxy, :enabled], true)
90 clear_config([Pleroma.Web.Endpoint, :secret_key_base], "00000000000")
92 original_url = "https://google.fn/test.png"
95 url: MediaProxy.encode_preview_url(original_url),
96 media_proxy_url: MediaProxy.encode_url(original_url)
100 test "returns 404 when media proxy is disabled", %{conn: conn} do
101 clear_config([:media_proxy, :enabled], false)
105 resp_body: "Not Found"
106 } = get(conn, "/proxy/preview/hhgfh/eeeee")
110 resp_body: "Not Found"
111 } = get(conn, "/proxy/preview/hhgfh/fff")
114 test "returns 404 when disabled", %{conn: conn} do
115 clear_config([:media_preview_proxy, :enabled], false)
119 resp_body: "Not Found"
120 } = get(conn, "/proxy/preview/hhgfh/eeeee")
124 resp_body: "Not Found"
125 } = get(conn, "/proxy/preview/hhgfh/fff")
128 test "it returns 403 for invalid signature", %{conn: conn, url: url} do
129 clear_config([Pleroma.Web.Endpoint, :secret_key_base], "000")
130 %{path: path} = URI.parse(url)
134 resp_body: "Forbidden"
139 resp_body: "Forbidden"
140 } = get(conn, "/proxy/preview/hhgfh/eeee")
144 resp_body: "Forbidden"
145 } = get(conn, "/proxy/preview/hhgfh/eeee/fff")
148 test "redirects to valid url when filename is invalidated", %{conn: conn, url: url} do
149 invalid_url = String.replace(url, "test.png", "test-file.png")
150 response = get(conn, invalid_url)
151 assert response.status == 302
152 assert redirected_to(response) == url
155 test "responds with 424 Failed Dependency if HEAD request to media proxy fails", %{
158 media_proxy_url: media_proxy_url
161 %{method: "head", url: ^media_proxy_url} ->
162 %Tesla.Env{status: 500, body: ""}
165 response = get(conn, url)
166 assert response.status == 424
167 assert response.resp_body == "Can't fetch HTTP headers (HTTP 500)."
170 test "redirects to media proxy URI on unsupported content type", %{
173 media_proxy_url: media_proxy_url
176 %{method: "head", url: ^media_proxy_url} ->
177 %Tesla.Env{status: 200, body: "", headers: [{"content-type", "application/pdf"}]}
180 response = get(conn, url)
181 assert response.status == 302
182 assert redirected_to(response) == media_proxy_url
185 test "with `static=true` and GIF image preview requested, responds with JPEG image", %{
188 media_proxy_url: media_proxy_url
190 assert_dependencies_installed()
192 # Setting a high :min_content_length to ensure this scenario is not affected by its logic
193 clear_config([:media_preview_proxy, :min_content_length], 1_000_000_000)
196 %{method: "head", url: ^media_proxy_url} ->
200 headers: [{"content-type", "image/gif"}, {"content-length", "1001718"}]
203 %{method: :get, url: ^media_proxy_url} ->
204 %Tesla.Env{status: 200, body: File.read!("test/fixtures/image.gif")}
207 response = get(conn, url <> "?static=true")
209 assert response.status == 200
210 assert Conn.get_resp_header(response, "content-type") == ["image/jpeg"]
211 assert response.resp_body != ""
214 test "with GIF image preview requested and no `static` param, redirects to media proxy URI",
218 media_proxy_url: media_proxy_url
221 %{method: "head", url: ^media_proxy_url} ->
222 %Tesla.Env{status: 200, body: "", headers: [{"content-type", "image/gif"}]}
225 response = get(conn, url)
227 assert response.status == 302
228 assert redirected_to(response) == media_proxy_url
231 test "with `static` param and non-GIF image preview requested, " <>
232 "redirects to media preview proxy URI without `static` param",
236 media_proxy_url: media_proxy_url
239 %{method: "head", url: ^media_proxy_url} ->
240 %Tesla.Env{status: 200, body: "", headers: [{"content-type", "image/jpeg"}]}
243 response = get(conn, url <> "?static=true")
245 assert response.status == 302
246 assert redirected_to(response) == url
249 test "with :min_content_length setting not matched by Content-Length header, " <>
250 "redirects to media proxy URI",
254 media_proxy_url: media_proxy_url
256 clear_config([:media_preview_proxy, :min_content_length], 100_000)
259 %{method: "head", url: ^media_proxy_url} ->
263 headers: [{"content-type", "image/gif"}, {"content-length", "5000"}]
267 response = get(conn, url)
269 assert response.status == 302
270 assert redirected_to(response) == media_proxy_url
273 test "thumbnails PNG images into PNG", %{
276 media_proxy_url: media_proxy_url
278 assert_dependencies_installed()
281 %{method: "head", url: ^media_proxy_url} ->
282 %Tesla.Env{status: 200, body: "", headers: [{"content-type", "image/png"}]}
284 %{method: :get, url: ^media_proxy_url} ->
285 %Tesla.Env{status: 200, body: File.read!("test/fixtures/image.png")}
288 response = get(conn, url)
290 assert response.status == 200
291 assert Conn.get_resp_header(response, "content-type") == ["image/png"]
292 assert response.resp_body != ""
295 test "thumbnails JPEG images into JPEG", %{
298 media_proxy_url: media_proxy_url
300 assert_dependencies_installed()
303 %{method: "head", url: ^media_proxy_url} ->
304 %Tesla.Env{status: 200, body: "", headers: [{"content-type", "image/jpeg"}]}
306 %{method: :get, url: ^media_proxy_url} ->
307 %Tesla.Env{status: 200, body: File.read!("test/fixtures/image.jpg")}
310 response = get(conn, url)
312 assert response.status == 200
313 assert Conn.get_resp_header(response, "content-type") == ["image/jpeg"]
314 assert response.resp_body != ""
317 test "redirects to media proxy URI in case of thumbnailing error", %{
320 media_proxy_url: media_proxy_url
323 %{method: "head", url: ^media_proxy_url} ->
324 %Tesla.Env{status: 200, body: "", headers: [{"content-type", "image/jpeg"}]}
326 %{method: :get, url: ^media_proxy_url} ->
327 %Tesla.Env{status: 200, body: "<html><body>error</body></html>"}
330 response = get(conn, url)
332 assert response.status == 302
333 assert redirected_to(response) == media_proxy_url