1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 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
14 on_exit(fn -> Cachex.clear(:banned_urls_cache) end)
17 describe "Media Proxy" do
19 clear_config([:media_proxy, :enabled], true)
20 clear_config([Pleroma.Web.Endpoint, :secret_key_base], "00000000000")
22 [url: MediaProxy.encode_url("https://google.fn/test.png")]
25 test "it returns 404 when disabled", %{conn: conn} do
26 clear_config([:media_proxy, :enabled], false)
30 resp_body: "Not Found"
31 } = get(conn, "/proxy/hhgfh/eeeee")
35 resp_body: "Not Found"
36 } = get(conn, "/proxy/hhgfh/eeee/fff")
39 test "it returns 403 for invalid signature", %{conn: conn, url: url} do
40 Pleroma.Config.put([Pleroma.Web.Endpoint, :secret_key_base], "000")
41 %{path: path} = URI.parse(url)
45 resp_body: "Forbidden"
50 resp_body: "Forbidden"
51 } = get(conn, "/proxy/hhgfh/eeee")
55 resp_body: "Forbidden"
56 } = get(conn, "/proxy/hhgfh/eeee/fff")
59 test "redirects to valid url when filename is invalidated", %{conn: conn, url: url} do
60 invalid_url = String.replace(url, "test.png", "test-file.png")
61 response = get(conn, invalid_url)
62 assert response.status == 302
63 assert redirected_to(response) == url
66 test "it performs ReverseProxy.call with valid signature", %{conn: conn, url: url} do
67 with_mock Pleroma.ReverseProxy,
68 call: fn _conn, _url, _opts -> %Conn{status: :success} end do
69 assert %Conn{status: :success} = get(conn, url)
73 test "it returns 404 when url is in banned_urls cache", %{conn: conn, url: url} do
74 MediaProxy.put_in_banned_urls("https://google.fn/test.png")
76 with_mock Pleroma.ReverseProxy,
77 call: fn _conn, _url, _opts -> %Conn{status: :success} end do
78 assert %Conn{status: 404, resp_body: "Not Found"} = get(conn, url)
83 describe "Media Preview Proxy" do
85 clear_config([:media_proxy, :enabled], true)
86 clear_config([:media_preview_proxy, :enabled], true)
87 clear_config([Pleroma.Web.Endpoint, :secret_key_base], "00000000000")
89 original_url = "https://google.fn/test.png"
92 url: MediaProxy.encode_preview_url(original_url),
93 media_proxy_url: MediaProxy.encode_url(original_url)
97 test "returns 404 when media proxy is disabled", %{conn: conn} do
98 clear_config([:media_proxy, :enabled], false)
102 resp_body: "Not Found"
103 } = get(conn, "/proxy/preview/hhgfh/eeeee")
107 resp_body: "Not Found"
108 } = get(conn, "/proxy/preview/hhgfh/fff")
111 test "returns 404 when disabled", %{conn: conn} do
112 clear_config([:media_preview_proxy, :enabled], false)
116 resp_body: "Not Found"
117 } = get(conn, "/proxy/preview/hhgfh/eeeee")
121 resp_body: "Not Found"
122 } = get(conn, "/proxy/preview/hhgfh/fff")
125 test "it returns 403 for invalid signature", %{conn: conn, url: url} do
126 Pleroma.Config.put([Pleroma.Web.Endpoint, :secret_key_base], "000")
127 %{path: path} = URI.parse(url)
131 resp_body: "Forbidden"
136 resp_body: "Forbidden"
137 } = get(conn, "/proxy/preview/hhgfh/eeee")
141 resp_body: "Forbidden"
142 } = get(conn, "/proxy/preview/hhgfh/eeee/fff")
145 test "redirects to valid url when filename is invalidated", %{conn: conn, url: url} do
146 invalid_url = String.replace(url, "test.png", "test-file.png")
147 response = get(conn, invalid_url)
148 assert response.status == 302
149 assert redirected_to(response) == url
152 test "responds with 424 Failed Dependency if HEAD request to media proxy fails", %{
155 media_proxy_url: media_proxy_url
158 %{method: "head", url: ^media_proxy_url} ->
159 %Tesla.Env{status: 500, body: ""}
162 response = get(conn, url)
163 assert response.status == 424
164 assert response.resp_body == "Can't fetch HTTP headers (HTTP 500)."
167 test "redirects to media proxy URI on unsupported content type", %{
170 media_proxy_url: media_proxy_url
173 %{method: "head", url: ^media_proxy_url} ->
174 %Tesla.Env{status: 200, body: "", headers: [{"content-type", "application/pdf"}]}
177 response = get(conn, url)
178 assert response.status == 302
179 assert redirected_to(response) == media_proxy_url
182 test "with `static=true` and GIF image preview requested, responds with JPEG image", %{
185 media_proxy_url: media_proxy_url
187 # Setting a high :min_content_length to ensure this scenario is not affected by its logic
188 clear_config([:media_preview_proxy, :min_content_length], 1_000_000_000)
191 %{method: "head", url: ^media_proxy_url} ->
195 headers: [{"content-type", "image/gif"}, {"content-length", "1001718"}]
198 %{method: :get, url: ^media_proxy_url} ->
199 %Tesla.Env{status: 200, body: File.read!("test/fixtures/image.gif")}
202 response = get(conn, url <> "?static=true")
204 assert response.status == 200
205 assert Conn.get_resp_header(response, "content-type") == ["image/jpeg"]
206 assert response.resp_body != ""
209 test "with GIF image preview requested and no `static` param, redirects to media proxy URI",
213 media_proxy_url: media_proxy_url
216 %{method: "head", url: ^media_proxy_url} ->
217 %Tesla.Env{status: 200, body: "", headers: [{"content-type", "image/gif"}]}
220 response = get(conn, url)
222 assert response.status == 302
223 assert redirected_to(response) == media_proxy_url
226 test "with `static` param and non-GIF image preview requested, " <>
227 "redirects to media preview proxy URI without `static` param",
231 media_proxy_url: media_proxy_url
234 %{method: "head", url: ^media_proxy_url} ->
235 %Tesla.Env{status: 200, body: "", headers: [{"content-type", "image/jpeg"}]}
238 response = get(conn, url <> "?static=true")
240 assert response.status == 302
241 assert redirected_to(response) == url
244 test "with :min_content_length setting not matched by Content-Length header, " <>
245 "redirects to media proxy URI",
249 media_proxy_url: media_proxy_url
251 clear_config([:media_preview_proxy, :min_content_length], 100_000)
254 %{method: "head", url: ^media_proxy_url} ->
258 headers: [{"content-type", "image/gif"}, {"content-length", "5000"}]
262 response = get(conn, url)
264 assert response.status == 302
265 assert redirected_to(response) == media_proxy_url
268 test "thumbnails PNG images into PNG", %{
271 media_proxy_url: media_proxy_url
274 %{method: "head", url: ^media_proxy_url} ->
275 %Tesla.Env{status: 200, body: "", headers: [{"content-type", "image/png"}]}
277 %{method: :get, url: ^media_proxy_url} ->
278 %Tesla.Env{status: 200, body: File.read!("test/fixtures/image.png")}
281 response = get(conn, url)
283 assert response.status == 200
284 assert Conn.get_resp_header(response, "content-type") == ["image/png"]
285 assert response.resp_body != ""
288 test "thumbnails JPEG images into JPEG", %{
291 media_proxy_url: media_proxy_url
294 %{method: "head", url: ^media_proxy_url} ->
295 %Tesla.Env{status: 200, body: "", headers: [{"content-type", "image/jpeg"}]}
297 %{method: :get, url: ^media_proxy_url} ->
298 %Tesla.Env{status: 200, body: File.read!("test/fixtures/image.jpg")}
301 response = get(conn, url)
303 assert response.status == 200
304 assert Conn.get_resp_header(response, "content-type") == ["image/jpeg"]
305 assert response.resp_body != ""
308 test "redirects to media proxy URI in case of thumbnailing error", %{
311 media_proxy_url: media_proxy_url
314 %{method: "head", url: ^media_proxy_url} ->
315 %Tesla.Env{status: 200, body: "", headers: [{"content-type", "image/jpeg"}]}
317 %{method: :get, url: ^media_proxy_url} ->
318 %Tesla.Env{status: 200, body: "<html><body>error</body></html>"}
321 response = get(conn, url)
323 assert response.status == 302
324 assert redirected_to(response) == media_proxy_url