# Pleroma: A lightweight social networking server # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do use Pleroma.Web.ConnCase import Tesla.Mock import Pleroma.Factory @emoji_dir_path Path.join( Pleroma.Config.get!([:instance, :static_dir]), "emoji" ) setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], false) test "shared & non-shared pack information in list_packs is ok" do conn = build_conn() resp = conn |> get(emoji_api_path(conn, :list_packs)) |> json_response(200) assert Map.has_key?(resp, "test_pack") pack = resp["test_pack"] assert Map.has_key?(pack["pack"], "download-sha256") assert pack["pack"]["can-download"] assert pack["files"] == %{"blank" => "blank.png"} # Non-shared pack assert Map.has_key?(resp, "test_pack_nonshared") pack = resp["test_pack_nonshared"] refute pack["pack"]["shared"] refute pack["pack"]["can-download"] end test "listing remote packs" do admin = insert(:user, is_admin: true) %{conn: conn} = oauth_access(["admin:write"], user: admin) resp = build_conn() |> get(emoji_api_path(conn, :list_packs)) |> json_response(200) mock(fn %{method: :get, url: "https://example.com/.well-known/nodeinfo"} -> json(%{links: [%{href: "https://example.com/nodeinfo/2.1.json"}]}) %{method: :get, url: "https://example.com/nodeinfo/2.1.json"} -> json(%{metadata: %{features: ["shareable_emoji_packs"]}}) %{method: :get, url: "https://example.com/api/pleroma/emoji/packs"} -> json(resp) end) assert conn |> post(emoji_api_path(conn, :list_from), %{instance_address: "https://example.com"}) |> json_response(200) == resp end test "downloading a shared pack from download_shared" do conn = build_conn() resp = conn |> get(emoji_api_path(conn, :download_shared, "test_pack")) |> response(200) {:ok, arch} = :zip.unzip(resp, [:memory]) assert Enum.find(arch, fn {n, _} -> n == 'pack.json' end) assert Enum.find(arch, fn {n, _} -> n == 'blank.png' end) end test "downloading shared & unshared packs from another instance via download_from, deleting them" do on_exit(fn -> File.rm_rf!("#{@emoji_dir_path}/test_pack2") File.rm_rf!("#{@emoji_dir_path}/test_pack_nonshared2") end) mock(fn %{method: :get, url: "https://old-instance/.well-known/nodeinfo"} -> json(%{links: [%{href: "https://old-instance/nodeinfo/2.1.json"}]}) %{method: :get, url: "https://old-instance/nodeinfo/2.1.json"} -> json(%{metadata: %{features: []}}) %{method: :get, url: "https://example.com/.well-known/nodeinfo"} -> json(%{links: [%{href: "https://example.com/nodeinfo/2.1.json"}]}) %{method: :get, url: "https://example.com/nodeinfo/2.1.json"} -> json(%{metadata: %{features: ["shareable_emoji_packs"]}}) %{ method: :get, url: "https://example.com/api/pleroma/emoji/packs/list" } -> conn = build_conn() conn |> get(emoji_api_path(conn, :list_packs)) |> json_response(200) |> json() %{ method: :get, url: "https://example.com/api/pleroma/emoji/packs/download_shared/test_pack" } -> conn = build_conn() conn |> get(emoji_api_path(conn, :download_shared, "test_pack")) |> response(200) |> text() %{ method: :get, url: "https://nonshared-pack" } -> text(File.read!("#{@emoji_dir_path}/test_pack_nonshared/nonshared.zip")) end) admin = insert(:user, is_admin: true) conn = build_conn() |> assign(:user, admin) |> assign(:token, insert(:oauth_admin_token, user: admin, scopes: ["admin:write"])) assert (conn |> put_req_header("content-type", "application/json") |> post( emoji_api_path( conn, :download_from ), %{ instance_address: "https://old-instance", pack_name: "test_pack", as: "test_pack2" } |> Jason.encode!() ) |> json_response(500))["error"] =~ "does not support" assert conn |> put_req_header("content-type", "application/json") |> post( emoji_api_path( conn, :download_from ), %{ instance_address: "https://example.com", pack_name: "test_pack", as: "test_pack2" } |> Jason.encode!() ) |> json_response(200) == "ok" assert File.exists?("#{@emoji_dir_path}/test_pack2/pack.json") assert File.exists?("#{@emoji_dir_path}/test_pack2/blank.png") assert conn |> delete(emoji_api_path(conn, :delete, "test_pack2")) |> json_response(200) == "ok" refute File.exists?("#{@emoji_dir_path}/test_pack2") # non-shared, downloaded from the fallback URL assert conn |> put_req_header("content-type", "application/json") |> post( emoji_api_path( conn, :download_from ), %{ instance_address: "https://example.com", pack_name: "test_pack_nonshared", as: "test_pack_nonshared2" } |> Jason.encode!() ) |> json_response(200) == "ok" assert File.exists?("#{@emoji_dir_path}/test_pack_nonshared2/pack.json") assert File.exists?("#{@emoji_dir_path}/test_pack_nonshared2/blank.png") assert conn |> delete(emoji_api_path(conn, :delete, "test_pack_nonshared2")) |> json_response(200) == "ok" refute File.exists?("#{@emoji_dir_path}/test_pack_nonshared2") end describe "updating pack metadata" do setup do pack_file = "#{@emoji_dir_path}/test_pack/pack.json" original_content = File.read!(pack_file) on_exit(fn -> File.write!(pack_file, original_content) end) admin = insert(:user, is_admin: true) %{conn: conn} = oauth_access(["admin:write"], user: admin) {:ok, admin: admin, conn: conn, pack_file: pack_file, new_data: %{ "license" => "Test license changed", "homepage" => "https://pleroma.social", "description" => "Test description", "share-files" => false }} end test "for a pack without a fallback source", ctx do conn = ctx[:conn] assert conn |> post( emoji_api_path(conn, :update_metadata, "test_pack"), %{ "new_data" => ctx[:new_data] } ) |> json_response(200) == ctx[:new_data] assert Jason.decode!(File.read!(ctx[:pack_file]))["pack"] == ctx[:new_data] end test "for a pack with a fallback source", ctx do mock(fn %{ method: :get, url: "https://nonshared-pack" } -> text(File.read!("#{@emoji_dir_path}/test_pack_nonshared/nonshared.zip")) end) new_data = Map.put(ctx[:new_data], "fallback-src", "https://nonshared-pack") new_data_with_sha = Map.put( new_data, "fallback-src-sha256", "74409E2674DAA06C072729C6C8426C4CB3B7E0B85ED77792DB7A436E11D76DAF" ) conn = ctx[:conn] assert conn |> post( emoji_api_path(conn, :update_metadata, "test_pack"), %{ "new_data" => new_data } ) |> json_response(200) == new_data_with_sha assert Jason.decode!(File.read!(ctx[:pack_file]))["pack"] == new_data_with_sha end test "when the fallback source doesn't have all the files", ctx do mock(fn %{ method: :get, url: "https://nonshared-pack" } -> {:ok, {'empty.zip', empty_arch}} = :zip.zip('empty.zip', [], [:memory]) text(empty_arch) end) new_data = Map.put(ctx[:new_data], "fallback-src", "https://nonshared-pack") conn = ctx[:conn] assert (conn |> post( emoji_api_path(conn, :update_metadata, "test_pack"), %{ "new_data" => new_data } ) |> json_response(:bad_request))["error"] =~ "does not have all" end end test "updating pack files" do pack_file = "#{@emoji_dir_path}/test_pack/pack.json" original_content = File.read!(pack_file) on_exit(fn -> File.write!(pack_file, original_content) File.rm_rf!("#{@emoji_dir_path}/test_pack/blank_url.png") File.rm_rf!("#{@emoji_dir_path}/test_pack/dir") File.rm_rf!("#{@emoji_dir_path}/test_pack/dir_2") end) admin = insert(:user, is_admin: true) %{conn: conn} = oauth_access(["admin:write"], user: admin) same_name = %{ "action" => "add", "shortcode" => "blank", "filename" => "dir/blank.png", "file" => %Plug.Upload{ filename: "blank.png", path: "#{@emoji_dir_path}/test_pack/blank.png" } } different_name = %{same_name | "shortcode" => "blank_2"} assert (conn |> post(emoji_api_path(conn, :update_file, "test_pack"), same_name) |> json_response(:conflict))["error"] =~ "already exists" assert conn |> post(emoji_api_path(conn, :update_file, "test_pack"), different_name) |> json_response(200) == %{"blank" => "blank.png", "blank_2" => "dir/blank.png"} assert File.exists?("#{@emoji_dir_path}/test_pack/dir/blank.png") assert conn |> post(emoji_api_path(conn, :update_file, "test_pack"), %{ "action" => "update", "shortcode" => "blank_2", "new_shortcode" => "blank_3", "new_filename" => "dir_2/blank_3.png" }) |> json_response(200) == %{"blank" => "blank.png", "blank_3" => "dir_2/blank_3.png"} refute File.exists?("#{@emoji_dir_path}/test_pack/dir/") assert File.exists?("#{@emoji_dir_path}/test_pack/dir_2/blank_3.png") assert conn |> post(emoji_api_path(conn, :update_file, "test_pack"), %{ "action" => "remove", "shortcode" => "blank_3" }) |> json_response(200) == %{"blank" => "blank.png"} refute File.exists?("#{@emoji_dir_path}/test_pack/dir_2/") mock(fn %{ method: :get, url: "https://test-blank/blank_url.png" } -> text(File.read!("#{@emoji_dir_path}/test_pack/blank.png")) end) # The name should be inferred from the URL ending from_url = %{ "action" => "add", "shortcode" => "blank_url", "file" => "https://test-blank/blank_url.png" } assert conn |> post(emoji_api_path(conn, :update_file, "test_pack"), from_url) |> json_response(200) == %{ "blank" => "blank.png", "blank_url" => "blank_url.png" } assert File.exists?("#{@emoji_dir_path}/test_pack/blank_url.png") assert conn |> post(emoji_api_path(conn, :update_file, "test_pack"), %{ "action" => "remove", "shortcode" => "blank_url" }) |> json_response(200) == %{"blank" => "blank.png"} refute File.exists?("#{@emoji_dir_path}/test_pack/blank_url.png") end test "creating and deleting a pack" do on_exit(fn -> File.rm_rf!("#{@emoji_dir_path}/test_created") end) admin = insert(:user, is_admin: true) %{conn: conn} = oauth_access(["admin:write"], user: admin) assert conn |> put_req_header("content-type", "application/json") |> put( emoji_api_path( conn, :create, "test_created" ) ) |> json_response(200) == "ok" assert File.exists?("#{@emoji_dir_path}/test_created/pack.json") assert Jason.decode!(File.read!("#{@emoji_dir_path}/test_created/pack.json")) == %{ "pack" => %{}, "files" => %{} } assert conn |> delete(emoji_api_path(conn, :delete, "test_created")) |> json_response(200) == "ok" refute File.exists?("#{@emoji_dir_path}/test_created/pack.json") end test "filesystem import" do on_exit(fn -> File.rm!("#{@emoji_dir_path}/test_pack_for_import/emoji.txt") File.rm!("#{@emoji_dir_path}/test_pack_for_import/pack.json") end) conn = build_conn() resp = conn |> get(emoji_api_path(conn, :list_packs)) |> json_response(200) refute Map.has_key?(resp, "test_pack_for_import") admin = insert(:user, is_admin: true) %{conn: conn} = oauth_access(["admin:write"], user: admin) assert conn |> post(emoji_api_path(conn, :import_from_fs)) |> json_response(200) == ["test_pack_for_import"] resp = conn |> get(emoji_api_path(conn, :list_packs)) |> json_response(200) assert resp["test_pack_for_import"]["files"] == %{"blank" => "blank.png"} File.rm!("#{@emoji_dir_path}/test_pack_for_import/pack.json") refute File.exists?("#{@emoji_dir_path}/test_pack_for_import/pack.json") emoji_txt_content = "blank, blank.png, Fun\n\nblank2, blank.png" File.write!("#{@emoji_dir_path}/test_pack_for_import/emoji.txt", emoji_txt_content) assert conn |> post(emoji_api_path(conn, :import_from_fs)) |> json_response(200) == ["test_pack_for_import"] resp = build_conn() |> get(emoji_api_path(conn, :list_packs)) |> json_response(200) assert resp["test_pack_for_import"]["files"] == %{ "blank" => "blank.png", "blank2" => "blank.png" } end end