diff options
Diffstat (limited to 'test/web/pleroma_api')
6 files changed, 1143 insertions, 523 deletions
| diff --git a/test/web/pleroma_api/controllers/account_controller_test.exs b/test/web/pleroma_api/controllers/account_controller_test.exs index 3b4665afd..103997c31 100644 --- a/test/web/pleroma_api/controllers/account_controller_test.exs +++ b/test/web/pleroma_api/controllers/account_controller_test.exs @@ -1,12 +1,11 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do    use Pleroma.Web.ConnCase    alias Pleroma.Config -  alias Pleroma.Repo    alias Pleroma.Tests.ObanHelpers    alias Pleroma.User    alias Pleroma.Web.CommonAPI @@ -20,23 +19,40 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do      setup do        {:ok, user} =          insert(:user) -        |> User.change_info(&User.Info.confirmation_changeset(&1, need_confirmation: true)) -        |> Repo.update() +        |> User.confirmation_changeset(need_confirmation: true) +        |> User.update_and_set_cache() -      assert user.info.confirmation_pending +      assert user.confirmation_pending        [user: user]      end -    clear_config([:instance, :account_activation_required]) do -      Config.put([:instance, :account_activation_required], true) -    end +    setup do: clear_config([:instance, :account_activation_required], true)      test "resend account confirmation email", %{conn: conn, user: user} do        conn -      |> assign(:user, user) +      |> put_req_header("content-type", "application/json")        |> post("/api/v1/pleroma/accounts/confirmation_resend?email=#{user.email}") -      |> json_response(:no_content) +      |> json_response_and_validate_schema(:no_content) + +      ObanHelpers.perform_all() + +      email = Pleroma.Emails.UserEmail.account_confirmation_email(user) +      notify_email = Config.get([:instance, :notify_email]) +      instance_name = Config.get([:instance, :name]) + +      assert_email_sent( +        from: {instance_name, notify_email}, +        to: {user.name, user.email}, +        html_body: email.html_body +      ) +    end + +    test "resend account confirmation email (with nickname)", %{conn: conn, user: user} do +      conn +      |> put_req_header("content-type", "application/json") +      |> post("/api/v1/pleroma/accounts/confirmation_resend?nickname=#{user.nickname}") +      |> json_response_and_validate_schema(:no_content)        ObanHelpers.perform_all() @@ -53,13 +69,14 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do    end    describe "PATCH /api/v1/pleroma/accounts/update_avatar" do -    test "user avatar can be set", %{conn: conn} do -      user = insert(:user) +    setup do: oauth_access(["write:accounts"]) + +    test "user avatar can be set", %{user: user, conn: conn} do        avatar_image = File.read!("test/fixtures/avatar_data_uri")        conn =          conn -        |> assign(:user, user) +        |> put_req_header("content-type", "multipart/form-data")          |> patch("/api/v1/pleroma/accounts/update_avatar", %{img: avatar_image})        user = refresh_record(user) @@ -76,102 +93,96 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do                 ]               } = user.avatar -      assert %{"url" => _} = json_response(conn, 200) +      assert %{"url" => _} = json_response_and_validate_schema(conn, 200)      end -    test "user avatar can be reset", %{conn: conn} do -      user = insert(:user) - +    test "user avatar can be reset", %{user: user, conn: conn} do        conn =          conn -        |> assign(:user, user) +        |> put_req_header("content-type", "multipart/form-data")          |> patch("/api/v1/pleroma/accounts/update_avatar", %{img: ""})        user = User.get_cached_by_id(user.id)        assert user.avatar == nil -      assert %{"url" => nil} = json_response(conn, 200) +      assert %{"url" => nil} = json_response_and_validate_schema(conn, 200)      end    end    describe "PATCH /api/v1/pleroma/accounts/update_banner" do -    test "can set profile banner", %{conn: conn} do -      user = insert(:user) +    setup do: oauth_access(["write:accounts"]) +    test "can set profile banner", %{user: user, conn: conn} do        conn =          conn -        |> assign(:user, user) +        |> put_req_header("content-type", "multipart/form-data")          |> patch("/api/v1/pleroma/accounts/update_banner", %{"banner" => @image})        user = refresh_record(user) -      assert user.info.banner["type"] == "Image" +      assert user.banner["type"] == "Image" -      assert %{"url" => _} = json_response(conn, 200) +      assert %{"url" => _} = json_response_and_validate_schema(conn, 200)      end -    test "can reset profile banner", %{conn: conn} do -      user = insert(:user) - +    test "can reset profile banner", %{user: user, conn: conn} do        conn =          conn -        |> assign(:user, user) +        |> put_req_header("content-type", "multipart/form-data")          |> patch("/api/v1/pleroma/accounts/update_banner", %{"banner" => ""})        user = refresh_record(user) -      assert user.info.banner == %{} +      assert user.banner == %{} -      assert %{"url" => nil} = json_response(conn, 200) +      assert %{"url" => nil} = json_response_and_validate_schema(conn, 200)      end    end    describe "PATCH /api/v1/pleroma/accounts/update_background" do -    test "background image can be set", %{conn: conn} do -      user = insert(:user) +    setup do: oauth_access(["write:accounts"]) +    test "background image can be set", %{user: user, conn: conn} do        conn =          conn -        |> assign(:user, user) +        |> put_req_header("content-type", "multipart/form-data")          |> patch("/api/v1/pleroma/accounts/update_background", %{"img" => @image})        user = refresh_record(user) -      assert user.info.background["type"] == "Image" -      assert %{"url" => _} = json_response(conn, 200) +      assert user.background["type"] == "Image" +      # assert %{"url" => _} = json_response(conn, 200) +      assert %{"url" => _} = json_response_and_validate_schema(conn, 200)      end -    test "background image can be reset", %{conn: conn} do -      user = insert(:user) - +    test "background image can be reset", %{user: user, conn: conn} do        conn =          conn -        |> assign(:user, user) +        |> put_req_header("content-type", "multipart/form-data")          |> patch("/api/v1/pleroma/accounts/update_background", %{"img" => ""})        user = refresh_record(user) -      assert user.info.background == %{} -      assert %{"url" => nil} = json_response(conn, 200) +      assert user.background == %{} +      assert %{"url" => nil} = json_response_and_validate_schema(conn, 200)      end    end    describe "getting favorites timeline of specified user" do      setup do -      [current_user, user] = insert_pair(:user, %{info: %{hide_favorites: false}}) -      [current_user: current_user, user: user] +      [current_user, user] = insert_pair(:user, hide_favorites: false) +      %{user: current_user, conn: conn} = oauth_access(["read:favourites"], user: current_user) +      [current_user: current_user, user: user, conn: conn]      end      test "returns list of statuses favorited by specified user", %{        conn: conn, -      current_user: current_user,        user: user      } do        [activity | _] = insert_pair(:note_activity) -      CommonAPI.favorite(activity.id, user) +      CommonAPI.favorite(user, activity.id)        response =          conn -        |> assign(:user, current_user)          |> get("/api/v1/pleroma/accounts/#{user.id}/favourites") -        |> json_response(:ok) +        |> json_response_and_validate_schema(:ok)        [like] = response @@ -179,83 +190,81 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do        assert like["id"] == activity.id      end -    test "returns favorites for specified user_id when user is not logged in", %{ -      conn: conn, +    test "returns favorites for specified user_id when requester is not logged in", %{        user: user      } do        activity = insert(:note_activity) -      CommonAPI.favorite(activity.id, user) +      CommonAPI.favorite(user, activity.id)        response = -        conn +        build_conn()          |> get("/api/v1/pleroma/accounts/#{user.id}/favourites") -        |> json_response(:ok) +        |> json_response_and_validate_schema(200)        assert length(response) == 1      end      test "returns favorited DM only when user is logged in and he is one of recipients", %{ -      conn: conn,        current_user: current_user,        user: user      } do        {:ok, direct} =          CommonAPI.post(current_user, %{ -          "status" => "Hi @#{user.nickname}!", -          "visibility" => "direct" +          status: "Hi @#{user.nickname}!", +          visibility: "direct"          }) -      CommonAPI.favorite(direct.id, user) +      CommonAPI.favorite(user, direct.id) -      response = -        conn -        |> assign(:user, current_user) -        |> get("/api/v1/pleroma/accounts/#{user.id}/favourites") -        |> json_response(:ok) +      for u <- [user, current_user] do +        response = +          build_conn() +          |> assign(:user, u) +          |> assign(:token, insert(:oauth_token, user: u, scopes: ["read:favourites"])) +          |> get("/api/v1/pleroma/accounts/#{user.id}/favourites") +          |> json_response_and_validate_schema(:ok) -      assert length(response) == 1 +        assert length(response) == 1 +      end -      anonymous_response = -        conn +      response = +        build_conn()          |> get("/api/v1/pleroma/accounts/#{user.id}/favourites") -        |> json_response(:ok) +        |> json_response_and_validate_schema(200) -      assert Enum.empty?(anonymous_response) +      assert length(response) == 0      end      test "does not return others' favorited DM when user is not one of recipients", %{        conn: conn, -      current_user: current_user,        user: user      } do        user_two = insert(:user)        {:ok, direct} =          CommonAPI.post(user_two, %{ -          "status" => "Hi @#{user.nickname}!", -          "visibility" => "direct" +          status: "Hi @#{user.nickname}!", +          visibility: "direct"          }) -      CommonAPI.favorite(direct.id, user) +      CommonAPI.favorite(user, direct.id)        response =          conn -        |> assign(:user, current_user)          |> get("/api/v1/pleroma/accounts/#{user.id}/favourites") -        |> json_response(:ok) +        |> json_response_and_validate_schema(:ok)        assert Enum.empty?(response)      end      test "paginates favorites using since_id and max_id", %{        conn: conn, -      current_user: current_user,        user: user      } do        activities = insert_list(10, :note_activity)        Enum.each(activities, fn activity -> -        CommonAPI.favorite(activity.id, user) +        CommonAPI.favorite(user, activity.id)        end)        third_activity = Enum.at(activities, 2) @@ -263,12 +272,12 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do        response =          conn -        |> assign(:user, current_user) -        |> get("/api/v1/pleroma/accounts/#{user.id}/favourites", %{ -          since_id: third_activity.id, -          max_id: seventh_activity.id -        }) -        |> json_response(:ok) +        |> get( +          "/api/v1/pleroma/accounts/#{user.id}/favourites?since_id=#{third_activity.id}&max_id=#{ +            seventh_activity.id +          }" +        ) +        |> json_response_and_validate_schema(:ok)        assert length(response) == 3        refute third_activity in response @@ -277,34 +286,30 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do      test "limits favorites using limit parameter", %{        conn: conn, -      current_user: current_user,        user: user      } do        7        |> insert_list(:note_activity)        |> Enum.each(fn activity -> -        CommonAPI.favorite(activity.id, user) +        CommonAPI.favorite(user, activity.id)        end)        response =          conn -        |> assign(:user, current_user) -        |> get("/api/v1/pleroma/accounts/#{user.id}/favourites", %{limit: "3"}) -        |> json_response(:ok) +        |> get("/api/v1/pleroma/accounts/#{user.id}/favourites?limit=3") +        |> json_response_and_validate_schema(:ok)        assert length(response) == 3      end      test "returns empty response when user does not have any favorited statuses", %{        conn: conn, -      current_user: current_user,        user: user      } do        response =          conn -        |> assign(:user, current_user)          |> get("/api/v1/pleroma/accounts/#{user.id}/favourites") -        |> json_response(:ok) +        |> json_response_and_validate_schema(:ok)        assert Enum.empty?(response)      end @@ -312,84 +317,67 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do      test "returns 404 error when specified user is not exist", %{conn: conn} do        conn = get(conn, "/api/v1/pleroma/accounts/test/favourites") -      assert json_response(conn, 404) == %{"error" => "Record not found"} +      assert json_response_and_validate_schema(conn, 404) == %{"error" => "Record not found"}      end -    test "returns 403 error when user has hidden own favorites", %{ -      conn: conn, -      current_user: current_user -    } do -      user = insert(:user, %{info: %{hide_favorites: true}}) +    test "returns 403 error when user has hidden own favorites", %{conn: conn} do +      user = insert(:user, hide_favorites: true)        activity = insert(:note_activity) -      CommonAPI.favorite(activity.id, user) +      CommonAPI.favorite(user, activity.id) -      conn = -        conn -        |> assign(:user, current_user) -        |> get("/api/v1/pleroma/accounts/#{user.id}/favourites") +      conn = get(conn, "/api/v1/pleroma/accounts/#{user.id}/favourites") -      assert json_response(conn, 403) == %{"error" => "Can't get favorites"} +      assert json_response_and_validate_schema(conn, 403) == %{"error" => "Can't get favorites"}      end -    test "hides favorites for new users by default", %{conn: conn, current_user: current_user} do +    test "hides favorites for new users by default", %{conn: conn} do        user = insert(:user)        activity = insert(:note_activity) -      CommonAPI.favorite(activity.id, user) +      CommonAPI.favorite(user, activity.id) -      conn = -        conn -        |> assign(:user, current_user) -        |> get("/api/v1/pleroma/accounts/#{user.id}/favourites") +      assert user.hide_favorites +      conn = get(conn, "/api/v1/pleroma/accounts/#{user.id}/favourites") -      assert user.info.hide_favorites -      assert json_response(conn, 403) == %{"error" => "Can't get favorites"} +      assert json_response_and_validate_schema(conn, 403) == %{"error" => "Can't get favorites"}      end    end    describe "subscribing / unsubscribing" do -    test "subscribing / unsubscribing to a user", %{conn: conn} do -      user = insert(:user) +    test "subscribing / unsubscribing to a user" do +      %{user: user, conn: conn} = oauth_access(["follow"])        subscription_target = insert(:user) -      conn = +      ret_conn =          conn          |> assign(:user, user)          |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/subscribe") -      assert %{"id" => _id, "subscribing" => true} = json_response(conn, 200) +      assert %{"id" => _id, "subscribing" => true} = +               json_response_and_validate_schema(ret_conn, 200) -      conn = -        build_conn() -        |> assign(:user, user) -        |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/unsubscribe") +      conn = post(conn, "/api/v1/pleroma/accounts/#{subscription_target.id}/unsubscribe") -      assert %{"id" => _id, "subscribing" => false} = json_response(conn, 200) +      assert %{"id" => _id, "subscribing" => false} = json_response_and_validate_schema(conn, 200)      end    end    describe "subscribing" do -    test "returns 404 when subscription_target not found", %{conn: conn} do -      user = insert(:user) +    test "returns 404 when subscription_target not found" do +      %{conn: conn} = oauth_access(["write:follows"]) -      conn = -        conn -        |> assign(:user, user) -        |> post("/api/v1/pleroma/accounts/target_id/subscribe") +      conn = post(conn, "/api/v1/pleroma/accounts/target_id/subscribe") -      assert %{"error" => "Record not found"} = json_response(conn, 404) +      assert %{"error" => "Record not found"} = json_response_and_validate_schema(conn, 404)      end    end    describe "unsubscribing" do -    test "returns 404 when subscription_target not found", %{conn: conn} do -      user = insert(:user) +    test "returns 404 when subscription_target not found" do +      %{conn: conn} = oauth_access(["follow"]) -      conn = -        conn -        |> assign(:user, user) -        |> post("/api/v1/pleroma/accounts/target_id/unsubscribe") +      conn = post(conn, "/api/v1/pleroma/accounts/target_id/unsubscribe") -      assert %{"error" => "Record not found"} = json_response(conn, 404) +      assert %{"error" => "Record not found"} = json_response_and_validate_schema(conn, 404)      end    end  end diff --git a/test/web/pleroma_api/controllers/emoji_api_controller_test.exs b/test/web/pleroma_api/controllers/emoji_api_controller_test.exs index 5f74460e8..d343256fe 100644 --- a/test/web/pleroma_api/controllers/emoji_api_controller_test.exs +++ b/test/web/pleroma_api/controllers/emoji_api_controller_test.exs @@ -1,204 +1,298 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# 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" -                  ) - -  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) +  @emoji_path Path.join( +                Pleroma.Config.get!([:instance, :static_dir]), +                "emoji" +              ) +  setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], false) -    assert Map.has_key?(resp, "test_pack") +  setup do +    admin = insert(:user, is_admin: true) +    token = insert(:oauth_admin_token, user: admin) -    pack = resp["test_pack"] +    admin_conn = +      build_conn() +      |> assign(:user, admin) +      |> assign(:token, token) -    assert Map.has_key?(pack["pack"], "download-sha256") -    assert pack["pack"]["can-download"] +    Pleroma.Emoji.reload() +    {:ok, %{admin_conn: admin_conn}} +  end -    assert pack["files"] == %{"blank" => "blank.png"} +  test "GET /api/pleroma/emoji/packs", %{conn: conn} do +    resp = conn |> get("/api/pleroma/emoji/packs") |> json_response(200) -    # Non-shared pack +    shared = resp["test_pack"] +    assert shared["files"] == %{"blank" => "blank.png"} +    assert Map.has_key?(shared["pack"], "download-sha256") +    assert shared["pack"]["can-download"] +    assert shared["pack"]["share-files"] -    assert Map.has_key?(resp, "test_pack_nonshared") +    non_shared = resp["test_pack_nonshared"] +    assert non_shared["pack"]["share-files"] == false +    assert non_shared["pack"]["can-download"] == false +  end -    pack = resp["test_pack_nonshared"] +  describe "GET /api/pleroma/emoji/packs/remote" do +    test "shareable instance", %{admin_conn: admin_conn, conn: conn} do +      resp = +        conn +        |> get("/api/pleroma/emoji/packs") +        |> json_response(200) -    refute pack["pack"]["shared"] -    refute pack["pack"]["can-download"] -  end +      mock(fn +        %{method: :get, url: "https://example.com/.well-known/nodeinfo"} -> +          json(%{links: [%{href: "https://example.com/nodeinfo/2.1.json"}]}) -  test "listing remote packs" do -    admin = insert(:user, info: %{is_admin: true}) -    conn = build_conn() |> assign(:user, admin) +        %{method: :get, url: "https://example.com/nodeinfo/2.1.json"} -> +          json(%{metadata: %{features: ["shareable_emoji_packs"]}}) -    resp = conn |> get(emoji_api_path(conn, :list_packs)) |> json_response(200) +        %{method: :get, url: "https://example.com/api/pleroma/emoji/packs"} -> +          json(resp) +      end) -    mock(fn -      %{method: :get, url: "https://example.com/.well-known/nodeinfo"} -> -        json(%{links: [%{href: "https://example.com/nodeinfo/2.1.json"}]}) +      assert admin_conn +             |> get("/api/pleroma/emoji/packs/remote", %{ +               url: "https://example.com" +             }) +             |> json_response(200) == resp +    end -      %{method: :get, url: "https://example.com/nodeinfo/2.1.json"} -> -        json(%{metadata: %{features: ["shareable_emoji_packs"]}}) +    test "non shareable instance", %{admin_conn: admin_conn} do +      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/api/pleroma/emoji/packs"} -> -        json(resp) -    end) +        %{method: :get, url: "https://example.com/nodeinfo/2.1.json"} -> +          json(%{metadata: %{features: []}}) +      end) -    assert conn -           |> post(emoji_api_path(conn, :list_from), %{instance_address: "https://example.com"}) -           |> json_response(200) == resp +      assert admin_conn +             |> get("/api/pleroma/emoji/packs/remote", %{url: "https://example.com"}) +             |> json_response(500) == %{ +               "error" => "The requested instance does not support sharing emoji packs" +             } +    end    end -  test "downloading a shared pack from download_shared" do -    conn = build_conn() +  describe "GET /api/pleroma/emoji/packs/:name/archive" do +    test "download shared pack", %{conn: conn} do +      resp = +        conn +        |> get("/api/pleroma/emoji/packs/test_pack/archive") +        |> response(200) + +      {:ok, arch} = :zip.unzip(resp, [:memory]) -    resp = -      conn -      |> get(emoji_api_path(conn, :download_shared, "test_pack")) -      |> response(200) +      assert Enum.find(arch, fn {n, _} -> n == 'pack.json' end) +      assert Enum.find(arch, fn {n, _} -> n == 'blank.png' end) +    end -    {:ok, arch} = :zip.unzip(resp, [:memory]) +    test "non existing pack", %{conn: conn} do +      assert conn +             |> get("/api/pleroma/emoji/packs/test_pack_for_import/archive") +             |> json_response(:not_found) == %{ +               "error" => "Pack test_pack_for_import does not exist" +             } +    end -    assert Enum.find(arch, fn {n, _} -> n == 'pack.json' end) -    assert Enum.find(arch, fn {n, _} -> n == 'blank.png' end) +    test "non downloadable pack", %{conn: conn} do +      assert conn +             |> get("/api/pleroma/emoji/packs/test_pack_nonshared/archive") +             |> json_response(:forbidden) == %{ +               "error" => +                 "Pack test_pack_nonshared cannot be downloaded from this instance, either pack sharing was disabled for this pack or some files are missing" +             } +    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) +  describe "POST /api/pleroma/emoji/packs/download" do +    test "shared pack from remote and non shared from fallback-src", %{ +      admin_conn: admin_conn, +      conn: conn +    } do +      mock(fn +        %{method: :get, url: "https://example.com/.well-known/nodeinfo"} -> +          json(%{links: [%{href: "https://example.com/nodeinfo/2.1.json"}]}) -    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://example.com/nodeinfo/2.1.json"} -> +          json(%{metadata: %{features: ["shareable_emoji_packs"]}}) -      %{method: :get, url: "https://old-instance/nodeinfo/2.1.json"} -> -        json(%{metadata: %{features: []}}) +        %{ +          method: :get, +          url: "https://example.com/api/pleroma/emoji/packs/test_pack" +        } -> +          conn +          |> get("/api/pleroma/emoji/packs/test_pack") +          |> json_response(200) +          |> json() -      %{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/api/pleroma/emoji/packs/test_pack/archive" +        } -> +          conn +          |> get("/api/pleroma/emoji/packs/test_pack/archive") +          |> response(200) +          |> text() -      %{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/test_pack_nonshared" +        } -> +          conn +          |> get("/api/pleroma/emoji/packs/test_pack_nonshared") +          |> json_response(200) +          |> json() -      %{ -        method: :get, -        url: "https://example.com/api/pleroma/emoji/packs/list" -      } -> -        conn = build_conn() +        %{ +          method: :get, +          url: "https://nonshared-pack" +        } -> +          text(File.read!("#{@emoji_path}/test_pack_nonshared/nonshared.zip")) +      end) -        conn -        |> get(emoji_api_path(conn, :list_packs)) -        |> json_response(200) -        |> json() +      assert admin_conn +             |> post("/api/pleroma/emoji/packs/download", %{ +               url: "https://example.com", +               name: "test_pack", +               as: "test_pack2" +             }) +             |> json_response(200) == "ok" -      %{ -        method: :get, -        url: "https://example.com/api/pleroma/emoji/packs/download_shared/test_pack" -      } -> -        conn = build_conn() +      assert File.exists?("#{@emoji_path}/test_pack2/pack.json") +      assert File.exists?("#{@emoji_path}/test_pack2/blank.png") -        conn -        |> get(emoji_api_path(conn, :download_shared, "test_pack")) -        |> response(200) -        |> text() +      assert admin_conn +             |> delete("/api/pleroma/emoji/packs/test_pack2") +             |> json_response(200) == "ok" -      %{ -        method: :get, -        url: "https://nonshared-pack" -      } -> -        text(File.read!("#{@emoji_dir_path}/test_pack_nonshared/nonshared.zip")) -    end) +      refute File.exists?("#{@emoji_path}/test_pack2") -    admin = insert(:user, info: %{is_admin: true}) - -    conn = build_conn() |> assign(:user, admin) - -    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" +      assert admin_conn +             |> post( +               "/api/pleroma/emoji/packs/download", +               %{ +                 url: "https://example.com", +                 name: "test_pack_nonshared", +                 as: "test_pack_nonshared2" +               } +             ) +             |> json_response(200) == "ok" + +      assert File.exists?("#{@emoji_path}/test_pack_nonshared2/pack.json") +      assert File.exists?("#{@emoji_path}/test_pack_nonshared2/blank.png") + +      assert admin_conn +             |> delete("/api/pleroma/emoji/packs/test_pack_nonshared2") +             |> json_response(200) == "ok" + +      refute File.exists?("#{@emoji_path}/test_pack_nonshared2") +    end + +    test "nonshareable instance", %{admin_conn: admin_conn} do +      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: []}}) +      end) + +      assert admin_conn +             |> post( +               "/api/pleroma/emoji/packs/download", +               %{ +                 url: "https://old-instance", +                 name: "test_pack", +                 as: "test_pack2" +               } +             ) +             |> json_response(500) == %{ +               "error" => "The requested instance does not support sharing emoji packs"               } -             |> 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 - -    conn = build_conn() |> assign(:user, admin) - -    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" +    end + +    test "checksum fail", %{admin_conn: admin_conn} do +      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/pack_bad_sha" +        } -> +          %Tesla.Env{ +            status: 200, +            body: Pleroma.Emoji.Pack.load_pack("pack_bad_sha") |> Jason.encode!() +          } + +        %{ +          method: :get, +          url: "https://example.com/api/pleroma/emoji/packs/pack_bad_sha/archive" +        } -> +          %Tesla.Env{ +            status: 200, +            body: File.read!("test/instance_static/emoji/pack_bad_sha/pack_bad_sha.zip") +          } +      end) + +      assert admin_conn +             |> post("/api/pleroma/emoji/packs/download", %{ +               url: "https://example.com", +               name: "pack_bad_sha", +               as: "pack_bad_sha2" +             }) +             |> json_response(:internal_server_error) == %{ +               "error" => "SHA256 for the pack doesn't match the one sent by the server"               } -             |> Jason.encode!() -           ) -           |> json_response(200) == "ok" +    end + +    test "other error", %{admin_conn: admin_conn} do +      mock(fn +        %{method: :get, url: "https://example.com/.well-known/nodeinfo"} -> +          json(%{links: [%{href: "https://example.com/nodeinfo/2.1.json"}]}) -    assert File.exists?("#{@emoji_dir_path}/test_pack_nonshared2/pack.json") -    assert File.exists?("#{@emoji_dir_path}/test_pack_nonshared2/blank.png") +        %{method: :get, url: "https://example.com/nodeinfo/2.1.json"} -> +          json(%{metadata: %{features: ["shareable_emoji_packs"]}}) -    assert conn -           |> delete(emoji_api_path(conn, :delete, "test_pack_nonshared2")) -           |> json_response(200) == "ok" +        %{ +          method: :get, +          url: "https://example.com/api/pleroma/emoji/packs/test_pack" +        } -> +          %Tesla.Env{ +            status: 200, +            body: Pleroma.Emoji.Pack.load_pack("test_pack") |> Jason.encode!() +          } +      end) -    refute File.exists?("#{@emoji_dir_path}/test_pack_nonshared2") +      assert admin_conn +             |> post("/api/pleroma/emoji/packs/download", %{ +               url: "https://example.com", +               name: "test_pack", +               as: "test_pack2" +             }) +             |> json_response(:internal_server_error) == %{ +               "error" => +                 "The pack was not set as shared and there is no fallback src to download from" +             } +    end    end -  describe "updating pack metadata" do +  describe "PATCH /api/pleroma/emoji/packs/:name" do      setup do -      pack_file = "#{@emoji_dir_path}/test_pack/pack.json" +      pack_file = "#{@emoji_path}/test_pack/pack.json"        original_content = File.read!(pack_file)        on_exit(fn -> @@ -206,7 +300,6 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do        end)        {:ok, -       admin: insert(:user, info: %{is_admin: true}),         pack_file: pack_file,         new_data: %{           "license" => "Test license changed", @@ -217,16 +310,8 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do      end      test "for a pack without a fallback source", ctx do -      conn = build_conn() - -      assert conn -             |> assign(:user, ctx[:admin]) -             |> post( -               emoji_api_path(conn, :update_metadata, "test_pack"), -               %{ -                 "new_data" => ctx[:new_data] -               } -             ) +      assert ctx[:admin_conn] +             |> patch("/api/pleroma/emoji/packs/test_pack", %{"metadata" => ctx[:new_data]})               |> json_response(200) == ctx[:new_data]        assert Jason.decode!(File.read!(ctx[:pack_file]))["pack"] == ctx[:new_data] @@ -238,7 +323,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do            method: :get,            url: "https://nonshared-pack"          } -> -          text(File.read!("#{@emoji_dir_path}/test_pack_nonshared/nonshared.zip")) +          text(File.read!("#{@emoji_path}/test_pack_nonshared/nonshared.zip"))        end)        new_data = Map.put(ctx[:new_data], "fallback-src", "https://nonshared-pack") @@ -250,16 +335,8 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do            "74409E2674DAA06C072729C6C8426C4CB3B7E0B85ED77792DB7A436E11D76DAF"          ) -      conn = build_conn() - -      assert conn -             |> assign(:user, ctx[:admin]) -             |> post( -               emoji_api_path(conn, :update_metadata, "test_pack"), -               %{ -                 "new_data" => new_data -               } -             ) +      assert ctx[:admin_conn] +             |> patch("/api/pleroma/emoji/packs/test_pack", %{metadata: new_data})               |> json_response(200) == new_data_with_sha        assert Jason.decode!(File.read!(ctx[:pack_file]))["pack"] == new_data_with_sha @@ -277,187 +354,377 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIControllerTest do        new_data = Map.put(ctx[:new_data], "fallback-src", "https://nonshared-pack") -      conn = build_conn() - -      assert (conn -              |> assign(:user, ctx[:admin]) -              |> post( -                emoji_api_path(conn, :update_metadata, "test_pack"), -                %{ -                  "new_data" => new_data -                } -              ) -              |> json_response(:bad_request))["error"] =~ "does not have all" +      assert ctx[:admin_conn] +             |> patch("/api/pleroma/emoji/packs/test_pack", %{metadata: new_data}) +             |> json_response(:bad_request) == %{ +               "error" => "The fallback archive does not have all files specified in pack.json" +             }      end    end -  test "updating pack files" do -    pack_file = "#{@emoji_dir_path}/test_pack/pack.json" -    original_content = File.read!(pack_file) +  describe "POST/PATCH/DELETE /api/pleroma/emoji/packs/:name/files" do +    setup do +      pack_file = "#{@emoji_path}/test_pack/pack.json" +      original_content = File.read!(pack_file) -    on_exit(fn -> -      File.write!(pack_file, original_content) +      on_exit(fn -> +        File.write!(pack_file, original_content) +      end) -      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) +      :ok +    end -    admin = insert(:user, info: %{is_admin: true}) - -    conn = build_conn() - -    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"} - -    conn = conn |> assign(:user, admin) - -    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) +    test "create shortcode exists", %{admin_conn: admin_conn} do +      assert admin_conn +             |> post("/api/pleroma/emoji/packs/test_pack/files", %{ +               shortcode: "blank", +               filename: "dir/blank.png", +               file: %Plug.Upload{ +                 filename: "blank.png", +                 path: "#{@emoji_path}/test_pack/blank.png" +               } +             }) +             |> json_response(:conflict) == %{ +               "error" => "An emoji with the \"blank\" shortcode already exists" +             } +    end -    # The name should be inferred from the URL ending -    from_url = %{ -      "action" => "add", -      "shortcode" => "blank_url", -      "file" => "https://test-blank/blank_url.png" -    } +    test "don't rewrite old emoji", %{admin_conn: admin_conn} do +      on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/dir/") end) -    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 admin_conn +             |> post("/api/pleroma/emoji/packs/test_pack/files", %{ +               shortcode: "blank2", +               filename: "dir/blank.png", +               file: %Plug.Upload{ +                 filename: "blank.png", +                 path: "#{@emoji_path}/test_pack/blank.png" +               } +             }) +             |> json_response(200) == %{"blank" => "blank.png", "blank2" => "dir/blank.png"} + +      assert File.exists?("#{@emoji_path}/test_pack/dir/blank.png") + +      assert admin_conn +             |> patch("/api/pleroma/emoji/packs/test_pack/files", %{ +               shortcode: "blank", +               new_shortcode: "blank2", +               new_filename: "dir_2/blank_3.png" +             }) +             |> json_response(:conflict) == %{ +               "error" => +                 "New shortcode \"blank2\" is already used. If you want to override emoji use 'force' option" +             } +    end + +    test "rewrite old emoji with force option", %{admin_conn: admin_conn} do +      on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/dir_2/") end) + +      assert admin_conn +             |> post("/api/pleroma/emoji/packs/test_pack/files", %{ +               shortcode: "blank2", +               filename: "dir/blank.png", +               file: %Plug.Upload{ +                 filename: "blank.png", +                 path: "#{@emoji_path}/test_pack/blank.png" +               } +             }) +             |> json_response(200) == %{"blank" => "blank.png", "blank2" => "dir/blank.png"} + +      assert File.exists?("#{@emoji_path}/test_pack/dir/blank.png") + +      assert admin_conn +             |> patch("/api/pleroma/emoji/packs/test_pack/files", %{ +               shortcode: "blank2", +               new_shortcode: "blank3", +               new_filename: "dir_2/blank_3.png", +               force: true +             }) +             |> json_response(200) == %{ +               "blank" => "blank.png", +               "blank3" => "dir_2/blank_3.png" +             } + +      assert File.exists?("#{@emoji_path}/test_pack/dir_2/blank_3.png") +    end + +    test "with empty filename", %{admin_conn: admin_conn} do +      assert admin_conn +             |> post("/api/pleroma/emoji/packs/test_pack/files", %{ +               shortcode: "blank2", +               filename: "", +               file: %Plug.Upload{ +                 filename: "blank.png", +                 path: "#{@emoji_path}/test_pack/blank.png" +               } +             }) +             |> json_response(:bad_request) == %{ +               "error" => "pack name, shortcode or filename cannot be empty" +             } +    end + +    test "add file with not loaded pack", %{admin_conn: admin_conn} do +      assert admin_conn +             |> post("/api/pleroma/emoji/packs/not_loaded/files", %{ +               shortcode: "blank2", +               filename: "dir/blank.png", +               file: %Plug.Upload{ +                 filename: "blank.png", +                 path: "#{@emoji_path}/test_pack/blank.png" +               } +             }) +             |> json_response(:bad_request) == %{ +               "error" => "pack \"not_loaded\" is not found" +             } +    end + +    test "remove file with not loaded pack", %{admin_conn: admin_conn} do +      assert admin_conn +             |> delete("/api/pleroma/emoji/packs/not_loaded/files", %{shortcode: "blank3"}) +             |> json_response(:bad_request) == %{"error" => "pack \"not_loaded\" is not found"} +    end + +    test "remove file with empty shortcode", %{admin_conn: admin_conn} do +      assert admin_conn +             |> delete("/api/pleroma/emoji/packs/not_loaded/files", %{shortcode: ""}) +             |> json_response(:bad_request) == %{ +               "error" => "pack name or shortcode cannot be empty" +             } +    end + +    test "update file with not loaded pack", %{admin_conn: admin_conn} do +      assert admin_conn +             |> patch("/api/pleroma/emoji/packs/not_loaded/files", %{ +               shortcode: "blank4", +               new_shortcode: "blank3", +               new_filename: "dir_2/blank_3.png" +             }) +             |> json_response(:bad_request) == %{"error" => "pack \"not_loaded\" is not found"} +    end + +    test "new with shortcode as file with update", %{admin_conn: admin_conn} do +      assert admin_conn +             |> post("/api/pleroma/emoji/packs/test_pack/files", %{ +               shortcode: "blank4", +               filename: "dir/blank.png", +               file: %Plug.Upload{ +                 filename: "blank.png", +                 path: "#{@emoji_path}/test_pack/blank.png" +               } +             }) +             |> json_response(200) == %{"blank" => "blank.png", "blank4" => "dir/blank.png"} + +      assert File.exists?("#{@emoji_path}/test_pack/dir/blank.png") + +      assert admin_conn +             |> patch("/api/pleroma/emoji/packs/test_pack/files", %{ +               shortcode: "blank4", +               new_shortcode: "blank3", +               new_filename: "dir_2/blank_3.png" +             }) +             |> json_response(200) == %{"blank3" => "dir_2/blank_3.png", "blank" => "blank.png"} -    assert File.exists?("#{@emoji_dir_path}/test_pack/blank_url.png") +      refute File.exists?("#{@emoji_path}/test_pack/dir/") +      assert File.exists?("#{@emoji_path}/test_pack/dir_2/blank_3.png") -    assert conn -           |> post(emoji_api_path(conn, :update_file, "test_pack"), %{ -             "action" => "remove", -             "shortcode" => "blank_url" -           }) -           |> json_response(200) == %{"blank" => "blank.png"} +      assert admin_conn +             |> delete("/api/pleroma/emoji/packs/test_pack/files", %{shortcode: "blank3"}) +             |> json_response(200) == %{"blank" => "blank.png"} -    refute File.exists?("#{@emoji_dir_path}/test_pack/blank_url.png") +      refute File.exists?("#{@emoji_path}/test_pack/dir_2/") + +      on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/dir") end) +    end + +    test "new with shortcode from url", %{admin_conn: admin_conn} do +      mock(fn +        %{ +          method: :get, +          url: "https://test-blank/blank_url.png" +        } -> +          text(File.read!("#{@emoji_path}/test_pack/blank.png")) +      end) + +      assert admin_conn +             |> post("/api/pleroma/emoji/packs/test_pack/files", %{ +               shortcode: "blank_url", +               file: "https://test-blank/blank_url.png" +             }) +             |> json_response(200) == %{ +               "blank_url" => "blank_url.png", +               "blank" => "blank.png" +             } + +      assert File.exists?("#{@emoji_path}/test_pack/blank_url.png") + +      on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/blank_url.png") end) +    end + +    test "new without shortcode", %{admin_conn: admin_conn} do +      on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/shortcode.png") end) + +      assert admin_conn +             |> post("/api/pleroma/emoji/packs/test_pack/files", %{ +               file: %Plug.Upload{ +                 filename: "shortcode.png", +                 path: "#{Pleroma.Config.get([:instance, :static_dir])}/add/shortcode.png" +               } +             }) +             |> json_response(200) == %{"shortcode" => "shortcode.png", "blank" => "blank.png"} +    end + +    test "remove non existing shortcode in pack.json", %{admin_conn: admin_conn} do +      assert admin_conn +             |> delete("/api/pleroma/emoji/packs/test_pack/files", %{shortcode: "blank2"}) +             |> json_response(:bad_request) == %{"error" => "Emoji \"blank2\" does not exist"} +    end + +    test "update non existing emoji", %{admin_conn: admin_conn} do +      assert admin_conn +             |> patch("/api/pleroma/emoji/packs/test_pack/files", %{ +               shortcode: "blank2", +               new_shortcode: "blank3", +               new_filename: "dir_2/blank_3.png" +             }) +             |> json_response(:bad_request) == %{"error" => "Emoji \"blank2\" does not exist"} +    end + +    test "update with empty shortcode", %{admin_conn: admin_conn} do +      assert admin_conn +             |> patch("/api/pleroma/emoji/packs/test_pack/files", %{ +               shortcode: "blank", +               new_filename: "dir_2/blank_3.png" +             }) +             |> json_response(:bad_request) == %{ +               "error" => "new_shortcode or new_filename cannot be empty" +             } +    end    end -  test "creating and deleting a pack" do -    on_exit(fn -> -      File.rm_rf!("#{@emoji_dir_path}/test_created") -    end) +  describe "POST/DELETE /api/pleroma/emoji/packs/:name" do +    test "creating and deleting a pack", %{admin_conn: admin_conn} do +      assert admin_conn +             |> post("/api/pleroma/emoji/packs/test_created") +             |> json_response(200) == "ok" -    admin = insert(:user, info: %{is_admin: true}) +      assert File.exists?("#{@emoji_path}/test_created/pack.json") -    conn = build_conn() |> assign(:user, admin) +      assert Jason.decode!(File.read!("#{@emoji_path}/test_created/pack.json")) == %{ +               "pack" => %{}, +               "files" => %{} +             } -    assert conn -           |> put_req_header("content-type", "application/json") -           |> put( -             emoji_api_path( -               conn, -               :create, -               "test_created" -             ) -           ) -           |> json_response(200) == "ok" +      assert admin_conn +             |> delete("/api/pleroma/emoji/packs/test_created") +             |> json_response(200) == "ok" -    assert File.exists?("#{@emoji_dir_path}/test_created/pack.json") +      refute File.exists?("#{@emoji_path}/test_created/pack.json") +    end -    assert Jason.decode!(File.read!("#{@emoji_dir_path}/test_created/pack.json")) == %{ -             "pack" => %{}, -             "files" => %{} -           } +    test "if pack exists", %{admin_conn: admin_conn} do +      path = Path.join(@emoji_path, "test_created") +      File.mkdir(path) +      pack_file = Jason.encode!(%{files: %{}, pack: %{}}) +      File.write!(Path.join(path, "pack.json"), pack_file) + +      assert admin_conn +             |> post("/api/pleroma/emoji/packs/test_created") +             |> json_response(:conflict) == %{ +               "error" => "A pack named \"test_created\" already exists" +             } + +      on_exit(fn -> File.rm_rf(path) end) +    end + +    test "with empty name", %{admin_conn: admin_conn} do +      assert admin_conn +             |> post("/api/pleroma/emoji/packs/ ") +             |> json_response(:bad_request) == %{"error" => "pack name cannot be empty"} +    end +  end -    assert conn -           |> delete(emoji_api_path(conn, :delete, "test_created")) -           |> json_response(200) == "ok" +  test "deleting nonexisting pack", %{admin_conn: admin_conn} do +    assert admin_conn +           |> delete("/api/pleroma/emoji/packs/non_existing") +           |> json_response(:not_found) == %{"error" => "Pack non_existing does not exist"} +  end -    refute File.exists?("#{@emoji_dir_path}/test_created/pack.json") +  test "deleting with empty name", %{admin_conn: admin_conn} do +    assert admin_conn +           |> delete("/api/pleroma/emoji/packs/ ") +           |> json_response(:bad_request) == %{"error" => "pack name cannot be empty"}    end -  test "filesystem import" do +  test "filesystem import", %{admin_conn: admin_conn, conn: conn} 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") +      File.rm!("#{@emoji_path}/test_pack_for_import/emoji.txt") +      File.rm!("#{@emoji_path}/test_pack_for_import/pack.json")      end) -    conn = build_conn() -    resp = conn |> get(emoji_api_path(conn, :list_packs)) |> json_response(200) +    resp = conn |> get("/api/pleroma/emoji/packs") |> json_response(200)      refute Map.has_key?(resp, "test_pack_for_import") -    admin = insert(:user, info: %{is_admin: true}) - -    assert conn -           |> assign(:user, admin) -           |> post(emoji_api_path(conn, :import_from_fs)) +    assert admin_conn +           |> get("/api/pleroma/emoji/packs/import")             |> json_response(200) == ["test_pack_for_import"] -    resp = conn |> get(emoji_api_path(conn, :list_packs)) |> json_response(200) +    resp = conn |> get("/api/pleroma/emoji/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") +    File.rm!("#{@emoji_path}/test_pack_for_import/pack.json") +    refute File.exists?("#{@emoji_path}/test_pack_for_import/pack.json") -    emoji_txt_content = "blank, blank.png, Fun\n\nblank2, blank.png" +    emoji_txt_content = """ +    blank, blank.png, Fun +    blank2, blank.png +    foo, /emoji/test_pack_for_import/blank.png +    bar +    """ -    File.write!("#{@emoji_dir_path}/test_pack_for_import/emoji.txt", emoji_txt_content) +    File.write!("#{@emoji_path}/test_pack_for_import/emoji.txt", emoji_txt_content) -    assert conn -           |> assign(:user, admin) -           |> post(emoji_api_path(conn, :import_from_fs)) +    assert admin_conn +           |> get("/api/pleroma/emoji/packs/import")             |> json_response(200) == ["test_pack_for_import"] -    resp = conn |> get(emoji_api_path(conn, :list_packs)) |> json_response(200) +    resp = conn |> get("/api/pleroma/emoji/packs") |> json_response(200)      assert resp["test_pack_for_import"]["files"] == %{               "blank" => "blank.png", -             "blank2" => "blank.png" +             "blank2" => "blank.png", +             "foo" => "blank.png"             }    end + +  describe "GET /api/pleroma/emoji/packs/:name" do +    test "shows pack.json", %{conn: conn} do +      assert %{ +               "files" => %{"blank" => "blank.png"}, +               "pack" => %{ +                 "can-download" => true, +                 "description" => "Test description", +                 "download-sha256" => _, +                 "homepage" => "https://pleroma.social", +                 "license" => "Test license", +                 "share-files" => true +               } +             } = +               conn +               |> get("/api/pleroma/emoji/packs/test_pack") +               |> json_response(200) +    end + +    test "non existing pack", %{conn: conn} do +      assert conn +             |> get("/api/pleroma/emoji/packs/non_existing") +             |> json_response(:not_found) == %{"error" => "Pack non_existing does not exist"} +    end + +    test "error name", %{conn: conn} do +      assert conn +             |> get("/api/pleroma/emoji/packs/ ") +             |> json_response(:bad_request) == %{"error" => "pack name cannot be empty"} +    end +  end  end diff --git a/test/web/pleroma_api/controllers/mascot_controller_test.exs b/test/web/pleroma_api/controllers/mascot_controller_test.exs index ae9539b04..617831b02 100644 --- a/test/web/pleroma_api/controllers/mascot_controller_test.exs +++ b/test/web/pleroma_api/controllers/mascot_controller_test.exs @@ -1,5 +1,5 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.PleromaAPI.MascotControllerTest do @@ -7,10 +7,8 @@ defmodule Pleroma.Web.PleromaAPI.MascotControllerTest do    alias Pleroma.User -  import Pleroma.Factory - -  test "mascot upload", %{conn: conn} do -    user = insert(:user) +  test "mascot upload" do +    %{conn: conn} = oauth_access(["write:accounts"])      non_image_file = %Plug.Upload{        content_type: "audio/mpeg", @@ -18,12 +16,9 @@ defmodule Pleroma.Web.PleromaAPI.MascotControllerTest do        filename: "sound.mp3"      } -    conn = -      conn -      |> assign(:user, user) -      |> put("/api/v1/pleroma/mascot", %{"file" => non_image_file}) +    ret_conn = put(conn, "/api/v1/pleroma/mascot", %{"file" => non_image_file}) -    assert json_response(conn, 415) +    assert json_response(ret_conn, 415)      file = %Plug.Upload{        content_type: "image/jpg", @@ -31,23 +26,18 @@ defmodule Pleroma.Web.PleromaAPI.MascotControllerTest do        filename: "an_image.jpg"      } -    conn = -      build_conn() -      |> assign(:user, user) -      |> put("/api/v1/pleroma/mascot", %{"file" => file}) +    conn = put(conn, "/api/v1/pleroma/mascot", %{"file" => file})      assert %{"id" => _, "type" => image} = json_response(conn, 200)    end -  test "mascot retrieving", %{conn: conn} do -    user = insert(:user) +  test "mascot retrieving" do +    %{user: user, conn: conn} = oauth_access(["read:accounts", "write:accounts"]) +      # When user hasn't set a mascot, we should just get pleroma tan back -    conn = -      conn -      |> assign(:user, user) -      |> get("/api/v1/pleroma/mascot") +    ret_conn = get(conn, "/api/v1/pleroma/mascot") -    assert %{"url" => url} = json_response(conn, 200) +    assert %{"url" => url} = json_response(ret_conn, 200)      assert url =~ "pleroma-fox-tan-smol"      # When a user sets their mascot, we should get that back @@ -57,17 +47,14 @@ defmodule Pleroma.Web.PleromaAPI.MascotControllerTest do        filename: "an_image.jpg"      } -    conn = -      build_conn() -      |> assign(:user, user) -      |> put("/api/v1/pleroma/mascot", %{"file" => file}) +    ret_conn = put(conn, "/api/v1/pleroma/mascot", %{"file" => file}) -    assert json_response(conn, 200) +    assert json_response(ret_conn, 200)      user = User.get_cached_by_id(user.id)      conn = -      build_conn() +      conn        |> assign(:user, user)        |> get("/api/v1/pleroma/mascot") diff --git a/test/web/pleroma_api/controllers/pleroma_api_controller_test.exs b/test/web/pleroma_api/controllers/pleroma_api_controller_test.exs index 9cccc8c8a..cfd1dbd24 100644 --- a/test/web/pleroma_api/controllers/pleroma_api_controller_test.exs +++ b/test/web/pleroma_api/controllers/pleroma_api_controller_test.exs @@ -1,59 +1,172 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.PleromaAPI.PleromaAPIControllerTest do +  use Oban.Testing, repo: Pleroma.Repo    use Pleroma.Web.ConnCase    alias Pleroma.Conversation.Participation    alias Pleroma.Notification +  alias Pleroma.Object    alias Pleroma.Repo +  alias Pleroma.Tests.ObanHelpers    alias Pleroma.User    alias Pleroma.Web.CommonAPI    import Pleroma.Factory -  test "/api/v1/pleroma/conversations/:id", %{conn: conn} do +  test "PUT /api/v1/pleroma/statuses/:id/reactions/:emoji", %{conn: conn} do      user = insert(:user)      other_user = insert(:user) +    {:ok, activity} = CommonAPI.post(user, %{status: "#cofe"}) + +    result = +      conn +      |> assign(:user, other_user) +      |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["write:statuses"])) +      |> put("/api/v1/pleroma/statuses/#{activity.id}/reactions/☕") +      |> json_response(200) + +    # We return the status, but this our implementation detail. +    assert %{"id" => id} = result +    assert to_string(activity.id) == id + +    assert result["pleroma"]["emoji_reactions"] == [ +             %{"name" => "☕", "count" => 1, "me" => true} +           ] +  end + +  test "DELETE /api/v1/pleroma/statuses/:id/reactions/:emoji", %{conn: conn} do +    user = insert(:user) +    other_user = insert(:user) + +    {:ok, activity} = CommonAPI.post(user, %{status: "#cofe"}) +    {:ok, _reaction_activity} = CommonAPI.react_with_emoji(activity.id, other_user, "☕") + +    ObanHelpers.perform_all() + +    result = +      conn +      |> assign(:user, other_user) +      |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["write:statuses"])) +      |> delete("/api/v1/pleroma/statuses/#{activity.id}/reactions/☕") + +    assert %{"id" => id} = json_response(result, 200) +    assert to_string(activity.id) == id + +    ObanHelpers.perform_all() + +    object = Object.get_by_ap_id(activity.data["object"]) + +    assert object.data["reaction_count"] == 0 +  end + +  test "GET /api/v1/pleroma/statuses/:id/reactions", %{conn: conn} do +    user = insert(:user) +    other_user = insert(:user) +    doomed_user = insert(:user) + +    {:ok, activity} = CommonAPI.post(user, %{status: "#cofe"}) + +    result = +      conn +      |> get("/api/v1/pleroma/statuses/#{activity.id}/reactions") +      |> json_response(200) + +    assert result == [] + +    {:ok, _} = CommonAPI.react_with_emoji(activity.id, other_user, "🎅") +    {:ok, _} = CommonAPI.react_with_emoji(activity.id, doomed_user, "🎅") + +    User.perform(:delete, doomed_user) + +    result = +      conn +      |> get("/api/v1/pleroma/statuses/#{activity.id}/reactions") +      |> json_response(200) + +    [%{"name" => "🎅", "count" => 1, "accounts" => [represented_user], "me" => false}] = result + +    assert represented_user["id"] == other_user.id + +    result = +      conn +      |> assign(:user, other_user) +      |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["read:statuses"])) +      |> get("/api/v1/pleroma/statuses/#{activity.id}/reactions") +      |> json_response(200) + +    assert [%{"name" => "🎅", "count" => 1, "accounts" => [_represented_user], "me" => true}] = +             result +  end + +  test "GET /api/v1/pleroma/statuses/:id/reactions/:emoji", %{conn: conn} do +    user = insert(:user) +    other_user = insert(:user) + +    {:ok, activity} = CommonAPI.post(user, %{status: "#cofe"}) + +    result = +      conn +      |> get("/api/v1/pleroma/statuses/#{activity.id}/reactions/🎅") +      |> json_response(200) + +    assert result == [] + +    {:ok, _} = CommonAPI.react_with_emoji(activity.id, other_user, "🎅") +    {:ok, _} = CommonAPI.react_with_emoji(activity.id, other_user, "☕") + +    result = +      conn +      |> get("/api/v1/pleroma/statuses/#{activity.id}/reactions/🎅") +      |> json_response(200) + +    [%{"name" => "🎅", "count" => 1, "accounts" => [represented_user], "me" => false}] = result + +    assert represented_user["id"] == other_user.id +  end + +  test "/api/v1/pleroma/conversations/:id" do +    user = insert(:user) +    %{user: other_user, conn: conn} = oauth_access(["read:statuses"]) +      {:ok, _activity} = -      CommonAPI.post(user, %{"status" => "Hi @#{other_user.nickname}!", "visibility" => "direct"}) +      CommonAPI.post(user, %{status: "Hi @#{other_user.nickname}!", visibility: "direct"})      [participation] = Participation.for_user(other_user)      result =        conn -      |> assign(:user, other_user)        |> get("/api/v1/pleroma/conversations/#{participation.id}")        |> json_response(200)      assert result["id"] == participation.id |> to_string()    end -  test "/api/v1/pleroma/conversations/:id/statuses", %{conn: conn} do +  test "/api/v1/pleroma/conversations/:id/statuses" do      user = insert(:user) -    other_user = insert(:user) +    %{user: other_user, conn: conn} = oauth_access(["read:statuses"])      third_user = insert(:user)      {:ok, _activity} = -      CommonAPI.post(user, %{"status" => "Hi @#{third_user.nickname}!", "visibility" => "direct"}) +      CommonAPI.post(user, %{status: "Hi @#{third_user.nickname}!", visibility: "direct"})      {:ok, activity} = -      CommonAPI.post(user, %{"status" => "Hi @#{other_user.nickname}!", "visibility" => "direct"}) +      CommonAPI.post(user, %{status: "Hi @#{other_user.nickname}!", visibility: "direct"})      [participation] = Participation.for_user(other_user)      {:ok, activity_two} =        CommonAPI.post(other_user, %{ -        "status" => "Hi!", -        "in_reply_to_status_id" => activity.id, -        "in_reply_to_conversation_id" => participation.id +        status: "Hi!", +        in_reply_to_status_id: activity.id, +        in_reply_to_conversation_id: participation.id        })      result =        conn -      |> assign(:user, other_user)        |> get("/api/v1/pleroma/conversations/#{participation.id}/statuses")        |> json_response(200) @@ -62,13 +175,30 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIControllerTest do      id_one = activity.id      id_two = activity_two.id      assert [%{"id" => ^id_one}, %{"id" => ^id_two}] = result + +    {:ok, %{id: id_three}} = +      CommonAPI.post(other_user, %{ +        status: "Bye!", +        in_reply_to_status_id: activity.id, +        in_reply_to_conversation_id: participation.id +      }) + +    assert [%{"id" => ^id_two}, %{"id" => ^id_three}] = +             conn +             |> get("/api/v1/pleroma/conversations/#{participation.id}/statuses?limit=2") +             |> json_response(:ok) + +    assert [%{"id" => ^id_three}] = +             conn +             |> get("/api/v1/pleroma/conversations/#{participation.id}/statuses?min_id=#{id_two}") +             |> json_response(:ok)    end -  test "PATCH /api/v1/pleroma/conversations/:id", %{conn: conn} do -    user = insert(:user) +  test "PATCH /api/v1/pleroma/conversations/:id" do +    %{user: user, conn: conn} = oauth_access(["write:conversations"])      other_user = insert(:user) -    {:ok, _activity} = CommonAPI.post(user, %{"status" => "Hi", "visibility" => "direct"}) +    {:ok, _activity} = CommonAPI.post(user, %{status: "Hi", visibility: "direct"})      [participation] = Participation.for_user(user) @@ -80,7 +210,6 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIControllerTest do      result =        conn -      |> assign(:user, user)        |> patch("/api/v1/pleroma/conversations/#{participation.id}", %{          "recipients" => [user.id, other_user.id]        }) @@ -95,45 +224,44 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIControllerTest do      assert other_user in participation.recipients    end -  test "POST /api/v1/pleroma/conversations/read", %{conn: conn} do +  test "POST /api/v1/pleroma/conversations/read" do      user = insert(:user) -    other_user = insert(:user) +    %{user: other_user, conn: conn} = oauth_access(["write:conversations"])      {:ok, _activity} = -      CommonAPI.post(user, %{"status" => "Hi @#{other_user.nickname}", "visibility" => "direct"}) +      CommonAPI.post(user, %{status: "Hi @#{other_user.nickname}", visibility: "direct"})      {:ok, _activity} = -      CommonAPI.post(user, %{"status" => "Hi @#{other_user.nickname}", "visibility" => "direct"}) +      CommonAPI.post(user, %{status: "Hi @#{other_user.nickname}", visibility: "direct"})      [participation2, participation1] = Participation.for_user(other_user)      assert Participation.get(participation2.id).read == false      assert Participation.get(participation1.id).read == false -    assert User.get_cached_by_id(other_user.id).info.unread_conversation_count == 2 +    assert User.get_cached_by_id(other_user.id).unread_conversation_count == 2      [%{"unread" => false}, %{"unread" => false}] =        conn -      |> assign(:user, other_user)        |> post("/api/v1/pleroma/conversations/read", %{})        |> json_response(200)      [participation2, participation1] = Participation.for_user(other_user)      assert Participation.get(participation2.id).read == true      assert Participation.get(participation1.id).read == true -    assert User.get_cached_by_id(other_user.id).info.unread_conversation_count == 0 +    assert User.get_cached_by_id(other_user.id).unread_conversation_count == 0    end    describe "POST /api/v1/pleroma/notifications/read" do -    test "it marks a single notification as read", %{conn: conn} do -      user1 = insert(:user) +    setup do: oauth_access(["write:notifications"]) + +    test "it marks a single notification as read", %{user: user1, conn: conn} do        user2 = insert(:user) -      {:ok, activity1} = CommonAPI.post(user2, %{"status" => "hi @#{user1.nickname}"}) -      {:ok, activity2} = CommonAPI.post(user2, %{"status" => "hi @#{user1.nickname}"}) +      {:ok, activity1} = CommonAPI.post(user2, %{status: "hi @#{user1.nickname}"}) +      {:ok, activity2} = CommonAPI.post(user2, %{status: "hi @#{user1.nickname}"})        {:ok, [notification1]} = Notification.create_notifications(activity1)        {:ok, [notification2]} = Notification.create_notifications(activity2)        response =          conn -        |> assign(:user, user1)          |> post("/api/v1/pleroma/notifications/read", %{"id" => "#{notification1.id}"})          |> json_response(:ok) @@ -142,18 +270,16 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIControllerTest do        refute Repo.get(Notification, notification2.id).seen      end -    test "it marks multiple notifications as read", %{conn: conn} do -      user1 = insert(:user) +    test "it marks multiple notifications as read", %{user: user1, conn: conn} do        user2 = insert(:user) -      {:ok, _activity1} = CommonAPI.post(user2, %{"status" => "hi @#{user1.nickname}"}) -      {:ok, _activity2} = CommonAPI.post(user2, %{"status" => "hi @#{user1.nickname}"}) -      {:ok, _activity3} = CommonAPI.post(user2, %{"status" => "HIE @#{user1.nickname}"}) +      {:ok, _activity1} = CommonAPI.post(user2, %{status: "hi @#{user1.nickname}"}) +      {:ok, _activity2} = CommonAPI.post(user2, %{status: "hi @#{user1.nickname}"}) +      {:ok, _activity3} = CommonAPI.post(user2, %{status: "HIE @#{user1.nickname}"})        [notification3, notification2, notification1] = Notification.for_user(user1, %{limit: 3})        [response1, response2] =          conn -        |> assign(:user, user1)          |> post("/api/v1/pleroma/notifications/read", %{"max_id" => "#{notification2.id}"})          |> json_response(:ok) @@ -165,11 +291,8 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIControllerTest do      end      test "it returns error when notification not found", %{conn: conn} do -      user1 = insert(:user) -        response =          conn -        |> assign(:user, user1)          |> post("/api/v1/pleroma/notifications/read", %{"id" => "22222222222222"})          |> json_response(:bad_request) diff --git a/test/web/pleroma_api/controllers/scrobble_controller_test.exs b/test/web/pleroma_api/controllers/scrobble_controller_test.exs index 881f8012c..1b945040c 100644 --- a/test/web/pleroma_api/controllers/scrobble_controller_test.exs +++ b/test/web/pleroma_api/controllers/scrobble_controller_test.exs @@ -1,21 +1,18 @@  # Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>  # SPDX-License-Identifier: AGPL-3.0-only  defmodule Pleroma.Web.PleromaAPI.ScrobbleControllerTest do    use Pleroma.Web.ConnCase    alias Pleroma.Web.CommonAPI -  import Pleroma.Factory    describe "POST /api/v1/pleroma/scrobble" do -    test "works correctly", %{conn: conn} do -      user = insert(:user) +    test "works correctly" do +      %{conn: conn} = oauth_access(["write"])        conn = -        conn -        |> assign(:user, user) -        |> post("/api/v1/pleroma/scrobble", %{ +        post(conn, "/api/v1/pleroma/scrobble", %{            "title" => "lain radio episode 1",            "artist" => "lain",            "album" => "lain radio", @@ -27,8 +24,8 @@ defmodule Pleroma.Web.PleromaAPI.ScrobbleControllerTest do    end    describe "GET /api/v1/pleroma/accounts/:id/scrobbles" do -    test "works correctly", %{conn: conn} do -      user = insert(:user) +    test "works correctly" do +      %{user: user, conn: conn} = oauth_access(["read"])        {:ok, _activity} =          CommonAPI.listen(user, %{ @@ -51,9 +48,7 @@ defmodule Pleroma.Web.PleromaAPI.ScrobbleControllerTest do            "album" => "lain radio"          }) -      conn = -        conn -        |> get("/api/v1/pleroma/accounts/#{user.id}/scrobbles") +      conn = get(conn, "/api/v1/pleroma/accounts/#{user.id}/scrobbles")        result = json_response(conn, 200) diff --git a/test/web/pleroma_api/controllers/two_factor_authentication_controller_test.exs b/test/web/pleroma_api/controllers/two_factor_authentication_controller_test.exs new file mode 100644 index 000000000..d23d08a00 --- /dev/null +++ b/test/web/pleroma_api/controllers/two_factor_authentication_controller_test.exs @@ -0,0 +1,260 @@ +defmodule Pleroma.Web.PleromaAPI.TwoFactorAuthenticationControllerTest do +  use Pleroma.Web.ConnCase + +  import Pleroma.Factory +  alias Pleroma.MFA.Settings +  alias Pleroma.MFA.TOTP + +  describe "GET /api/pleroma/accounts/mfa/settings" do +    test "returns user mfa settings for new user", %{conn: conn} do +      token = insert(:oauth_token, scopes: ["read", "follow"]) +      token2 = insert(:oauth_token, scopes: ["write"]) + +      assert conn +             |> put_req_header("authorization", "Bearer #{token.token}") +             |> get("/api/pleroma/accounts/mfa") +             |> json_response(:ok) == %{ +               "settings" => %{"enabled" => false, "totp" => false} +             } + +      assert conn +             |> put_req_header("authorization", "Bearer #{token2.token}") +             |> get("/api/pleroma/accounts/mfa") +             |> json_response(403) == %{ +               "error" => "Insufficient permissions: read:security." +             } +    end + +    test "returns user mfa settings with enabled totp", %{conn: conn} do +      user = +        insert(:user, +          multi_factor_authentication_settings: %Settings{ +            enabled: true, +            totp: %Settings.TOTP{secret: "XXX", delivery_type: "app", confirmed: true} +          } +        ) + +      token = insert(:oauth_token, scopes: ["read", "follow"], user: user) + +      assert conn +             |> put_req_header("authorization", "Bearer #{token.token}") +             |> get("/api/pleroma/accounts/mfa") +             |> json_response(:ok) == %{ +               "settings" => %{"enabled" => true, "totp" => true} +             } +    end +  end + +  describe "GET /api/pleroma/accounts/mfa/backup_codes" do +    test "returns backup codes", %{conn: conn} do +      user = +        insert(:user, +          multi_factor_authentication_settings: %Settings{ +            backup_codes: ["1", "2", "3"], +            totp: %Settings.TOTP{secret: "secret"} +          } +        ) + +      token = insert(:oauth_token, scopes: ["write", "follow"], user: user) +      token2 = insert(:oauth_token, scopes: ["read"]) + +      response = +        conn +        |> put_req_header("authorization", "Bearer #{token.token}") +        |> get("/api/pleroma/accounts/mfa/backup_codes") +        |> json_response(:ok) + +      assert [<<_::bytes-size(6)>>, <<_::bytes-size(6)>>] = response["codes"] +      user = refresh_record(user) +      mfa_settings = user.multi_factor_authentication_settings +      assert mfa_settings.totp.secret == "secret" +      refute mfa_settings.backup_codes == ["1", "2", "3"] +      refute mfa_settings.backup_codes == [] + +      assert conn +             |> put_req_header("authorization", "Bearer #{token2.token}") +             |> get("/api/pleroma/accounts/mfa/backup_codes") +             |> json_response(403) == %{ +               "error" => "Insufficient permissions: write:security." +             } +    end +  end + +  describe "GET /api/pleroma/accounts/mfa/setup/totp" do +    test "return errors when method is invalid", %{conn: conn} do +      user = insert(:user) +      token = insert(:oauth_token, scopes: ["write", "follow"], user: user) + +      response = +        conn +        |> put_req_header("authorization", "Bearer #{token.token}") +        |> get("/api/pleroma/accounts/mfa/setup/torf") +        |> json_response(400) + +      assert response == %{"error" => "undefined method"} +    end + +    test "returns key and provisioning_uri", %{conn: conn} do +      user = +        insert(:user, +          multi_factor_authentication_settings: %Settings{backup_codes: ["1", "2", "3"]} +        ) + +      token = insert(:oauth_token, scopes: ["write", "follow"], user: user) +      token2 = insert(:oauth_token, scopes: ["read"]) + +      response = +        conn +        |> put_req_header("authorization", "Bearer #{token.token}") +        |> get("/api/pleroma/accounts/mfa/setup/totp") +        |> json_response(:ok) + +      user = refresh_record(user) +      mfa_settings = user.multi_factor_authentication_settings +      secret = mfa_settings.totp.secret +      refute mfa_settings.enabled +      assert mfa_settings.backup_codes == ["1", "2", "3"] + +      assert response == %{ +               "key" => secret, +               "provisioning_uri" => TOTP.provisioning_uri(secret, "#{user.email}") +             } + +      assert conn +             |> put_req_header("authorization", "Bearer #{token2.token}") +             |> get("/api/pleroma/accounts/mfa/setup/totp") +             |> json_response(403) == %{ +               "error" => "Insufficient permissions: write:security." +             } +    end +  end + +  describe "GET /api/pleroma/accounts/mfa/confirm/totp" do +    test "returns success result", %{conn: conn} do +      secret = TOTP.generate_secret() +      code = TOTP.generate_token(secret) + +      user = +        insert(:user, +          multi_factor_authentication_settings: %Settings{ +            backup_codes: ["1", "2", "3"], +            totp: %Settings.TOTP{secret: secret} +          } +        ) + +      token = insert(:oauth_token, scopes: ["write", "follow"], user: user) +      token2 = insert(:oauth_token, scopes: ["read"]) + +      assert conn +             |> put_req_header("authorization", "Bearer #{token.token}") +             |> post("/api/pleroma/accounts/mfa/confirm/totp", %{password: "test", code: code}) +             |> json_response(:ok) + +      settings = refresh_record(user).multi_factor_authentication_settings +      assert settings.enabled +      assert settings.totp.secret == secret +      assert settings.totp.confirmed +      assert settings.backup_codes == ["1", "2", "3"] + +      assert conn +             |> put_req_header("authorization", "Bearer #{token2.token}") +             |> post("/api/pleroma/accounts/mfa/confirm/totp", %{password: "test", code: code}) +             |> json_response(403) == %{ +               "error" => "Insufficient permissions: write:security." +             } +    end + +    test "returns error if password incorrect", %{conn: conn} do +      secret = TOTP.generate_secret() +      code = TOTP.generate_token(secret) + +      user = +        insert(:user, +          multi_factor_authentication_settings: %Settings{ +            backup_codes: ["1", "2", "3"], +            totp: %Settings.TOTP{secret: secret} +          } +        ) + +      token = insert(:oauth_token, scopes: ["write", "follow"], user: user) + +      response = +        conn +        |> put_req_header("authorization", "Bearer #{token.token}") +        |> post("/api/pleroma/accounts/mfa/confirm/totp", %{password: "xxx", code: code}) +        |> json_response(422) + +      settings = refresh_record(user).multi_factor_authentication_settings +      refute settings.enabled +      refute settings.totp.confirmed +      assert settings.backup_codes == ["1", "2", "3"] +      assert response == %{"error" => "Invalid password."} +    end + +    test "returns error if code incorrect", %{conn: conn} do +      secret = TOTP.generate_secret() + +      user = +        insert(:user, +          multi_factor_authentication_settings: %Settings{ +            backup_codes: ["1", "2", "3"], +            totp: %Settings.TOTP{secret: secret} +          } +        ) + +      token = insert(:oauth_token, scopes: ["write", "follow"], user: user) +      token2 = insert(:oauth_token, scopes: ["read"]) + +      response = +        conn +        |> put_req_header("authorization", "Bearer #{token.token}") +        |> post("/api/pleroma/accounts/mfa/confirm/totp", %{password: "test", code: "code"}) +        |> json_response(422) + +      settings = refresh_record(user).multi_factor_authentication_settings +      refute settings.enabled +      refute settings.totp.confirmed +      assert settings.backup_codes == ["1", "2", "3"] +      assert response == %{"error" => "invalid_token"} + +      assert conn +             |> put_req_header("authorization", "Bearer #{token2.token}") +             |> post("/api/pleroma/accounts/mfa/confirm/totp", %{password: "test", code: "code"}) +             |> json_response(403) == %{ +               "error" => "Insufficient permissions: write:security." +             } +    end +  end + +  describe "DELETE /api/pleroma/accounts/mfa/totp" do +    test "returns success result", %{conn: conn} do +      user = +        insert(:user, +          multi_factor_authentication_settings: %Settings{ +            backup_codes: ["1", "2", "3"], +            totp: %Settings.TOTP{secret: "secret"} +          } +        ) + +      token = insert(:oauth_token, scopes: ["write", "follow"], user: user) +      token2 = insert(:oauth_token, scopes: ["read"]) + +      assert conn +             |> put_req_header("authorization", "Bearer #{token.token}") +             |> delete("/api/pleroma/accounts/mfa/totp", %{password: "test"}) +             |> json_response(:ok) + +      settings = refresh_record(user).multi_factor_authentication_settings +      refute settings.enabled +      assert settings.totp.secret == nil +      refute settings.totp.confirmed + +      assert conn +             |> put_req_header("authorization", "Bearer #{token2.token}") +             |> delete("/api/pleroma/accounts/mfa/totp", %{password: "test"}) +             |> json_response(403) == %{ +               "error" => "Insufficient permissions: write:security." +             } +    end +  end +end | 
