First
[anni] / test / pleroma / upload_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.UploadTest do
6   use Pleroma.DataCase
7
8   import ExUnit.CaptureLog
9
10   alias Pleroma.Upload
11   alias Pleroma.Uploaders.Uploader
12
13   @upload_file %Plug.Upload{
14     content_type: "image/jpeg",
15     path: Path.absname("test/fixtures/image_tmp.jpg"),
16     filename: "image.jpg"
17   }
18
19   defmodule TestUploaderBase do
20     def put_file(%{path: path} = _upload, module_name) do
21       task_pid =
22         Task.async(fn ->
23           :timer.sleep(10)
24
25           {Uploader, path}
26           |> :global.whereis_name()
27           |> send({Uploader, self(), {:test}, %{}})
28
29           assert_receive {Uploader, {:test}}, 4_000
30         end)
31
32       Agent.start(fn -> task_pid end, name: module_name)
33
34       :wait_callback
35     end
36   end
37
38   describe "Tried storing a file when http callback response success result" do
39     defmodule TestUploaderSuccess do
40       def http_callback(conn, _params),
41         do: {:ok, conn, {:file, "post-process-file.jpg"}}
42
43       def put_file(upload), do: TestUploaderBase.put_file(upload, __MODULE__)
44     end
45
46     setup do: [uploader: TestUploaderSuccess]
47     setup [:ensure_local_uploader]
48
49     test "it returns file" do
50       File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
51
52       assert {:ok, result} = Upload.store(@upload_file)
53
54       assert result ==
55                %{
56                  "id" => result["id"],
57                  "name" => "image.jpg",
58                  "type" => "Document",
59                  "mediaType" => "image/jpeg",
60                  "url" => [
61                    %{
62                      "href" => "http://localhost:4001/media/post-process-file.jpg",
63                      "mediaType" => "image/jpeg",
64                      "type" => "Link"
65                    }
66                  ]
67                }
68
69       Task.await(Agent.get(TestUploaderSuccess, fn task_pid -> task_pid end))
70     end
71   end
72
73   describe "Tried storing a file when http callback response error" do
74     defmodule TestUploaderError do
75       def http_callback(conn, _params), do: {:error, conn, "Errors"}
76
77       def put_file(upload), do: TestUploaderBase.put_file(upload, __MODULE__)
78     end
79
80     setup do: [uploader: TestUploaderError]
81     setup [:ensure_local_uploader]
82
83     test "it returns error" do
84       File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
85
86       assert capture_log(fn ->
87                assert Upload.store(@upload_file) == {:error, "Errors"}
88                Task.await(Agent.get(TestUploaderError, fn task_pid -> task_pid end))
89              end) =~
90                "[error] Elixir.Pleroma.Upload store (using Pleroma.UploadTest.TestUploaderError) failed: \"Errors\""
91     end
92   end
93
94   describe "Tried storing a file when http callback doesn't response by timeout" do
95     defmodule(TestUploader, do: def(put_file(_upload), do: :wait_callback))
96     setup do: [uploader: TestUploader]
97     setup [:ensure_local_uploader]
98
99     test "it returns error" do
100       File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
101
102       assert capture_log(fn ->
103                assert Upload.store(@upload_file) == {:error, "Uploader callback timeout"}
104              end) =~
105                "[error] Elixir.Pleroma.Upload store (using Pleroma.UploadTest.TestUploader) failed: \"Uploader callback timeout\""
106     end
107   end
108
109   describe "Storing a file with the Local uploader" do
110     setup [:ensure_local_uploader]
111
112     test "does not allow descriptions longer than the post limit" do
113       clear_config([:instance, :description_limit], 2)
114       File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
115
116       file = %Plug.Upload{
117         content_type: "image/jpeg",
118         path: Path.absname("test/fixtures/image_tmp.jpg"),
119         filename: "image.jpg"
120       }
121
122       {:error, :description_too_long} = Upload.store(file, description: "123")
123     end
124
125     test "returns a media url" do
126       File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
127
128       file = %Plug.Upload{
129         content_type: "image/jpeg",
130         path: Path.absname("test/fixtures/image_tmp.jpg"),
131         filename: "image.jpg"
132       }
133
134       {:ok, data} = Upload.store(file)
135
136       assert %{"url" => [%{"href" => url}]} = data
137
138       assert String.starts_with?(url, Pleroma.Upload.base_url())
139     end
140
141     test "copies the file to the configured folder with deduping" do
142       File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
143
144       file = %Plug.Upload{
145         content_type: "image/jpeg",
146         path: Path.absname("test/fixtures/image_tmp.jpg"),
147         filename: "an [image.jpg"
148       }
149
150       {:ok, data} = Upload.store(file, filters: [Pleroma.Upload.Filter.Dedupe])
151
152       assert List.first(data["url"])["href"] ==
153                Pleroma.Upload.base_url() <>
154                  "e30397b58d226d6583ab5b8b3c5defb0c682bda5c31ef07a9f57c1c4986e3781.jpg"
155     end
156
157     test "copies the file to the configured folder without deduping" do
158       File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
159
160       file = %Plug.Upload{
161         content_type: "image/jpeg",
162         path: Path.absname("test/fixtures/image_tmp.jpg"),
163         filename: "an [image.jpg"
164       }
165
166       {:ok, data} = Upload.store(file)
167       assert data["name"] == "an [image.jpg"
168     end
169
170     test "fixes incorrect content type when base64 is given" do
171       params = %{
172         img: "data:image/png;base64,#{Base.encode64(File.read!("test/fixtures/image.jpg"))}"
173       }
174
175       {:ok, data} = Upload.store(params)
176       assert hd(data["url"])["mediaType"] == "image/jpeg"
177     end
178
179     test "adds extension when base64 is given" do
180       File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
181
182       params = %{
183         img: "data:image/png;base64,#{Base.encode64(File.read!("test/fixtures/image.jpg"))}"
184       }
185
186       {:ok, data} = Upload.store(params)
187       assert String.ends_with?(data["name"], ".jpg")
188     end
189
190     test "copies the file to the configured folder with anonymizing filename" do
191       File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
192
193       file = %Plug.Upload{
194         content_type: "image/jpeg",
195         path: Path.absname("test/fixtures/image_tmp.jpg"),
196         filename: "an [image.jpg"
197       }
198
199       {:ok, data} = Upload.store(file, filters: [Pleroma.Upload.Filter.AnonymizeFilename])
200
201       refute data["name"] == "an [image.jpg"
202     end
203
204     test "escapes invalid characters in url" do
205       File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
206
207       file = %Plug.Upload{
208         content_type: "image/jpeg",
209         path: Path.absname("test/fixtures/image_tmp.jpg"),
210         filename: "an… image.jpg"
211       }
212
213       {:ok, data} = Upload.store(file)
214       [attachment_url | _] = data["url"]
215
216       assert Path.basename(attachment_url["href"]) == "an%E2%80%A6%20image.jpg"
217     end
218
219     test "escapes reserved uri characters" do
220       File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
221
222       file = %Plug.Upload{
223         content_type: "image/jpeg",
224         path: Path.absname("test/fixtures/image_tmp.jpg"),
225         filename: ":?#[]@!$&\\'()*+,;=.jpg"
226       }
227
228       {:ok, data} = Upload.store(file)
229       [attachment_url | _] = data["url"]
230
231       assert Path.basename(attachment_url["href"]) ==
232                "%3A%3F%23%5B%5D%40%21%24%26%5C%27%28%29%2A%2B%2C%3B%3D.jpg"
233     end
234   end
235
236   describe "Setting a custom base_url for uploaded media" do
237     setup do: clear_config([Pleroma.Upload, :base_url], "https://cache.pleroma.social")
238
239     test "returns a media url with configured base_url" do
240       base_url = Pleroma.Config.get([Pleroma.Upload, :base_url])
241
242       File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
243
244       file = %Plug.Upload{
245         content_type: "image/jpeg",
246         path: Path.absname("test/fixtures/image_tmp.jpg"),
247         filename: "image.jpg"
248       }
249
250       {:ok, data} = Upload.store(file, base_url: base_url)
251
252       assert %{"url" => [%{"href" => url}]} = data
253
254       refute String.starts_with?(url, base_url <> "/media/")
255     end
256   end
257 end