1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do
6 use Pleroma.Web.ConnCase, async: false
10 import Pleroma.Factory
12 @emoji_path Path.join(
13 Pleroma.Config.get!([:instance, :static_dir]),
17 setup do: clear_config([:instance, :public], true)
20 admin = insert(:user, is_admin: true)
21 token = insert(:oauth_admin_token, user: admin)
25 |> assign(:user, admin)
26 |> assign(:token, token)
28 Pleroma.Emoji.reload()
29 {:ok, %{admin_conn: admin_conn}}
32 test "GET /api/pleroma/emoji/packs when :public: false", %{conn: conn} do
33 clear_config([:instance, :public], false)
34 conn |> get("/api/pleroma/emoji/packs") |> json_response_and_validate_schema(200)
37 test "GET /api/pleroma/emoji/packs", %{conn: conn} do
38 resp = conn |> get("/api/pleroma/emoji/packs") |> json_response_and_validate_schema(200)
40 assert resp["count"] == 4
46 shared = resp["packs"]["test_pack"]
47 assert shared["files"] == %{"blank" => "blank.png", "blank2" => "blank2.png"}
48 assert Map.has_key?(shared["pack"], "download-sha256")
49 assert shared["pack"]["can-download"]
50 assert shared["pack"]["share-files"]
52 non_shared = resp["packs"]["test_pack_nonshared"]
53 assert non_shared["pack"]["share-files"] == false
54 assert non_shared["pack"]["can-download"] == false
58 |> get("/api/pleroma/emoji/packs?page_size=1")
59 |> json_response_and_validate_schema(200)
61 assert resp["count"] == 4
63 packs = Map.keys(resp["packs"])
65 assert length(packs) == 1
71 |> get("/api/pleroma/emoji/packs?page_size=1&page=2")
72 |> json_response_and_validate_schema(200)
74 assert resp["count"] == 4
75 packs = Map.keys(resp["packs"])
76 assert length(packs) == 1
81 |> get("/api/pleroma/emoji/packs?page_size=1&page=3")
82 |> json_response_and_validate_schema(200)
84 assert resp["count"] == 4
85 packs = Map.keys(resp["packs"])
86 assert length(packs) == 1
91 |> get("/api/pleroma/emoji/packs?page_size=1&page=4")
92 |> json_response_and_validate_schema(200)
94 assert resp["count"] == 4
95 packs = Map.keys(resp["packs"])
96 assert length(packs) == 1
98 assert [pack1, pack2, pack3, pack4] |> Enum.uniq() |> length() == 4
101 describe "GET /api/pleroma/emoji/packs/remote" do
103 clear_config([:instance, :admin_privileges], [:emoji_manage_emoji])
106 test "shareable instance", %{admin_conn: admin_conn, conn: conn} do
109 |> get("/api/pleroma/emoji/packs?page=2&page_size=1")
110 |> json_response_and_validate_schema(200)
113 %{method: :get, url: "https://example.com/.well-known/nodeinfo"} ->
114 json(%{links: [%{href: "https://example.com/nodeinfo/2.1.json"}]})
116 %{method: :get, url: "https://example.com/nodeinfo/2.1.json"} ->
117 json(%{metadata: %{features: ["shareable_emoji_packs"]}})
119 %{method: :get, url: "https://example.com/api/pleroma/emoji/packs?page=2&page_size=1"} ->
124 |> get("/api/pleroma/emoji/packs/remote?url=https://example.com&page=2&page_size=1")
125 |> json_response_and_validate_schema(200) == resp
128 test "non shareable instance", %{admin_conn: admin_conn} do
130 %{method: :get, url: "https://example.com/.well-known/nodeinfo"} ->
131 json(%{links: [%{href: "https://example.com/nodeinfo/2.1.json"}]})
133 %{method: :get, url: "https://example.com/nodeinfo/2.1.json"} ->
134 json(%{metadata: %{features: []}})
138 |> get("/api/pleroma/emoji/packs/remote?url=https://example.com")
139 |> json_response_and_validate_schema(500) == %{
140 "error" => "The requested instance does not support sharing emoji packs"
144 test "it requires privileged role :emoji_manage_emoji", %{admin_conn: admin_conn} do
145 clear_config([:instance, :admin_privileges], [])
148 |> get("/api/pleroma/emoji/packs/remote?url=https://example.com")
149 |> json_response(:forbidden)
153 describe "GET /api/pleroma/emoji/packs/archive?name=:name" do
154 test "download shared pack", %{conn: conn} do
157 |> get("/api/pleroma/emoji/packs/archive?name=test_pack")
160 {:ok, arch} = :zip.unzip(resp, [:memory])
162 assert Enum.find(arch, fn {n, _} -> n == 'pack.json' end)
163 assert Enum.find(arch, fn {n, _} -> n == 'blank.png' end)
166 test "non existing pack", %{conn: conn} do
168 |> get("/api/pleroma/emoji/packs/archive?name=test_pack_for_import")
169 |> json_response_and_validate_schema(:not_found) == %{
170 "error" => "Pack test_pack_for_import does not exist"
174 test "non downloadable pack", %{conn: conn} do
176 |> get("/api/pleroma/emoji/packs/archive?name=test_pack_nonshared")
177 |> json_response_and_validate_schema(:forbidden) == %{
179 "Pack test_pack_nonshared cannot be downloaded from this instance, either pack sharing was disabled for this pack or some files are missing"
184 describe "POST /api/pleroma/emoji/packs/download" do
186 clear_config([:instance, :admin_privileges], [:emoji_manage_emoji])
189 test "shared pack from remote and non shared from fallback-src", %{
190 admin_conn: admin_conn,
194 %{method: :get, url: "https://example.com/.well-known/nodeinfo"} ->
195 json(%{links: [%{href: "https://example.com/nodeinfo/2.1.json"}]})
197 %{method: :get, url: "https://example.com/nodeinfo/2.1.json"} ->
198 json(%{metadata: %{features: ["shareable_emoji_packs"]}})
202 url: "https://example.com/api/pleroma/emoji/pack?name=test_pack"
205 |> get("/api/pleroma/emoji/pack?name=test_pack")
206 |> json_response_and_validate_schema(200)
211 url: "https://example.com/api/pleroma/emoji/packs/archive?name=test_pack"
214 |> get("/api/pleroma/emoji/packs/archive?name=test_pack")
220 url: "https://example.com/api/pleroma/emoji/pack?name=test_pack_nonshared"
223 |> get("/api/pleroma/emoji/pack?name=test_pack_nonshared")
224 |> json_response_and_validate_schema(200)
229 url: "https://nonshared-pack"
231 text(File.read!("#{@emoji_path}/test_pack_nonshared/nonshared.zip"))
235 |> put_req_header("content-type", "multipart/form-data")
236 |> post("/api/pleroma/emoji/packs/download", %{
237 url: "https://example.com",
241 |> json_response_and_validate_schema(200) == "ok"
243 assert File.exists?("#{@emoji_path}/test_pack2/pack.json")
244 assert File.exists?("#{@emoji_path}/test_pack2/blank.png")
247 |> delete("/api/pleroma/emoji/pack?name=test_pack2")
248 |> json_response_and_validate_schema(200) == "ok"
250 refute File.exists?("#{@emoji_path}/test_pack2")
253 |> put_req_header("content-type", "multipart/form-data")
255 "/api/pleroma/emoji/packs/download",
257 url: "https://example.com",
258 name: "test_pack_nonshared",
259 as: "test_pack_nonshared2"
262 |> json_response_and_validate_schema(200) == "ok"
264 assert File.exists?("#{@emoji_path}/test_pack_nonshared2/pack.json")
265 assert File.exists?("#{@emoji_path}/test_pack_nonshared2/blank.png")
268 |> delete("/api/pleroma/emoji/pack?name=test_pack_nonshared2")
269 |> json_response_and_validate_schema(200) == "ok"
271 refute File.exists?("#{@emoji_path}/test_pack_nonshared2")
274 test "nonshareable instance", %{admin_conn: admin_conn} do
276 %{method: :get, url: "https://old-instance/.well-known/nodeinfo"} ->
277 json(%{links: [%{href: "https://old-instance/nodeinfo/2.1.json"}]})
279 %{method: :get, url: "https://old-instance/nodeinfo/2.1.json"} ->
280 json(%{metadata: %{features: []}})
284 |> put_req_header("content-type", "multipart/form-data")
286 "/api/pleroma/emoji/packs/download",
288 url: "https://old-instance",
293 |> json_response_and_validate_schema(500) == %{
294 "error" => "The requested instance does not support sharing emoji packs"
298 test "checksum fail", %{admin_conn: admin_conn} do
300 %{method: :get, url: "https://example.com/.well-known/nodeinfo"} ->
301 json(%{links: [%{href: "https://example.com/nodeinfo/2.1.json"}]})
303 %{method: :get, url: "https://example.com/nodeinfo/2.1.json"} ->
304 json(%{metadata: %{features: ["shareable_emoji_packs"]}})
308 url: "https://example.com/api/pleroma/emoji/pack?name=pack_bad_sha"
310 {:ok, pack} = Pleroma.Emoji.Pack.load_pack("pack_bad_sha")
311 %Tesla.Env{status: 200, body: Jason.encode!(pack)}
315 url: "https://example.com/api/pleroma/emoji/packs/archive?name=pack_bad_sha"
319 body: File.read!("test/instance_static/emoji/pack_bad_sha/pack_bad_sha.zip")
324 |> put_req_header("content-type", "multipart/form-data")
325 |> post("/api/pleroma/emoji/packs/download", %{
326 url: "https://example.com",
327 name: "pack_bad_sha",
330 |> json_response_and_validate_schema(:internal_server_error) == %{
331 "error" => "SHA256 for the pack doesn't match the one sent by the server"
335 test "other error", %{admin_conn: admin_conn} do
337 %{method: :get, url: "https://example.com/.well-known/nodeinfo"} ->
338 json(%{links: [%{href: "https://example.com/nodeinfo/2.1.json"}]})
340 %{method: :get, url: "https://example.com/nodeinfo/2.1.json"} ->
341 json(%{metadata: %{features: ["shareable_emoji_packs"]}})
345 url: "https://example.com/api/pleroma/emoji/pack?name=test_pack"
347 {:ok, pack} = Pleroma.Emoji.Pack.load_pack("test_pack")
348 %Tesla.Env{status: 200, body: Jason.encode!(pack)}
352 |> put_req_header("content-type", "multipart/form-data")
353 |> post("/api/pleroma/emoji/packs/download", %{
354 url: "https://example.com",
358 |> json_response_and_validate_schema(:internal_server_error) == %{
360 "The pack was not set as shared and there is no fallback src to download from"
364 test "it requires privileged role :emoji_manage_emoji", %{admin_conn: conn} do
365 clear_config([:instance, :admin_privileges], [])
368 |> put_req_header("content-type", "multipart/form-data")
369 |> post("/api/pleroma/emoji/packs/download", %{
370 url: "https://example.com",
374 |> json_response(:forbidden)
378 describe "PATCH/update /api/pleroma/emoji/pack?name=:name" do
380 clear_config([:instance, :admin_privileges], [:emoji_manage_emoji])
381 pack_file = "#{@emoji_path}/test_pack/pack.json"
382 original_content = File.read!(pack_file)
385 File.write!(pack_file, original_content)
389 pack_file: pack_file,
391 "license" => "Test license changed",
392 "homepage" => "https://pleroma.social",
393 "description" => "Test description",
394 "share-files" => false
398 test "returns error when file system not writable", %{admin_conn: conn} = ctx do
400 {File, [:passthrough], [stat: fn _ -> {:error, :eacces} end]}
403 |> put_req_header("content-type", "multipart/form-data")
405 "/api/pleroma/emoji/pack?name=test_pack",
406 %{"metadata" => ctx[:new_data]}
408 |> json_response_and_validate_schema(500)
412 test "for a pack without a fallback source", ctx do
413 assert ctx[:admin_conn]
414 |> put_req_header("content-type", "multipart/form-data")
415 |> patch("/api/pleroma/emoji/pack?name=test_pack", %{
416 "metadata" => ctx[:new_data]
418 |> json_response_and_validate_schema(200) == ctx[:new_data]
420 assert Jason.decode!(File.read!(ctx[:pack_file]))["pack"] == ctx[:new_data]
423 test "for a pack with a fallback source", ctx do
427 url: "https://nonshared-pack"
429 text(File.read!("#{@emoji_path}/test_pack_nonshared/nonshared.zip"))
432 new_data = Map.put(ctx[:new_data], "fallback-src", "https://nonshared-pack")
437 "fallback-src-sha256",
438 "1967BB4E42BCC34BCC12D57BE7811D3B7BE52F965BCE45C87BD377B9499CE11D"
441 assert ctx[:admin_conn]
442 |> put_req_header("content-type", "multipart/form-data")
443 |> patch("/api/pleroma/emoji/pack?name=test_pack", %{metadata: new_data})
444 |> json_response_and_validate_schema(200) == new_data_with_sha
446 assert Jason.decode!(File.read!(ctx[:pack_file]))["pack"] == new_data_with_sha
449 test "when the fallback source doesn't have all the files", ctx do
453 url: "https://nonshared-pack"
455 {:ok, {'empty.zip', empty_arch}} = :zip.zip('empty.zip', [], [:memory])
459 new_data = Map.put(ctx[:new_data], "fallback-src", "https://nonshared-pack")
461 assert ctx[:admin_conn]
462 |> put_req_header("content-type", "multipart/form-data")
463 |> patch("/api/pleroma/emoji/pack?name=test_pack", %{metadata: new_data})
464 |> json_response_and_validate_schema(:bad_request) == %{
465 "error" => "The fallback archive does not have all files specified in pack.json"
469 test "it requires privileged role :emoji_manage_emoji", %{
473 clear_config([:instance, :admin_privileges], [])
476 |> put_req_header("content-type", "multipart/form-data")
477 |> patch("/api/pleroma/emoji/pack?name=test_pack", %{metadata: new_data})
478 |> json_response(:forbidden)
482 describe "POST/DELETE /api/pleroma/emoji/pack?name=:name" do
484 clear_config([:instance, :admin_privileges], [:emoji_manage_emoji])
487 test "returns an error on creates pack when file system not writable", %{
488 admin_conn: admin_conn
490 path_pack = Path.join(@emoji_path, "test_pack")
493 {File, [:passthrough], [mkdir: fn ^path_pack -> {:error, :eacces} end]}
496 |> post("/api/pleroma/emoji/pack?name=test_pack")
497 |> json_response_and_validate_schema(500) == %{
499 "Unexpected error occurred while creating pack. (POSIX error: Permission denied)"
504 test "returns an error on deletes pack when the file system is not writable", %{
505 admin_conn: admin_conn
507 path_pack = Path.join(@emoji_path, "test_emoji_pack")
510 {:ok, _pack} = Pleroma.Emoji.Pack.create("test_emoji_pack")
513 {File, [:passthrough], [rm_rf: fn ^path_pack -> {:error, :eacces, path_pack} end]}
516 |> delete("/api/pleroma/emoji/pack?name=test_emoji_pack")
517 |> json_response_and_validate_schema(500) == %{
519 "Couldn't delete the `test_emoji_pack` pack (POSIX error: Permission denied)"
523 File.rm_rf(path_pack)
527 test "creating and deleting a pack", %{admin_conn: admin_conn} do
529 |> post("/api/pleroma/emoji/pack?name=test_created")
530 |> json_response_and_validate_schema(200) == "ok"
532 assert File.exists?("#{@emoji_path}/test_created/pack.json")
534 assert Jason.decode!(File.read!("#{@emoji_path}/test_created/pack.json")) == %{
541 |> delete("/api/pleroma/emoji/pack?name=test_created")
542 |> json_response_and_validate_schema(200) == "ok"
544 refute File.exists?("#{@emoji_path}/test_created/pack.json")
547 test "if pack exists", %{admin_conn: admin_conn} do
548 path = Path.join(@emoji_path, "test_created")
550 pack_file = Jason.encode!(%{files: %{}, pack: %{}})
551 File.write!(Path.join(path, "pack.json"), pack_file)
554 |> post("/api/pleroma/emoji/pack?name=test_created")
555 |> json_response_and_validate_schema(:conflict) == %{
556 "error" => "A pack named \"test_created\" already exists"
559 on_exit(fn -> File.rm_rf(path) end)
562 test "with empty name", %{admin_conn: admin_conn} do
564 |> post("/api/pleroma/emoji/pack?name= ")
565 |> json_response_and_validate_schema(:bad_request) == %{
566 "error" => "pack name cannot be empty"
570 test "it requires privileged role :emoji_manage_emoji", %{admin_conn: admin_conn} do
571 clear_config([:instance, :admin_privileges], [])
574 |> post("/api/pleroma/emoji/pack?name= ")
575 |> json_response(:forbidden)
578 |> delete("/api/pleroma/emoji/pack?name= ")
579 |> json_response(:forbidden)
583 test "deleting nonexisting pack", %{admin_conn: admin_conn} do
585 |> delete("/api/pleroma/emoji/pack?name=non_existing")
586 |> json_response_and_validate_schema(:not_found) == %{
587 "error" => "Pack non_existing does not exist"
591 test "deleting with empty name", %{admin_conn: admin_conn} do
593 |> delete("/api/pleroma/emoji/pack?name= ")
594 |> json_response_and_validate_schema(:bad_request) == %{
595 "error" => "pack name cannot be empty"
599 test "filesystem import", %{admin_conn: admin_conn, conn: conn} do
601 File.rm!("#{@emoji_path}/test_pack_for_import/emoji.txt")
602 File.rm!("#{@emoji_path}/test_pack_for_import/pack.json")
605 resp = conn |> get("/api/pleroma/emoji/packs") |> json_response_and_validate_schema(200)
607 refute Map.has_key?(resp["packs"], "test_pack_for_import")
610 |> get("/api/pleroma/emoji/packs/import")
611 |> json_response_and_validate_schema(200) == ["test_pack_for_import"]
613 resp = conn |> get("/api/pleroma/emoji/packs") |> json_response_and_validate_schema(200)
614 assert resp["packs"]["test_pack_for_import"]["files"] == %{"blank" => "blank.png"}
616 File.rm!("#{@emoji_path}/test_pack_for_import/pack.json")
617 refute File.exists?("#{@emoji_path}/test_pack_for_import/pack.json")
619 emoji_txt_content = """
620 blank, blank.png, Fun
622 foo, /emoji/test_pack_for_import/blank.png
626 File.write!("#{@emoji_path}/test_pack_for_import/emoji.txt", emoji_txt_content)
629 |> get("/api/pleroma/emoji/packs/import")
630 |> json_response_and_validate_schema(200) == ["test_pack_for_import"]
632 resp = conn |> get("/api/pleroma/emoji/packs") |> json_response_and_validate_schema(200)
634 assert resp["packs"]["test_pack_for_import"]["files"] == %{
635 "blank" => "blank.png",
636 "blank2" => "blank.png",
640 clear_config([:instance, :admin_privileges], [])
643 |> get("/api/pleroma/emoji/packs/import")
644 |> json_response(:forbidden)
647 describe "GET /api/pleroma/emoji/pack?name=:name" do
648 test "shows pack.json", %{conn: conn} do
653 "can-download" => true,
654 "description" => "Test description",
655 "download-sha256" => _,
656 "homepage" => "https://pleroma.social",
657 "license" => "Test license",
658 "share-files" => true
662 |> get("/api/pleroma/emoji/pack?name=test_pack")
663 |> json_response_and_validate_schema(200)
665 assert files == %{"blank" => "blank.png", "blank2" => "blank2.png"}
672 |> get("/api/pleroma/emoji/pack?name=test_pack&page_size=1")
673 |> json_response_and_validate_schema(200)
675 assert files |> Map.keys() |> length() == 1
682 |> get("/api/pleroma/emoji/pack?name=test_pack&page_size=1&page=2")
683 |> json_response_and_validate_schema(200)
685 assert files |> Map.keys() |> length() == 1
688 test "for pack name with special chars", %{conn: conn} do
693 "can-download" => true,
694 "description" => "Test description",
695 "download-sha256" => _,
696 "homepage" => "https://pleroma.social",
697 "license" => "Test license",
698 "share-files" => true
702 |> get("/api/pleroma/emoji/pack?name=blobs.gg")
703 |> json_response_and_validate_schema(200)
706 test "non existing pack", %{conn: conn} do
708 |> get("/api/pleroma/emoji/pack?name=non_existing")
709 |> json_response_and_validate_schema(:not_found) == %{
710 "error" => "Pack non_existing does not exist"
714 test "error name", %{conn: conn} do
716 |> get("/api/pleroma/emoji/pack?name= ")
717 |> json_response_and_validate_schema(:bad_request) == %{
718 "error" => "pack name cannot be empty"