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`): #{
85 inspect(missing_dependencies)
90 clear_config([:media_proxy, :enabled], true)
91 clear_config([:media_preview_proxy, :enabled], true)
92 clear_config([Pleroma.Web.Endpoint, :secret_key_base], "00000000000")
94 original_url = "https://google.fn/test.png"
97 url: MediaProxy.encode_preview_url(original_url),
98 media_proxy_url: MediaProxy.encode_url(original_url)
102 test "returns 404 when media proxy is disabled", %{conn: conn} do
103 clear_config([:media_proxy, :enabled], false)
107 resp_body: "Not Found"
108 } = get(conn, "/proxy/preview/hhgfh/eeeee")
112 resp_body: "Not Found"
113 } = get(conn, "/proxy/preview/hhgfh/fff")
116 test "returns 404 when disabled", %{conn: conn} do
117 clear_config([:media_preview_proxy, :enabled], false)
121 resp_body: "Not Found"
122 } = get(conn, "/proxy/preview/hhgfh/eeeee")
126 resp_body: "Not Found"
127 } = get(conn, "/proxy/preview/hhgfh/fff")
130 test "it returns 403 for invalid signature", %{conn: conn, url: url} do
131 clear_config([Pleroma.Web.Endpoint, :secret_key_base], "000")
132 %{path: path} = URI.parse(url)
136 resp_body: "Forbidden"
141 resp_body: "Forbidden"
142 } = get(conn, "/proxy/preview/hhgfh/eeee")
146 resp_body: "Forbidden"
147 } = get(conn, "/proxy/preview/hhgfh/eeee/fff")
150 test "redirects to valid url when filename is invalidated", %{conn: conn, url: url} do
151 invalid_url = String.replace(url, "test.png", "test-file.png")
152 response = get(conn, invalid_url)
153 assert response.status == 302
154 assert redirected_to(response) == url
157 test "responds with 424 Failed Dependency if HEAD request to media proxy fails", %{
160 media_proxy_url: media_proxy_url
163 %{method: "head", url: ^media_proxy_url} ->
164 %Tesla.Env{status: 500, body: ""}
167 response = get(conn, url)
168 assert response.status == 424
169 assert response.resp_body == "Can't fetch HTTP headers (HTTP 500)."
172 test "redirects to media proxy URI on unsupported content type", %{
175 media_proxy_url: media_proxy_url
178 %{method: "head", url: ^media_proxy_url} ->
179 %Tesla.Env{status: 200, body: "", headers: [{"content-type", "application/pdf"}]}
182 response = get(conn, url)
183 assert response.status == 302
184 assert redirected_to(response) == media_proxy_url
187 test "with `static=true` and GIF image preview requested, responds with JPEG image", %{
190 media_proxy_url: media_proxy_url
192 assert_dependencies_installed()
194 # Setting a high :min_content_length to ensure this scenario is not affected by its logic
195 clear_config([:media_preview_proxy, :min_content_length], 1_000_000_000)
198 %{method: "head", url: ^media_proxy_url} ->
202 headers: [{"content-type", "image/gif"}, {"content-length", "1001718"}]
205 %{method: :get, url: ^media_proxy_url} ->
206 %Tesla.Env{status: 200, body: File.read!("test/fixtures/image.gif")}
209 response = get(conn, url <> "?static=true")
211 assert response.status == 200
212 assert Conn.get_resp_header(response, "content-type") == ["image/jpeg"]
213 assert response.resp_body != ""
216 test "with GIF image preview requested and no `static` param, redirects to media proxy URI",
220 media_proxy_url: media_proxy_url
223 %{method: "head", url: ^media_proxy_url} ->
224 %Tesla.Env{status: 200, body: "", headers: [{"content-type", "image/gif"}]}
227 response = get(conn, url)
229 assert response.status == 302
230 assert redirected_to(response) == media_proxy_url
233 test "with `static` param and non-GIF image preview requested, " <>
234 "redirects to media preview proxy URI without `static` param",
238 media_proxy_url: media_proxy_url
241 %{method: "head", url: ^media_proxy_url} ->
242 %Tesla.Env{status: 200, body: "", headers: [{"content-type", "image/jpeg"}]}
245 response = get(conn, url <> "?static=true")
247 assert response.status == 302
248 assert redirected_to(response) == url
251 test "with :min_content_length setting not matched by Content-Length header, " <>
252 "redirects to media proxy URI",
256 media_proxy_url: media_proxy_url
258 clear_config([:media_preview_proxy, :min_content_length], 100_000)
261 %{method: "head", url: ^media_proxy_url} ->
265 headers: [{"content-type", "image/gif"}, {"content-length", "5000"}]
269 response = get(conn, url)
271 assert response.status == 302
272 assert redirected_to(response) == media_proxy_url
275 test "thumbnails PNG images into PNG", %{
278 media_proxy_url: media_proxy_url
280 assert_dependencies_installed()
283 %{method: "head", url: ^media_proxy_url} ->
284 %Tesla.Env{status: 200, body: "", headers: [{"content-type", "image/png"}]}
286 %{method: :get, url: ^media_proxy_url} ->
287 %Tesla.Env{status: 200, body: File.read!("test/fixtures/image.png")}
290 response = get(conn, url)
292 assert response.status == 200
293 assert Conn.get_resp_header(response, "content-type") == ["image/png"]
294 assert response.resp_body != ""
297 test "thumbnails JPEG images into JPEG", %{
300 media_proxy_url: media_proxy_url
302 assert_dependencies_installed()
305 %{method: "head", url: ^media_proxy_url} ->
306 %Tesla.Env{status: 200, body: "", headers: [{"content-type", "image/jpeg"}]}
308 %{method: :get, url: ^media_proxy_url} ->
309 %Tesla.Env{status: 200, body: File.read!("test/fixtures/image.jpg")}
312 response = get(conn, url)
314 assert response.status == 200
315 assert Conn.get_resp_header(response, "content-type") == ["image/jpeg"]
316 assert response.resp_body != ""
319 test "redirects to media proxy URI in case of thumbnailing error", %{
322 media_proxy_url: media_proxy_url
325 %{method: "head", url: ^media_proxy_url} ->
326 %Tesla.Env{status: 200, body: "", headers: [{"content-type", "image/jpeg"}]}
328 %{method: :get, url: ^media_proxy_url} ->
329 %Tesla.Env{status: 200, body: "<html><body>error</body></html>"}
332 response = get(conn, url)
334 assert response.status == 302
335 assert redirected_to(response) == media_proxy_url