diff options
| author | Mark Felder <feld@FreeBSD.org> | 2020-06-12 16:52:52 -0500 | 
|---|---|---|
| committer | Mark Felder <feld@FreeBSD.org> | 2020-06-12 16:52:52 -0500 | 
| commit | 26f710b9e36d286ee34dd679fdaf99e39d8c0bf2 (patch) | |
| tree | 168a4f0522a19d424aaaefa0c85e63139c8fead2 /test | |
| parent | a42d135cce3e6326cd8a16f08f4ab83633386c2e (diff) | |
| parent | e2793744c5dced3ced98acb21a2ef2b13ab65ac9 (diff) | |
| download | pleroma-26f710b9e36d286ee34dd679fdaf99e39d8c0bf2.tar.gz pleroma-26f710b9e36d286ee34dd679fdaf99e39d8c0bf2.zip | |
Merge branch 'develop' into preload-data
Diffstat (limited to 'test')
37 files changed, 3477 insertions, 1500 deletions
| diff --git a/test/chat/message_reference_test.exs b/test/chat/message_reference_test.exs new file mode 100644 index 000000000..aaa7c1ad4 --- /dev/null +++ b/test/chat/message_reference_test.exs @@ -0,0 +1,29 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Chat.MessageReferenceTest do +  use Pleroma.DataCase, async: true + +  alias Pleroma.Chat +  alias Pleroma.Chat.MessageReference +  alias Pleroma.Web.CommonAPI + +  import Pleroma.Factory + +  describe "messages" do +    test "it returns the last message in a chat" do +      user = insert(:user) +      recipient = insert(:user) + +      {:ok, _message_1} = CommonAPI.post_chat_message(user, recipient, "hey") +      {:ok, _message_2} = CommonAPI.post_chat_message(recipient, user, "ho") + +      {:ok, chat} = Chat.get_or_create(user.id, recipient.ap_id) + +      message = MessageReference.last_message_for_chat(chat) + +      assert message.object.data["content"] == "ho" +    end +  end +end diff --git a/test/chat_test.exs b/test/chat_test.exs new file mode 100644 index 000000000..332f2180a --- /dev/null +++ b/test/chat_test.exs @@ -0,0 +1,61 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.ChatTest do +  use Pleroma.DataCase, async: true + +  alias Pleroma.Chat + +  import Pleroma.Factory + +  describe "creation and getting" do +    test "it only works if the recipient is a valid user (for now)" do +      user = insert(:user) + +      assert {:error, _chat} = Chat.bump_or_create(user.id, "http://some/nonexisting/account") +      assert {:error, _chat} = Chat.get_or_create(user.id, "http://some/nonexisting/account") +    end + +    test "it creates a chat for a user and recipient" do +      user = insert(:user) +      other_user = insert(:user) + +      {:ok, chat} = Chat.bump_or_create(user.id, other_user.ap_id) + +      assert chat.id +    end + +    test "it returns and bumps a chat for a user and recipient if it already exists" do +      user = insert(:user) +      other_user = insert(:user) + +      {:ok, chat} = Chat.bump_or_create(user.id, other_user.ap_id) +      {:ok, chat_two} = Chat.bump_or_create(user.id, other_user.ap_id) + +      assert chat.id == chat_two.id +    end + +    test "it returns a chat for a user and recipient if it already exists" do +      user = insert(:user) +      other_user = insert(:user) + +      {:ok, chat} = Chat.get_or_create(user.id, other_user.ap_id) +      {:ok, chat_two} = Chat.get_or_create(user.id, other_user.ap_id) + +      assert chat.id == chat_two.id +    end + +    test "a returning chat will have an updated `update_at` field" do +      user = insert(:user) +      other_user = insert(:user) + +      {:ok, chat} = Chat.bump_or_create(user.id, other_user.ap_id) +      :timer.sleep(1500) +      {:ok, chat_two} = Chat.bump_or_create(user.id, other_user.ap_id) + +      assert chat.id == chat_two.id +      assert chat.updated_at != chat_two.updated_at +    end +  end +end diff --git a/test/fixtures/create-chat-message.json b/test/fixtures/create-chat-message.json new file mode 100644 index 000000000..9c23a1c9b --- /dev/null +++ b/test/fixtures/create-chat-message.json @@ -0,0 +1,31 @@ +{ +  "actor": "http://2hu.gensokyo/users/raymoo", +  "id": "http://2hu.gensokyo/objects/1", +  "object": { +    "attributedTo": "http://2hu.gensokyo/users/raymoo", +    "content": "You expected a cute girl? Too bad. <script>alert('XSS')</script>", +    "id": "http://2hu.gensokyo/objects/2", +    "published": "2020-02-12T14:08:20Z", +    "to": [ +      "http://2hu.gensokyo/users/marisa" +    ], +    "tag": [ +      { +        "icon": { +          "type": "Image", +          "url": "http://2hu.gensokyo/emoji/Firefox.gif" +        }, +        "id": "http://2hu.gensokyo/emoji/Firefox.gif", +        "name": ":firefox:", +        "type": "Emoji", +        "updated": "1970-01-01T00:00:00Z" +      } +    ], +    "type": "ChatMessage" +  }, +  "published": "2018-02-12T14:08:20Z", +  "to": [ +    "http://2hu.gensokyo/users/marisa" +  ], +  "type": "Create" +} diff --git a/test/migration_helper/notification_backfill_test.exs b/test/migration_helper/notification_backfill_test.exs new file mode 100644 index 000000000..2a62a2b00 --- /dev/null +++ b/test/migration_helper/notification_backfill_test.exs @@ -0,0 +1,56 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.MigrationHelper.NotificationBackfillTest do +  use Pleroma.DataCase + +  alias Pleroma.Activity +  alias Pleroma.MigrationHelper.NotificationBackfill +  alias Pleroma.Notification +  alias Pleroma.Repo +  alias Pleroma.Web.CommonAPI + +  import Pleroma.Factory + +  describe "fill_in_notification_types" do +    test "it fills in missing notification types" do +      user = insert(:user) +      other_user = insert(:user) + +      {:ok, post} = CommonAPI.post(user, %{status: "yeah, @#{other_user.nickname}"}) +      {:ok, chat} = CommonAPI.post_chat_message(user, other_user, "yo") +      {:ok, react} = CommonAPI.react_with_emoji(post.id, other_user, "☕") +      {:ok, like} = CommonAPI.favorite(other_user, post.id) +      {:ok, react_2} = CommonAPI.react_with_emoji(post.id, other_user, "☕") + +      data = +        react_2.data +        |> Map.put("type", "EmojiReaction") + +      {:ok, react_2} = +        react_2 +        |> Activity.change(%{data: data}) +        |> Repo.update() + +      assert {5, nil} = Repo.update_all(Notification, set: [type: nil]) + +      NotificationBackfill.fill_in_notification_types() + +      assert %{type: "mention"} = +               Repo.get_by(Notification, user_id: other_user.id, activity_id: post.id) + +      assert %{type: "favourite"} = +               Repo.get_by(Notification, user_id: user.id, activity_id: like.id) + +      assert %{type: "pleroma:emoji_reaction"} = +               Repo.get_by(Notification, user_id: user.id, activity_id: react.id) + +      assert %{type: "pleroma:emoji_reaction"} = +               Repo.get_by(Notification, user_id: user.id, activity_id: react_2.id) + +      assert %{type: "pleroma:chat_mention"} = +               Repo.get_by(Notification, user_id: other_user.id, activity_id: chat.id) +    end +  end +end diff --git a/test/notification_test.exs b/test/notification_test.exs index 37c255fee..b9bbdceca 100644 --- a/test/notification_test.exs +++ b/test/notification_test.exs @@ -10,6 +10,7 @@ defmodule Pleroma.NotificationTest do    alias Pleroma.FollowingRelationship    alias Pleroma.Notification +  alias Pleroma.Repo    alias Pleroma.Tests.ObanHelpers    alias Pleroma.User    alias Pleroma.Web.ActivityPub.ActivityPub @@ -31,6 +32,7 @@ defmodule Pleroma.NotificationTest do        {:ok, [notification]} = Notification.create_notifications(activity)        assert notification.user_id == user.id +      assert notification.type == "pleroma:emoji_reaction"      end      test "notifies someone when they are directly addressed" do @@ -48,6 +50,7 @@ defmodule Pleroma.NotificationTest do        notified_ids = Enum.sort([notification.user_id, other_notification.user_id])        assert notified_ids == [other_user.id, third_user.id]        assert notification.activity_id == activity.id +      assert notification.type == "mention"        assert other_notification.activity_id == activity.id        assert [%Pleroma.Marker{unread_count: 2}] = @@ -335,9 +338,12 @@ defmodule Pleroma.NotificationTest do        # After request is accepted, the same notification is rendered with type "follow":        assert {:ok, _} = CommonAPI.accept_follow_request(user, followed_user) -      notification_id = notification.id -      assert [%{id: ^notification_id}] = Notification.for_user(followed_user) -      assert %{type: "follow"} = NotificationView.render("show.json", render_opts) +      notification = +        Repo.get(Notification, notification.id) +        |> Repo.preload(:activity) + +      assert %{type: "follow"} = +               NotificationView.render("show.json", notification: notification, for: followed_user)      end      test "it doesn't create a notification for follow-unfollow-follow chains" do diff --git a/test/pagination_test.exs b/test/pagination_test.exs index d5b1b782d..9165427ae 100644 --- a/test/pagination_test.exs +++ b/test/pagination_test.exs @@ -21,7 +21,7 @@ defmodule Pleroma.PaginationTest do        id = Enum.at(notes, 2).id |> Integer.to_string()        %{total: total, items: paginated} = -        Pagination.fetch_paginated(Object, %{"min_id" => id, "total" => true}) +        Pagination.fetch_paginated(Object, %{min_id: id, total: true})        assert length(paginated) == 2        assert total == 5 @@ -31,7 +31,7 @@ defmodule Pleroma.PaginationTest do        id = Enum.at(notes, 2).id |> Integer.to_string()        %{total: total, items: paginated} = -        Pagination.fetch_paginated(Object, %{"since_id" => id, "total" => true}) +        Pagination.fetch_paginated(Object, %{since_id: id, total: true})        assert length(paginated) == 2        assert total == 5 @@ -41,7 +41,7 @@ defmodule Pleroma.PaginationTest do        id = Enum.at(notes, 1).id |> Integer.to_string()        %{total: total, items: paginated} = -        Pagination.fetch_paginated(Object, %{"max_id" => id, "total" => true}) +        Pagination.fetch_paginated(Object, %{max_id: id, total: true})        assert length(paginated) == 1        assert total == 5 @@ -50,7 +50,7 @@ defmodule Pleroma.PaginationTest do      test "paginates by min_id & limit", %{notes: notes} do        id = Enum.at(notes, 2).id |> Integer.to_string() -      paginated = Pagination.fetch_paginated(Object, %{"min_id" => id, "limit" => 1}) +      paginated = Pagination.fetch_paginated(Object, %{min_id: id, limit: 1})        assert length(paginated) == 1      end @@ -64,13 +64,13 @@ defmodule Pleroma.PaginationTest do      end      test "paginates by limit" do -      paginated = Pagination.fetch_paginated(Object, %{"limit" => 2}, :offset) +      paginated = Pagination.fetch_paginated(Object, %{limit: 2}, :offset)        assert length(paginated) == 2      end      test "paginates by limit & offset" do -      paginated = Pagination.fetch_paginated(Object, %{"limit" => 2, "offset" => 4}, :offset) +      paginated = Pagination.fetch_paginated(Object, %{limit: 2, offset: 4}, :offset)        assert length(paginated) == 1      end diff --git a/test/tasks/relay_test.exs b/test/tasks/relay_test.exs index 678288854..a8ba0658d 100644 --- a/test/tasks/relay_test.exs +++ b/test/tasks/relay_test.exs @@ -62,11 +62,11 @@ defmodule Mix.Tasks.Pleroma.RelayTest do        [undo_activity] =          ActivityPub.fetch_activities([], %{ -          "type" => "Undo", -          "actor_id" => follower_id, -          "limit" => 1, -          "skip_preload" => true, -          "invisible_actors" => true +          type: "Undo", +          actor_id: follower_id, +          limit: 1, +          skip_preload: true, +          invisible_actors: true          })        assert undo_activity.data["type"] == "Undo" diff --git a/test/tasks/user_test.exs b/test/tasks/user_test.exs index b55aa1cdb..9220d23fc 100644 --- a/test/tasks/user_test.exs +++ b/test/tasks/user_test.exs @@ -4,6 +4,7 @@  defmodule Mix.Tasks.Pleroma.UserTest do    alias Pleroma.Activity +  alias Pleroma.MFA    alias Pleroma.Object    alias Pleroma.Repo    alias Pleroma.Tests.ObanHelpers @@ -278,6 +279,35 @@ defmodule Mix.Tasks.Pleroma.UserTest do      end    end +  describe "running reset_mfa" do +    test "disables MFA" do +      user = +        insert(:user, +          multi_factor_authentication_settings: %MFA.Settings{ +            enabled: true, +            totp: %MFA.Settings.TOTP{secret: "xx", confirmed: true} +          } +        ) + +      Mix.Tasks.Pleroma.User.run(["reset_mfa", user.nickname]) + +      assert_received {:mix_shell, :info, [message]} +      assert message == "Multi-Factor Authentication disabled for #{user.nickname}" + +      assert %{enabled: false, totp: false} == +               user.nickname +               |> User.get_cached_by_nickname() +               |> MFA.mfa_settings() +    end + +    test "no user to reset MFA" do +      Mix.Tasks.Pleroma.User.run(["reset_password", "nonexistent"]) + +      assert_received {:mix_shell, :error, [message]} +      assert message =~ "No local user" +    end +  end +    describe "running invite" do      test "invite token is generated" do        assert capture_io(fn -> diff --git a/test/upload_test.exs b/test/upload_test.exs index 060a940bb..2abf0edec 100644 --- a/test/upload_test.exs +++ b/test/upload_test.exs @@ -54,6 +54,7 @@ defmodule Pleroma.UploadTest do                  %{                    "name" => "image.jpg",                    "type" => "Document", +                  "mediaType" => "image/jpeg",                    "url" => [                      %{                        "href" => "http://localhost:4001/media/post-process-file.jpg", diff --git a/test/user_test.exs b/test/user_test.exs index 6b344158d..98c79da4f 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -1122,7 +1122,7 @@ defmodule Pleroma.UserTest do        assert [%{activity | thread_muted?: CommonAPI.thread_muted?(user2, activity)}] ==                 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{ -                 "user" => user2 +                 user: user2                 })        {:ok, _user} = User.deactivate(user) @@ -1132,7 +1132,7 @@ defmodule Pleroma.UserTest do        assert [] ==                 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{ -                 "user" => user2 +                 user: user2                 })      end    end @@ -1159,6 +1159,9 @@ defmodule Pleroma.UserTest do        follower = insert(:user)        {:ok, follower} = User.follow(follower, user) +      locked_user = insert(:user, name: "locked", locked: true) +      {:ok, _} = User.follow(user, locked_user, :follow_pending) +        object = insert(:note, user: user)        activity = insert(:note_activity, user: user, note: object) @@ -1177,6 +1180,8 @@ defmodule Pleroma.UserTest do        refute User.following?(follower, user)        assert %{deactivated: true} = User.get_by_id(user.id) +      assert [] == User.get_follow_requests(locked_user) +        user_activities =          user.ap_id          |> Activity.Queries.by_actor() diff --git a/test/web/activity_pub/activity_pub_controller_test.exs b/test/web/activity_pub/activity_pub_controller_test.exs index 24edab41a..e490a5744 100644 --- a/test/web/activity_pub/activity_pub_controller_test.exs +++ b/test/web/activity_pub/activity_pub_controller_test.exs @@ -804,17 +804,63 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do    end    describe "GET /users/:nickname/outbox" do +    test "it paginates correctly", %{conn: conn} do +      user = insert(:user) +      conn = assign(conn, :user, user) +      outbox_endpoint = user.ap_id <> "/outbox" + +      _posts = +        for i <- 0..25 do +          {:ok, activity} = CommonAPI.post(user, %{status: "post #{i}"}) +          activity +        end + +      result = +        conn +        |> put_req_header("accept", "application/activity+json") +        |> get(outbox_endpoint <> "?page=true") +        |> json_response(200) + +      result_ids = Enum.map(result["orderedItems"], fn x -> x["id"] end) +      assert length(result["orderedItems"]) == 20 +      assert length(result_ids) == 20 +      assert result["next"] +      assert String.starts_with?(result["next"], outbox_endpoint) + +      result_next = +        conn +        |> put_req_header("accept", "application/activity+json") +        |> get(result["next"]) +        |> json_response(200) + +      result_next_ids = Enum.map(result_next["orderedItems"], fn x -> x["id"] end) +      assert length(result_next["orderedItems"]) == 6 +      assert length(result_next_ids) == 6 +      refute Enum.find(result_next_ids, fn x -> x in result_ids end) +      refute Enum.find(result_ids, fn x -> x in result_next_ids end) +      assert String.starts_with?(result["id"], outbox_endpoint) + +      result_next_again = +        conn +        |> put_req_header("accept", "application/activity+json") +        |> get(result_next["id"]) +        |> json_response(200) + +      assert result_next == result_next_again +    end +      test "it returns 200 even if there're no activities", %{conn: conn} do        user = insert(:user) +      outbox_endpoint = user.ap_id <> "/outbox"        conn =          conn          |> assign(:user, user)          |> put_req_header("accept", "application/activity+json") -        |> get("/users/#{user.nickname}/outbox") +        |> get(outbox_endpoint)        result = json_response(conn, 200) -      assert user.ap_id <> "/outbox" == result["id"] +      assert outbox_endpoint == result["id"]      end      test "it returns a note activity in a collection", %{conn: conn} do diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs index 3dcb62873..7693f6400 100644 --- a/test/web/activity_pub/activity_pub_test.exs +++ b/test/web/activity_pub/activity_pub_test.exs @@ -82,30 +82,28 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        {:ok, private_activity} = CommonAPI.post(user, %{status: ".", visibility: "private"}) -      activities = -        ActivityPub.fetch_activities([], %{:visibility => "direct", "actor_id" => user.ap_id}) +      activities = ActivityPub.fetch_activities([], %{visibility: "direct", actor_id: user.ap_id})        assert activities == [direct_activity]        activities = -        ActivityPub.fetch_activities([], %{:visibility => "unlisted", "actor_id" => user.ap_id}) +        ActivityPub.fetch_activities([], %{visibility: "unlisted", actor_id: user.ap_id})        assert activities == [unlisted_activity]        activities = -        ActivityPub.fetch_activities([], %{:visibility => "private", "actor_id" => user.ap_id}) +        ActivityPub.fetch_activities([], %{visibility: "private", actor_id: user.ap_id})        assert activities == [private_activity] -      activities = -        ActivityPub.fetch_activities([], %{:visibility => "public", "actor_id" => user.ap_id}) +      activities = ActivityPub.fetch_activities([], %{visibility: "public", actor_id: user.ap_id})        assert activities == [public_activity]        activities =          ActivityPub.fetch_activities([], %{ -          :visibility => ~w[private public], -          "actor_id" => user.ap_id +          visibility: ~w[private public], +          actor_id: user.ap_id          })        assert activities == [public_activity, private_activity] @@ -126,8 +124,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        activities =          ActivityPub.fetch_activities([], %{ -          "exclude_visibilities" => "direct", -          "actor_id" => user.ap_id +          exclude_visibilities: "direct", +          actor_id: user.ap_id          })        assert public_activity in activities @@ -137,8 +135,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        activities =          ActivityPub.fetch_activities([], %{ -          "exclude_visibilities" => "unlisted", -          "actor_id" => user.ap_id +          exclude_visibilities: "unlisted", +          actor_id: user.ap_id          })        assert public_activity in activities @@ -148,8 +146,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        activities =          ActivityPub.fetch_activities([], %{ -          "exclude_visibilities" => "private", -          "actor_id" => user.ap_id +          exclude_visibilities: "private", +          actor_id: user.ap_id          })        assert public_activity in activities @@ -159,8 +157,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        activities =          ActivityPub.fetch_activities([], %{ -          "exclude_visibilities" => "public", -          "actor_id" => user.ap_id +          exclude_visibilities: "public", +          actor_id: user.ap_id          })        refute public_activity in activities @@ -193,23 +191,22 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        {:ok, status_two} = CommonAPI.post(user, %{status: ". #essais"})        {:ok, status_three} = CommonAPI.post(user, %{status: ". #test #reject"}) -      fetch_one = ActivityPub.fetch_activities([], %{"type" => "Create", "tag" => "test"}) +      fetch_one = ActivityPub.fetch_activities([], %{type: "Create", tag: "test"}) -      fetch_two = -        ActivityPub.fetch_activities([], %{"type" => "Create", "tag" => ["test", "essais"]}) +      fetch_two = ActivityPub.fetch_activities([], %{type: "Create", tag: ["test", "essais"]})        fetch_three =          ActivityPub.fetch_activities([], %{ -          "type" => "Create", -          "tag" => ["test", "essais"], -          "tag_reject" => ["reject"] +          type: "Create", +          tag: ["test", "essais"], +          tag_reject: ["reject"]          })        fetch_four =          ActivityPub.fetch_activities([], %{ -          "type" => "Create", -          "tag" => ["test"], -          "tag_all" => ["test", "reject"] +          type: "Create", +          tag: ["test"], +          tag_all: ["test", "reject"]          })        assert fetch_one == [status_one, status_three] @@ -375,7 +372,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        _listen_activity_2 = insert(:listen)        _listen_activity_3 = insert(:listen) -      timeline = ActivityPub.fetch_activities([], %{"type" => ["Listen"]}) +      timeline = ActivityPub.fetch_activities([], %{type: ["Listen"]})        assert length(timeline) == 3      end @@ -507,7 +504,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        {:ok, _user_relationship} = User.block(user, %{ap_id: activity_five.data["actor"]}) -      activities = ActivityPub.fetch_activities_for_context("2hu", %{"blocking_user" => user}) +      activities = ActivityPub.fetch_activities_for_context("2hu", %{blocking_user: user})        assert activities == [activity_two, activity]      end    end @@ -520,8 +517,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      booster = insert(:user)      {:ok, _user_relationship} = User.block(user, %{ap_id: activity_one.data["actor"]}) -    activities = -      ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true}) +    activities = ActivityPub.fetch_activities([], %{blocking_user: user, skip_preload: true})      assert Enum.member?(activities, activity_two)      assert Enum.member?(activities, activity_three) @@ -529,8 +525,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      {:ok, _user_block} = User.unblock(user, %{ap_id: activity_one.data["actor"]}) -    activities = -      ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true}) +    activities = ActivityPub.fetch_activities([], %{blocking_user: user, skip_preload: true})      assert Enum.member?(activities, activity_two)      assert Enum.member?(activities, activity_three) @@ -541,16 +536,14 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      %Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id)      activity_three = Activity.get_by_id(activity_three.id) -    activities = -      ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true}) +    activities = ActivityPub.fetch_activities([], %{blocking_user: user, skip_preload: true})      assert Enum.member?(activities, activity_two)      refute Enum.member?(activities, activity_three)      refute Enum.member?(activities, boost_activity)      assert Enum.member?(activities, activity_one) -    activities = -      ActivityPub.fetch_activities([], %{"blocking_user" => nil, "skip_preload" => true}) +    activities = ActivityPub.fetch_activities([], %{blocking_user: nil, skip_preload: true})      assert Enum.member?(activities, activity_two)      assert Enum.member?(activities, activity_three) @@ -573,7 +566,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      {:ok, activity_four} = CommonAPI.post(blockee, %{status: "hey! @#{blocker.nickname}"}) -    activities = ActivityPub.fetch_activities([], %{"blocking_user" => blocker}) +    activities = ActivityPub.fetch_activities([], %{blocking_user: blocker})      assert Enum.member?(activities, activity_one)      refute Enum.member?(activities, activity_two) @@ -581,7 +574,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      refute Enum.member?(activities, activity_four)    end -  test "doesn't return announce activities concerning blocked users" do +  test "doesn't return announce activities with blocked users in 'to'" do      blocker = insert(:user)      blockee = insert(:user)      friend = insert(:user) @@ -595,7 +588,40 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      {:ok, activity_three} = CommonAPI.repeat(activity_two.id, friend)      activities = -      ActivityPub.fetch_activities([], %{"blocking_user" => blocker}) +      ActivityPub.fetch_activities([], %{blocking_user: blocker}) +      |> Enum.map(fn act -> act.id end) + +    assert Enum.member?(activities, activity_one.id) +    refute Enum.member?(activities, activity_two.id) +    refute Enum.member?(activities, activity_three.id) +  end + +  test "doesn't return announce activities with blocked users in 'cc'" do +    blocker = insert(:user) +    blockee = insert(:user) +    friend = insert(:user) + +    {:ok, _user_relationship} = User.block(blocker, blockee) + +    {:ok, activity_one} = CommonAPI.post(friend, %{status: "hey!"}) + +    {:ok, activity_two} = CommonAPI.post(blockee, %{status: "hey! @#{friend.nickname}"}) + +    assert object = Pleroma.Object.normalize(activity_two) + +    data = %{ +      "actor" => friend.ap_id, +      "object" => object.data["id"], +      "context" => object.data["context"], +      "type" => "Announce", +      "to" => ["https://www.w3.org/ns/activitystreams#Public"], +      "cc" => [blockee.ap_id] +    } + +    assert {:ok, activity_three} = ActivityPub.insert(data) + +    activities = +      ActivityPub.fetch_activities([], %{blocking_user: blocker})        |> Enum.map(fn act -> act.id end)      assert Enum.member?(activities, activity_one.id) @@ -611,8 +637,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      user = insert(:user)      {:ok, user} = User.block_domain(user, domain) -    activities = -      ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true}) +    activities = ActivityPub.fetch_activities([], %{blocking_user: user, skip_preload: true})      refute activity in activities @@ -620,8 +645,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      ActivityPub.follow(user, followed_user)      {:ok, repeat_activity} = CommonAPI.repeat(activity.id, followed_user) -    activities = -      ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true}) +    activities = ActivityPub.fetch_activities([], %{blocking_user: user, skip_preload: true})      refute repeat_activity in activities    end @@ -641,8 +665,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      note = insert(:note, %{data: %{"actor" => domain_user.ap_id}})      activity = insert(:note_activity, %{note: note}) -    activities = -      ActivityPub.fetch_activities([], %{"blocking_user" => blocker, "skip_preload" => true}) +    activities = ActivityPub.fetch_activities([], %{blocking_user: blocker, skip_preload: true})      assert activity in activities @@ -653,8 +676,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      bad_activity = insert(:note_activity, %{note: bad_note})      {:ok, repeat_activity} = CommonAPI.repeat(bad_activity.id, domain_user) -    activities = -      ActivityPub.fetch_activities([], %{"blocking_user" => blocker, "skip_preload" => true}) +    activities = ActivityPub.fetch_activities([], %{blocking_user: blocker, skip_preload: true})      refute repeat_activity in activities    end @@ -669,8 +691,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      activity_one_actor = User.get_by_ap_id(activity_one.data["actor"])      {:ok, _user_relationships} = User.mute(user, activity_one_actor) -    activities = -      ActivityPub.fetch_activities([], %{"muting_user" => user, "skip_preload" => true}) +    activities = ActivityPub.fetch_activities([], %{muting_user: user, skip_preload: true})      assert Enum.member?(activities, activity_two)      assert Enum.member?(activities, activity_three) @@ -679,9 +700,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      # Calling with 'with_muted' will deliver muted activities, too.      activities =        ActivityPub.fetch_activities([], %{ -        "muting_user" => user, -        "with_muted" => true, -        "skip_preload" => true +        muting_user: user, +        with_muted: true, +        skip_preload: true        })      assert Enum.member?(activities, activity_two) @@ -690,8 +711,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      {:ok, _user_mute} = User.unmute(user, activity_one_actor) -    activities = -      ActivityPub.fetch_activities([], %{"muting_user" => user, "skip_preload" => true}) +    activities = ActivityPub.fetch_activities([], %{muting_user: user, skip_preload: true})      assert Enum.member?(activities, activity_two)      assert Enum.member?(activities, activity_three) @@ -703,15 +723,14 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      %Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id)      activity_three = Activity.get_by_id(activity_three.id) -    activities = -      ActivityPub.fetch_activities([], %{"muting_user" => user, "skip_preload" => true}) +    activities = ActivityPub.fetch_activities([], %{muting_user: user, skip_preload: true})      assert Enum.member?(activities, activity_two)      refute Enum.member?(activities, activity_three)      refute Enum.member?(activities, boost_activity)      assert Enum.member?(activities, activity_one) -    activities = ActivityPub.fetch_activities([], %{"muting_user" => nil, "skip_preload" => true}) +    activities = ActivityPub.fetch_activities([], %{muting_user: nil, skip_preload: true})      assert Enum.member?(activities, activity_two)      assert Enum.member?(activities, activity_three) @@ -727,7 +746,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      {:ok, _activity_two} = CommonAPI.add_mute(user, activity_two) -    assert [_activity_one] = ActivityPub.fetch_activities([], %{"muting_user" => user}) +    assert [_activity_one] = ActivityPub.fetch_activities([], %{muting_user: user})    end    test "returns thread muted activities when with_muted is set" do @@ -739,7 +758,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      {:ok, _activity_two} = CommonAPI.add_mute(user, activity_two)      assert [_activity_two, _activity_one] = -             ActivityPub.fetch_activities([], %{"muting_user" => user, "with_muted" => true}) +             ActivityPub.fetch_activities([], %{muting_user: user, with_muted: true})    end    test "does include announces on request" do @@ -761,7 +780,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      {:ok, expected_activity} = ActivityBuilder.insert(%{"type" => "Create"}, %{:user => user})      {:ok, _} = ActivityBuilder.insert(%{"type" => "Announce"}, %{:user => user}) -    [activity] = ActivityPub.fetch_user_activities(user, nil, %{"exclude_reblogs" => "true"}) +    [activity] = ActivityPub.fetch_user_activities(user, nil, %{exclude_reblogs: true})      assert activity == expected_activity    end @@ -804,7 +823,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        expected_activities = ActivityBuilder.insert_list(10)        since_id = List.last(activities).id -      activities = ActivityPub.fetch_public_activities(%{"since_id" => since_id}) +      activities = ActivityPub.fetch_public_activities(%{since_id: since_id})        assert collect_ids(activities) == collect_ids(expected_activities)        assert length(activities) == 10 @@ -819,7 +838,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do          |> ActivityBuilder.insert_list()          |> List.first() -      activities = ActivityPub.fetch_public_activities(%{"max_id" => max_id}) +      activities = ActivityPub.fetch_public_activities(%{max_id: max_id})        assert length(activities) == 20        assert collect_ids(activities) == collect_ids(expected_activities) @@ -831,8 +850,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        later_activities = ActivityBuilder.insert_list(10) -      activities = -        ActivityPub.fetch_public_activities(%{"page" => "2", "page_size" => "20"}, :offset) +      activities = ActivityPub.fetch_public_activities(%{page: "2", page_size: "20"}, :offset)        assert length(activities) == 20 @@ -848,7 +866,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        {:ok, activity} = CommonAPI.repeat(activity.id, booster) -      activities = ActivityPub.fetch_activities([], %{"muting_user" => user}) +      activities = ActivityPub.fetch_activities([], %{muting_user: user})        refute Enum.any?(activities, fn %{id: id} -> id == activity.id end)      end @@ -862,7 +880,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        {:ok, activity} = CommonAPI.repeat(activity.id, booster) -      activities = ActivityPub.fetch_activities([], %{"muting_user" => user}) +      activities = ActivityPub.fetch_activities([], %{muting_user: user})        assert Enum.any?(activities, fn %{id: id} -> id == activity.id end)      end @@ -1066,7 +1084,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        assert length(activities) == 3        activities = -        ActivityPub.fetch_activities([user1.ap_id | User.following(user1)], %{"user" => user1}) +        ActivityPub.fetch_activities([user1.ap_id | User.following(user1)], %{user: user1})          |> Enum.map(fn a -> a.id end)        assert [public_activity.id, private_activity_1.id] == activities @@ -1115,7 +1133,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      CommonAPI.pin(activity_three.id, user)      user = refresh_record(user) -    activities = ActivityPub.fetch_user_activities(user, nil, %{"pinned" => "true"}) +    activities = ActivityPub.fetch_user_activities(user, nil, %{pinned: true})      assert 3 = length(activities)    end @@ -1226,7 +1244,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      activity = Repo.preload(activity, :bookmark)      activity = %Activity{activity | thread_muted?: !!activity.thread_muted?} -    assert ActivityPub.fetch_activities([], %{"user" => user}) == [activity] +    assert ActivityPub.fetch_activities([], %{user: user}) == [activity]    end    def data_uri do @@ -1400,7 +1418,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        assert Enum.map(result, & &1.id) == [a1.id, a5.id, a3.id, a4.id] -      result = ActivityPub.fetch_favourites(user, %{"limit" => 2}) +      result = ActivityPub.fetch_favourites(user, %{limit: 2})        assert Enum.map(result, & &1.id) == [a1.id, a5.id]      end    end @@ -1470,7 +1488,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      {:ok, _reply} = CommonAPI.post(user, %{status: "yeah", in_reply_to_status_id: activity.id}) -    [result] = ActivityPub.fetch_public_activities(%{"exclude_replies" => "true"}) +    [result] = ActivityPub.fetch_public_activities(%{exclude_replies: true})      assert result.id == activity.id @@ -1483,11 +1501,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      test "public timeline", %{users: %{u1: user}} do        activities_ids =          %{} -        |> Map.put("type", ["Create", "Announce"]) -        |> Map.put("local_only", false) -        |> Map.put("blocking_user", user) -        |> Map.put("muting_user", user) -        |> Map.put("reply_filtering_user", user) +        |> Map.put(:type, ["Create", "Announce"]) +        |> Map.put(:local_only, false) +        |> Map.put(:blocking_user, user) +        |> Map.put(:muting_user, user) +        |> Map.put(:reply_filtering_user, user)          |> ActivityPub.fetch_public_activities()          |> Enum.map(& &1.id) @@ -1504,12 +1522,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      } do        activities_ids =          %{} -        |> Map.put("type", ["Create", "Announce"]) -        |> Map.put("local_only", false) -        |> Map.put("blocking_user", user) -        |> Map.put("muting_user", user) -        |> Map.put("reply_visibility", "following") -        |> Map.put("reply_filtering_user", user) +        |> Map.put(:type, ["Create", "Announce"]) +        |> Map.put(:local_only, false) +        |> Map.put(:blocking_user, user) +        |> Map.put(:muting_user, user) +        |> Map.put(:reply_visibility, "following") +        |> Map.put(:reply_filtering_user, user)          |> ActivityPub.fetch_public_activities()          |> Enum.map(& &1.id) @@ -1531,12 +1549,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      } do        activities_ids =          %{} -        |> Map.put("type", ["Create", "Announce"]) -        |> Map.put("local_only", false) -        |> Map.put("blocking_user", user) -        |> Map.put("muting_user", user) -        |> Map.put("reply_visibility", "self") -        |> Map.put("reply_filtering_user", user) +        |> Map.put(:type, ["Create", "Announce"]) +        |> Map.put(:local_only, false) +        |> Map.put(:blocking_user, user) +        |> Map.put(:muting_user, user) +        |> Map.put(:reply_visibility, "self") +        |> Map.put(:reply_filtering_user, user)          |> ActivityPub.fetch_public_activities()          |> Enum.map(& &1.id) @@ -1555,11 +1573,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      } do        params =          %{} -        |> Map.put("type", ["Create", "Announce"]) -        |> Map.put("blocking_user", user) -        |> Map.put("muting_user", user) -        |> Map.put("user", user) -        |> Map.put("reply_filtering_user", user) +        |> Map.put(:type, ["Create", "Announce"]) +        |> Map.put(:blocking_user, user) +        |> Map.put(:muting_user, user) +        |> Map.put(:user, user) +        |> Map.put(:reply_filtering_user, user)        activities_ids =          ActivityPub.fetch_activities([user.ap_id | User.following(user)], params) @@ -1593,12 +1611,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      } do        params =          %{} -        |> Map.put("type", ["Create", "Announce"]) -        |> Map.put("blocking_user", user) -        |> Map.put("muting_user", user) -        |> Map.put("user", user) -        |> Map.put("reply_visibility", "following") -        |> Map.put("reply_filtering_user", user) +        |> Map.put(:type, ["Create", "Announce"]) +        |> Map.put(:blocking_user, user) +        |> Map.put(:muting_user, user) +        |> Map.put(:user, user) +        |> Map.put(:reply_visibility, "following") +        |> Map.put(:reply_filtering_user, user)        activities_ids =          ActivityPub.fetch_activities([user.ap_id | User.following(user)], params) @@ -1632,12 +1650,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      } do        params =          %{} -        |> Map.put("type", ["Create", "Announce"]) -        |> Map.put("blocking_user", user) -        |> Map.put("muting_user", user) -        |> Map.put("user", user) -        |> Map.put("reply_visibility", "self") -        |> Map.put("reply_filtering_user", user) +        |> Map.put(:type, ["Create", "Announce"]) +        |> Map.put(:blocking_user, user) +        |> Map.put(:muting_user, user) +        |> Map.put(:user, user) +        |> Map.put(:reply_visibility, "self") +        |> Map.put(:reply_filtering_user, user)        activities_ids =          ActivityPub.fetch_activities([user.ap_id | User.following(user)], params) @@ -1658,6 +1676,40 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        assert Enum.all?(visible_ids, &(&1 in activities_ids))      end + +    test "filtering out announces where the user is the actor of the announced message" do +      user = insert(:user) +      other_user = insert(:user) +      third_user = insert(:user) +      User.follow(user, other_user) + +      {:ok, post} = CommonAPI.post(user, %{status: "yo"}) +      {:ok, other_post} = CommonAPI.post(third_user, %{status: "yo"}) +      {:ok, _announce} = CommonAPI.repeat(post.id, other_user) +      {:ok, _announce} = CommonAPI.repeat(post.id, third_user) +      {:ok, announce} = CommonAPI.repeat(other_post.id, other_user) + +      params = %{ +        type: ["Announce"] +      } + +      results = +        [user.ap_id | User.following(user)] +        |> ActivityPub.fetch_activities(params) + +      assert length(results) == 3 + +      params = %{ +        type: ["Announce"], +        announce_filtering_user: user +      } + +      [result] = +        [user.ap_id | User.following(user)] +        |> ActivityPub.fetch_activities(params) + +      assert result.id == announce.id +    end    end    describe "replies filtering with private messages" do @@ -1666,11 +1718,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      test "public timeline", %{users: %{u1: user}} do        activities_ids =          %{} -        |> Map.put("type", ["Create", "Announce"]) -        |> Map.put("local_only", false) -        |> Map.put("blocking_user", user) -        |> Map.put("muting_user", user) -        |> Map.put("user", user) +        |> Map.put(:type, ["Create", "Announce"]) +        |> Map.put(:local_only, false) +        |> Map.put(:blocking_user, user) +        |> Map.put(:muting_user, user) +        |> Map.put(:user, user)          |> ActivityPub.fetch_public_activities()          |> Enum.map(& &1.id) @@ -1680,13 +1732,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      test "public timeline with default reply_visibility `following`", %{users: %{u1: user}} do        activities_ids =          %{} -        |> Map.put("type", ["Create", "Announce"]) -        |> Map.put("local_only", false) -        |> Map.put("blocking_user", user) -        |> Map.put("muting_user", user) -        |> Map.put("reply_visibility", "following") -        |> Map.put("reply_filtering_user", user) -        |> Map.put("user", user) +        |> Map.put(:type, ["Create", "Announce"]) +        |> Map.put(:local_only, false) +        |> Map.put(:blocking_user, user) +        |> Map.put(:muting_user, user) +        |> Map.put(:reply_visibility, "following") +        |> Map.put(:reply_filtering_user, user) +        |> Map.put(:user, user)          |> ActivityPub.fetch_public_activities()          |> Enum.map(& &1.id) @@ -1696,13 +1748,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      test "public timeline with default reply_visibility `self`", %{users: %{u1: user}} do        activities_ids =          %{} -        |> Map.put("type", ["Create", "Announce"]) -        |> Map.put("local_only", false) -        |> Map.put("blocking_user", user) -        |> Map.put("muting_user", user) -        |> Map.put("reply_visibility", "self") -        |> Map.put("reply_filtering_user", user) -        |> Map.put("user", user) +        |> Map.put(:type, ["Create", "Announce"]) +        |> Map.put(:local_only, false) +        |> Map.put(:blocking_user, user) +        |> Map.put(:muting_user, user) +        |> Map.put(:reply_visibility, "self") +        |> Map.put(:reply_filtering_user, user) +        |> Map.put(:user, user)          |> ActivityPub.fetch_public_activities()          |> Enum.map(& &1.id) @@ -1712,10 +1764,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      test "home timeline", %{users: %{u1: user}} do        params =          %{} -        |> Map.put("type", ["Create", "Announce"]) -        |> Map.put("blocking_user", user) -        |> Map.put("muting_user", user) -        |> Map.put("user", user) +        |> Map.put(:type, ["Create", "Announce"]) +        |> Map.put(:blocking_user, user) +        |> Map.put(:muting_user, user) +        |> Map.put(:user, user)        activities_ids =          ActivityPub.fetch_activities([user.ap_id | User.following(user)], params) @@ -1727,12 +1779,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      test "home timeline with default reply_visibility `following`", %{users: %{u1: user}} do        params =          %{} -        |> Map.put("type", ["Create", "Announce"]) -        |> Map.put("blocking_user", user) -        |> Map.put("muting_user", user) -        |> Map.put("user", user) -        |> Map.put("reply_visibility", "following") -        |> Map.put("reply_filtering_user", user) +        |> Map.put(:type, ["Create", "Announce"]) +        |> Map.put(:blocking_user, user) +        |> Map.put(:muting_user, user) +        |> Map.put(:user, user) +        |> Map.put(:reply_visibility, "following") +        |> Map.put(:reply_filtering_user, user)        activities_ids =          ActivityPub.fetch_activities([user.ap_id | User.following(user)], params) @@ -1751,12 +1803,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      } do        params =          %{} -        |> Map.put("type", ["Create", "Announce"]) -        |> Map.put("blocking_user", user) -        |> Map.put("muting_user", user) -        |> Map.put("user", user) -        |> Map.put("reply_visibility", "self") -        |> Map.put("reply_filtering_user", user) +        |> Map.put(:type, ["Create", "Announce"]) +        |> Map.put(:blocking_user, user) +        |> Map.put(:muting_user, user) +        |> Map.put(:user, user) +        |> Map.put(:reply_visibility, "self") +        |> Map.put(:reply_filtering_user, user)        activities_ids =          ActivityPub.fetch_activities([user.ap_id | User.following(user)], params) @@ -2001,4 +2053,20 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do               end) =~ "Follower/Following counter update for #{user.ap_id} failed"      end    end + +  describe "global activity expiration" do +    setup do: clear_config([:instance, :rewrite_policy]) + +    test "creates an activity expiration for local Create activities" do +      Pleroma.Config.put( +        [:instance, :rewrite_policy], +        Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicy +      ) + +      {:ok, %{id: id_create}} = ActivityBuilder.insert(%{"type" => "Create", "context" => "3hu"}) +      {:ok, _follow} = ActivityBuilder.insert(%{"type" => "Follow", "context" => "3hu"}) + +      assert [%{activity_id: ^id_create}] = Pleroma.ActivityExpiration |> Repo.all() +    end +  end  end diff --git a/test/web/activity_pub/mrf/activity_expiration_policy_test.exs b/test/web/activity_pub/mrf/activity_expiration_policy_test.exs new file mode 100644 index 000000000..8babf49e7 --- /dev/null +++ b/test/web/activity_pub/mrf/activity_expiration_policy_test.exs @@ -0,0 +1,77 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicyTest do +  use ExUnit.Case, async: true +  alias Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicy + +  @id Pleroma.Web.Endpoint.url() <> "/activities/cofe" + +  test "adds `expires_at` property" do +    assert {:ok, %{"type" => "Create", "expires_at" => expires_at}} = +             ActivityExpirationPolicy.filter(%{ +               "id" => @id, +               "type" => "Create", +               "object" => %{"type" => "Note"} +             }) + +    assert Timex.diff(expires_at, NaiveDateTime.utc_now(), :days) == 364 +  end + +  test "keeps existing `expires_at` if it less than the config setting" do +    expires_at = NaiveDateTime.utc_now() |> Timex.shift(days: 1) + +    assert {:ok, %{"type" => "Create", "expires_at" => ^expires_at}} = +             ActivityExpirationPolicy.filter(%{ +               "id" => @id, +               "type" => "Create", +               "expires_at" => expires_at, +               "object" => %{"type" => "Note"} +             }) +  end + +  test "overwrites existing `expires_at` if it greater than the config setting" do +    too_distant_future = NaiveDateTime.utc_now() |> Timex.shift(years: 2) + +    assert {:ok, %{"type" => "Create", "expires_at" => expires_at}} = +             ActivityExpirationPolicy.filter(%{ +               "id" => @id, +               "type" => "Create", +               "expires_at" => too_distant_future, +               "object" => %{"type" => "Note"} +             }) + +    assert Timex.diff(expires_at, NaiveDateTime.utc_now(), :days) == 364 +  end + +  test "ignores remote activities" do +    assert {:ok, activity} = +             ActivityExpirationPolicy.filter(%{ +               "id" => "https://example.com/123", +               "type" => "Create", +               "object" => %{"type" => "Note"} +             }) + +    refute Map.has_key?(activity, "expires_at") +  end + +  test "ignores non-Create/Note activities" do +    assert {:ok, activity} = +             ActivityExpirationPolicy.filter(%{ +               "id" => "https://example.com/123", +               "type" => "Follow" +             }) + +    refute Map.has_key?(activity, "expires_at") + +    assert {:ok, activity} = +             ActivityExpirationPolicy.filter(%{ +               "id" => "https://example.com/123", +               "type" => "Create", +               "object" => %{"type" => "Cofe"} +             }) + +    refute Map.has_key?(activity, "expires_at") +  end +end diff --git a/test/web/activity_pub/object_validator_test.exs b/test/web/activity_pub/object_validator_test.exs index 7953eecf2..31224abe0 100644 --- a/test/web/activity_pub/object_validator_test.exs +++ b/test/web/activity_pub/object_validator_test.exs @@ -2,14 +2,264 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidatorTest do    use Pleroma.DataCase    alias Pleroma.Object +  alias Pleroma.Web.ActivityPub.ActivityPub    alias Pleroma.Web.ActivityPub.Builder    alias Pleroma.Web.ActivityPub.ObjectValidator +  alias Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidator    alias Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator    alias Pleroma.Web.ActivityPub.Utils    alias Pleroma.Web.CommonAPI    import Pleroma.Factory +  describe "attachments" do +    test "works with honkerific attachments" do +      attachment = %{ +        "mediaType" => "", +        "name" => "", +        "summary" => "298p3RG7j27tfsZ9RQ.jpg", +        "type" => "Document", +        "url" => "https://honk.tedunangst.com/d/298p3RG7j27tfsZ9RQ.jpg" +      } + +      assert {:ok, attachment} = +               AttachmentValidator.cast_and_validate(attachment) +               |> Ecto.Changeset.apply_action(:insert) + +      assert attachment.mediaType == "application/octet-stream" +    end + +    test "it turns mastodon attachments into our attachments" do +      attachment = %{ +        "url" => +          "http://mastodon.example.org/system/media_attachments/files/000/000/002/original/334ce029e7bfb920.jpg", +        "type" => "Document", +        "name" => nil, +        "mediaType" => "image/jpeg" +      } + +      {:ok, attachment} = +        AttachmentValidator.cast_and_validate(attachment) +        |> Ecto.Changeset.apply_action(:insert) + +      assert [ +               %{ +                 href: +                   "http://mastodon.example.org/system/media_attachments/files/000/000/002/original/334ce029e7bfb920.jpg", +                 type: "Link", +                 mediaType: "image/jpeg" +               } +             ] = attachment.url + +      assert attachment.mediaType == "image/jpeg" +    end + +    test "it handles our own uploads" do +      user = insert(:user) + +      file = %Plug.Upload{ +        content_type: "image/jpg", +        path: Path.absname("test/fixtures/image.jpg"), +        filename: "an_image.jpg" +      } + +      {:ok, attachment} = ActivityPub.upload(file, actor: user.ap_id) + +      {:ok, attachment} = +        attachment.data +        |> AttachmentValidator.cast_and_validate() +        |> Ecto.Changeset.apply_action(:insert) + +      assert attachment.mediaType == "image/jpeg" +    end +  end + +  describe "chat message create activities" do +    test "it is invalid if the object already exists" do +      user = insert(:user) +      recipient = insert(:user) +      {:ok, activity} = CommonAPI.post_chat_message(user, recipient, "hey") +      object = Object.normalize(activity, false) + +      {:ok, create_data, _} = Builder.create(user, object.data, [recipient.ap_id]) + +      {:error, cng} = ObjectValidator.validate(create_data, []) + +      assert {:object, {"The object to create already exists", []}} in cng.errors +    end + +    test "it is invalid if the object data has a different `to` or `actor` field" do +      user = insert(:user) +      recipient = insert(:user) +      {:ok, object_data, _} = Builder.chat_message(recipient, user.ap_id, "Hey") + +      {:ok, create_data, _} = Builder.create(user, object_data, [recipient.ap_id]) + +      {:error, cng} = ObjectValidator.validate(create_data, []) + +      assert {:to, {"Recipients don't match with object recipients", []}} in cng.errors +      assert {:actor, {"Actor doesn't match with object actor", []}} in cng.errors +    end +  end + +  describe "chat messages" do +    setup do +      clear_config([:instance, :remote_limit]) +      user = insert(:user) +      recipient = insert(:user, local: false) + +      {:ok, valid_chat_message, _} = Builder.chat_message(user, recipient.ap_id, "hey :firefox:") + +      %{user: user, recipient: recipient, valid_chat_message: valid_chat_message} +    end + +    test "let's through some basic html", %{user: user, recipient: recipient} do +      {:ok, valid_chat_message, _} = +        Builder.chat_message( +          user, +          recipient.ap_id, +          "hey <a href='https://example.org'>example</a> <script>alert('uguu')</script>" +        ) + +      assert {:ok, object, _meta} = ObjectValidator.validate(valid_chat_message, []) + +      assert object["content"] == +               "hey <a href=\"https://example.org\">example</a> alert('uguu')" +    end + +    test "validates for a basic object we build", %{valid_chat_message: valid_chat_message} do +      assert {:ok, object, _meta} = ObjectValidator.validate(valid_chat_message, []) + +      assert Map.put(valid_chat_message, "attachment", nil) == object +    end + +    test "validates for a basic object with an attachment", %{ +      valid_chat_message: valid_chat_message, +      user: user +    } do +      file = %Plug.Upload{ +        content_type: "image/jpg", +        path: Path.absname("test/fixtures/image.jpg"), +        filename: "an_image.jpg" +      } + +      {:ok, attachment} = ActivityPub.upload(file, actor: user.ap_id) + +      valid_chat_message = +        valid_chat_message +        |> Map.put("attachment", attachment.data) + +      assert {:ok, object, _meta} = ObjectValidator.validate(valid_chat_message, []) + +      assert object["attachment"] +    end + +    test "validates for a basic object with an attachment in an array", %{ +      valid_chat_message: valid_chat_message, +      user: user +    } do +      file = %Plug.Upload{ +        content_type: "image/jpg", +        path: Path.absname("test/fixtures/image.jpg"), +        filename: "an_image.jpg" +      } + +      {:ok, attachment} = ActivityPub.upload(file, actor: user.ap_id) + +      valid_chat_message = +        valid_chat_message +        |> Map.put("attachment", [attachment.data]) + +      assert {:ok, object, _meta} = ObjectValidator.validate(valid_chat_message, []) + +      assert object["attachment"] +    end + +    test "validates for a basic object with an attachment but without content", %{ +      valid_chat_message: valid_chat_message, +      user: user +    } do +      file = %Plug.Upload{ +        content_type: "image/jpg", +        path: Path.absname("test/fixtures/image.jpg"), +        filename: "an_image.jpg" +      } + +      {:ok, attachment} = ActivityPub.upload(file, actor: user.ap_id) + +      valid_chat_message = +        valid_chat_message +        |> Map.put("attachment", attachment.data) +        |> Map.delete("content") + +      assert {:ok, object, _meta} = ObjectValidator.validate(valid_chat_message, []) + +      assert object["attachment"] +    end + +    test "does not validate if the message has no content", %{ +      valid_chat_message: valid_chat_message +    } do +      contentless = +        valid_chat_message +        |> Map.delete("content") + +      refute match?({:ok, _object, _meta}, ObjectValidator.validate(contentless, [])) +    end + +    test "does not validate if the message is longer than the remote_limit", %{ +      valid_chat_message: valid_chat_message +    } do +      Pleroma.Config.put([:instance, :remote_limit], 2) +      refute match?({:ok, _object, _meta}, ObjectValidator.validate(valid_chat_message, [])) +    end + +    test "does not validate if the recipient is blocking the actor", %{ +      valid_chat_message: valid_chat_message, +      user: user, +      recipient: recipient +    } do +      Pleroma.User.block(recipient, user) +      refute match?({:ok, _object, _meta}, ObjectValidator.validate(valid_chat_message, [])) +    end + +    test "does not validate if the actor or the recipient is not in our system", %{ +      valid_chat_message: valid_chat_message +    } do +      chat_message = +        valid_chat_message +        |> Map.put("actor", "https://raymoo.com/raymoo") + +      {:error, _} = ObjectValidator.validate(chat_message, []) + +      chat_message = +        valid_chat_message +        |> Map.put("to", ["https://raymoo.com/raymoo"]) + +      {:error, _} = ObjectValidator.validate(chat_message, []) +    end + +    test "does not validate for a message with multiple recipients", %{ +      valid_chat_message: valid_chat_message, +      user: user, +      recipient: recipient +    } do +      chat_message = +        valid_chat_message +        |> Map.put("to", [user.ap_id, recipient.ap_id]) + +      assert {:error, _} = ObjectValidator.validate(chat_message, []) +    end + +    test "does not validate if it doesn't concern local users" do +      user = insert(:user, local: false) +      recipient = insert(:user, local: false) + +      {:ok, valid_chat_message, _} = Builder.chat_message(user, recipient.ap_id, "hey") +      assert {:error, _} = ObjectValidator.validate(valid_chat_message, []) +    end +  end +    describe "EmojiReacts" do      setup do        user = insert(:user) diff --git a/test/web/activity_pub/object_validators/types/object_id_test.exs b/test/web/activity_pub/object_validators/types/object_id_test.exs index 834213182..c8911948e 100644 --- a/test/web/activity_pub/object_validators/types/object_id_test.exs +++ b/test/web/activity_pub/object_validators/types/object_id_test.exs @@ -1,3 +1,7 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only +  defmodule Pleroma.Web.ObjectValidators.Types.ObjectIDTest do    alias Pleroma.Web.ActivityPub.ObjectValidators.Types.ObjectID    use Pleroma.DataCase diff --git a/test/web/activity_pub/object_validators/types/safe_text_test.exs b/test/web/activity_pub/object_validators/types/safe_text_test.exs new file mode 100644 index 000000000..d4a574554 --- /dev/null +++ b/test/web/activity_pub/object_validators/types/safe_text_test.exs @@ -0,0 +1,30 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.ObjectValidators.Types.SafeTextTest do +  use Pleroma.DataCase + +  alias Pleroma.Web.ActivityPub.ObjectValidators.Types.SafeText + +  test "it lets normal text go through" do +    text = "hey how are you" +    assert {:ok, text} == SafeText.cast(text) +  end + +  test "it removes html tags from text" do +    text = "hey look xss <script>alert('foo')</script>" +    assert {:ok, "hey look xss alert('foo')"} == SafeText.cast(text) +  end + +  test "it keeps basic html tags" do +    text = "hey <a href='http://gensokyo.2hu'>look</a> xss <script>alert('foo')</script>" + +    assert {:ok, "hey <a href=\"http://gensokyo.2hu\">look</a> xss alert('foo')"} == +             SafeText.cast(text) +  end + +  test "errors for non-text" do +    assert :error == SafeText.cast(1) +  end +end diff --git a/test/web/activity_pub/pipeline_test.exs b/test/web/activity_pub/pipeline_test.exs index 26557720b..8deb64501 100644 --- a/test/web/activity_pub/pipeline_test.exs +++ b/test/web/activity_pub/pipeline_test.exs @@ -33,7 +33,10 @@ defmodule Pleroma.Web.ActivityPub.PipelineTest do          {            Pleroma.Web.ActivityPub.SideEffects,            [], -          [handle: fn o, m -> {:ok, o, m} end] +          [ +            handle: fn o, m -> {:ok, o, m} end, +            handle_after_transaction: fn m -> m end +          ]          },          {            Pleroma.Web.Federator, @@ -71,7 +74,7 @@ defmodule Pleroma.Web.ActivityPub.PipelineTest do          {            Pleroma.Web.ActivityPub.SideEffects,            [], -          [handle: fn o, m -> {:ok, o, m} end] +          [handle: fn o, m -> {:ok, o, m} end, handle_after_transaction: fn m -> m end]          },          {            Pleroma.Web.Federator, @@ -110,7 +113,7 @@ defmodule Pleroma.Web.ActivityPub.PipelineTest do          {            Pleroma.Web.ActivityPub.SideEffects,            [], -          [handle: fn o, m -> {:ok, o, m} end] +          [handle: fn o, m -> {:ok, o, m} end, handle_after_transaction: fn m -> m end]          },          {            Pleroma.Web.Federator, diff --git a/test/web/activity_pub/side_effects_test.exs b/test/web/activity_pub/side_effects_test.exs index a80104ea7..6bbbaae87 100644 --- a/test/web/activity_pub/side_effects_test.exs +++ b/test/web/activity_pub/side_effects_test.exs @@ -7,6 +7,8 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do    use Pleroma.DataCase    alias Pleroma.Activity +  alias Pleroma.Chat +  alias Pleroma.Chat.MessageReference    alias Pleroma.Notification    alias Pleroma.Object    alias Pleroma.Repo @@ -20,6 +22,48 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do    import Pleroma.Factory    import Mock +  describe "handle_after_transaction" do +    test "it streams out notifications and streams" do +      author = insert(:user, local: true) +      recipient = insert(:user, local: true) + +      {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey") + +      {:ok, create_activity_data, _meta} = +        Builder.create(author, chat_message_data["id"], [recipient.ap_id]) + +      {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false) + +      {:ok, _create_activity, meta} = +        SideEffects.handle(create_activity, local: false, object_data: chat_message_data) + +      assert [notification] = meta[:notifications] + +      with_mocks([ +        { +          Pleroma.Web.Streamer, +          [], +          [ +            stream: fn _, _ -> nil end +          ] +        }, +        { +          Pleroma.Web.Push, +          [], +          [ +            send: fn _ -> nil end +          ] +        } +      ]) do +        SideEffects.handle_after_transaction(meta) + +        assert called(Pleroma.Web.Streamer.stream(["user", "user:notification"], notification)) +        assert called(Pleroma.Web.Streamer.stream(["user", "user:pleroma_chat"], :_)) +        assert called(Pleroma.Web.Push.send(notification)) +      end +    end +  end +    describe "delete objects" do      setup do        user = insert(:user) @@ -290,6 +334,147 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do      end    end +  describe "creation of ChatMessages" do +    test "notifies the recipient" do +      author = insert(:user, local: false) +      recipient = insert(:user, local: true) + +      {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey") + +      {:ok, create_activity_data, _meta} = +        Builder.create(author, chat_message_data["id"], [recipient.ap_id]) + +      {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false) + +      {:ok, _create_activity, _meta} = +        SideEffects.handle(create_activity, local: false, object_data: chat_message_data) + +      assert Repo.get_by(Notification, user_id: recipient.id, activity_id: create_activity.id) +    end + +    test "it streams the created ChatMessage" do +      author = insert(:user, local: true) +      recipient = insert(:user, local: true) + +      {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey") + +      {:ok, create_activity_data, _meta} = +        Builder.create(author, chat_message_data["id"], [recipient.ap_id]) + +      {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false) + +      {:ok, _create_activity, meta} = +        SideEffects.handle(create_activity, local: false, object_data: chat_message_data) + +      assert [_, _] = meta[:streamables] +    end + +    test "it creates a Chat and MessageReferences for the local users and bumps the unread count, except for the author" do +      author = insert(:user, local: true) +      recipient = insert(:user, local: true) + +      {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey") + +      {:ok, create_activity_data, _meta} = +        Builder.create(author, chat_message_data["id"], [recipient.ap_id]) + +      {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false) + +      with_mocks([ +        { +          Pleroma.Web.Streamer, +          [], +          [ +            stream: fn _, _ -> nil end +          ] +        }, +        { +          Pleroma.Web.Push, +          [], +          [ +            send: fn _ -> nil end +          ] +        } +      ]) do +        {:ok, _create_activity, meta} = +          SideEffects.handle(create_activity, local: false, object_data: chat_message_data) + +        # The notification gets created +        assert [notification] = meta[:notifications] +        assert notification.activity_id == create_activity.id + +        # But it is not sent out +        refute called(Pleroma.Web.Streamer.stream(["user", "user:notification"], notification)) +        refute called(Pleroma.Web.Push.send(notification)) + +        # Same for the user chat stream +        assert [{topics, _}, _] = meta[:streamables] +        assert topics == ["user", "user:pleroma_chat"] +        refute called(Pleroma.Web.Streamer.stream(["user", "user:pleroma_chat"], :_)) + +        chat = Chat.get(author.id, recipient.ap_id) + +        [cm_ref] = MessageReference.for_chat_query(chat) |> Repo.all() + +        assert cm_ref.object.data["content"] == "hey" +        assert cm_ref.unread == false + +        chat = Chat.get(recipient.id, author.ap_id) + +        [cm_ref] = MessageReference.for_chat_query(chat) |> Repo.all() + +        assert cm_ref.object.data["content"] == "hey" +        assert cm_ref.unread == true +      end +    end + +    test "it creates a Chat for the local users and bumps the unread count" do +      author = insert(:user, local: false) +      recipient = insert(:user, local: true) + +      {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey") + +      {:ok, create_activity_data, _meta} = +        Builder.create(author, chat_message_data["id"], [recipient.ap_id]) + +      {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false) + +      {:ok, _create_activity, _meta} = +        SideEffects.handle(create_activity, local: false, object_data: chat_message_data) + +      # An object is created +      assert Object.get_by_ap_id(chat_message_data["id"]) + +      # The remote user won't get a chat +      chat = Chat.get(author.id, recipient.ap_id) +      refute chat + +      # The local user will get a chat +      chat = Chat.get(recipient.id, author.ap_id) +      assert chat + +      author = insert(:user, local: true) +      recipient = insert(:user, local: true) + +      {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey") + +      {:ok, create_activity_data, _meta} = +        Builder.create(author, chat_message_data["id"], [recipient.ap_id]) + +      {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false) + +      {:ok, _create_activity, _meta} = +        SideEffects.handle(create_activity, local: false, object_data: chat_message_data) + +      # Both users are local and get the chat +      chat = Chat.get(author.id, recipient.ap_id) +      assert chat + +      chat = Chat.get(recipient.id, author.ap_id) +      assert chat +    end +  end +    describe "announce objects" do      setup do        poster = insert(:user) diff --git a/test/web/activity_pub/transmogrifier/chat_message_test.exs b/test/web/activity_pub/transmogrifier/chat_message_test.exs new file mode 100644 index 000000000..d6736dc3e --- /dev/null +++ b/test/web/activity_pub/transmogrifier/chat_message_test.exs @@ -0,0 +1,153 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.Transmogrifier.ChatMessageTest do +  use Pleroma.DataCase + +  import Pleroma.Factory + +  alias Pleroma.Activity +  alias Pleroma.Chat +  alias Pleroma.Object +  alias Pleroma.Web.ActivityPub.Transmogrifier + +  describe "handle_incoming" do +    test "handles chonks with attachment" do +      data = %{ +        "@context" => "https://www.w3.org/ns/activitystreams", +        "actor" => "https://honk.tedunangst.com/u/tedu", +        "id" => "https://honk.tedunangst.com/u/tedu/honk/x6gt8X8PcyGkQcXxzg1T", +        "object" => %{ +          "attachment" => [ +            %{ +              "mediaType" => "image/jpeg", +              "name" => "298p3RG7j27tfsZ9RQ.jpg", +              "summary" => "298p3RG7j27tfsZ9RQ.jpg", +              "type" => "Document", +              "url" => "https://honk.tedunangst.com/d/298p3RG7j27tfsZ9RQ.jpg" +            } +          ], +          "attributedTo" => "https://honk.tedunangst.com/u/tedu", +          "content" => "", +          "id" => "https://honk.tedunangst.com/u/tedu/chonk/26L4wl5yCbn4dr4y1b", +          "published" => "2020-05-18T01:13:03Z", +          "to" => [ +            "https://dontbulling.me/users/lain" +          ], +          "type" => "ChatMessage" +        }, +        "published" => "2020-05-18T01:13:03Z", +        "to" => [ +          "https://dontbulling.me/users/lain" +        ], +        "type" => "Create" +      } + +      _user = insert(:user, ap_id: data["actor"]) +      _user = insert(:user, ap_id: hd(data["to"])) + +      assert {:ok, _activity} = Transmogrifier.handle_incoming(data) +    end + +    test "it rejects messages that don't contain content" do +      data = +        File.read!("test/fixtures/create-chat-message.json") +        |> Poison.decode!() + +      object = +        data["object"] +        |> Map.delete("content") + +      data = +        data +        |> Map.put("object", object) + +      _author = +        insert(:user, ap_id: data["actor"], local: false, last_refreshed_at: DateTime.utc_now()) + +      _recipient = +        insert(:user, +          ap_id: List.first(data["to"]), +          local: true, +          last_refreshed_at: DateTime.utc_now() +        ) + +      {:error, _} = Transmogrifier.handle_incoming(data) +    end + +    test "it rejects messages that don't concern local users" do +      data = +        File.read!("test/fixtures/create-chat-message.json") +        |> Poison.decode!() + +      _author = +        insert(:user, ap_id: data["actor"], local: false, last_refreshed_at: DateTime.utc_now()) + +      _recipient = +        insert(:user, +          ap_id: List.first(data["to"]), +          local: false, +          last_refreshed_at: DateTime.utc_now() +        ) + +      {:error, _} = Transmogrifier.handle_incoming(data) +    end + +    test "it rejects messages where the `to` field of activity and object don't match" do +      data = +        File.read!("test/fixtures/create-chat-message.json") +        |> Poison.decode!() + +      author = insert(:user, ap_id: data["actor"]) +      _recipient = insert(:user, ap_id: List.first(data["to"])) + +      data = +        data +        |> Map.put("to", author.ap_id) + +      assert match?({:error, _}, Transmogrifier.handle_incoming(data)) +      refute Object.get_by_ap_id(data["object"]["id"]) +    end + +    test "it fetches the actor if they aren't in our system" do +      Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end) + +      data = +        File.read!("test/fixtures/create-chat-message.json") +        |> Poison.decode!() +        |> Map.put("actor", "http://mastodon.example.org/users/admin") +        |> put_in(["object", "actor"], "http://mastodon.example.org/users/admin") + +      _recipient = insert(:user, ap_id: List.first(data["to"]), local: true) + +      {:ok, %Activity{} = _activity} = Transmogrifier.handle_incoming(data) +    end + +    test "it inserts it and creates a chat" do +      data = +        File.read!("test/fixtures/create-chat-message.json") +        |> Poison.decode!() + +      author = +        insert(:user, ap_id: data["actor"], local: false, last_refreshed_at: DateTime.utc_now()) + +      recipient = insert(:user, ap_id: List.first(data["to"]), local: true) + +      {:ok, %Activity{} = activity} = Transmogrifier.handle_incoming(data) +      assert activity.local == false + +      assert activity.actor == author.ap_id +      assert activity.recipients == [recipient.ap_id, author.ap_id] + +      %Object{} = object = Object.get_by_ap_id(activity.data["object"]) + +      assert object +      assert object.data["content"] == "You expected a cute girl? Too bad. alert('XSS')" +      assert match?(%{"firefox" => _}, object.data["emoji"]) + +      refute Chat.get(author.id, recipient.ap_id) +      assert Chat.get(recipient.id, author.ap_id) +    end +  end +end diff --git a/test/web/activity_pub/transmogrifier/follow_handling_test.exs b/test/web/activity_pub/transmogrifier/follow_handling_test.exs index 967389fae..06c39eed6 100644 --- a/test/web/activity_pub/transmogrifier/follow_handling_test.exs +++ b/test/web/activity_pub/transmogrifier/follow_handling_test.exs @@ -5,6 +5,7 @@  defmodule Pleroma.Web.ActivityPub.Transmogrifier.FollowHandlingTest do    use Pleroma.DataCase    alias Pleroma.Activity +  alias Pleroma.Notification    alias Pleroma.Repo    alias Pleroma.User    alias Pleroma.Web.ActivityPub.Transmogrifier @@ -12,6 +13,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.FollowHandlingTest do    import Pleroma.Factory    import Ecto.Query +  import Mock    setup_all do      Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) @@ -57,9 +59,12 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.FollowHandlingTest do        activity = Repo.get(Activity, activity.id)        assert activity.data["state"] == "accept"        assert User.following?(User.get_cached_by_ap_id(data["actor"]), user) + +      [notification] = Notification.for_user(user) +      assert notification.type == "follow"      end -    test "with locked accounts, it does not create a follow or an accept" do +    test "with locked accounts, it does create a Follow, but not an Accept" do        user = insert(:user, locked: true)        data = @@ -81,6 +86,9 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.FollowHandlingTest do          |> Repo.all()        assert Enum.empty?(accepts) + +      [notification] = Notification.for_user(user) +      assert notification.type == "follow_request"      end      test "it works for follow requests when you are already followed, creating a new accept activity" do @@ -144,6 +152,23 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.FollowHandlingTest do        assert activity.data["state"] == "reject"      end +    test "it rejects incoming follow requests if the following errors for some reason" do +      user = insert(:user) + +      data = +        File.read!("test/fixtures/mastodon-follow-activity.json") +        |> Poison.decode!() +        |> Map.put("object", user.ap_id) + +      with_mock Pleroma.User, [:passthrough], follow: fn _, _ -> {:error, :testing} end do +        {:ok, %Activity{data: %{"id" => id}}} = Transmogrifier.handle_incoming(data) + +        %Activity{} = activity = Activity.get_by_ap_id(id) + +        assert activity.data["state"] == "reject" +      end +    end +      test "it works for incoming follow requests from hubzilla" do        user = insert(:user) diff --git a/test/web/activity_pub/views/user_view_test.exs b/test/web/activity_pub/views/user_view_test.exs index 20b0f223c..bec15a996 100644 --- a/test/web/activity_pub/views/user_view_test.exs +++ b/test/web/activity_pub/views/user_view_test.exs @@ -158,35 +158,4 @@ defmodule Pleroma.Web.ActivityPub.UserViewTest do        assert %{"totalItems" => 1} = UserView.render("following.json", %{user: user})      end    end - -  test "activity collection page aginates correctly" do -    user = insert(:user) - -    posts = -      for i <- 0..25 do -        {:ok, activity} = CommonAPI.post(user, %{status: "post #{i}"}) -        activity -      end - -    # outbox sorts chronologically, newest first, with ten per page -    posts = Enum.reverse(posts) - -    %{"next" => next_url} = -      UserView.render("activity_collection_page.json", %{ -        iri: "#{user.ap_id}/outbox", -        activities: Enum.take(posts, 10) -      }) - -    next_id = Enum.at(posts, 9).id -    assert next_url =~ next_id - -    %{"next" => next_url} = -      UserView.render("activity_collection_page.json", %{ -        iri: "#{user.ap_id}/outbox", -        activities: Enum.take(Enum.drop(posts, 10), 10) -      }) - -    next_id = Enum.at(posts, 19).id -    assert next_url =~ next_id -  end  end diff --git a/test/web/admin_api/controllers/admin_api_controller_test.exs b/test/web/admin_api/controllers/admin_api_controller_test.exs index a1bff5688..e3d3ccb8d 100644 --- a/test/web/admin_api/controllers/admin_api_controller_test.exs +++ b/test/web/admin_api/controllers/admin_api_controller_test.exs @@ -12,7 +12,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do    alias Pleroma.Activity    alias Pleroma.Config -  alias Pleroma.ConfigDB    alias Pleroma.HTML    alias Pleroma.MFA    alias Pleroma.ModerationLog @@ -338,7 +337,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do          "tags" => [],          "avatar" => User.avatar_url(user) |> MediaProxy.url(),          "display_name" => HTML.strip_tags(user.name || user.nickname), -        "confirmation_pending" => false +        "confirmation_pending" => false, +        "url" => user.ap_id        }        assert expected == json_response(conn, 200) @@ -615,7 +615,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do              "tags" => [],              "avatar" => User.avatar_url(admin) |> MediaProxy.url(),              "display_name" => HTML.strip_tags(admin.name || admin.nickname), -            "confirmation_pending" => false +            "confirmation_pending" => false, +            "url" => admin.ap_id            },            %{              "deactivated" => user.deactivated, @@ -626,7 +627,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do              "tags" => ["foo", "bar"],              "avatar" => User.avatar_url(user) |> MediaProxy.url(),              "display_name" => HTML.strip_tags(user.name || user.nickname), -            "confirmation_pending" => false +            "confirmation_pending" => false, +            "url" => user.ap_id            }          ]          |> Enum.sort_by(& &1["nickname"]) @@ -698,7 +700,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do                     "tags" => [],                     "avatar" => User.avatar_url(user) |> MediaProxy.url(),                     "display_name" => HTML.strip_tags(user.name || user.nickname), -                   "confirmation_pending" => false +                   "confirmation_pending" => false, +                   "url" => user.ap_id                   }                 ]               } @@ -723,7 +726,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do                     "tags" => [],                     "avatar" => User.avatar_url(user) |> MediaProxy.url(),                     "display_name" => HTML.strip_tags(user.name || user.nickname), -                   "confirmation_pending" => false +                   "confirmation_pending" => false, +                   "url" => user.ap_id                   }                 ]               } @@ -748,7 +752,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do                     "tags" => [],                     "avatar" => User.avatar_url(user) |> MediaProxy.url(),                     "display_name" => HTML.strip_tags(user.name || user.nickname), -                   "confirmation_pending" => false +                   "confirmation_pending" => false, +                   "url" => user.ap_id                   }                 ]               } @@ -773,7 +778,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do                     "tags" => [],                     "avatar" => User.avatar_url(user) |> MediaProxy.url(),                     "display_name" => HTML.strip_tags(user.name || user.nickname), -                   "confirmation_pending" => false +                   "confirmation_pending" => false, +                   "url" => user.ap_id                   }                 ]               } @@ -798,7 +804,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do                     "tags" => [],                     "avatar" => User.avatar_url(user) |> MediaProxy.url(),                     "display_name" => HTML.strip_tags(user.name || user.nickname), -                   "confirmation_pending" => false +                   "confirmation_pending" => false, +                   "url" => user.ap_id                   }                 ]               } @@ -823,7 +830,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do                     "tags" => [],                     "avatar" => User.avatar_url(user) |> MediaProxy.url(),                     "display_name" => HTML.strip_tags(user.name || user.nickname), -                   "confirmation_pending" => false +                   "confirmation_pending" => false, +                   "url" => user.ap_id                   }                 ]               } @@ -843,7 +851,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do                     "tags" => [],                     "avatar" => User.avatar_url(user2) |> MediaProxy.url(),                     "display_name" => HTML.strip_tags(user2.name || user2.nickname), -                   "confirmation_pending" => false +                   "confirmation_pending" => false, +                   "url" => user2.ap_id                   }                 ]               } @@ -875,7 +884,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do                     "tags" => [],                     "avatar" => User.avatar_url(user) |> MediaProxy.url(),                     "display_name" => HTML.strip_tags(user.name || user.nickname), -                   "confirmation_pending" => false +                   "confirmation_pending" => false, +                   "url" => user.ap_id                   }                 ]               } @@ -900,7 +910,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do              "tags" => [],              "avatar" => User.avatar_url(user) |> MediaProxy.url(),              "display_name" => HTML.strip_tags(user.name || user.nickname), -            "confirmation_pending" => false +            "confirmation_pending" => false, +            "url" => user.ap_id            },            %{              "deactivated" => admin.deactivated, @@ -911,7 +922,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do              "tags" => [],              "avatar" => User.avatar_url(admin) |> MediaProxy.url(),              "display_name" => HTML.strip_tags(admin.name || admin.nickname), -            "confirmation_pending" => false +            "confirmation_pending" => false, +            "url" => admin.ap_id            },            %{              "deactivated" => false, @@ -922,7 +934,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do              "tags" => [],              "avatar" => User.avatar_url(old_admin) |> MediaProxy.url(),              "display_name" => HTML.strip_tags(old_admin.name || old_admin.nickname), -            "confirmation_pending" => false +            "confirmation_pending" => false, +            "url" => old_admin.ap_id            }          ]          |> Enum.sort_by(& &1["nickname"]) @@ -952,7 +965,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do              "tags" => [],              "avatar" => User.avatar_url(admin) |> MediaProxy.url(),              "display_name" => HTML.strip_tags(admin.name || admin.nickname), -            "confirmation_pending" => false +            "confirmation_pending" => false, +            "url" => admin.ap_id            },            %{              "deactivated" => false, @@ -963,7 +977,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do              "tags" => [],              "avatar" => User.avatar_url(second_admin) |> MediaProxy.url(),              "display_name" => HTML.strip_tags(second_admin.name || second_admin.nickname), -            "confirmation_pending" => false +            "confirmation_pending" => false, +            "url" => second_admin.ap_id            }          ]          |> Enum.sort_by(& &1["nickname"]) @@ -995,7 +1010,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do                     "tags" => [],                     "avatar" => User.avatar_url(moderator) |> MediaProxy.url(),                     "display_name" => HTML.strip_tags(moderator.name || moderator.nickname), -                   "confirmation_pending" => false +                   "confirmation_pending" => false, +                   "url" => moderator.ap_id                   }                 ]               } @@ -1020,7 +1036,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do              "tags" => ["first"],              "avatar" => User.avatar_url(user1) |> MediaProxy.url(),              "display_name" => HTML.strip_tags(user1.name || user1.nickname), -            "confirmation_pending" => false +            "confirmation_pending" => false, +            "url" => user1.ap_id            },            %{              "deactivated" => false, @@ -1031,7 +1048,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do              "tags" => ["second"],              "avatar" => User.avatar_url(user2) |> MediaProxy.url(),              "display_name" => HTML.strip_tags(user2.name || user2.nickname), -            "confirmation_pending" => false +            "confirmation_pending" => false, +            "url" => user2.ap_id            }          ]          |> Enum.sort_by(& &1["nickname"]) @@ -1070,7 +1088,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do                     "tags" => [],                     "avatar" => User.avatar_url(user) |> MediaProxy.url(),                     "display_name" => HTML.strip_tags(user.name || user.nickname), -                   "confirmation_pending" => false +                   "confirmation_pending" => false, +                   "url" => user.ap_id                   }                 ]               } @@ -1094,7 +1113,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do                     "tags" => [],                     "avatar" => User.avatar_url(admin) |> MediaProxy.url(),                     "display_name" => HTML.strip_tags(admin.name || admin.nickname), -                   "confirmation_pending" => false +                   "confirmation_pending" => false, +                   "url" => admin.ap_id                   }                 ]               } @@ -1156,7 +1176,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do                 "tags" => [],                 "avatar" => User.avatar_url(user) |> MediaProxy.url(),                 "display_name" => HTML.strip_tags(user.name || user.nickname), -               "confirmation_pending" => false +               "confirmation_pending" => false, +               "url" => user.ap_id               }      log_entry = Repo.one(ModerationLog) @@ -1197,1175 +1218,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do      end    end -  describe "GET /api/pleroma/admin/config" do -    setup do: clear_config(:configurable_from_database, true) - -    test "when configuration from database is off", %{conn: conn} do -      Config.put(:configurable_from_database, false) -      conn = get(conn, "/api/pleroma/admin/config") - -      assert json_response(conn, 400) == -               %{ -                 "error" => "To use this endpoint you need to enable configuration from database." -               } -    end - -    test "with settings only in db", %{conn: conn} do -      config1 = insert(:config) -      config2 = insert(:config) - -      conn = get(conn, "/api/pleroma/admin/config", %{"only_db" => true}) - -      %{ -        "configs" => [ -          %{ -            "group" => ":pleroma", -            "key" => key1, -            "value" => _ -          }, -          %{ -            "group" => ":pleroma", -            "key" => key2, -            "value" => _ -          } -        ] -      } = json_response(conn, 200) - -      assert key1 == config1.key -      assert key2 == config2.key -    end - -    test "db is added to settings that are in db", %{conn: conn} do -      _config = insert(:config, key: ":instance", value: ConfigDB.to_binary(name: "Some name")) - -      %{"configs" => configs} = -        conn -        |> get("/api/pleroma/admin/config") -        |> json_response(200) - -      [instance_config] = -        Enum.filter(configs, fn %{"group" => group, "key" => key} -> -          group == ":pleroma" and key == ":instance" -        end) - -      assert instance_config["db"] == [":name"] -    end - -    test "merged default setting with db settings", %{conn: conn} do -      config1 = insert(:config) -      config2 = insert(:config) - -      config3 = -        insert(:config, -          value: ConfigDB.to_binary(k1: :v1, k2: :v2) -        ) - -      %{"configs" => configs} = -        conn -        |> get("/api/pleroma/admin/config") -        |> json_response(200) - -      assert length(configs) > 3 - -      received_configs = -        Enum.filter(configs, fn %{"group" => group, "key" => key} -> -          group == ":pleroma" and key in [config1.key, config2.key, config3.key] -        end) - -      assert length(received_configs) == 3 - -      db_keys = -        config3.value -        |> ConfigDB.from_binary() -        |> Keyword.keys() -        |> ConfigDB.convert() - -      Enum.each(received_configs, fn %{"value" => value, "db" => db} -> -        assert db in [[config1.key], [config2.key], db_keys] - -        assert value in [ -                 ConfigDB.from_binary_with_convert(config1.value), -                 ConfigDB.from_binary_with_convert(config2.value), -                 ConfigDB.from_binary_with_convert(config3.value) -               ] -      end) -    end - -    test "subkeys with full update right merge", %{conn: conn} do -      config1 = -        insert(:config, -          key: ":emoji", -          value: ConfigDB.to_binary(groups: [a: 1, b: 2], key: [a: 1]) -        ) - -      config2 = -        insert(:config, -          key: ":assets", -          value: ConfigDB.to_binary(mascots: [a: 1, b: 2], key: [a: 1]) -        ) - -      %{"configs" => configs} = -        conn -        |> get("/api/pleroma/admin/config") -        |> json_response(200) - -      vals = -        Enum.filter(configs, fn %{"group" => group, "key" => key} -> -          group == ":pleroma" and key in [config1.key, config2.key] -        end) - -      emoji = Enum.find(vals, fn %{"key" => key} -> key == ":emoji" end) -      assets = Enum.find(vals, fn %{"key" => key} -> key == ":assets" end) - -      emoji_val = ConfigDB.transform_with_out_binary(emoji["value"]) -      assets_val = ConfigDB.transform_with_out_binary(assets["value"]) - -      assert emoji_val[:groups] == [a: 1, b: 2] -      assert assets_val[:mascots] == [a: 1, b: 2] -    end -  end - -  test "POST /api/pleroma/admin/config error", %{conn: conn} do -    conn = post(conn, "/api/pleroma/admin/config", %{"configs" => []}) - -    assert json_response(conn, 400) == -             %{"error" => "To use this endpoint you need to enable configuration from database."} -  end - -  describe "POST /api/pleroma/admin/config" do -    setup do -      http = Application.get_env(:pleroma, :http) - -      on_exit(fn -> -        Application.delete_env(:pleroma, :key1) -        Application.delete_env(:pleroma, :key2) -        Application.delete_env(:pleroma, :key3) -        Application.delete_env(:pleroma, :key4) -        Application.delete_env(:pleroma, :keyaa1) -        Application.delete_env(:pleroma, :keyaa2) -        Application.delete_env(:pleroma, Pleroma.Web.Endpoint.NotReal) -        Application.delete_env(:pleroma, Pleroma.Captcha.NotReal) -        Application.put_env(:pleroma, :http, http) -        Application.put_env(:tesla, :adapter, Tesla.Mock) -        Restarter.Pleroma.refresh() -      end) -    end - -    setup do: clear_config(:configurable_from_database, true) - -    @tag capture_log: true -    test "create new config setting in db", %{conn: conn} do -      ueberauth = Application.get_env(:ueberauth, Ueberauth) -      on_exit(fn -> Application.put_env(:ueberauth, Ueberauth, ueberauth) end) - -      conn = -        post(conn, "/api/pleroma/admin/config", %{ -          configs: [ -            %{group: ":pleroma", key: ":key1", value: "value1"}, -            %{ -              group: ":ueberauth", -              key: "Ueberauth", -              value: [%{"tuple" => [":consumer_secret", "aaaa"]}] -            }, -            %{ -              group: ":pleroma", -              key: ":key2", -              value: %{ -                ":nested_1" => "nested_value1", -                ":nested_2" => [ -                  %{":nested_22" => "nested_value222"}, -                  %{":nested_33" => %{":nested_44" => "nested_444"}} -                ] -              } -            }, -            %{ -              group: ":pleroma", -              key: ":key3", -              value: [ -                %{"nested_3" => ":nested_3", "nested_33" => "nested_33"}, -                %{"nested_4" => true} -              ] -            }, -            %{ -              group: ":pleroma", -              key: ":key4", -              value: %{":nested_5" => ":upload", "endpoint" => "https://example.com"} -            }, -            %{ -              group: ":idna", -              key: ":key5", -              value: %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]} -            } -          ] -        }) - -      assert json_response(conn, 200) == %{ -               "configs" => [ -                 %{ -                   "group" => ":pleroma", -                   "key" => ":key1", -                   "value" => "value1", -                   "db" => [":key1"] -                 }, -                 %{ -                   "group" => ":ueberauth", -                   "key" => "Ueberauth", -                   "value" => [%{"tuple" => [":consumer_secret", "aaaa"]}], -                   "db" => [":consumer_secret"] -                 }, -                 %{ -                   "group" => ":pleroma", -                   "key" => ":key2", -                   "value" => %{ -                     ":nested_1" => "nested_value1", -                     ":nested_2" => [ -                       %{":nested_22" => "nested_value222"}, -                       %{":nested_33" => %{":nested_44" => "nested_444"}} -                     ] -                   }, -                   "db" => [":key2"] -                 }, -                 %{ -                   "group" => ":pleroma", -                   "key" => ":key3", -                   "value" => [ -                     %{"nested_3" => ":nested_3", "nested_33" => "nested_33"}, -                     %{"nested_4" => true} -                   ], -                   "db" => [":key3"] -                 }, -                 %{ -                   "group" => ":pleroma", -                   "key" => ":key4", -                   "value" => %{"endpoint" => "https://example.com", ":nested_5" => ":upload"}, -                   "db" => [":key4"] -                 }, -                 %{ -                   "group" => ":idna", -                   "key" => ":key5", -                   "value" => %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]}, -                   "db" => [":key5"] -                 } -               ] -             } - -      assert Application.get_env(:pleroma, :key1) == "value1" - -      assert Application.get_env(:pleroma, :key2) == %{ -               nested_1: "nested_value1", -               nested_2: [ -                 %{nested_22: "nested_value222"}, -                 %{nested_33: %{nested_44: "nested_444"}} -               ] -             } - -      assert Application.get_env(:pleroma, :key3) == [ -               %{"nested_3" => :nested_3, "nested_33" => "nested_33"}, -               %{"nested_4" => true} -             ] - -      assert Application.get_env(:pleroma, :key4) == %{ -               "endpoint" => "https://example.com", -               nested_5: :upload -             } - -      assert Application.get_env(:idna, :key5) == {"string", Pleroma.Captcha.NotReal, []} -    end - -    test "save configs setting without explicit key", %{conn: conn} do -      level = Application.get_env(:quack, :level) -      meta = Application.get_env(:quack, :meta) -      webhook_url = Application.get_env(:quack, :webhook_url) - -      on_exit(fn -> -        Application.put_env(:quack, :level, level) -        Application.put_env(:quack, :meta, meta) -        Application.put_env(:quack, :webhook_url, webhook_url) -      end) - -      conn = -        post(conn, "/api/pleroma/admin/config", %{ -          configs: [ -            %{ -              group: ":quack", -              key: ":level", -              value: ":info" -            }, -            %{ -              group: ":quack", -              key: ":meta", -              value: [":none"] -            }, -            %{ -              group: ":quack", -              key: ":webhook_url", -              value: "https://hooks.slack.com/services/KEY" -            } -          ] -        }) - -      assert json_response(conn, 200) == %{ -               "configs" => [ -                 %{ -                   "group" => ":quack", -                   "key" => ":level", -                   "value" => ":info", -                   "db" => [":level"] -                 }, -                 %{ -                   "group" => ":quack", -                   "key" => ":meta", -                   "value" => [":none"], -                   "db" => [":meta"] -                 }, -                 %{ -                   "group" => ":quack", -                   "key" => ":webhook_url", -                   "value" => "https://hooks.slack.com/services/KEY", -                   "db" => [":webhook_url"] -                 } -               ] -             } - -      assert Application.get_env(:quack, :level) == :info -      assert Application.get_env(:quack, :meta) == [:none] -      assert Application.get_env(:quack, :webhook_url) == "https://hooks.slack.com/services/KEY" -    end - -    test "saving config with partial update", %{conn: conn} do -      config = insert(:config, key: ":key1", value: :erlang.term_to_binary(key1: 1, key2: 2)) - -      conn = -        post(conn, "/api/pleroma/admin/config", %{ -          configs: [ -            %{group: config.group, key: config.key, value: [%{"tuple" => [":key3", 3]}]} -          ] -        }) - -      assert json_response(conn, 200) == %{ -               "configs" => [ -                 %{ -                   "group" => ":pleroma", -                   "key" => ":key1", -                   "value" => [ -                     %{"tuple" => [":key1", 1]}, -                     %{"tuple" => [":key2", 2]}, -                     %{"tuple" => [":key3", 3]} -                   ], -                   "db" => [":key1", ":key2", ":key3"] -                 } -               ] -             } -    end - -    test "saving config which need pleroma reboot", %{conn: conn} do -      chat = Config.get(:chat) -      on_exit(fn -> Config.put(:chat, chat) end) - -      assert post( -               conn, -               "/api/pleroma/admin/config", -               %{ -                 configs: [ -                   %{group: ":pleroma", key: ":chat", value: [%{"tuple" => [":enabled", true]}]} -                 ] -               } -             ) -             |> json_response(200) == %{ -               "configs" => [ -                 %{ -                   "db" => [":enabled"], -                   "group" => ":pleroma", -                   "key" => ":chat", -                   "value" => [%{"tuple" => [":enabled", true]}] -                 } -               ], -               "need_reboot" => true -             } - -      configs = -        conn -        |> get("/api/pleroma/admin/config") -        |> json_response(200) - -      assert configs["need_reboot"] - -      capture_log(fn -> -        assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{} -      end) =~ "pleroma restarted" - -      configs = -        conn -        |> get("/api/pleroma/admin/config") -        |> json_response(200) - -      assert configs["need_reboot"] == false -    end - -    test "update setting which need reboot, don't change reboot flag until reboot", %{conn: conn} do -      chat = Config.get(:chat) -      on_exit(fn -> Config.put(:chat, chat) end) - -      assert post( -               conn, -               "/api/pleroma/admin/config", -               %{ -                 configs: [ -                   %{group: ":pleroma", key: ":chat", value: [%{"tuple" => [":enabled", true]}]} -                 ] -               } -             ) -             |> json_response(200) == %{ -               "configs" => [ -                 %{ -                   "db" => [":enabled"], -                   "group" => ":pleroma", -                   "key" => ":chat", -                   "value" => [%{"tuple" => [":enabled", true]}] -                 } -               ], -               "need_reboot" => true -             } - -      assert post(conn, "/api/pleroma/admin/config", %{ -               configs: [ -                 %{group: ":pleroma", key: ":key1", value: [%{"tuple" => [":key3", 3]}]} -               ] -             }) -             |> json_response(200) == %{ -               "configs" => [ -                 %{ -                   "group" => ":pleroma", -                   "key" => ":key1", -                   "value" => [ -                     %{"tuple" => [":key3", 3]} -                   ], -                   "db" => [":key3"] -                 } -               ], -               "need_reboot" => true -             } - -      capture_log(fn -> -        assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{} -      end) =~ "pleroma restarted" - -      configs = -        conn -        |> get("/api/pleroma/admin/config") -        |> json_response(200) - -      assert configs["need_reboot"] == false -    end - -    test "saving config with nested merge", %{conn: conn} do -      config = -        insert(:config, key: ":key1", value: :erlang.term_to_binary(key1: 1, key2: [k1: 1, k2: 2])) - -      conn = -        post(conn, "/api/pleroma/admin/config", %{ -          configs: [ -            %{ -              group: config.group, -              key: config.key, -              value: [ -                %{"tuple" => [":key3", 3]}, -                %{ -                  "tuple" => [ -                    ":key2", -                    [ -                      %{"tuple" => [":k2", 1]}, -                      %{"tuple" => [":k3", 3]} -                    ] -                  ] -                } -              ] -            } -          ] -        }) - -      assert json_response(conn, 200) == %{ -               "configs" => [ -                 %{ -                   "group" => ":pleroma", -                   "key" => ":key1", -                   "value" => [ -                     %{"tuple" => [":key1", 1]}, -                     %{"tuple" => [":key3", 3]}, -                     %{ -                       "tuple" => [ -                         ":key2", -                         [ -                           %{"tuple" => [":k1", 1]}, -                           %{"tuple" => [":k2", 1]}, -                           %{"tuple" => [":k3", 3]} -                         ] -                       ] -                     } -                   ], -                   "db" => [":key1", ":key3", ":key2"] -                 } -               ] -             } -    end - -    test "saving special atoms", %{conn: conn} do -      conn = -        post(conn, "/api/pleroma/admin/config", %{ -          "configs" => [ -            %{ -              "group" => ":pleroma", -              "key" => ":key1", -              "value" => [ -                %{ -                  "tuple" => [ -                    ":ssl_options", -                    [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}] -                  ] -                } -              ] -            } -          ] -        }) - -      assert json_response(conn, 200) == %{ -               "configs" => [ -                 %{ -                   "group" => ":pleroma", -                   "key" => ":key1", -                   "value" => [ -                     %{ -                       "tuple" => [ -                         ":ssl_options", -                         [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}] -                       ] -                     } -                   ], -                   "db" => [":ssl_options"] -                 } -               ] -             } - -      assert Application.get_env(:pleroma, :key1) == [ -               ssl_options: [versions: [:tlsv1, :"tlsv1.1", :"tlsv1.2"]] -             ] -    end - -    test "saving full setting if value is in full_key_update list", %{conn: conn} do -      backends = Application.get_env(:logger, :backends) -      on_exit(fn -> Application.put_env(:logger, :backends, backends) end) - -      config = -        insert(:config, -          group: ":logger", -          key: ":backends", -          value: :erlang.term_to_binary([]) -        ) - -      Pleroma.Config.TransferTask.load_and_update_env([], false) - -      assert Application.get_env(:logger, :backends) == [] - -      conn = -        post(conn, "/api/pleroma/admin/config", %{ -          configs: [ -            %{ -              group: config.group, -              key: config.key, -              value: [":console"] -            } -          ] -        }) - -      assert json_response(conn, 200) == %{ -               "configs" => [ -                 %{ -                   "group" => ":logger", -                   "key" => ":backends", -                   "value" => [ -                     ":console" -                   ], -                   "db" => [":backends"] -                 } -               ] -             } - -      assert Application.get_env(:logger, :backends) == [ -               :console -             ] -    end - -    test "saving full setting if value is not keyword", %{conn: conn} do -      config = -        insert(:config, -          group: ":tesla", -          key: ":adapter", -          value: :erlang.term_to_binary(Tesla.Adapter.Hackey) -        ) - -      conn = -        post(conn, "/api/pleroma/admin/config", %{ -          configs: [ -            %{group: config.group, key: config.key, value: "Tesla.Adapter.Httpc"} -          ] -        }) - -      assert json_response(conn, 200) == %{ -               "configs" => [ -                 %{ -                   "group" => ":tesla", -                   "key" => ":adapter", -                   "value" => "Tesla.Adapter.Httpc", -                   "db" => [":adapter"] -                 } -               ] -             } -    end - -    test "update config setting & delete with fallback to default value", %{ -      conn: conn, -      admin: admin, -      token: token -    } do -      ueberauth = Application.get_env(:ueberauth, Ueberauth) -      config1 = insert(:config, key: ":keyaa1") -      config2 = insert(:config, key: ":keyaa2") - -      config3 = -        insert(:config, -          group: ":ueberauth", -          key: "Ueberauth" -        ) - -      conn = -        post(conn, "/api/pleroma/admin/config", %{ -          configs: [ -            %{group: config1.group, key: config1.key, value: "another_value"}, -            %{group: config2.group, key: config2.key, value: "another_value"} -          ] -        }) - -      assert json_response(conn, 200) == %{ -               "configs" => [ -                 %{ -                   "group" => ":pleroma", -                   "key" => config1.key, -                   "value" => "another_value", -                   "db" => [":keyaa1"] -                 }, -                 %{ -                   "group" => ":pleroma", -                   "key" => config2.key, -                   "value" => "another_value", -                   "db" => [":keyaa2"] -                 } -               ] -             } - -      assert Application.get_env(:pleroma, :keyaa1) == "another_value" -      assert Application.get_env(:pleroma, :keyaa2) == "another_value" -      assert Application.get_env(:ueberauth, Ueberauth) == ConfigDB.from_binary(config3.value) - -      conn = -        build_conn() -        |> assign(:user, admin) -        |> assign(:token, token) -        |> post("/api/pleroma/admin/config", %{ -          configs: [ -            %{group: config2.group, key: config2.key, delete: true}, -            %{ -              group: ":ueberauth", -              key: "Ueberauth", -              delete: true -            } -          ] -        }) - -      assert json_response(conn, 200) == %{ -               "configs" => [] -             } - -      assert Application.get_env(:ueberauth, Ueberauth) == ueberauth -      refute Keyword.has_key?(Application.get_all_env(:pleroma), :keyaa2) -    end - -    test "common config example", %{conn: conn} do -      conn = -        post(conn, "/api/pleroma/admin/config", %{ -          configs: [ -            %{ -              "group" => ":pleroma", -              "key" => "Pleroma.Captcha.NotReal", -              "value" => [ -                %{"tuple" => [":enabled", false]}, -                %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]}, -                %{"tuple" => [":seconds_valid", 60]}, -                %{"tuple" => [":path", ""]}, -                %{"tuple" => [":key1", nil]}, -                %{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]}, -                %{"tuple" => [":regex1", "~r/https:\/\/example.com/"]}, -                %{"tuple" => [":regex2", "~r/https:\/\/example.com/u"]}, -                %{"tuple" => [":regex3", "~r/https:\/\/example.com/i"]}, -                %{"tuple" => [":regex4", "~r/https:\/\/example.com/s"]}, -                %{"tuple" => [":name", "Pleroma"]} -              ] -            } -          ] -        }) - -      assert Config.get([Pleroma.Captcha.NotReal, :name]) == "Pleroma" - -      assert json_response(conn, 200) == %{ -               "configs" => [ -                 %{ -                   "group" => ":pleroma", -                   "key" => "Pleroma.Captcha.NotReal", -                   "value" => [ -                     %{"tuple" => [":enabled", false]}, -                     %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]}, -                     %{"tuple" => [":seconds_valid", 60]}, -                     %{"tuple" => [":path", ""]}, -                     %{"tuple" => [":key1", nil]}, -                     %{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]}, -                     %{"tuple" => [":regex1", "~r/https:\\/\\/example.com/"]}, -                     %{"tuple" => [":regex2", "~r/https:\\/\\/example.com/u"]}, -                     %{"tuple" => [":regex3", "~r/https:\\/\\/example.com/i"]}, -                     %{"tuple" => [":regex4", "~r/https:\\/\\/example.com/s"]}, -                     %{"tuple" => [":name", "Pleroma"]} -                   ], -                   "db" => [ -                     ":enabled", -                     ":method", -                     ":seconds_valid", -                     ":path", -                     ":key1", -                     ":partial_chain", -                     ":regex1", -                     ":regex2", -                     ":regex3", -                     ":regex4", -                     ":name" -                   ] -                 } -               ] -             } -    end - -    test "tuples with more than two values", %{conn: conn} do -      conn = -        post(conn, "/api/pleroma/admin/config", %{ -          configs: [ -            %{ -              "group" => ":pleroma", -              "key" => "Pleroma.Web.Endpoint.NotReal", -              "value" => [ -                %{ -                  "tuple" => [ -                    ":http", -                    [ -                      %{ -                        "tuple" => [ -                          ":key2", -                          [ -                            %{ -                              "tuple" => [ -                                ":_", -                                [ -                                  %{ -                                    "tuple" => [ -                                      "/api/v1/streaming", -                                      "Pleroma.Web.MastodonAPI.WebsocketHandler", -                                      [] -                                    ] -                                  }, -                                  %{ -                                    "tuple" => [ -                                      "/websocket", -                                      "Phoenix.Endpoint.CowboyWebSocket", -                                      %{ -                                        "tuple" => [ -                                          "Phoenix.Transports.WebSocket", -                                          %{ -                                            "tuple" => [ -                                              "Pleroma.Web.Endpoint", -                                              "Pleroma.Web.UserSocket", -                                              [] -                                            ] -                                          } -                                        ] -                                      } -                                    ] -                                  }, -                                  %{ -                                    "tuple" => [ -                                      ":_", -                                      "Phoenix.Endpoint.Cowboy2Handler", -                                      %{"tuple" => ["Pleroma.Web.Endpoint", []]} -                                    ] -                                  } -                                ] -                              ] -                            } -                          ] -                        ] -                      } -                    ] -                  ] -                } -              ] -            } -          ] -        }) - -      assert json_response(conn, 200) == %{ -               "configs" => [ -                 %{ -                   "group" => ":pleroma", -                   "key" => "Pleroma.Web.Endpoint.NotReal", -                   "value" => [ -                     %{ -                       "tuple" => [ -                         ":http", -                         [ -                           %{ -                             "tuple" => [ -                               ":key2", -                               [ -                                 %{ -                                   "tuple" => [ -                                     ":_", -                                     [ -                                       %{ -                                         "tuple" => [ -                                           "/api/v1/streaming", -                                           "Pleroma.Web.MastodonAPI.WebsocketHandler", -                                           [] -                                         ] -                                       }, -                                       %{ -                                         "tuple" => [ -                                           "/websocket", -                                           "Phoenix.Endpoint.CowboyWebSocket", -                                           %{ -                                             "tuple" => [ -                                               "Phoenix.Transports.WebSocket", -                                               %{ -                                                 "tuple" => [ -                                                   "Pleroma.Web.Endpoint", -                                                   "Pleroma.Web.UserSocket", -                                                   [] -                                                 ] -                                               } -                                             ] -                                           } -                                         ] -                                       }, -                                       %{ -                                         "tuple" => [ -                                           ":_", -                                           "Phoenix.Endpoint.Cowboy2Handler", -                                           %{"tuple" => ["Pleroma.Web.Endpoint", []]} -                                         ] -                                       } -                                     ] -                                   ] -                                 } -                               ] -                             ] -                           } -                         ] -                       ] -                     } -                   ], -                   "db" => [":http"] -                 } -               ] -             } -    end - -    test "settings with nesting map", %{conn: conn} do -      conn = -        post(conn, "/api/pleroma/admin/config", %{ -          configs: [ -            %{ -              "group" => ":pleroma", -              "key" => ":key1", -              "value" => [ -                %{"tuple" => [":key2", "some_val"]}, -                %{ -                  "tuple" => [ -                    ":key3", -                    %{ -                      ":max_options" => 20, -                      ":max_option_chars" => 200, -                      ":min_expiration" => 0, -                      ":max_expiration" => 31_536_000, -                      "nested" => %{ -                        ":max_options" => 20, -                        ":max_option_chars" => 200, -                        ":min_expiration" => 0, -                        ":max_expiration" => 31_536_000 -                      } -                    } -                  ] -                } -              ] -            } -          ] -        }) - -      assert json_response(conn, 200) == -               %{ -                 "configs" => [ -                   %{ -                     "group" => ":pleroma", -                     "key" => ":key1", -                     "value" => [ -                       %{"tuple" => [":key2", "some_val"]}, -                       %{ -                         "tuple" => [ -                           ":key3", -                           %{ -                             ":max_expiration" => 31_536_000, -                             ":max_option_chars" => 200, -                             ":max_options" => 20, -                             ":min_expiration" => 0, -                             "nested" => %{ -                               ":max_expiration" => 31_536_000, -                               ":max_option_chars" => 200, -                               ":max_options" => 20, -                               ":min_expiration" => 0 -                             } -                           } -                         ] -                       } -                     ], -                     "db" => [":key2", ":key3"] -                   } -                 ] -               } -    end - -    test "value as map", %{conn: conn} do -      conn = -        post(conn, "/api/pleroma/admin/config", %{ -          configs: [ -            %{ -              "group" => ":pleroma", -              "key" => ":key1", -              "value" => %{"key" => "some_val"} -            } -          ] -        }) - -      assert json_response(conn, 200) == -               %{ -                 "configs" => [ -                   %{ -                     "group" => ":pleroma", -                     "key" => ":key1", -                     "value" => %{"key" => "some_val"}, -                     "db" => [":key1"] -                   } -                 ] -               } -    end - -    test "queues key as atom", %{conn: conn} do -      conn = -        post(conn, "/api/pleroma/admin/config", %{ -          configs: [ -            %{ -              "group" => ":oban", -              "key" => ":queues", -              "value" => [ -                %{"tuple" => [":federator_incoming", 50]}, -                %{"tuple" => [":federator_outgoing", 50]}, -                %{"tuple" => [":web_push", 50]}, -                %{"tuple" => [":mailer", 10]}, -                %{"tuple" => [":transmogrifier", 20]}, -                %{"tuple" => [":scheduled_activities", 10]}, -                %{"tuple" => [":background", 5]} -              ] -            } -          ] -        }) - -      assert json_response(conn, 200) == %{ -               "configs" => [ -                 %{ -                   "group" => ":oban", -                   "key" => ":queues", -                   "value" => [ -                     %{"tuple" => [":federator_incoming", 50]}, -                     %{"tuple" => [":federator_outgoing", 50]}, -                     %{"tuple" => [":web_push", 50]}, -                     %{"tuple" => [":mailer", 10]}, -                     %{"tuple" => [":transmogrifier", 20]}, -                     %{"tuple" => [":scheduled_activities", 10]}, -                     %{"tuple" => [":background", 5]} -                   ], -                   "db" => [ -                     ":federator_incoming", -                     ":federator_outgoing", -                     ":web_push", -                     ":mailer", -                     ":transmogrifier", -                     ":scheduled_activities", -                     ":background" -                   ] -                 } -               ] -             } -    end - -    test "delete part of settings by atom subkeys", %{conn: conn} do -      config = -        insert(:config, -          key: ":keyaa1", -          value: :erlang.term_to_binary(subkey1: "val1", subkey2: "val2", subkey3: "val3") -        ) - -      conn = -        post(conn, "/api/pleroma/admin/config", %{ -          configs: [ -            %{ -              group: config.group, -              key: config.key, -              subkeys: [":subkey1", ":subkey3"], -              delete: true -            } -          ] -        }) - -      assert json_response(conn, 200) == %{ -               "configs" => [ -                 %{ -                   "group" => ":pleroma", -                   "key" => ":keyaa1", -                   "value" => [%{"tuple" => [":subkey2", "val2"]}], -                   "db" => [":subkey2"] -                 } -               ] -             } -    end - -    test "proxy tuple localhost", %{conn: conn} do -      conn = -        post(conn, "/api/pleroma/admin/config", %{ -          configs: [ -            %{ -              group: ":pleroma", -              key: ":http", -              value: [ -                %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]} -              ] -            } -          ] -        }) - -      assert %{ -               "configs" => [ -                 %{ -                   "group" => ":pleroma", -                   "key" => ":http", -                   "value" => value, -                   "db" => db -                 } -               ] -             } = json_response(conn, 200) - -      assert %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]} in value -      assert ":proxy_url" in db -    end - -    test "proxy tuple domain", %{conn: conn} do -      conn = -        post(conn, "/api/pleroma/admin/config", %{ -          configs: [ -            %{ -              group: ":pleroma", -              key: ":http", -              value: [ -                %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]} -              ] -            } -          ] -        }) - -      assert %{ -               "configs" => [ -                 %{ -                   "group" => ":pleroma", -                   "key" => ":http", -                   "value" => value, -                   "db" => db -                 } -               ] -             } = json_response(conn, 200) - -      assert %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]} in value -      assert ":proxy_url" in db -    end - -    test "proxy tuple ip", %{conn: conn} do -      conn = -        post(conn, "/api/pleroma/admin/config", %{ -          configs: [ -            %{ -              group: ":pleroma", -              key: ":http", -              value: [ -                %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]} -              ] -            } -          ] -        }) - -      assert %{ -               "configs" => [ -                 %{ -                   "group" => ":pleroma", -                   "key" => ":http", -                   "value" => value, -                   "db" => db -                 } -               ] -             } = json_response(conn, 200) - -      assert %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]} in value -      assert ":proxy_url" in db -    end - -    @tag capture_log: true -    test "doesn't set keys not in the whitelist", %{conn: conn} do -      clear_config(:database_config_whitelist, [ -        {:pleroma, :key1}, -        {:pleroma, :key2}, -        {:pleroma, Pleroma.Captcha.NotReal}, -        {:not_real} -      ]) - -      post(conn, "/api/pleroma/admin/config", %{ -        configs: [ -          %{group: ":pleroma", key: ":key1", value: "value1"}, -          %{group: ":pleroma", key: ":key2", value: "value2"}, -          %{group: ":pleroma", key: ":key3", value: "value3"}, -          %{group: ":pleroma", key: "Pleroma.Web.Endpoint.NotReal", value: "value4"}, -          %{group: ":pleroma", key: "Pleroma.Captcha.NotReal", value: "value5"}, -          %{group: ":not_real", key: ":anything", value: "value6"} -        ] -      }) - -      assert Application.get_env(:pleroma, :key1) == "value1" -      assert Application.get_env(:pleroma, :key2) == "value2" -      assert Application.get_env(:pleroma, :key3) == nil -      assert Application.get_env(:pleroma, Pleroma.Web.Endpoint.NotReal) == nil -      assert Application.get_env(:pleroma, Pleroma.Captcha.NotReal) == "value5" -      assert Application.get_env(:not_real, :anything) == "value6" -    end -  end -    describe "GET /api/pleroma/admin/restart" do      setup do: clear_config(:configurable_from_database, true) @@ -2774,57 +1626,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do      end    end -  describe "relays" do -    test "POST /relay", %{conn: conn, admin: admin} do -      conn = -        post(conn, "/api/pleroma/admin/relay", %{ -          relay_url: "http://mastodon.example.org/users/admin" -        }) - -      assert json_response(conn, 200) == "http://mastodon.example.org/users/admin" - -      log_entry = Repo.one(ModerationLog) - -      assert ModerationLog.get_log_entry_message(log_entry) == -               "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin" -    end - -    test "GET /relay", %{conn: conn} do -      relay_user = Pleroma.Web.ActivityPub.Relay.get_actor() - -      ["http://mastodon.example.org/users/admin", "https://mstdn.io/users/mayuutann"] -      |> Enum.each(fn ap_id -> -        {:ok, user} = User.get_or_fetch_by_ap_id(ap_id) -        User.follow(relay_user, user) -      end) - -      conn = get(conn, "/api/pleroma/admin/relay") - -      assert json_response(conn, 200)["relays"] -- ["mastodon.example.org", "mstdn.io"] == [] -    end - -    test "DELETE /relay", %{conn: conn, admin: admin} do -      post(conn, "/api/pleroma/admin/relay", %{ -        relay_url: "http://mastodon.example.org/users/admin" -      }) - -      conn = -        delete(conn, "/api/pleroma/admin/relay", %{ -          relay_url: "http://mastodon.example.org/users/admin" -        }) - -      assert json_response(conn, 200) == "http://mastodon.example.org/users/admin" - -      [log_entry_one, log_entry_two] = Repo.all(ModerationLog) - -      assert ModerationLog.get_log_entry_message(log_entry_one) == -               "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin" - -      assert ModerationLog.get_log_entry_message(log_entry_two) == -               "@#{admin.nickname} unfollowed relay: http://mastodon.example.org/users/admin" -    end -  end -    describe "instances" do      test "GET /instances/:instance/statuses", %{conn: conn} do        user = insert(:user, local: false, nickname: "archaeme@archae.me") @@ -2914,56 +1715,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do      end    end -  describe "GET /api/pleroma/admin/config/descriptions" do -    test "structure", %{conn: conn} do -      admin = insert(:user, is_admin: true) - -      conn = -        assign(conn, :user, admin) -        |> get("/api/pleroma/admin/config/descriptions") - -      assert [child | _others] = json_response(conn, 200) - -      assert child["children"] -      assert child["key"] -      assert String.starts_with?(child["group"], ":") -      assert child["description"] -    end - -    test "filters by database configuration whitelist", %{conn: conn} do -      clear_config(:database_config_whitelist, [ -        {:pleroma, :instance}, -        {:pleroma, :activitypub}, -        {:pleroma, Pleroma.Upload}, -        {:esshd} -      ]) - -      admin = insert(:user, is_admin: true) - -      conn = -        assign(conn, :user, admin) -        |> get("/api/pleroma/admin/config/descriptions") - -      children = json_response(conn, 200) - -      assert length(children) == 4 - -      assert Enum.count(children, fn c -> c["group"] == ":pleroma" end) == 3 - -      instance = Enum.find(children, fn c -> c["key"] == ":instance" end) -      assert instance["children"] - -      activitypub = Enum.find(children, fn c -> c["key"] == ":activitypub" end) -      assert activitypub["children"] - -      web_endpoint = Enum.find(children, fn c -> c["key"] == "Pleroma.Upload" end) -      assert web_endpoint["children"] - -      esshd = Enum.find(children, fn c -> c["group"] == ":esshd" end) -      assert esshd["children"] -    end -  end -    describe "/api/pleroma/admin/stats" do      test "status visibility count", %{conn: conn} do        admin = insert(:user, is_admin: true) diff --git a/test/web/admin_api/controllers/config_controller_test.exs b/test/web/admin_api/controllers/config_controller_test.exs new file mode 100644 index 000000000..780de8d18 --- /dev/null +++ b/test/web/admin_api/controllers/config_controller_test.exs @@ -0,0 +1,1290 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do +  use Pleroma.Web.ConnCase, async: true + +  import ExUnit.CaptureLog +  import Pleroma.Factory + +  alias Pleroma.Config +  alias Pleroma.ConfigDB + +  setup do +    admin = insert(:user, is_admin: true) +    token = insert(:oauth_admin_token, user: admin) + +    conn = +      build_conn() +      |> assign(:user, admin) +      |> assign(:token, token) + +    {:ok, %{admin: admin, token: token, conn: conn}} +  end + +  describe "GET /api/pleroma/admin/config" do +    setup do: clear_config(:configurable_from_database, true) + +    test "when configuration from database is off", %{conn: conn} do +      Config.put(:configurable_from_database, false) +      conn = get(conn, "/api/pleroma/admin/config") + +      assert json_response_and_validate_schema(conn, 400) == +               %{ +                 "error" => "To use this endpoint you need to enable configuration from database." +               } +    end + +    test "with settings only in db", %{conn: conn} do +      config1 = insert(:config) +      config2 = insert(:config) + +      conn = get(conn, "/api/pleroma/admin/config?only_db=true") + +      %{ +        "configs" => [ +          %{ +            "group" => ":pleroma", +            "key" => key1, +            "value" => _ +          }, +          %{ +            "group" => ":pleroma", +            "key" => key2, +            "value" => _ +          } +        ] +      } = json_response_and_validate_schema(conn, 200) + +      assert key1 == config1.key +      assert key2 == config2.key +    end + +    test "db is added to settings that are in db", %{conn: conn} do +      _config = insert(:config, key: ":instance", value: ConfigDB.to_binary(name: "Some name")) + +      %{"configs" => configs} = +        conn +        |> get("/api/pleroma/admin/config") +        |> json_response_and_validate_schema(200) + +      [instance_config] = +        Enum.filter(configs, fn %{"group" => group, "key" => key} -> +          group == ":pleroma" and key == ":instance" +        end) + +      assert instance_config["db"] == [":name"] +    end + +    test "merged default setting with db settings", %{conn: conn} do +      config1 = insert(:config) +      config2 = insert(:config) + +      config3 = +        insert(:config, +          value: ConfigDB.to_binary(k1: :v1, k2: :v2) +        ) + +      %{"configs" => configs} = +        conn +        |> get("/api/pleroma/admin/config") +        |> json_response_and_validate_schema(200) + +      assert length(configs) > 3 + +      received_configs = +        Enum.filter(configs, fn %{"group" => group, "key" => key} -> +          group == ":pleroma" and key in [config1.key, config2.key, config3.key] +        end) + +      assert length(received_configs) == 3 + +      db_keys = +        config3.value +        |> ConfigDB.from_binary() +        |> Keyword.keys() +        |> ConfigDB.convert() + +      Enum.each(received_configs, fn %{"value" => value, "db" => db} -> +        assert db in [[config1.key], [config2.key], db_keys] + +        assert value in [ +                 ConfigDB.from_binary_with_convert(config1.value), +                 ConfigDB.from_binary_with_convert(config2.value), +                 ConfigDB.from_binary_with_convert(config3.value) +               ] +      end) +    end + +    test "subkeys with full update right merge", %{conn: conn} do +      config1 = +        insert(:config, +          key: ":emoji", +          value: ConfigDB.to_binary(groups: [a: 1, b: 2], key: [a: 1]) +        ) + +      config2 = +        insert(:config, +          key: ":assets", +          value: ConfigDB.to_binary(mascots: [a: 1, b: 2], key: [a: 1]) +        ) + +      %{"configs" => configs} = +        conn +        |> get("/api/pleroma/admin/config") +        |> json_response_and_validate_schema(200) + +      vals = +        Enum.filter(configs, fn %{"group" => group, "key" => key} -> +          group == ":pleroma" and key in [config1.key, config2.key] +        end) + +      emoji = Enum.find(vals, fn %{"key" => key} -> key == ":emoji" end) +      assets = Enum.find(vals, fn %{"key" => key} -> key == ":assets" end) + +      emoji_val = ConfigDB.transform_with_out_binary(emoji["value"]) +      assets_val = ConfigDB.transform_with_out_binary(assets["value"]) + +      assert emoji_val[:groups] == [a: 1, b: 2] +      assert assets_val[:mascots] == [a: 1, b: 2] +    end +  end + +  test "POST /api/pleroma/admin/config error", %{conn: conn} do +    conn = +      conn +      |> put_req_header("content-type", "application/json") +      |> post("/api/pleroma/admin/config", %{"configs" => []}) + +    assert json_response_and_validate_schema(conn, 400) == +             %{"error" => "To use this endpoint you need to enable configuration from database."} +  end + +  describe "POST /api/pleroma/admin/config" do +    setup do +      http = Application.get_env(:pleroma, :http) + +      on_exit(fn -> +        Application.delete_env(:pleroma, :key1) +        Application.delete_env(:pleroma, :key2) +        Application.delete_env(:pleroma, :key3) +        Application.delete_env(:pleroma, :key4) +        Application.delete_env(:pleroma, :keyaa1) +        Application.delete_env(:pleroma, :keyaa2) +        Application.delete_env(:pleroma, Pleroma.Web.Endpoint.NotReal) +        Application.delete_env(:pleroma, Pleroma.Captcha.NotReal) +        Application.put_env(:pleroma, :http, http) +        Application.put_env(:tesla, :adapter, Tesla.Mock) +        Restarter.Pleroma.refresh() +      end) +    end + +    setup do: clear_config(:configurable_from_database, true) + +    @tag capture_log: true +    test "create new config setting in db", %{conn: conn} do +      ueberauth = Application.get_env(:ueberauth, Ueberauth) +      on_exit(fn -> Application.put_env(:ueberauth, Ueberauth, ueberauth) end) + +      conn = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/api/pleroma/admin/config", %{ +          configs: [ +            %{group: ":pleroma", key: ":key1", value: "value1"}, +            %{ +              group: ":ueberauth", +              key: "Ueberauth", +              value: [%{"tuple" => [":consumer_secret", "aaaa"]}] +            }, +            %{ +              group: ":pleroma", +              key: ":key2", +              value: %{ +                ":nested_1" => "nested_value1", +                ":nested_2" => [ +                  %{":nested_22" => "nested_value222"}, +                  %{":nested_33" => %{":nested_44" => "nested_444"}} +                ] +              } +            }, +            %{ +              group: ":pleroma", +              key: ":key3", +              value: [ +                %{"nested_3" => ":nested_3", "nested_33" => "nested_33"}, +                %{"nested_4" => true} +              ] +            }, +            %{ +              group: ":pleroma", +              key: ":key4", +              value: %{":nested_5" => ":upload", "endpoint" => "https://example.com"} +            }, +            %{ +              group: ":idna", +              key: ":key5", +              value: %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]} +            } +          ] +        }) + +      assert json_response_and_validate_schema(conn, 200) == %{ +               "configs" => [ +                 %{ +                   "group" => ":pleroma", +                   "key" => ":key1", +                   "value" => "value1", +                   "db" => [":key1"] +                 }, +                 %{ +                   "group" => ":ueberauth", +                   "key" => "Ueberauth", +                   "value" => [%{"tuple" => [":consumer_secret", "aaaa"]}], +                   "db" => [":consumer_secret"] +                 }, +                 %{ +                   "group" => ":pleroma", +                   "key" => ":key2", +                   "value" => %{ +                     ":nested_1" => "nested_value1", +                     ":nested_2" => [ +                       %{":nested_22" => "nested_value222"}, +                       %{":nested_33" => %{":nested_44" => "nested_444"}} +                     ] +                   }, +                   "db" => [":key2"] +                 }, +                 %{ +                   "group" => ":pleroma", +                   "key" => ":key3", +                   "value" => [ +                     %{"nested_3" => ":nested_3", "nested_33" => "nested_33"}, +                     %{"nested_4" => true} +                   ], +                   "db" => [":key3"] +                 }, +                 %{ +                   "group" => ":pleroma", +                   "key" => ":key4", +                   "value" => %{"endpoint" => "https://example.com", ":nested_5" => ":upload"}, +                   "db" => [":key4"] +                 }, +                 %{ +                   "group" => ":idna", +                   "key" => ":key5", +                   "value" => %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]}, +                   "db" => [":key5"] +                 } +               ] +             } + +      assert Application.get_env(:pleroma, :key1) == "value1" + +      assert Application.get_env(:pleroma, :key2) == %{ +               nested_1: "nested_value1", +               nested_2: [ +                 %{nested_22: "nested_value222"}, +                 %{nested_33: %{nested_44: "nested_444"}} +               ] +             } + +      assert Application.get_env(:pleroma, :key3) == [ +               %{"nested_3" => :nested_3, "nested_33" => "nested_33"}, +               %{"nested_4" => true} +             ] + +      assert Application.get_env(:pleroma, :key4) == %{ +               "endpoint" => "https://example.com", +               nested_5: :upload +             } + +      assert Application.get_env(:idna, :key5) == {"string", Pleroma.Captcha.NotReal, []} +    end + +    test "save configs setting without explicit key", %{conn: conn} do +      level = Application.get_env(:quack, :level) +      meta = Application.get_env(:quack, :meta) +      webhook_url = Application.get_env(:quack, :webhook_url) + +      on_exit(fn -> +        Application.put_env(:quack, :level, level) +        Application.put_env(:quack, :meta, meta) +        Application.put_env(:quack, :webhook_url, webhook_url) +      end) + +      conn = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/api/pleroma/admin/config", %{ +          configs: [ +            %{ +              group: ":quack", +              key: ":level", +              value: ":info" +            }, +            %{ +              group: ":quack", +              key: ":meta", +              value: [":none"] +            }, +            %{ +              group: ":quack", +              key: ":webhook_url", +              value: "https://hooks.slack.com/services/KEY" +            } +          ] +        }) + +      assert json_response_and_validate_schema(conn, 200) == %{ +               "configs" => [ +                 %{ +                   "group" => ":quack", +                   "key" => ":level", +                   "value" => ":info", +                   "db" => [":level"] +                 }, +                 %{ +                   "group" => ":quack", +                   "key" => ":meta", +                   "value" => [":none"], +                   "db" => [":meta"] +                 }, +                 %{ +                   "group" => ":quack", +                   "key" => ":webhook_url", +                   "value" => "https://hooks.slack.com/services/KEY", +                   "db" => [":webhook_url"] +                 } +               ] +             } + +      assert Application.get_env(:quack, :level) == :info +      assert Application.get_env(:quack, :meta) == [:none] +      assert Application.get_env(:quack, :webhook_url) == "https://hooks.slack.com/services/KEY" +    end + +    test "saving config with partial update", %{conn: conn} do +      config = insert(:config, key: ":key1", value: :erlang.term_to_binary(key1: 1, key2: 2)) + +      conn = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/api/pleroma/admin/config", %{ +          configs: [ +            %{group: config.group, key: config.key, value: [%{"tuple" => [":key3", 3]}]} +          ] +        }) + +      assert json_response_and_validate_schema(conn, 200) == %{ +               "configs" => [ +                 %{ +                   "group" => ":pleroma", +                   "key" => ":key1", +                   "value" => [ +                     %{"tuple" => [":key1", 1]}, +                     %{"tuple" => [":key2", 2]}, +                     %{"tuple" => [":key3", 3]} +                   ], +                   "db" => [":key1", ":key2", ":key3"] +                 } +               ] +             } +    end + +    test "saving config which need pleroma reboot", %{conn: conn} do +      chat = Config.get(:chat) +      on_exit(fn -> Config.put(:chat, chat) end) + +      assert conn +             |> put_req_header("content-type", "application/json") +             |> post( +               "/api/pleroma/admin/config", +               %{ +                 configs: [ +                   %{group: ":pleroma", key: ":chat", value: [%{"tuple" => [":enabled", true]}]} +                 ] +               } +             ) +             |> json_response_and_validate_schema(200) == %{ +               "configs" => [ +                 %{ +                   "db" => [":enabled"], +                   "group" => ":pleroma", +                   "key" => ":chat", +                   "value" => [%{"tuple" => [":enabled", true]}] +                 } +               ], +               "need_reboot" => true +             } + +      configs = +        conn +        |> get("/api/pleroma/admin/config") +        |> json_response_and_validate_schema(200) + +      assert configs["need_reboot"] + +      capture_log(fn -> +        assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == +                 %{} +      end) =~ "pleroma restarted" + +      configs = +        conn +        |> get("/api/pleroma/admin/config") +        |> json_response_and_validate_schema(200) + +      assert configs["need_reboot"] == false +    end + +    test "update setting which need reboot, don't change reboot flag until reboot", %{conn: conn} do +      chat = Config.get(:chat) +      on_exit(fn -> Config.put(:chat, chat) end) + +      assert conn +             |> put_req_header("content-type", "application/json") +             |> post( +               "/api/pleroma/admin/config", +               %{ +                 configs: [ +                   %{group: ":pleroma", key: ":chat", value: [%{"tuple" => [":enabled", true]}]} +                 ] +               } +             ) +             |> json_response_and_validate_schema(200) == %{ +               "configs" => [ +                 %{ +                   "db" => [":enabled"], +                   "group" => ":pleroma", +                   "key" => ":chat", +                   "value" => [%{"tuple" => [":enabled", true]}] +                 } +               ], +               "need_reboot" => true +             } + +      assert conn +             |> put_req_header("content-type", "application/json") +             |> post("/api/pleroma/admin/config", %{ +               configs: [ +                 %{group: ":pleroma", key: ":key1", value: [%{"tuple" => [":key3", 3]}]} +               ] +             }) +             |> json_response_and_validate_schema(200) == %{ +               "configs" => [ +                 %{ +                   "group" => ":pleroma", +                   "key" => ":key1", +                   "value" => [ +                     %{"tuple" => [":key3", 3]} +                   ], +                   "db" => [":key3"] +                 } +               ], +               "need_reboot" => true +             } + +      capture_log(fn -> +        assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == +                 %{} +      end) =~ "pleroma restarted" + +      configs = +        conn +        |> get("/api/pleroma/admin/config") +        |> json_response_and_validate_schema(200) + +      assert configs["need_reboot"] == false +    end + +    test "saving config with nested merge", %{conn: conn} do +      config = +        insert(:config, key: ":key1", value: :erlang.term_to_binary(key1: 1, key2: [k1: 1, k2: 2])) + +      conn = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/api/pleroma/admin/config", %{ +          configs: [ +            %{ +              group: config.group, +              key: config.key, +              value: [ +                %{"tuple" => [":key3", 3]}, +                %{ +                  "tuple" => [ +                    ":key2", +                    [ +                      %{"tuple" => [":k2", 1]}, +                      %{"tuple" => [":k3", 3]} +                    ] +                  ] +                } +              ] +            } +          ] +        }) + +      assert json_response_and_validate_schema(conn, 200) == %{ +               "configs" => [ +                 %{ +                   "group" => ":pleroma", +                   "key" => ":key1", +                   "value" => [ +                     %{"tuple" => [":key1", 1]}, +                     %{"tuple" => [":key3", 3]}, +                     %{ +                       "tuple" => [ +                         ":key2", +                         [ +                           %{"tuple" => [":k1", 1]}, +                           %{"tuple" => [":k2", 1]}, +                           %{"tuple" => [":k3", 3]} +                         ] +                       ] +                     } +                   ], +                   "db" => [":key1", ":key3", ":key2"] +                 } +               ] +             } +    end + +    test "saving special atoms", %{conn: conn} do +      conn = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/api/pleroma/admin/config", %{ +          "configs" => [ +            %{ +              "group" => ":pleroma", +              "key" => ":key1", +              "value" => [ +                %{ +                  "tuple" => [ +                    ":ssl_options", +                    [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}] +                  ] +                } +              ] +            } +          ] +        }) + +      assert json_response_and_validate_schema(conn, 200) == %{ +               "configs" => [ +                 %{ +                   "group" => ":pleroma", +                   "key" => ":key1", +                   "value" => [ +                     %{ +                       "tuple" => [ +                         ":ssl_options", +                         [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}] +                       ] +                     } +                   ], +                   "db" => [":ssl_options"] +                 } +               ] +             } + +      assert Application.get_env(:pleroma, :key1) == [ +               ssl_options: [versions: [:tlsv1, :"tlsv1.1", :"tlsv1.2"]] +             ] +    end + +    test "saving full setting if value is in full_key_update list", %{conn: conn} do +      backends = Application.get_env(:logger, :backends) +      on_exit(fn -> Application.put_env(:logger, :backends, backends) end) + +      config = +        insert(:config, +          group: ":logger", +          key: ":backends", +          value: :erlang.term_to_binary([]) +        ) + +      Pleroma.Config.TransferTask.load_and_update_env([], false) + +      assert Application.get_env(:logger, :backends) == [] + +      conn = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/api/pleroma/admin/config", %{ +          configs: [ +            %{ +              group: config.group, +              key: config.key, +              value: [":console"] +            } +          ] +        }) + +      assert json_response_and_validate_schema(conn, 200) == %{ +               "configs" => [ +                 %{ +                   "group" => ":logger", +                   "key" => ":backends", +                   "value" => [ +                     ":console" +                   ], +                   "db" => [":backends"] +                 } +               ] +             } + +      assert Application.get_env(:logger, :backends) == [ +               :console +             ] +    end + +    test "saving full setting if value is not keyword", %{conn: conn} do +      config = +        insert(:config, +          group: ":tesla", +          key: ":adapter", +          value: :erlang.term_to_binary(Tesla.Adapter.Hackey) +        ) + +      conn = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/api/pleroma/admin/config", %{ +          configs: [ +            %{group: config.group, key: config.key, value: "Tesla.Adapter.Httpc"} +          ] +        }) + +      assert json_response_and_validate_schema(conn, 200) == %{ +               "configs" => [ +                 %{ +                   "group" => ":tesla", +                   "key" => ":adapter", +                   "value" => "Tesla.Adapter.Httpc", +                   "db" => [":adapter"] +                 } +               ] +             } +    end + +    test "update config setting & delete with fallback to default value", %{ +      conn: conn, +      admin: admin, +      token: token +    } do +      ueberauth = Application.get_env(:ueberauth, Ueberauth) +      config1 = insert(:config, key: ":keyaa1") +      config2 = insert(:config, key: ":keyaa2") + +      config3 = +        insert(:config, +          group: ":ueberauth", +          key: "Ueberauth" +        ) + +      conn = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/api/pleroma/admin/config", %{ +          configs: [ +            %{group: config1.group, key: config1.key, value: "another_value"}, +            %{group: config2.group, key: config2.key, value: "another_value"} +          ] +        }) + +      assert json_response_and_validate_schema(conn, 200) == %{ +               "configs" => [ +                 %{ +                   "group" => ":pleroma", +                   "key" => config1.key, +                   "value" => "another_value", +                   "db" => [":keyaa1"] +                 }, +                 %{ +                   "group" => ":pleroma", +                   "key" => config2.key, +                   "value" => "another_value", +                   "db" => [":keyaa2"] +                 } +               ] +             } + +      assert Application.get_env(:pleroma, :keyaa1) == "another_value" +      assert Application.get_env(:pleroma, :keyaa2) == "another_value" +      assert Application.get_env(:ueberauth, Ueberauth) == ConfigDB.from_binary(config3.value) + +      conn = +        build_conn() +        |> assign(:user, admin) +        |> assign(:token, token) +        |> put_req_header("content-type", "application/json") +        |> post("/api/pleroma/admin/config", %{ +          configs: [ +            %{group: config2.group, key: config2.key, delete: true}, +            %{ +              group: ":ueberauth", +              key: "Ueberauth", +              delete: true +            } +          ] +        }) + +      assert json_response_and_validate_schema(conn, 200) == %{ +               "configs" => [] +             } + +      assert Application.get_env(:ueberauth, Ueberauth) == ueberauth +      refute Keyword.has_key?(Application.get_all_env(:pleroma), :keyaa2) +    end + +    test "common config example", %{conn: conn} do +      conn = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/api/pleroma/admin/config", %{ +          configs: [ +            %{ +              "group" => ":pleroma", +              "key" => "Pleroma.Captcha.NotReal", +              "value" => [ +                %{"tuple" => [":enabled", false]}, +                %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]}, +                %{"tuple" => [":seconds_valid", 60]}, +                %{"tuple" => [":path", ""]}, +                %{"tuple" => [":key1", nil]}, +                %{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]}, +                %{"tuple" => [":regex1", "~r/https:\/\/example.com/"]}, +                %{"tuple" => [":regex2", "~r/https:\/\/example.com/u"]}, +                %{"tuple" => [":regex3", "~r/https:\/\/example.com/i"]}, +                %{"tuple" => [":regex4", "~r/https:\/\/example.com/s"]}, +                %{"tuple" => [":name", "Pleroma"]} +              ] +            } +          ] +        }) + +      assert Config.get([Pleroma.Captcha.NotReal, :name]) == "Pleroma" + +      assert json_response_and_validate_schema(conn, 200) == %{ +               "configs" => [ +                 %{ +                   "group" => ":pleroma", +                   "key" => "Pleroma.Captcha.NotReal", +                   "value" => [ +                     %{"tuple" => [":enabled", false]}, +                     %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]}, +                     %{"tuple" => [":seconds_valid", 60]}, +                     %{"tuple" => [":path", ""]}, +                     %{"tuple" => [":key1", nil]}, +                     %{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]}, +                     %{"tuple" => [":regex1", "~r/https:\\/\\/example.com/"]}, +                     %{"tuple" => [":regex2", "~r/https:\\/\\/example.com/u"]}, +                     %{"tuple" => [":regex3", "~r/https:\\/\\/example.com/i"]}, +                     %{"tuple" => [":regex4", "~r/https:\\/\\/example.com/s"]}, +                     %{"tuple" => [":name", "Pleroma"]} +                   ], +                   "db" => [ +                     ":enabled", +                     ":method", +                     ":seconds_valid", +                     ":path", +                     ":key1", +                     ":partial_chain", +                     ":regex1", +                     ":regex2", +                     ":regex3", +                     ":regex4", +                     ":name" +                   ] +                 } +               ] +             } +    end + +    test "tuples with more than two values", %{conn: conn} do +      conn = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/api/pleroma/admin/config", %{ +          configs: [ +            %{ +              "group" => ":pleroma", +              "key" => "Pleroma.Web.Endpoint.NotReal", +              "value" => [ +                %{ +                  "tuple" => [ +                    ":http", +                    [ +                      %{ +                        "tuple" => [ +                          ":key2", +                          [ +                            %{ +                              "tuple" => [ +                                ":_", +                                [ +                                  %{ +                                    "tuple" => [ +                                      "/api/v1/streaming", +                                      "Pleroma.Web.MastodonAPI.WebsocketHandler", +                                      [] +                                    ] +                                  }, +                                  %{ +                                    "tuple" => [ +                                      "/websocket", +                                      "Phoenix.Endpoint.CowboyWebSocket", +                                      %{ +                                        "tuple" => [ +                                          "Phoenix.Transports.WebSocket", +                                          %{ +                                            "tuple" => [ +                                              "Pleroma.Web.Endpoint", +                                              "Pleroma.Web.UserSocket", +                                              [] +                                            ] +                                          } +                                        ] +                                      } +                                    ] +                                  }, +                                  %{ +                                    "tuple" => [ +                                      ":_", +                                      "Phoenix.Endpoint.Cowboy2Handler", +                                      %{"tuple" => ["Pleroma.Web.Endpoint", []]} +                                    ] +                                  } +                                ] +                              ] +                            } +                          ] +                        ] +                      } +                    ] +                  ] +                } +              ] +            } +          ] +        }) + +      assert json_response_and_validate_schema(conn, 200) == %{ +               "configs" => [ +                 %{ +                   "group" => ":pleroma", +                   "key" => "Pleroma.Web.Endpoint.NotReal", +                   "value" => [ +                     %{ +                       "tuple" => [ +                         ":http", +                         [ +                           %{ +                             "tuple" => [ +                               ":key2", +                               [ +                                 %{ +                                   "tuple" => [ +                                     ":_", +                                     [ +                                       %{ +                                         "tuple" => [ +                                           "/api/v1/streaming", +                                           "Pleroma.Web.MastodonAPI.WebsocketHandler", +                                           [] +                                         ] +                                       }, +                                       %{ +                                         "tuple" => [ +                                           "/websocket", +                                           "Phoenix.Endpoint.CowboyWebSocket", +                                           %{ +                                             "tuple" => [ +                                               "Phoenix.Transports.WebSocket", +                                               %{ +                                                 "tuple" => [ +                                                   "Pleroma.Web.Endpoint", +                                                   "Pleroma.Web.UserSocket", +                                                   [] +                                                 ] +                                               } +                                             ] +                                           } +                                         ] +                                       }, +                                       %{ +                                         "tuple" => [ +                                           ":_", +                                           "Phoenix.Endpoint.Cowboy2Handler", +                                           %{"tuple" => ["Pleroma.Web.Endpoint", []]} +                                         ] +                                       } +                                     ] +                                   ] +                                 } +                               ] +                             ] +                           } +                         ] +                       ] +                     } +                   ], +                   "db" => [":http"] +                 } +               ] +             } +    end + +    test "settings with nesting map", %{conn: conn} do +      conn = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/api/pleroma/admin/config", %{ +          configs: [ +            %{ +              "group" => ":pleroma", +              "key" => ":key1", +              "value" => [ +                %{"tuple" => [":key2", "some_val"]}, +                %{ +                  "tuple" => [ +                    ":key3", +                    %{ +                      ":max_options" => 20, +                      ":max_option_chars" => 200, +                      ":min_expiration" => 0, +                      ":max_expiration" => 31_536_000, +                      "nested" => %{ +                        ":max_options" => 20, +                        ":max_option_chars" => 200, +                        ":min_expiration" => 0, +                        ":max_expiration" => 31_536_000 +                      } +                    } +                  ] +                } +              ] +            } +          ] +        }) + +      assert json_response_and_validate_schema(conn, 200) == +               %{ +                 "configs" => [ +                   %{ +                     "group" => ":pleroma", +                     "key" => ":key1", +                     "value" => [ +                       %{"tuple" => [":key2", "some_val"]}, +                       %{ +                         "tuple" => [ +                           ":key3", +                           %{ +                             ":max_expiration" => 31_536_000, +                             ":max_option_chars" => 200, +                             ":max_options" => 20, +                             ":min_expiration" => 0, +                             "nested" => %{ +                               ":max_expiration" => 31_536_000, +                               ":max_option_chars" => 200, +                               ":max_options" => 20, +                               ":min_expiration" => 0 +                             } +                           } +                         ] +                       } +                     ], +                     "db" => [":key2", ":key3"] +                   } +                 ] +               } +    end + +    test "value as map", %{conn: conn} do +      conn = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/api/pleroma/admin/config", %{ +          configs: [ +            %{ +              "group" => ":pleroma", +              "key" => ":key1", +              "value" => %{"key" => "some_val"} +            } +          ] +        }) + +      assert json_response_and_validate_schema(conn, 200) == +               %{ +                 "configs" => [ +                   %{ +                     "group" => ":pleroma", +                     "key" => ":key1", +                     "value" => %{"key" => "some_val"}, +                     "db" => [":key1"] +                   } +                 ] +               } +    end + +    test "queues key as atom", %{conn: conn} do +      conn = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/api/pleroma/admin/config", %{ +          configs: [ +            %{ +              "group" => ":oban", +              "key" => ":queues", +              "value" => [ +                %{"tuple" => [":federator_incoming", 50]}, +                %{"tuple" => [":federator_outgoing", 50]}, +                %{"tuple" => [":web_push", 50]}, +                %{"tuple" => [":mailer", 10]}, +                %{"tuple" => [":transmogrifier", 20]}, +                %{"tuple" => [":scheduled_activities", 10]}, +                %{"tuple" => [":background", 5]} +              ] +            } +          ] +        }) + +      assert json_response_and_validate_schema(conn, 200) == %{ +               "configs" => [ +                 %{ +                   "group" => ":oban", +                   "key" => ":queues", +                   "value" => [ +                     %{"tuple" => [":federator_incoming", 50]}, +                     %{"tuple" => [":federator_outgoing", 50]}, +                     %{"tuple" => [":web_push", 50]}, +                     %{"tuple" => [":mailer", 10]}, +                     %{"tuple" => [":transmogrifier", 20]}, +                     %{"tuple" => [":scheduled_activities", 10]}, +                     %{"tuple" => [":background", 5]} +                   ], +                   "db" => [ +                     ":federator_incoming", +                     ":federator_outgoing", +                     ":web_push", +                     ":mailer", +                     ":transmogrifier", +                     ":scheduled_activities", +                     ":background" +                   ] +                 } +               ] +             } +    end + +    test "delete part of settings by atom subkeys", %{conn: conn} do +      config = +        insert(:config, +          key: ":keyaa1", +          value: :erlang.term_to_binary(subkey1: "val1", subkey2: "val2", subkey3: "val3") +        ) + +      conn = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/api/pleroma/admin/config", %{ +          configs: [ +            %{ +              group: config.group, +              key: config.key, +              subkeys: [":subkey1", ":subkey3"], +              delete: true +            } +          ] +        }) + +      assert json_response_and_validate_schema(conn, 200) == %{ +               "configs" => [ +                 %{ +                   "group" => ":pleroma", +                   "key" => ":keyaa1", +                   "value" => [%{"tuple" => [":subkey2", "val2"]}], +                   "db" => [":subkey2"] +                 } +               ] +             } +    end + +    test "proxy tuple localhost", %{conn: conn} do +      conn = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/api/pleroma/admin/config", %{ +          configs: [ +            %{ +              group: ":pleroma", +              key: ":http", +              value: [ +                %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]} +              ] +            } +          ] +        }) + +      assert %{ +               "configs" => [ +                 %{ +                   "group" => ":pleroma", +                   "key" => ":http", +                   "value" => value, +                   "db" => db +                 } +               ] +             } = json_response_and_validate_schema(conn, 200) + +      assert %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]} in value +      assert ":proxy_url" in db +    end + +    test "proxy tuple domain", %{conn: conn} do +      conn = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/api/pleroma/admin/config", %{ +          configs: [ +            %{ +              group: ":pleroma", +              key: ":http", +              value: [ +                %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]} +              ] +            } +          ] +        }) + +      assert %{ +               "configs" => [ +                 %{ +                   "group" => ":pleroma", +                   "key" => ":http", +                   "value" => value, +                   "db" => db +                 } +               ] +             } = json_response_and_validate_schema(conn, 200) + +      assert %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]} in value +      assert ":proxy_url" in db +    end + +    test "proxy tuple ip", %{conn: conn} do +      conn = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/api/pleroma/admin/config", %{ +          configs: [ +            %{ +              group: ":pleroma", +              key: ":http", +              value: [ +                %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]} +              ] +            } +          ] +        }) + +      assert %{ +               "configs" => [ +                 %{ +                   "group" => ":pleroma", +                   "key" => ":http", +                   "value" => value, +                   "db" => db +                 } +               ] +             } = json_response_and_validate_schema(conn, 200) + +      assert %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]} in value +      assert ":proxy_url" in db +    end + +    @tag capture_log: true +    test "doesn't set keys not in the whitelist", %{conn: conn} do +      clear_config(:database_config_whitelist, [ +        {:pleroma, :key1}, +        {:pleroma, :key2}, +        {:pleroma, Pleroma.Captcha.NotReal}, +        {:not_real} +      ]) + +      conn +      |> put_req_header("content-type", "application/json") +      |> post("/api/pleroma/admin/config", %{ +        configs: [ +          %{group: ":pleroma", key: ":key1", value: "value1"}, +          %{group: ":pleroma", key: ":key2", value: "value2"}, +          %{group: ":pleroma", key: ":key3", value: "value3"}, +          %{group: ":pleroma", key: "Pleroma.Web.Endpoint.NotReal", value: "value4"}, +          %{group: ":pleroma", key: "Pleroma.Captcha.NotReal", value: "value5"}, +          %{group: ":not_real", key: ":anything", value: "value6"} +        ] +      }) + +      assert Application.get_env(:pleroma, :key1) == "value1" +      assert Application.get_env(:pleroma, :key2) == "value2" +      assert Application.get_env(:pleroma, :key3) == nil +      assert Application.get_env(:pleroma, Pleroma.Web.Endpoint.NotReal) == nil +      assert Application.get_env(:pleroma, Pleroma.Captcha.NotReal) == "value5" +      assert Application.get_env(:not_real, :anything) == "value6" +    end +  end + +  describe "GET /api/pleroma/admin/config/descriptions" do +    test "structure", %{conn: conn} do +      admin = insert(:user, is_admin: true) + +      conn = +        assign(conn, :user, admin) +        |> get("/api/pleroma/admin/config/descriptions") + +      assert [child | _others] = json_response_and_validate_schema(conn, 200) + +      assert child["children"] +      assert child["key"] +      assert String.starts_with?(child["group"], ":") +      assert child["description"] +    end + +    test "filters by database configuration whitelist", %{conn: conn} do +      clear_config(:database_config_whitelist, [ +        {:pleroma, :instance}, +        {:pleroma, :activitypub}, +        {:pleroma, Pleroma.Upload}, +        {:esshd} +      ]) + +      admin = insert(:user, is_admin: true) + +      conn = +        assign(conn, :user, admin) +        |> get("/api/pleroma/admin/config/descriptions") + +      children = json_response_and_validate_schema(conn, 200) + +      assert length(children) == 4 + +      assert Enum.count(children, fn c -> c["group"] == ":pleroma" end) == 3 + +      instance = Enum.find(children, fn c -> c["key"] == ":instance" end) +      assert instance["children"] + +      activitypub = Enum.find(children, fn c -> c["key"] == ":activitypub" end) +      assert activitypub["children"] + +      web_endpoint = Enum.find(children, fn c -> c["key"] == "Pleroma.Upload" end) +      assert web_endpoint["children"] + +      esshd = Enum.find(children, fn c -> c["group"] == ":esshd" end) +      assert esshd["children"] +    end +  end +end diff --git a/test/web/admin_api/controllers/relay_controller_test.exs b/test/web/admin_api/controllers/relay_controller_test.exs new file mode 100644 index 000000000..64086adc5 --- /dev/null +++ b/test/web/admin_api/controllers/relay_controller_test.exs @@ -0,0 +1,92 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.AdminAPI.RelayControllerTest do +  use Pleroma.Web.ConnCase + +  import Pleroma.Factory + +  alias Pleroma.Config +  alias Pleroma.ModerationLog +  alias Pleroma.Repo +  alias Pleroma.User + +  setup_all do +    Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) + +    :ok +  end + +  setup do +    admin = insert(:user, is_admin: true) +    token = insert(:oauth_admin_token, user: admin) + +    conn = +      build_conn() +      |> assign(:user, admin) +      |> assign(:token, token) + +    {:ok, %{admin: admin, token: token, conn: conn}} +  end + +  describe "relays" do +    test "POST /relay", %{conn: conn, admin: admin} do +      conn = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/api/pleroma/admin/relay", %{ +          relay_url: "http://mastodon.example.org/users/admin" +        }) + +      assert json_response_and_validate_schema(conn, 200) == +               "http://mastodon.example.org/users/admin" + +      log_entry = Repo.one(ModerationLog) + +      assert ModerationLog.get_log_entry_message(log_entry) == +               "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin" +    end + +    test "GET /relay", %{conn: conn} do +      relay_user = Pleroma.Web.ActivityPub.Relay.get_actor() + +      ["http://mastodon.example.org/users/admin", "https://mstdn.io/users/mayuutann"] +      |> Enum.each(fn ap_id -> +        {:ok, user} = User.get_or_fetch_by_ap_id(ap_id) +        User.follow(relay_user, user) +      end) + +      conn = get(conn, "/api/pleroma/admin/relay") + +      assert json_response_and_validate_schema(conn, 200)["relays"] -- +               ["mastodon.example.org", "mstdn.io"] == [] +    end + +    test "DELETE /relay", %{conn: conn, admin: admin} do +      conn +      |> put_req_header("content-type", "application/json") +      |> post("/api/pleroma/admin/relay", %{ +        relay_url: "http://mastodon.example.org/users/admin" +      }) + +      conn = +        conn +        |> put_req_header("content-type", "application/json") +        |> delete("/api/pleroma/admin/relay", %{ +          relay_url: "http://mastodon.example.org/users/admin" +        }) + +      assert json_response_and_validate_schema(conn, 200) == +               "http://mastodon.example.org/users/admin" + +      [log_entry_one, log_entry_two] = Repo.all(ModerationLog) + +      assert ModerationLog.get_log_entry_message(log_entry_one) == +               "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin" + +      assert ModerationLog.get_log_entry_message(log_entry_two) == +               "@#{admin.nickname} unfollowed relay: http://mastodon.example.org/users/admin" +    end +  end +end diff --git a/test/web/common_api/common_api_test.exs b/test/web/common_api/common_api_test.exs index 2291f76dd..6bd26050e 100644 --- a/test/web/common_api/common_api_test.exs +++ b/test/web/common_api/common_api_test.exs @@ -5,7 +5,9 @@  defmodule Pleroma.Web.CommonAPITest do    use Pleroma.DataCase    alias Pleroma.Activity +  alias Pleroma.Chat    alias Pleroma.Conversation.Participation +  alias Pleroma.Notification    alias Pleroma.Object    alias Pleroma.User    alias Pleroma.Web.ActivityPub.ActivityPub @@ -23,6 +25,150 @@ defmodule Pleroma.Web.CommonAPITest do    setup do: clear_config([:instance, :limit])    setup do: clear_config([:instance, :max_pinned_statuses]) +  describe "posting chat messages" do +    setup do: clear_config([:instance, :chat_limit]) + +    test "it posts a chat message without content but with an attachment" do +      author = insert(:user) +      recipient = insert(:user) + +      file = %Plug.Upload{ +        content_type: "image/jpg", +        path: Path.absname("test/fixtures/image.jpg"), +        filename: "an_image.jpg" +      } + +      {:ok, upload} = ActivityPub.upload(file, actor: author.ap_id) + +      with_mocks([ +        { +          Pleroma.Web.Streamer, +          [], +          [ +            stream: fn _, _ -> +              nil +            end +          ] +        }, +        { +          Pleroma.Web.Push, +          [], +          [ +            send: fn _ -> nil end +          ] +        } +      ]) do +        {:ok, activity} = +          CommonAPI.post_chat_message( +            author, +            recipient, +            nil, +            media_id: upload.id +          ) + +        notification = +          Notification.for_user_and_activity(recipient, activity) +          |> Repo.preload(:activity) + +        assert called(Pleroma.Web.Push.send(notification)) +        assert called(Pleroma.Web.Streamer.stream(["user", "user:notification"], notification)) +        assert called(Pleroma.Web.Streamer.stream(["user", "user:pleroma_chat"], :_)) + +        assert activity +      end +    end + +    test "it adds html newlines" do +      author = insert(:user) +      recipient = insert(:user) + +      other_user = insert(:user) + +      {:ok, activity} = +        CommonAPI.post_chat_message( +          author, +          recipient, +          "uguu\nuguuu" +        ) + +      assert other_user.ap_id not in activity.recipients + +      object = Object.normalize(activity, false) + +      assert object.data["content"] == "uguu<br/>uguuu" +    end + +    test "it linkifies" do +      author = insert(:user) +      recipient = insert(:user) + +      other_user = insert(:user) + +      {:ok, activity} = +        CommonAPI.post_chat_message( +          author, +          recipient, +          "https://example.org is the site of @#{other_user.nickname} #2hu" +        ) + +      assert other_user.ap_id not in activity.recipients + +      object = Object.normalize(activity, false) + +      assert object.data["content"] == +               "<a href=\"https://example.org\" rel=\"ugc\">https://example.org</a> is the site of <span class=\"h-card\"><a class=\"u-url mention\" data-user=\"#{ +                 other_user.id +               }\" href=\"#{other_user.ap_id}\" rel=\"ugc\">@<span>#{other_user.nickname}</span></a></span> <a class=\"hashtag\" data-tag=\"2hu\" href=\"http://localhost:4001/tag/2hu\">#2hu</a>" +    end + +    test "it posts a chat message" do +      author = insert(:user) +      recipient = insert(:user) + +      {:ok, activity} = +        CommonAPI.post_chat_message( +          author, +          recipient, +          "a test message <script>alert('uuu')</script> :firefox:" +        ) + +      assert activity.data["type"] == "Create" +      assert activity.local +      object = Object.normalize(activity) + +      assert object.data["type"] == "ChatMessage" +      assert object.data["to"] == [recipient.ap_id] + +      assert object.data["content"] == +               "a test message <script>alert('uuu')</script> :firefox:" + +      assert object.data["emoji"] == %{ +               "firefox" => "http://localhost:4001/emoji/Firefox.gif" +             } + +      assert Chat.get(author.id, recipient.ap_id) +      assert Chat.get(recipient.id, author.ap_id) + +      assert :ok == Pleroma.Web.Federator.perform(:publish, activity) +    end + +    test "it reject messages over the local limit" do +      Pleroma.Config.put([:instance, :chat_limit], 2) + +      author = insert(:user) +      recipient = insert(:user) + +      {:error, message} = +        CommonAPI.post_chat_message( +          author, +          recipient, +          "123" +        ) + +      assert message == :content_too_long +    end +  end +    describe "unblocking" do      test "it works even without an existing block activity" do        blocked = insert(:user) diff --git a/test/web/mastodon_api/controllers/notification_controller_test.exs b/test/web/mastodon_api/controllers/notification_controller_test.exs index e278d61f5..698c99711 100644 --- a/test/web/mastodon_api/controllers/notification_controller_test.exs +++ b/test/web/mastodon_api/controllers/notification_controller_test.exs @@ -54,6 +54,27 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do      assert response == expected_response    end +  test "by default, does not contain pleroma:chat_mention" do +    %{user: user, conn: conn} = oauth_access(["read:notifications"]) +    other_user = insert(:user) + +    {:ok, _activity} = CommonAPI.post_chat_message(other_user, user, "hey") + +    result = +      conn +      |> get("/api/v1/notifications") +      |> json_response_and_validate_schema(200) + +    assert [] == result + +    result = +      conn +      |> get("/api/v1/notifications?include_types[]=pleroma:chat_mention") +      |> json_response_and_validate_schema(200) + +    assert [_] = result +  end +    test "getting a single notification" do      %{user: user, conn: conn} = oauth_access(["read:notifications"])      other_user = insert(:user) diff --git a/test/web/mastodon_api/controllers/search_controller_test.exs b/test/web/mastodon_api/controllers/search_controller_test.exs index 84d46895e..c605957b1 100644 --- a/test/web/mastodon_api/controllers/search_controller_test.exs +++ b/test/web/mastodon_api/controllers/search_controller_test.exs @@ -111,6 +111,44 @@ defmodule Pleroma.Web.MastodonAPI.SearchControllerTest do                 %{"name" => "prone", "url" => "#{Web.base_url()}/tag/prone"},                 %{"name" => "AccidentProne", "url" => "#{Web.base_url()}/tag/AccidentProne"}               ] + +      results = +        conn +        |> get("/api/v2/search?#{URI.encode_query(%{q: "https://shpposter.club/users/shpuld"})}") +        |> json_response_and_validate_schema(200) + +      assert results["hashtags"] == [ +               %{"name" => "shpuld", "url" => "#{Web.base_url()}/tag/shpuld"} +             ] + +      results = +        conn +        |> get( +          "/api/v2/search?#{ +            URI.encode_query(%{ +              q: +                "https://www.washingtonpost.com/sports/2020/06/10/" <> +                  "nascar-ban-display-confederate-flag-all-events-properties/" +            }) +          }" +        ) +        |> json_response_and_validate_schema(200) + +      assert results["hashtags"] == [ +               %{"name" => "nascar", "url" => "#{Web.base_url()}/tag/nascar"}, +               %{"name" => "ban", "url" => "#{Web.base_url()}/tag/ban"}, +               %{"name" => "display", "url" => "#{Web.base_url()}/tag/display"}, +               %{"name" => "confederate", "url" => "#{Web.base_url()}/tag/confederate"}, +               %{"name" => "flag", "url" => "#{Web.base_url()}/tag/flag"}, +               %{"name" => "all", "url" => "#{Web.base_url()}/tag/all"}, +               %{"name" => "events", "url" => "#{Web.base_url()}/tag/events"}, +               %{"name" => "properties", "url" => "#{Web.base_url()}/tag/properties"}, +               %{ +                 "name" => "NascarBanDisplayConfederateFlagAllEventsProperties", +                 "url" => +                   "#{Web.base_url()}/tag/NascarBanDisplayConfederateFlagAllEventsProperties" +               } +             ]      end      test "excludes a blocked users from search results", %{conn: conn} do diff --git a/test/web/mastodon_api/controllers/subscription_controller_test.exs b/test/web/mastodon_api/controllers/subscription_controller_test.exs index 4aa260663..d36bb1ae8 100644 --- a/test/web/mastodon_api/controllers/subscription_controller_test.exs +++ b/test/web/mastodon_api/controllers/subscription_controller_test.exs @@ -58,7 +58,9 @@ defmodule Pleroma.Web.MastodonAPI.SubscriptionControllerTest do        result =          conn          |> post("/api/v1/push/subscription", %{ -          "data" => %{"alerts" => %{"mention" => true, "test" => true}}, +          "data" => %{ +            "alerts" => %{"mention" => true, "test" => true, "pleroma:chat_mention" => true} +          },            "subscription" => @sub          })          |> json_response_and_validate_schema(200) @@ -66,7 +68,7 @@ defmodule Pleroma.Web.MastodonAPI.SubscriptionControllerTest do        [subscription] = Pleroma.Repo.all(Subscription)        assert %{ -               "alerts" => %{"mention" => true}, +               "alerts" => %{"mention" => true, "pleroma:chat_mention" => true},                 "endpoint" => subscription.endpoint,                 "id" => to_string(subscription.id),                 "server_key" => @server_key diff --git a/test/web/mastodon_api/views/account_view_test.exs b/test/web/mastodon_api/views/account_view_test.exs index f91333e5c..044f088a4 100644 --- a/test/web/mastodon_api/views/account_view_test.exs +++ b/test/web/mastodon_api/views/account_view_test.exs @@ -72,6 +72,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do          fields: []        },        pleroma: %{ +        ap_id: user.ap_id,          background_image: "https://example.com/images/asuka_hospital.png",          confirmation_pending: false,          tags: [], @@ -148,6 +149,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do          fields: []        },        pleroma: %{ +        ap_id: user.ap_id,          background_image: nil,          confirmation_pending: false,          tags: [], diff --git a/test/web/mastodon_api/views/notification_view_test.exs b/test/web/mastodon_api/views/notification_view_test.exs index f15be1df1..b2fa5b302 100644 --- a/test/web/mastodon_api/views/notification_view_test.exs +++ b/test/web/mastodon_api/views/notification_view_test.exs @@ -6,7 +6,10 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do    use Pleroma.DataCase    alias Pleroma.Activity +  alias Pleroma.Chat +  alias Pleroma.Chat.MessageReference    alias Pleroma.Notification +  alias Pleroma.Object    alias Pleroma.Repo    alias Pleroma.User    alias Pleroma.Web.CommonAPI @@ -14,6 +17,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do    alias Pleroma.Web.MastodonAPI.AccountView    alias Pleroma.Web.MastodonAPI.NotificationView    alias Pleroma.Web.MastodonAPI.StatusView +  alias Pleroma.Web.PleromaAPI.Chat.MessageReferenceView    import Pleroma.Factory    defp test_notifications_rendering(notifications, user, expected_result) do @@ -31,6 +35,30 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do      assert expected_result == result    end +  test "ChatMessage notification" do +    user = insert(:user) +    recipient = insert(:user) +    {:ok, activity} = CommonAPI.post_chat_message(user, recipient, "what's up my dude") + +    {:ok, [notification]} = Notification.create_notifications(activity) + +    object = Object.normalize(activity) +    chat = Chat.get(recipient.id, user.ap_id) + +    cm_ref = MessageReference.for_chat_and_object(chat, object) + +    expected = %{ +      id: to_string(notification.id), +      pleroma: %{is_seen: false}, +      type: "pleroma:chat_mention", +      account: AccountView.render("show.json", %{user: user, for: recipient}), +      chat_message: MessageReferenceView.render("show.json", %{chat_message_reference: cm_ref}), +      created_at: Utils.to_masto_date(notification.inserted_at) +    } + +    test_notifications_rendering([notification], recipient, [expected]) +  end +    test "Mention notification" do      user = insert(:user)      mentioned_user = insert(:user) diff --git a/test/web/node_info_test.exs b/test/web/node_info_test.exs index 9bcc07b37..00925caad 100644 --- a/test/web/node_info_test.exs +++ b/test/web/node_info_test.exs @@ -145,7 +145,8 @@ defmodule Pleroma.Web.NodeInfoTest do        "shareable_emoji_packs",        "multifetch",        "pleroma_emoji_reactions", -      "pleroma:api/v1/notifications:include_types_filter" +      "pleroma:api/v1/notifications:include_types_filter", +      "pleroma_chat_messages"      ]      assert MapSet.subset?( diff --git a/test/web/pleroma_api/controllers/chat_controller_test.exs b/test/web/pleroma_api/controllers/chat_controller_test.exs new file mode 100644 index 000000000..82e16741d --- /dev/null +++ b/test/web/pleroma_api/controllers/chat_controller_test.exs @@ -0,0 +1,336 @@ +# 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.ChatControllerTest do +  use Pleroma.Web.ConnCase, async: true + +  alias Pleroma.Chat +  alias Pleroma.Chat.MessageReference +  alias Pleroma.Object +  alias Pleroma.User +  alias Pleroma.Web.ActivityPub.ActivityPub +  alias Pleroma.Web.CommonAPI + +  import Pleroma.Factory + +  describe "POST /api/v1/pleroma/chats/:id/messages/:message_id/read" do +    setup do: oauth_access(["write:chats"]) + +    test "it marks one message as read", %{conn: conn, user: user} do +      other_user = insert(:user) + +      {:ok, create} = CommonAPI.post_chat_message(other_user, user, "sup") +      {:ok, _create} = CommonAPI.post_chat_message(other_user, user, "sup part 2") +      {:ok, chat} = Chat.get_or_create(user.id, other_user.ap_id) +      object = Object.normalize(create, false) +      cm_ref = MessageReference.for_chat_and_object(chat, object) + +      assert cm_ref.unread == true + +      result = +        conn +        |> post("/api/v1/pleroma/chats/#{chat.id}/messages/#{cm_ref.id}/read") +        |> json_response_and_validate_schema(200) + +      assert result["unread"] == false + +      cm_ref = MessageReference.for_chat_and_object(chat, object) + +      assert cm_ref.unread == false +    end +  end + +  describe "POST /api/v1/pleroma/chats/:id/read" do +    setup do: oauth_access(["write:chats"]) + +    test "given a `last_read_id`, it marks everything until then as read", %{ +      conn: conn, +      user: user +    } do +      other_user = insert(:user) + +      {:ok, create} = CommonAPI.post_chat_message(other_user, user, "sup") +      {:ok, _create} = CommonAPI.post_chat_message(other_user, user, "sup part 2") +      {:ok, chat} = Chat.get_or_create(user.id, other_user.ap_id) +      object = Object.normalize(create, false) +      cm_ref = MessageReference.for_chat_and_object(chat, object) + +      assert cm_ref.unread == true + +      result = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/api/v1/pleroma/chats/#{chat.id}/read", %{"last_read_id" => cm_ref.id}) +        |> json_response_and_validate_schema(200) + +      assert result["unread"] == 1 + +      cm_ref = MessageReference.for_chat_and_object(chat, object) + +      assert cm_ref.unread == false +    end +  end + +  describe "POST /api/v1/pleroma/chats/:id/messages" do +    setup do: oauth_access(["write:chats"]) + +    test "it posts a message to the chat", %{conn: conn, user: user} do +      other_user = insert(:user) + +      {:ok, chat} = Chat.get_or_create(user.id, other_user.ap_id) + +      result = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/api/v1/pleroma/chats/#{chat.id}/messages", %{"content" => "Hallo!!"}) +        |> json_response_and_validate_schema(200) + +      assert result["content"] == "Hallo!!" +      assert result["chat_id"] == chat.id |> to_string() +    end + +    test "it fails if there is no content", %{conn: conn, user: user} do +      other_user = insert(:user) + +      {:ok, chat} = Chat.get_or_create(user.id, other_user.ap_id) + +      result = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/api/v1/pleroma/chats/#{chat.id}/messages") +        |> json_response_and_validate_schema(400) + +      assert result +    end + +    test "it works with an attachment", %{conn: conn, user: user} do +      file = %Plug.Upload{ +        content_type: "image/jpg", +        path: Path.absname("test/fixtures/image.jpg"), +        filename: "an_image.jpg" +      } + +      {:ok, upload} = ActivityPub.upload(file, actor: user.ap_id) + +      other_user = insert(:user) + +      {:ok, chat} = Chat.get_or_create(user.id, other_user.ap_id) + +      result = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/api/v1/pleroma/chats/#{chat.id}/messages", %{ +          "media_id" => to_string(upload.id) +        }) +        |> json_response_and_validate_schema(200) + +      assert result["attachment"] +    end +  end + +  describe "DELETE /api/v1/pleroma/chats/:id/messages/:message_id" do +    setup do: oauth_access(["write:chats"]) + +    test "it deletes a message from the chat", %{conn: conn, user: user} do +      recipient = insert(:user) + +      {:ok, message} = +        CommonAPI.post_chat_message(user, recipient, "Hello darkness my old friend") + +      {:ok, other_message} = CommonAPI.post_chat_message(recipient, user, "nico nico ni") + +      object = Object.normalize(message, false) + +      chat = Chat.get(user.id, recipient.ap_id) + +      cm_ref = MessageReference.for_chat_and_object(chat, object) + +      # Deleting your own message removes the message and the reference +      result = +        conn +        |> put_req_header("content-type", "application/json") +        |> delete("/api/v1/pleroma/chats/#{chat.id}/messages/#{cm_ref.id}") +        |> json_response_and_validate_schema(200) + +      assert result["id"] == cm_ref.id +      refute MessageReference.get_by_id(cm_ref.id) +      assert %{data: %{"type" => "Tombstone"}} = Object.get_by_id(object.id) + +      # Deleting other people's messages just removes the reference +      object = Object.normalize(other_message, false) +      cm_ref = MessageReference.for_chat_and_object(chat, object) + +      result = +        conn +        |> put_req_header("content-type", "application/json") +        |> delete("/api/v1/pleroma/chats/#{chat.id}/messages/#{cm_ref.id}") +        |> json_response_and_validate_schema(200) + +      assert result["id"] == cm_ref.id +      refute MessageReference.get_by_id(cm_ref.id) +      assert Object.get_by_id(object.id) +    end +  end + +  describe "GET /api/v1/pleroma/chats/:id/messages" do +    setup do: oauth_access(["read:chats"]) + +    test "it paginates", %{conn: conn, user: user} do +      recipient = insert(:user) + +      Enum.each(1..30, fn _ -> +        {:ok, _} = CommonAPI.post_chat_message(user, recipient, "hey") +      end) + +      chat = Chat.get(user.id, recipient.ap_id) + +      result = +        conn +        |> get("/api/v1/pleroma/chats/#{chat.id}/messages") +        |> json_response_and_validate_schema(200) + +      assert length(result) == 20 + +      result = +        conn +        |> get("/api/v1/pleroma/chats/#{chat.id}/messages?max_id=#{List.last(result)["id"]}") +        |> json_response_and_validate_schema(200) + +      assert length(result) == 10 +    end + +    test "it returns the messages for a given chat", %{conn: conn, user: user} do +      other_user = insert(:user) +      third_user = insert(:user) + +      {:ok, _} = CommonAPI.post_chat_message(user, other_user, "hey") +      {:ok, _} = CommonAPI.post_chat_message(user, third_user, "hey") +      {:ok, _} = CommonAPI.post_chat_message(user, other_user, "how are you?") +      {:ok, _} = CommonAPI.post_chat_message(other_user, user, "fine, how about you?") + +      chat = Chat.get(user.id, other_user.ap_id) + +      result = +        conn +        |> get("/api/v1/pleroma/chats/#{chat.id}/messages") +        |> json_response_and_validate_schema(200) + +      result +      |> Enum.each(fn message -> +        assert message["chat_id"] == chat.id |> to_string() +      end) + +      assert length(result) == 3 + +      # Trying to get the chat of a different user +      result = +        conn +        |> assign(:user, other_user) +        |> get("/api/v1/pleroma/chats/#{chat.id}/messages") + +      assert result |> json_response(404) +    end +  end + +  describe "POST /api/v1/pleroma/chats/by-account-id/:id" do +    setup do: oauth_access(["write:chats"]) + +    test "it creates or returns a chat", %{conn: conn} do +      other_user = insert(:user) + +      result = +        conn +        |> post("/api/v1/pleroma/chats/by-account-id/#{other_user.id}") +        |> json_response_and_validate_schema(200) + +      assert result["id"] +    end +  end + +  describe "GET /api/v1/pleroma/chats/:id" do +    setup do: oauth_access(["read:chats"]) + +    test "it returns a chat", %{conn: conn, user: user} do +      other_user = insert(:user) + +      {:ok, chat} = Chat.get_or_create(user.id, other_user.ap_id) + +      result = +        conn +        |> get("/api/v1/pleroma/chats/#{chat.id}") +        |> json_response_and_validate_schema(200) + +      assert result["id"] == to_string(chat.id) +    end +  end + +  describe "GET /api/v1/pleroma/chats" do +    setup do: oauth_access(["read:chats"]) + +    test "it does not return chats with users you blocked", %{conn: conn, user: user} do +      recipient = insert(:user) + +      {:ok, _} = Chat.get_or_create(user.id, recipient.ap_id) + +      result = +        conn +        |> get("/api/v1/pleroma/chats") +        |> json_response_and_validate_schema(200) + +      assert length(result) == 1 + +      User.block(user, recipient) + +      result = +        conn +        |> get("/api/v1/pleroma/chats") +        |> json_response_and_validate_schema(200) + +      assert length(result) == 0 +    end + +    test "it returns all chats", %{conn: conn, user: user} do +      Enum.each(1..30, fn _ -> +        recipient = insert(:user) +        {:ok, _} = Chat.get_or_create(user.id, recipient.ap_id) +      end) + +      result = +        conn +        |> get("/api/v1/pleroma/chats") +        |> json_response_and_validate_schema(200) + +      assert length(result) == 30 +    end + +    test "it return a list of chats the current user is participating in, in descending order of updates", +         %{conn: conn, user: user} do +      har = insert(:user) +      jafnhar = insert(:user) +      tridi = insert(:user) + +      {:ok, chat_1} = Chat.get_or_create(user.id, har.ap_id) +      :timer.sleep(1000) +      {:ok, _chat_2} = Chat.get_or_create(user.id, jafnhar.ap_id) +      :timer.sleep(1000) +      {:ok, chat_3} = Chat.get_or_create(user.id, tridi.ap_id) +      :timer.sleep(1000) + +      # bump the second one +      {:ok, chat_2} = Chat.bump_or_create(user.id, jafnhar.ap_id) + +      result = +        conn +        |> get("/api/v1/pleroma/chats") +        |> json_response_and_validate_schema(200) + +      ids = Enum.map(result, & &1["id"]) + +      assert ids == [ +               chat_2.id |> to_string(), +               chat_3.id |> to_string(), +               chat_1.id |> to_string() +             ] +    end +  end +end diff --git a/test/web/pleroma_api/views/chat/message_reference_view_test.exs b/test/web/pleroma_api/views/chat/message_reference_view_test.exs new file mode 100644 index 000000000..e5b165255 --- /dev/null +++ b/test/web/pleroma_api/views/chat/message_reference_view_test.exs @@ -0,0 +1,61 @@ +# 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.Chat.MessageReferenceViewTest do +  use Pleroma.DataCase + +  alias Pleroma.Chat +  alias Pleroma.Chat.MessageReference +  alias Pleroma.Object +  alias Pleroma.Web.ActivityPub.ActivityPub +  alias Pleroma.Web.CommonAPI +  alias Pleroma.Web.PleromaAPI.Chat.MessageReferenceView + +  import Pleroma.Factory + +  test "it displays a chat message" do +    user = insert(:user) +    recipient = insert(:user) + +    file = %Plug.Upload{ +      content_type: "image/jpg", +      path: Path.absname("test/fixtures/image.jpg"), +      filename: "an_image.jpg" +    } + +    {:ok, upload} = ActivityPub.upload(file, actor: user.ap_id) +    {:ok, activity} = CommonAPI.post_chat_message(user, recipient, "kippis :firefox:") + +    chat = Chat.get(user.id, recipient.ap_id) + +    object = Object.normalize(activity) + +    cm_ref = MessageReference.for_chat_and_object(chat, object) + +    chat_message = MessageReferenceView.render("show.json", chat_message_reference: cm_ref) + +    assert chat_message[:id] == cm_ref.id +    assert chat_message[:content] == "kippis :firefox:" +    assert chat_message[:account_id] == user.id +    assert chat_message[:chat_id] +    assert chat_message[:created_at] +    assert chat_message[:unread] == false +    assert match?([%{shortcode: "firefox"}], chat_message[:emojis]) + +    {:ok, activity} = CommonAPI.post_chat_message(recipient, user, "gkgkgk", media_id: upload.id) + +    object = Object.normalize(activity) + +    cm_ref = MessageReference.for_chat_and_object(chat, object) + +    chat_message_two = MessageReferenceView.render("show.json", chat_message_reference: cm_ref) + +    assert chat_message_two[:id] == cm_ref.id +    assert chat_message_two[:content] == "gkgkgk" +    assert chat_message_two[:account_id] == recipient.id +    assert chat_message_two[:chat_id] == chat_message[:chat_id] +    assert chat_message_two[:attachment] +    assert chat_message_two[:unread] == true +  end +end diff --git a/test/web/pleroma_api/views/chat_view_test.exs b/test/web/pleroma_api/views/chat_view_test.exs new file mode 100644 index 000000000..14eecb1bd --- /dev/null +++ b/test/web/pleroma_api/views/chat_view_test.exs @@ -0,0 +1,48 @@ +# 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.ChatViewTest do +  use Pleroma.DataCase + +  alias Pleroma.Chat +  alias Pleroma.Chat.MessageReference +  alias Pleroma.Object +  alias Pleroma.Web.CommonAPI +  alias Pleroma.Web.CommonAPI.Utils +  alias Pleroma.Web.MastodonAPI.AccountView +  alias Pleroma.Web.PleromaAPI.Chat.MessageReferenceView +  alias Pleroma.Web.PleromaAPI.ChatView + +  import Pleroma.Factory + +  test "it represents a chat" do +    user = insert(:user) +    recipient = insert(:user) + +    {:ok, chat} = Chat.get_or_create(user.id, recipient.ap_id) + +    represented_chat = ChatView.render("show.json", chat: chat) + +    assert represented_chat == %{ +             id: "#{chat.id}", +             account: AccountView.render("show.json", user: recipient), +             unread: 0, +             last_message: nil, +             updated_at: Utils.to_masto_date(chat.updated_at) +           } + +    {:ok, chat_message_creation} = CommonAPI.post_chat_message(user, recipient, "hello") + +    chat_message = Object.normalize(chat_message_creation, false) + +    {:ok, chat} = Chat.get_or_create(user.id, recipient.ap_id) + +    represented_chat = ChatView.render("show.json", chat: chat) + +    cm_ref = MessageReference.for_chat_and_object(chat, chat_message) + +    assert represented_chat[:last_message] == +             MessageReferenceView.render("show.json", chat_message_reference: cm_ref) +  end +end diff --git a/test/web/push/impl_test.exs b/test/web/push/impl_test.exs index a826b24c9..b48952b29 100644 --- a/test/web/push/impl_test.exs +++ b/test/web/push/impl_test.exs @@ -5,8 +5,10 @@  defmodule Pleroma.Web.Push.ImplTest do    use Pleroma.DataCase +  alias Pleroma.Notification    alias Pleroma.Object    alias Pleroma.User +  alias Pleroma.Web.ActivityPub.ActivityPub    alias Pleroma.Web.CommonAPI    alias Pleroma.Web.Push.Impl    alias Pleroma.Web.Push.Subscription @@ -60,7 +62,8 @@ defmodule Pleroma.Web.Push.ImplTest do      notif =        insert(:notification,          user: user, -        activity: activity +        activity: activity, +        type: "mention"        )      assert Impl.perform(notif) == {:ok, [:ok, :ok]} @@ -126,7 +129,7 @@ defmodule Pleroma.Web.Push.ImplTest do             ) ==               "@Bob: Lorem ipsum dolor sit amet, consectetur  adipiscing elit. Fusce sagittis fini..." -    assert Impl.format_title(%{activity: activity}) == +    assert Impl.format_title(%{activity: activity, type: "mention"}) ==               "New Mention"    end @@ -136,9 +139,10 @@ defmodule Pleroma.Web.Push.ImplTest do      {:ok, _, _, activity} = CommonAPI.follow(user, other_user)      object = Object.normalize(activity, false) -    assert Impl.format_body(%{activity: activity}, user, object) == "@Bob has followed you" +    assert Impl.format_body(%{activity: activity, type: "follow"}, user, object) == +             "@Bob has followed you" -    assert Impl.format_title(%{activity: activity}) == +    assert Impl.format_title(%{activity: activity, type: "follow"}) ==               "New Follower"    end @@ -157,7 +161,7 @@ defmodule Pleroma.Web.Push.ImplTest do      assert Impl.format_body(%{activity: announce_activity}, user, object) ==               "@#{user.nickname} repeated: Lorem ipsum dolor sit amet, consectetur  adipiscing elit. Fusce sagittis fini..." -    assert Impl.format_title(%{activity: announce_activity}) == +    assert Impl.format_title(%{activity: announce_activity, type: "reblog"}) ==               "New Repeat"    end @@ -173,9 +177,10 @@ defmodule Pleroma.Web.Push.ImplTest do      {:ok, activity} = CommonAPI.favorite(user, activity.id)      object = Object.normalize(activity) -    assert Impl.format_body(%{activity: activity}, user, object) == "@Bob has favorited your post" +    assert Impl.format_body(%{activity: activity, type: "favourite"}, user, object) == +             "@Bob has favorited your post" -    assert Impl.format_title(%{activity: activity}) == +    assert Impl.format_title(%{activity: activity, type: "favourite"}) ==               "New Favorite"    end @@ -193,6 +198,46 @@ defmodule Pleroma.Web.Push.ImplTest do    end    describe "build_content/3" do +    test "builds content for chat messages" do +      user = insert(:user) +      recipient = insert(:user) + +      {:ok, chat} = CommonAPI.post_chat_message(user, recipient, "hey") +      object = Object.normalize(chat, false) +      [notification] = Notification.for_user(recipient) + +      res = Impl.build_content(notification, user, object) + +      assert res == %{ +               body: "@#{user.nickname}: hey", +               title: "New Chat Message" +             } +    end + +    test "builds content for chat messages with no content" do +      user = insert(:user) +      recipient = insert(:user) + +      file = %Plug.Upload{ +        content_type: "image/jpg", +        path: Path.absname("test/fixtures/image.jpg"), +        filename: "an_image.jpg" +      } + +      {:ok, upload} = ActivityPub.upload(file, actor: user.ap_id) + +      {:ok, chat} = CommonAPI.post_chat_message(user, recipient, nil, media_id: upload.id) +      object = Object.normalize(chat, false) +      [notification] = Notification.for_user(recipient) + +      res = Impl.build_content(notification, user, object) + +      assert res == %{ +               body: "@#{user.nickname}: (Attachment)", +               title: "New Chat Message" +             } +    end +      test "hides details for notifications when privacy option enabled" do        user = insert(:user, nickname: "Bob")        user2 = insert(:user, nickname: "Rob", notification_settings: %{privacy_option: true}) @@ -218,7 +263,7 @@ defmodule Pleroma.Web.Push.ImplTest do            status: "<Lorem ipsum dolor sit amet."          }) -      notif = insert(:notification, user: user2, activity: activity) +      notif = insert(:notification, user: user2, activity: activity, type: "mention")        actor = User.get_cached_by_ap_id(notif.activity.data["actor"])        object = Object.normalize(activity) @@ -229,7 +274,7 @@ defmodule Pleroma.Web.Push.ImplTest do        {:ok, activity} = CommonAPI.favorite(user, activity.id) -      notif = insert(:notification, user: user2, activity: activity) +      notif = insert(:notification, user: user2, activity: activity, type: "favourite")        actor = User.get_cached_by_ap_id(notif.activity.data["actor"])        object = Object.normalize(activity) @@ -268,7 +313,7 @@ defmodule Pleroma.Web.Push.ImplTest do              "<span>Lorem ipsum dolor sit amet</span>, consectetur :firefox: adipiscing elit. Fusce sagittis finibus turpis."          }) -      notif = insert(:notification, user: user2, activity: activity) +      notif = insert(:notification, user: user2, activity: activity, type: "mention")        actor = User.get_cached_by_ap_id(notif.activity.data["actor"])        object = Object.normalize(activity) @@ -281,7 +326,7 @@ defmodule Pleroma.Web.Push.ImplTest do        {:ok, activity} = CommonAPI.favorite(user, activity.id) -      notif = insert(:notification, user: user2, activity: activity) +      notif = insert(:notification, user: user2, activity: activity, type: "favourite")        actor = User.get_cached_by_ap_id(notif.activity.data["actor"])        object = Object.normalize(activity) diff --git a/test/web/streamer/streamer_test.exs b/test/web/streamer/streamer_test.exs index 3f012259a..245f6e63f 100644 --- a/test/web/streamer/streamer_test.exs +++ b/test/web/streamer/streamer_test.exs @@ -7,11 +7,15 @@ defmodule Pleroma.Web.StreamerTest do    import Pleroma.Factory +  alias Pleroma.Chat +  alias Pleroma.Chat.MessageReference    alias Pleroma.Conversation.Participation    alias Pleroma.List +  alias Pleroma.Object    alias Pleroma.User    alias Pleroma.Web.CommonAPI    alias Pleroma.Web.Streamer +  alias Pleroma.Web.StreamerView    @moduletag needs_streamer: true, capture_log: true @@ -145,6 +149,57 @@ defmodule Pleroma.Web.StreamerTest do        refute Streamer.filtered_by_user?(user, notify)      end +    test "it sends chat messages to the 'user:pleroma_chat' stream", %{user: user} do +      other_user = insert(:user) + +      {:ok, create_activity} = CommonAPI.post_chat_message(other_user, user, "hey cirno") +      object = Object.normalize(create_activity, false) +      chat = Chat.get(user.id, other_user.ap_id) +      cm_ref = MessageReference.for_chat_and_object(chat, object) +      cm_ref = %{cm_ref | chat: chat, object: object} + +      Streamer.get_topic_and_add_socket("user:pleroma_chat", user) +      Streamer.stream("user:pleroma_chat", {user, cm_ref}) + +      text = StreamerView.render("chat_update.json", %{chat_message_reference: cm_ref}) + +      assert text =~ "hey cirno" +      assert_receive {:text, ^text} +    end + +    test "it sends chat messages to the 'user' stream", %{user: user} do +      other_user = insert(:user) + +      {:ok, create_activity} = CommonAPI.post_chat_message(other_user, user, "hey cirno") +      object = Object.normalize(create_activity, false) +      chat = Chat.get(user.id, other_user.ap_id) +      cm_ref = MessageReference.for_chat_and_object(chat, object) +      cm_ref = %{cm_ref | chat: chat, object: object} + +      Streamer.get_topic_and_add_socket("user", user) +      Streamer.stream("user", {user, cm_ref}) + +      text = StreamerView.render("chat_update.json", %{chat_message_reference: cm_ref}) + +      assert text =~ "hey cirno" +      assert_receive {:text, ^text} +    end + +    test "it sends chat message notifications to the 'user:notification' stream", %{user: user} do +      other_user = insert(:user) + +      {:ok, create_activity} = CommonAPI.post_chat_message(other_user, user, "hey") + +      notify = +        Repo.get_by(Pleroma.Notification, user_id: user.id, activity_id: create_activity.id) +        |> Repo.preload(:activity) + +      Streamer.get_topic_and_add_socket("user:notification", user) +      Streamer.stream("user:notification", notify) +      assert_receive {:render_with_user, _, _, ^notify} +      refute Streamer.filtered_by_user?(user, notify) +    end +      test "it doesn't send notify to the 'user:notification' stream when a user is blocked", %{        user: user      } do diff --git a/test/workers/cron/purge_expired_activities_worker_test.exs b/test/workers/cron/purge_expired_activities_worker_test.exs index 5864f9e5f..6d2991a60 100644 --- a/test/workers/cron/purge_expired_activities_worker_test.exs +++ b/test/workers/cron/purge_expired_activities_worker_test.exs @@ -11,7 +11,10 @@ defmodule Pleroma.Workers.Cron.PurgeExpiredActivitiesWorkerTest do    import Pleroma.Factory    import ExUnit.CaptureLog -  setup do: clear_config([ActivityExpiration, :enabled]) +  setup do +    clear_config([ActivityExpiration, :enabled]) +    clear_config([:instance, :rewrite_policy]) +  end    test "deletes an expiration activity" do      Pleroma.Config.put([ActivityExpiration, :enabled], true) @@ -36,6 +39,35 @@ defmodule Pleroma.Workers.Cron.PurgeExpiredActivitiesWorkerTest do      refute Pleroma.Repo.get(Pleroma.ActivityExpiration, expiration.id)    end +  test "works with ActivityExpirationPolicy" do +    Pleroma.Config.put([ActivityExpiration, :enabled], true) + +    Pleroma.Config.put( +      [:instance, :rewrite_policy], +      Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicy +    ) + +    user = insert(:user) + +    days = Pleroma.Config.get([:mrf_activity_expiration, :days], 365) + +    {:ok, %{id: id} = activity} = Pleroma.Web.CommonAPI.post(user, %{status: "cofe"}) + +    past_date = +      NaiveDateTime.utc_now() |> Timex.shift(days: -days) |> NaiveDateTime.truncate(:second) + +    activity +    |> Repo.preload(:expiration) +    |> Map.get(:expiration) +    |> Ecto.Changeset.change(%{scheduled_at: past_date}) +    |> Repo.update!() + +    Pleroma.Workers.Cron.PurgeExpiredActivitiesWorker.perform(:ops, :pid) + +    assert [%{data: %{"type" => "Delete", "deleted_activity_id" => ^id}}] = +             Pleroma.Repo.all(Pleroma.Activity) +  end +    describe "delete_activity/1" do      test "adds log message if activity isn't find" do        assert capture_log([level: :error], fn -> | 
