diff options
Diffstat (limited to 'test/web')
39 files changed, 1443 insertions, 1102 deletions
| diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs index be7ab2ae4..38c98f658 100644 --- a/test/web/activity_pub/activity_pub_test.exs +++ b/test/web/activity_pub/activity_pub_test.exs @@ -507,6 +507,33 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        activities = ActivityPub.fetch_activities_for_context("2hu", %{blocking_user: user})        assert activities == [activity_two, activity]      end + +    test "doesn't return activities with filtered words" do +      user = insert(:user) +      user_two = insert(:user) +      insert(:filter, user: user, phrase: "test", hide: true) + +      {:ok, %{id: id1, data: %{"context" => context}}} = CommonAPI.post(user, %{status: "1"}) + +      {:ok, %{id: id2}} = CommonAPI.post(user_two, %{status: "2", in_reply_to_status_id: id1}) + +      {:ok, %{id: id3} = user_activity} = +        CommonAPI.post(user, %{status: "3 test?", in_reply_to_status_id: id2}) + +      {:ok, %{id: id4} = filtered_activity} = +        CommonAPI.post(user_two, %{status: "4 test!", in_reply_to_status_id: id3}) + +      {:ok, _} = CommonAPI.post(user, %{status: "5", in_reply_to_status_id: id4}) + +      activities = +        context +        |> ActivityPub.fetch_activities_for_context(%{user: user}) +        |> Enum.map(& &1.id) + +      assert length(activities) == 4 +      assert user_activity.id in activities +      refute filtered_activity.id in activities +    end    end    test "doesn't return blocked activities" do @@ -642,7 +669,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      refute activity in activities      followed_user = insert(:user) -    ActivityPub.follow(user, followed_user) +    CommonAPI.follow(user, followed_user)      {:ok, repeat_activity} = CommonAPI.repeat(activity.id, followed_user)      activities = ActivityPub.fetch_activities([], %{blocking_user: user, skip_preload: true}) @@ -785,6 +812,75 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      assert activity == expected_activity    end +  describe "irreversible filters" do +    setup do +      user = insert(:user) +      user_two = insert(:user) + +      insert(:filter, user: user_two, phrase: "cofe", hide: true) +      insert(:filter, user: user_two, phrase: "ok boomer", hide: true) +      insert(:filter, user: user_two, phrase: "test", hide: false) + +      params = %{ +        type: ["Create", "Announce"], +        user: user_two +      } + +      {:ok, %{user: user, user_two: user_two, params: params}} +    end + +    test "it returns statuses if they don't contain exact filter words", %{ +      user: user, +      params: params +    } do +      {:ok, _} = CommonAPI.post(user, %{status: "hey"}) +      {:ok, _} = CommonAPI.post(user, %{status: "got cofefe?"}) +      {:ok, _} = CommonAPI.post(user, %{status: "I am not a boomer"}) +      {:ok, _} = CommonAPI.post(user, %{status: "ok boomers"}) +      {:ok, _} = CommonAPI.post(user, %{status: "ccofee is not a word"}) +      {:ok, _} = CommonAPI.post(user, %{status: "this is a test"}) + +      activities = ActivityPub.fetch_activities([], params) + +      assert Enum.count(activities) == 6 +    end + +    test "it does not filter user's own statuses", %{user_two: user_two, params: params} do +      {:ok, _} = CommonAPI.post(user_two, %{status: "Give me some cofe!"}) +      {:ok, _} = CommonAPI.post(user_two, %{status: "ok boomer"}) + +      activities = ActivityPub.fetch_activities([], params) + +      assert Enum.count(activities) == 2 +    end + +    test "it excludes statuses with filter words", %{user: user, params: params} do +      {:ok, _} = CommonAPI.post(user, %{status: "Give me some cofe!"}) +      {:ok, _} = CommonAPI.post(user, %{status: "ok boomer"}) +      {:ok, _} = CommonAPI.post(user, %{status: "is it a cOfE?"}) +      {:ok, _} = CommonAPI.post(user, %{status: "cofe is all I need"}) +      {:ok, _} = CommonAPI.post(user, %{status: "— ok BOOMER\n"}) + +      activities = ActivityPub.fetch_activities([], params) + +      assert Enum.empty?(activities) +    end + +    test "it returns all statuses if user does not have any filters" do +      another_user = insert(:user) +      {:ok, _} = CommonAPI.post(another_user, %{status: "got cofe?"}) +      {:ok, _} = CommonAPI.post(another_user, %{status: "test!"}) + +      activities = +        ActivityPub.fetch_activities([], %{ +          type: ["Create", "Announce"], +          user: another_user +        }) + +      assert Enum.count(activities) == 2 +    end +  end +    describe "public fetch activities" do      test "doesn't retrieve unlisted activities" do        user = insert(:user) @@ -917,24 +1013,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      end    end -  describe "following / unfollowing" do -    test "it reverts follow activity" do -      follower = insert(:user) -      followed = insert(:user) - -      with_mock(Utils, [:passthrough], maybe_federate: fn _ -> {:error, :reverted} end) do -        assert {:error, :reverted} = ActivityPub.follow(follower, followed) -      end - -      assert Repo.aggregate(Activity, :count, :id) == 0 -      assert Repo.aggregate(Object, :count, :id) == 0 -    end - +  describe "unfollowing" do      test "it reverts unfollow activity" do        follower = insert(:user)        followed = insert(:user) -      {:ok, follow_activity} = ActivityPub.follow(follower, followed) +      {:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed)        with_mock(Utils, [:passthrough], maybe_federate: fn _ -> {:error, :reverted} end) do          assert {:error, :reverted} = ActivityPub.unfollow(follower, followed) @@ -947,21 +1031,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        assert activity.data["object"] == followed.ap_id      end -    test "creates a follow activity" do -      follower = insert(:user) -      followed = insert(:user) - -      {:ok, activity} = ActivityPub.follow(follower, followed) -      assert activity.data["type"] == "Follow" -      assert activity.data["actor"] == follower.ap_id -      assert activity.data["object"] == followed.ap_id -    end -      test "creates an undo activity for the last follow" do        follower = insert(:user)        followed = insert(:user) -      {:ok, follow_activity} = ActivityPub.follow(follower, followed) +      {:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed)        {:ok, activity} = ActivityPub.unfollow(follower, followed)        assert activity.data["type"] == "Undo" @@ -978,7 +1052,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        follower = insert(:user)        followed = insert(:user, %{locked: true}) -      {:ok, follow_activity} = ActivityPub.follow(follower, followed) +      {:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed)        {:ok, activity} = ActivityPub.unfollow(follower, followed)        assert activity.data["type"] == "Undo" @@ -992,54 +1066,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      end    end -  describe "blocking" do -    test "reverts block activity on error" do -      [blocker, blocked] = insert_list(2, :user) - -      with_mock(Utils, [:passthrough], maybe_federate: fn _ -> {:error, :reverted} end) do -        assert {:error, :reverted} = ActivityPub.block(blocker, blocked) -      end - -      assert Repo.aggregate(Activity, :count, :id) == 0 -      assert Repo.aggregate(Object, :count, :id) == 0 -    end - -    test "creates a block activity" do -      clear_config([:instance, :federating], true) -      blocker = insert(:user) -      blocked = insert(:user) - -      with_mock Pleroma.Web.Federator, -        publish: fn _ -> nil end do -        {:ok, activity} = ActivityPub.block(blocker, blocked) - -        assert activity.data["type"] == "Block" -        assert activity.data["actor"] == blocker.ap_id -        assert activity.data["object"] == blocked.ap_id - -        assert called(Pleroma.Web.Federator.publish(activity)) -      end -    end - -    test "works with outgoing blocks disabled, but doesn't federate" do -      clear_config([:instance, :federating], true) -      clear_config([:activitypub, :outgoing_blocks], false) -      blocker = insert(:user) -      blocked = insert(:user) - -      with_mock Pleroma.Web.Federator, -        publish: fn _ -> nil end do -        {:ok, activity} = ActivityPub.block(blocker, blocked) - -        assert activity.data["type"] == "Block" -        assert activity.data["actor"] == blocker.ap_id -        assert activity.data["object"] == blocked.ap_id - -        refute called(Pleroma.Web.Federator.publish(:_)) -      end -    end -  end -    describe "timeline post-processing" do      test "it filters broken threads" do        user1 = insert(:user) diff --git a/test/web/activity_pub/mrf/anti_link_spam_policy_test.exs b/test/web/activity_pub/mrf/anti_link_spam_policy_test.exs index 1a13699be..6867c9853 100644 --- a/test/web/activity_pub/mrf/anti_link_spam_policy_test.exs +++ b/test/web/activity_pub/mrf/anti_link_spam_policy_test.exs @@ -33,7 +33,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicyTest do    describe "with new user" do      test "it allows posts without links" do -      user = insert(:user) +      user = insert(:user, local: false)        assert user.note_count == 0 @@ -45,7 +45,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicyTest do      end      test "it disallows posts with links" do -      user = insert(:user) +      user = insert(:user, local: false)        assert user.note_count == 0 @@ -55,6 +55,18 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicyTest do        {:reject, _} = AntiLinkSpamPolicy.filter(message)      end + +    test "it allows posts with links for local users" do +      user = insert(:user) + +      assert user.note_count == 0 + +      message = +        @linkful_message +        |> Map.put("actor", user.ap_id) + +      {:ok, _message} = AntiLinkSpamPolicy.filter(message) +    end    end    describe "with old user" do diff --git a/test/web/activity_pub/object_validator_test.exs b/test/web/activity_pub/object_validator_test.exs deleted file mode 100644 index 770a8dcf8..000000000 --- a/test/web/activity_pub/object_validator_test.exs +++ /dev/null @@ -1,657 +0,0 @@ -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) -      {:ok, post_activity} = CommonAPI.post(user, %{status: "uguu"}) - -      object = Pleroma.Object.get_by_ap_id(post_activity.data["object"]) - -      {:ok, valid_emoji_react, []} = Builder.emoji_react(user, object, "👌") - -      %{user: user, post_activity: post_activity, valid_emoji_react: valid_emoji_react} -    end - -    test "it validates a valid EmojiReact", %{valid_emoji_react: valid_emoji_react} do -      assert {:ok, _, _} = ObjectValidator.validate(valid_emoji_react, []) -    end - -    test "it is not valid without a 'content' field", %{valid_emoji_react: valid_emoji_react} do -      without_content = -        valid_emoji_react -        |> Map.delete("content") - -      {:error, cng} = ObjectValidator.validate(without_content, []) - -      refute cng.valid? -      assert {:content, {"can't be blank", [validation: :required]}} in cng.errors -    end - -    test "it is not valid with a non-emoji content field", %{valid_emoji_react: valid_emoji_react} do -      without_emoji_content = -        valid_emoji_react -        |> Map.put("content", "x") - -      {:error, cng} = ObjectValidator.validate(without_emoji_content, []) - -      refute cng.valid? - -      assert {:content, {"must be a single character emoji", []}} in cng.errors -    end -  end - -  describe "Undos" do -    setup do -      user = insert(:user) -      {:ok, post_activity} = CommonAPI.post(user, %{status: "uguu"}) -      {:ok, like} = CommonAPI.favorite(user, post_activity.id) -      {:ok, valid_like_undo, []} = Builder.undo(user, like) - -      %{user: user, like: like, valid_like_undo: valid_like_undo} -    end - -    test "it validates a basic like undo", %{valid_like_undo: valid_like_undo} do -      assert {:ok, _, _} = ObjectValidator.validate(valid_like_undo, []) -    end - -    test "it does not validate if the actor of the undo is not the actor of the object", %{ -      valid_like_undo: valid_like_undo -    } do -      other_user = insert(:user, ap_id: "https://gensokyo.2hu/users/raymoo") - -      bad_actor = -        valid_like_undo -        |> Map.put("actor", other_user.ap_id) - -      {:error, cng} = ObjectValidator.validate(bad_actor, []) - -      assert {:actor, {"not the same as object actor", []}} in cng.errors -    end - -    test "it does not validate if the object is missing", %{valid_like_undo: valid_like_undo} do -      missing_object = -        valid_like_undo -        |> Map.put("object", "https://gensokyo.2hu/objects/1") - -      {:error, cng} = ObjectValidator.validate(missing_object, []) - -      assert {:object, {"can't find object", []}} in cng.errors -      assert length(cng.errors) == 1 -    end -  end - -  describe "deletes" do -    setup do -      user = insert(:user) -      {:ok, post_activity} = CommonAPI.post(user, %{status: "cancel me daddy"}) - -      {:ok, valid_post_delete, _} = Builder.delete(user, post_activity.data["object"]) -      {:ok, valid_user_delete, _} = Builder.delete(user, user.ap_id) - -      %{user: user, valid_post_delete: valid_post_delete, valid_user_delete: valid_user_delete} -    end - -    test "it is valid for a post deletion", %{valid_post_delete: valid_post_delete} do -      {:ok, valid_post_delete, _} = ObjectValidator.validate(valid_post_delete, []) - -      assert valid_post_delete["deleted_activity_id"] -    end - -    test "it is invalid if the object isn't in a list of certain types", %{ -      valid_post_delete: valid_post_delete -    } do -      object = Object.get_by_ap_id(valid_post_delete["object"]) - -      data = -        object.data -        |> Map.put("type", "Like") - -      {:ok, _object} = -        object -        |> Ecto.Changeset.change(%{data: data}) -        |> Object.update_and_set_cache() - -      {:error, cng} = ObjectValidator.validate(valid_post_delete, []) -      assert {:object, {"object not in allowed types", []}} in cng.errors -    end - -    test "it is valid for a user deletion", %{valid_user_delete: valid_user_delete} do -      assert match?({:ok, _, _}, ObjectValidator.validate(valid_user_delete, [])) -    end - -    test "it's invalid if the id is missing", %{valid_post_delete: valid_post_delete} do -      no_id = -        valid_post_delete -        |> Map.delete("id") - -      {:error, cng} = ObjectValidator.validate(no_id, []) - -      assert {:id, {"can't be blank", [validation: :required]}} in cng.errors -    end - -    test "it's invalid if the object doesn't exist", %{valid_post_delete: valid_post_delete} do -      missing_object = -        valid_post_delete -        |> Map.put("object", "http://does.not/exist") - -      {:error, cng} = ObjectValidator.validate(missing_object, []) - -      assert {:object, {"can't find object", []}} in cng.errors -    end - -    test "it's invalid if the actor of the object and the actor of delete are from different domains", -         %{valid_post_delete: valid_post_delete} do -      valid_user = insert(:user) - -      valid_other_actor = -        valid_post_delete -        |> Map.put("actor", valid_user.ap_id) - -      assert match?({:ok, _, _}, ObjectValidator.validate(valid_other_actor, [])) - -      invalid_other_actor = -        valid_post_delete -        |> Map.put("actor", "https://gensokyo.2hu/users/raymoo") - -      {:error, cng} = ObjectValidator.validate(invalid_other_actor, []) - -      assert {:actor, {"is not allowed to delete object", []}} in cng.errors -    end - -    test "it's valid if the actor of the object is a local superuser", -         %{valid_post_delete: valid_post_delete} do -      user = -        insert(:user, local: true, is_moderator: true, ap_id: "https://gensokyo.2hu/users/raymoo") - -      valid_other_actor = -        valid_post_delete -        |> Map.put("actor", user.ap_id) - -      {:ok, _, meta} = ObjectValidator.validate(valid_other_actor, []) -      assert meta[:do_not_federate] -    end -  end - -  describe "likes" do -    setup do -      user = insert(:user) -      {:ok, post_activity} = CommonAPI.post(user, %{status: "uguu"}) - -      valid_like = %{ -        "to" => [user.ap_id], -        "cc" => [], -        "type" => "Like", -        "id" => Utils.generate_activity_id(), -        "object" => post_activity.data["object"], -        "actor" => user.ap_id, -        "context" => "a context" -      } - -      %{valid_like: valid_like, user: user, post_activity: post_activity} -    end - -    test "returns ok when called in the ObjectValidator", %{valid_like: valid_like} do -      {:ok, object, _meta} = ObjectValidator.validate(valid_like, []) - -      assert "id" in Map.keys(object) -    end - -    test "is valid for a valid object", %{valid_like: valid_like} do -      assert LikeValidator.cast_and_validate(valid_like).valid? -    end - -    test "sets the 'to' field to the object actor if no recipients are given", %{ -      valid_like: valid_like, -      user: user -    } do -      without_recipients = -        valid_like -        |> Map.delete("to") - -      {:ok, object, _meta} = ObjectValidator.validate(without_recipients, []) - -      assert object["to"] == [user.ap_id] -    end - -    test "sets the context field to the context of the object if no context is given", %{ -      valid_like: valid_like, -      post_activity: post_activity -    } do -      without_context = -        valid_like -        |> Map.delete("context") - -      {:ok, object, _meta} = ObjectValidator.validate(without_context, []) - -      assert object["context"] == post_activity.data["context"] -    end - -    test "it errors when the actor is missing or not known", %{valid_like: valid_like} do -      without_actor = Map.delete(valid_like, "actor") - -      refute LikeValidator.cast_and_validate(without_actor).valid? - -      with_invalid_actor = Map.put(valid_like, "actor", "invalidactor") - -      refute LikeValidator.cast_and_validate(with_invalid_actor).valid? -    end - -    test "it errors when the object is missing or not known", %{valid_like: valid_like} do -      without_object = Map.delete(valid_like, "object") - -      refute LikeValidator.cast_and_validate(without_object).valid? - -      with_invalid_object = Map.put(valid_like, "object", "invalidobject") - -      refute LikeValidator.cast_and_validate(with_invalid_object).valid? -    end - -    test "it errors when the actor has already like the object", %{ -      valid_like: valid_like, -      user: user, -      post_activity: post_activity -    } do -      _like = CommonAPI.favorite(user, post_activity.id) - -      refute LikeValidator.cast_and_validate(valid_like).valid? -    end - -    test "it works when actor or object are wrapped in maps", %{valid_like: valid_like} do -      wrapped_like = -        valid_like -        |> Map.put("actor", %{"id" => valid_like["actor"]}) -        |> Map.put("object", %{"id" => valid_like["object"]}) - -      validated = LikeValidator.cast_and_validate(wrapped_like) - -      assert validated.valid? - -      assert {:actor, valid_like["actor"]} in validated.changes -      assert {:object, valid_like["object"]} in validated.changes -    end -  end - -  describe "announces" do -    setup do -      user = insert(:user) -      announcer = insert(:user) -      {:ok, post_activity} = CommonAPI.post(user, %{status: "uguu"}) - -      object = Object.normalize(post_activity, false) -      {:ok, valid_announce, []} = Builder.announce(announcer, object) - -      %{ -        valid_announce: valid_announce, -        user: user, -        post_activity: post_activity, -        announcer: announcer -      } -    end - -    test "returns ok for a valid announce", %{valid_announce: valid_announce} do -      assert {:ok, _object, _meta} = ObjectValidator.validate(valid_announce, []) -    end - -    test "returns an error if the object can't be found", %{valid_announce: valid_announce} do -      without_object = -        valid_announce -        |> Map.delete("object") - -      {:error, cng} = ObjectValidator.validate(without_object, []) - -      assert {:object, {"can't be blank", [validation: :required]}} in cng.errors - -      nonexisting_object = -        valid_announce -        |> Map.put("object", "https://gensokyo.2hu/objects/99999999") - -      {:error, cng} = ObjectValidator.validate(nonexisting_object, []) - -      assert {:object, {"can't find object", []}} in cng.errors -    end - -    test "returns an error if we don't have the actor", %{valid_announce: valid_announce} do -      nonexisting_actor = -        valid_announce -        |> Map.put("actor", "https://gensokyo.2hu/users/raymoo") - -      {:error, cng} = ObjectValidator.validate(nonexisting_actor, []) - -      assert {:actor, {"can't find user", []}} in cng.errors -    end - -    test "returns an error if the actor already announced the object", %{ -      valid_announce: valid_announce, -      announcer: announcer, -      post_activity: post_activity -    } do -      _announce = CommonAPI.repeat(post_activity.id, announcer) - -      {:error, cng} = ObjectValidator.validate(valid_announce, []) - -      assert {:actor, {"already announced this object", []}} in cng.errors -      assert {:object, {"already announced by this actor", []}} in cng.errors -    end - -    test "returns an error if the actor can't announce the object", %{ -      announcer: announcer, -      user: user -    } do -      {:ok, post_activity} = -        CommonAPI.post(user, %{status: "a secret post", visibility: "private"}) - -      object = Object.normalize(post_activity, false) - -      # Another user can't announce it -      {:ok, announce, []} = Builder.announce(announcer, object, public: false) - -      {:error, cng} = ObjectValidator.validate(announce, []) - -      assert {:actor, {"can not announce this object", []}} in cng.errors - -      # The actor of the object can announce it -      {:ok, announce, []} = Builder.announce(user, object, public: false) - -      assert {:ok, _, _} = ObjectValidator.validate(announce, []) - -      # The actor of the object can not announce it publicly -      {:ok, announce, []} = Builder.announce(user, object, public: true) - -      {:error, cng} = ObjectValidator.validate(announce, []) - -      assert {:actor, {"can not announce this object publicly", []}} in cng.errors -    end -  end - -  describe "updates" do -    setup do -      user = insert(:user) - -      object = %{ -        "id" => user.ap_id, -        "name" => "A new name", -        "summary" => "A new bio" -      } - -      {:ok, valid_update, []} = Builder.update(user, object) - -      %{user: user, valid_update: valid_update} -    end - -    test "validates a basic object", %{valid_update: valid_update} do -      assert {:ok, _update, []} = ObjectValidator.validate(valid_update, []) -    end - -    test "returns an error if the object can't be updated by the actor", %{ -      valid_update: valid_update -    } do -      other_user = insert(:user) - -      update = -        valid_update -        |> Map.put("actor", other_user.ap_id) - -      assert {:error, _cng} = ObjectValidator.validate(update, []) -    end -  end -end diff --git a/test/web/activity_pub/object_validators/announce_validation_test.exs b/test/web/activity_pub/object_validators/announce_validation_test.exs new file mode 100644 index 000000000..623342f76 --- /dev/null +++ b/test/web/activity_pub/object_validators/announce_validation_test.exs @@ -0,0 +1,106 @@ +# 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.AnnouncValidationTest do +  use Pleroma.DataCase + +  alias Pleroma.Object +  alias Pleroma.Web.ActivityPub.Builder +  alias Pleroma.Web.ActivityPub.ObjectValidator +  alias Pleroma.Web.CommonAPI + +  import Pleroma.Factory + +  describe "announces" do +    setup do +      user = insert(:user) +      announcer = insert(:user) +      {:ok, post_activity} = CommonAPI.post(user, %{status: "uguu"}) + +      object = Object.normalize(post_activity, false) +      {:ok, valid_announce, []} = Builder.announce(announcer, object) + +      %{ +        valid_announce: valid_announce, +        user: user, +        post_activity: post_activity, +        announcer: announcer +      } +    end + +    test "returns ok for a valid announce", %{valid_announce: valid_announce} do +      assert {:ok, _object, _meta} = ObjectValidator.validate(valid_announce, []) +    end + +    test "returns an error if the object can't be found", %{valid_announce: valid_announce} do +      without_object = +        valid_announce +        |> Map.delete("object") + +      {:error, cng} = ObjectValidator.validate(without_object, []) + +      assert {:object, {"can't be blank", [validation: :required]}} in cng.errors + +      nonexisting_object = +        valid_announce +        |> Map.put("object", "https://gensokyo.2hu/objects/99999999") + +      {:error, cng} = ObjectValidator.validate(nonexisting_object, []) + +      assert {:object, {"can't find object", []}} in cng.errors +    end + +    test "returns an error if we don't have the actor", %{valid_announce: valid_announce} do +      nonexisting_actor = +        valid_announce +        |> Map.put("actor", "https://gensokyo.2hu/users/raymoo") + +      {:error, cng} = ObjectValidator.validate(nonexisting_actor, []) + +      assert {:actor, {"can't find user", []}} in cng.errors +    end + +    test "returns an error if the actor already announced the object", %{ +      valid_announce: valid_announce, +      announcer: announcer, +      post_activity: post_activity +    } do +      _announce = CommonAPI.repeat(post_activity.id, announcer) + +      {:error, cng} = ObjectValidator.validate(valid_announce, []) + +      assert {:actor, {"already announced this object", []}} in cng.errors +      assert {:object, {"already announced by this actor", []}} in cng.errors +    end + +    test "returns an error if the actor can't announce the object", %{ +      announcer: announcer, +      user: user +    } do +      {:ok, post_activity} = +        CommonAPI.post(user, %{status: "a secret post", visibility: "private"}) + +      object = Object.normalize(post_activity, false) + +      # Another user can't announce it +      {:ok, announce, []} = Builder.announce(announcer, object, public: false) + +      {:error, cng} = ObjectValidator.validate(announce, []) + +      assert {:actor, {"can not announce this object", []}} in cng.errors + +      # The actor of the object can announce it +      {:ok, announce, []} = Builder.announce(user, object, public: false) + +      assert {:ok, _, _} = ObjectValidator.validate(announce, []) + +      # The actor of the object can not announce it publicly +      {:ok, announce, []} = Builder.announce(user, object, public: true) + +      {:error, cng} = ObjectValidator.validate(announce, []) + +      assert {:actor, {"can not announce this object publicly", []}} in cng.errors +    end +  end +end diff --git a/test/web/activity_pub/object_validators/attachment_validator_test.exs b/test/web/activity_pub/object_validators/attachment_validator_test.exs new file mode 100644 index 000000000..558bb3131 --- /dev/null +++ b/test/web/activity_pub/object_validators/attachment_validator_test.exs @@ -0,0 +1,74 @@ +# 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.AttachmentValidatorTest do +  use Pleroma.DataCase + +  alias Pleroma.Web.ActivityPub.ActivityPub +  alias Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidator + +  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 +end diff --git a/test/web/activity_pub/object_validators/block_validation_test.exs b/test/web/activity_pub/object_validators/block_validation_test.exs new file mode 100644 index 000000000..c08d4b2e8 --- /dev/null +++ b/test/web/activity_pub/object_validators/block_validation_test.exs @@ -0,0 +1,39 @@ +# 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.BlockValidationTest do +  use Pleroma.DataCase + +  alias Pleroma.Web.ActivityPub.Builder +  alias Pleroma.Web.ActivityPub.ObjectValidator + +  import Pleroma.Factory + +  describe "blocks" do +    setup do +      user = insert(:user, local: false) +      blocked = insert(:user) + +      {:ok, valid_block, []} = Builder.block(user, blocked) + +      %{user: user, valid_block: valid_block} +    end + +    test "validates a basic object", %{ +      valid_block: valid_block +    } do +      assert {:ok, _block, []} = ObjectValidator.validate(valid_block, []) +    end + +    test "returns an error if we don't know the blocked user", %{ +      valid_block: valid_block +    } do +      block = +        valid_block +        |> Map.put("object", "https://gensokyo.2hu/users/raymoo") + +      assert {:error, _cng} = ObjectValidator.validate(block, []) +    end +  end +end diff --git a/test/web/activity_pub/object_validators/chat_validation_test.exs b/test/web/activity_pub/object_validators/chat_validation_test.exs new file mode 100644 index 000000000..ec1e497fa --- /dev/null +++ b/test/web/activity_pub/object_validators/chat_validation_test.exs @@ -0,0 +1,200 @@ +# 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.ChatValidationTest 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.CommonAPI + +  import Pleroma.Factory + +  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 +end diff --git a/test/web/activity_pub/object_validators/delete_validation_test.exs b/test/web/activity_pub/object_validators/delete_validation_test.exs new file mode 100644 index 000000000..42cd18298 --- /dev/null +++ b/test/web/activity_pub/object_validators/delete_validation_test.exs @@ -0,0 +1,106 @@ +# 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.DeleteValidationTest do +  use Pleroma.DataCase + +  alias Pleroma.Object +  alias Pleroma.Web.ActivityPub.Builder +  alias Pleroma.Web.ActivityPub.ObjectValidator +  alias Pleroma.Web.CommonAPI + +  import Pleroma.Factory + +  describe "deletes" do +    setup do +      user = insert(:user) +      {:ok, post_activity} = CommonAPI.post(user, %{status: "cancel me daddy"}) + +      {:ok, valid_post_delete, _} = Builder.delete(user, post_activity.data["object"]) +      {:ok, valid_user_delete, _} = Builder.delete(user, user.ap_id) + +      %{user: user, valid_post_delete: valid_post_delete, valid_user_delete: valid_user_delete} +    end + +    test "it is valid for a post deletion", %{valid_post_delete: valid_post_delete} do +      {:ok, valid_post_delete, _} = ObjectValidator.validate(valid_post_delete, []) + +      assert valid_post_delete["deleted_activity_id"] +    end + +    test "it is invalid if the object isn't in a list of certain types", %{ +      valid_post_delete: valid_post_delete +    } do +      object = Object.get_by_ap_id(valid_post_delete["object"]) + +      data = +        object.data +        |> Map.put("type", "Like") + +      {:ok, _object} = +        object +        |> Ecto.Changeset.change(%{data: data}) +        |> Object.update_and_set_cache() + +      {:error, cng} = ObjectValidator.validate(valid_post_delete, []) +      assert {:object, {"object not in allowed types", []}} in cng.errors +    end + +    test "it is valid for a user deletion", %{valid_user_delete: valid_user_delete} do +      assert match?({:ok, _, _}, ObjectValidator.validate(valid_user_delete, [])) +    end + +    test "it's invalid if the id is missing", %{valid_post_delete: valid_post_delete} do +      no_id = +        valid_post_delete +        |> Map.delete("id") + +      {:error, cng} = ObjectValidator.validate(no_id, []) + +      assert {:id, {"can't be blank", [validation: :required]}} in cng.errors +    end + +    test "it's invalid if the object doesn't exist", %{valid_post_delete: valid_post_delete} do +      missing_object = +        valid_post_delete +        |> Map.put("object", "http://does.not/exist") + +      {:error, cng} = ObjectValidator.validate(missing_object, []) + +      assert {:object, {"can't find object", []}} in cng.errors +    end + +    test "it's invalid if the actor of the object and the actor of delete are from different domains", +         %{valid_post_delete: valid_post_delete} do +      valid_user = insert(:user) + +      valid_other_actor = +        valid_post_delete +        |> Map.put("actor", valid_user.ap_id) + +      assert match?({:ok, _, _}, ObjectValidator.validate(valid_other_actor, [])) + +      invalid_other_actor = +        valid_post_delete +        |> Map.put("actor", "https://gensokyo.2hu/users/raymoo") + +      {:error, cng} = ObjectValidator.validate(invalid_other_actor, []) + +      assert {:actor, {"is not allowed to delete object", []}} in cng.errors +    end + +    test "it's valid if the actor of the object is a local superuser", +         %{valid_post_delete: valid_post_delete} do +      user = +        insert(:user, local: true, is_moderator: true, ap_id: "https://gensokyo.2hu/users/raymoo") + +      valid_other_actor = +        valid_post_delete +        |> Map.put("actor", user.ap_id) + +      {:ok, _, meta} = ObjectValidator.validate(valid_other_actor, []) +      assert meta[:do_not_federate] +    end +  end +end diff --git a/test/web/activity_pub/object_validators/emoji_react_validation_test.exs b/test/web/activity_pub/object_validators/emoji_react_validation_test.exs new file mode 100644 index 000000000..582e6d785 --- /dev/null +++ b/test/web/activity_pub/object_validators/emoji_react_validation_test.exs @@ -0,0 +1,53 @@ +# 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.EmojiReactHandlingTest do +  use Pleroma.DataCase + +  alias Pleroma.Web.ActivityPub.Builder +  alias Pleroma.Web.ActivityPub.ObjectValidator +  alias Pleroma.Web.CommonAPI + +  import Pleroma.Factory + +  describe "EmojiReacts" do +    setup do +      user = insert(:user) +      {:ok, post_activity} = CommonAPI.post(user, %{status: "uguu"}) + +      object = Pleroma.Object.get_by_ap_id(post_activity.data["object"]) + +      {:ok, valid_emoji_react, []} = Builder.emoji_react(user, object, "👌") + +      %{user: user, post_activity: post_activity, valid_emoji_react: valid_emoji_react} +    end + +    test "it validates a valid EmojiReact", %{valid_emoji_react: valid_emoji_react} do +      assert {:ok, _, _} = ObjectValidator.validate(valid_emoji_react, []) +    end + +    test "it is not valid without a 'content' field", %{valid_emoji_react: valid_emoji_react} do +      without_content = +        valid_emoji_react +        |> Map.delete("content") + +      {:error, cng} = ObjectValidator.validate(without_content, []) + +      refute cng.valid? +      assert {:content, {"can't be blank", [validation: :required]}} in cng.errors +    end + +    test "it is not valid with a non-emoji content field", %{valid_emoji_react: valid_emoji_react} do +      without_emoji_content = +        valid_emoji_react +        |> Map.put("content", "x") + +      {:error, cng} = ObjectValidator.validate(without_emoji_content, []) + +      refute cng.valid? + +      assert {:content, {"must be a single character emoji", []}} in cng.errors +    end +  end +end diff --git a/test/web/activity_pub/object_validators/follow_validation_test.exs b/test/web/activity_pub/object_validators/follow_validation_test.exs new file mode 100644 index 000000000..6e1378be2 --- /dev/null +++ b/test/web/activity_pub/object_validators/follow_validation_test.exs @@ -0,0 +1,26 @@ +# 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.FollowValidationTest do +  use Pleroma.DataCase + +  alias Pleroma.Web.ActivityPub.Builder +  alias Pleroma.Web.ActivityPub.ObjectValidator + +  import Pleroma.Factory + +  describe "Follows" do +    setup do +      follower = insert(:user) +      followed = insert(:user) + +      {:ok, valid_follow, []} = Builder.follow(follower, followed) +      %{follower: follower, followed: followed, valid_follow: valid_follow} +    end + +    test "validates a basic follow object", %{valid_follow: valid_follow} do +      assert {:ok, _follow, []} = ObjectValidator.validate(valid_follow, []) +    end +  end +end diff --git a/test/web/activity_pub/object_validators/like_validation_test.exs b/test/web/activity_pub/object_validators/like_validation_test.exs new file mode 100644 index 000000000..2c033b7e2 --- /dev/null +++ b/test/web/activity_pub/object_validators/like_validation_test.exs @@ -0,0 +1,113 @@ +# 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.LikeValidationTest do +  use Pleroma.DataCase + +  alias Pleroma.Web.ActivityPub.ObjectValidator +  alias Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator +  alias Pleroma.Web.ActivityPub.Utils +  alias Pleroma.Web.CommonAPI + +  import Pleroma.Factory + +  describe "likes" do +    setup do +      user = insert(:user) +      {:ok, post_activity} = CommonAPI.post(user, %{status: "uguu"}) + +      valid_like = %{ +        "to" => [user.ap_id], +        "cc" => [], +        "type" => "Like", +        "id" => Utils.generate_activity_id(), +        "object" => post_activity.data["object"], +        "actor" => user.ap_id, +        "context" => "a context" +      } + +      %{valid_like: valid_like, user: user, post_activity: post_activity} +    end + +    test "returns ok when called in the ObjectValidator", %{valid_like: valid_like} do +      {:ok, object, _meta} = ObjectValidator.validate(valid_like, []) + +      assert "id" in Map.keys(object) +    end + +    test "is valid for a valid object", %{valid_like: valid_like} do +      assert LikeValidator.cast_and_validate(valid_like).valid? +    end + +    test "sets the 'to' field to the object actor if no recipients are given", %{ +      valid_like: valid_like, +      user: user +    } do +      without_recipients = +        valid_like +        |> Map.delete("to") + +      {:ok, object, _meta} = ObjectValidator.validate(without_recipients, []) + +      assert object["to"] == [user.ap_id] +    end + +    test "sets the context field to the context of the object if no context is given", %{ +      valid_like: valid_like, +      post_activity: post_activity +    } do +      without_context = +        valid_like +        |> Map.delete("context") + +      {:ok, object, _meta} = ObjectValidator.validate(without_context, []) + +      assert object["context"] == post_activity.data["context"] +    end + +    test "it errors when the actor is missing or not known", %{valid_like: valid_like} do +      without_actor = Map.delete(valid_like, "actor") + +      refute LikeValidator.cast_and_validate(without_actor).valid? + +      with_invalid_actor = Map.put(valid_like, "actor", "invalidactor") + +      refute LikeValidator.cast_and_validate(with_invalid_actor).valid? +    end + +    test "it errors when the object is missing or not known", %{valid_like: valid_like} do +      without_object = Map.delete(valid_like, "object") + +      refute LikeValidator.cast_and_validate(without_object).valid? + +      with_invalid_object = Map.put(valid_like, "object", "invalidobject") + +      refute LikeValidator.cast_and_validate(with_invalid_object).valid? +    end + +    test "it errors when the actor has already like the object", %{ +      valid_like: valid_like, +      user: user, +      post_activity: post_activity +    } do +      _like = CommonAPI.favorite(user, post_activity.id) + +      refute LikeValidator.cast_and_validate(valid_like).valid? +    end + +    test "it works when actor or object are wrapped in maps", %{valid_like: valid_like} do +      wrapped_like = +        valid_like +        |> Map.put("actor", %{"id" => valid_like["actor"]}) +        |> Map.put("object", %{"id" => valid_like["object"]}) + +      validated = LikeValidator.cast_and_validate(wrapped_like) + +      assert validated.valid? + +      assert {:actor, valid_like["actor"]} in validated.changes +      assert {:object, valid_like["object"]} in validated.changes +    end +  end +end diff --git a/test/web/activity_pub/object_validators/undo_validation_test.exs b/test/web/activity_pub/object_validators/undo_validation_test.exs new file mode 100644 index 000000000..75bbcc4b6 --- /dev/null +++ b/test/web/activity_pub/object_validators/undo_validation_test.exs @@ -0,0 +1,53 @@ +# 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.UndoHandlingTest do +  use Pleroma.DataCase + +  alias Pleroma.Web.ActivityPub.Builder +  alias Pleroma.Web.ActivityPub.ObjectValidator +  alias Pleroma.Web.CommonAPI + +  import Pleroma.Factory + +  describe "Undos" do +    setup do +      user = insert(:user) +      {:ok, post_activity} = CommonAPI.post(user, %{status: "uguu"}) +      {:ok, like} = CommonAPI.favorite(user, post_activity.id) +      {:ok, valid_like_undo, []} = Builder.undo(user, like) + +      %{user: user, like: like, valid_like_undo: valid_like_undo} +    end + +    test "it validates a basic like undo", %{valid_like_undo: valid_like_undo} do +      assert {:ok, _, _} = ObjectValidator.validate(valid_like_undo, []) +    end + +    test "it does not validate if the actor of the undo is not the actor of the object", %{ +      valid_like_undo: valid_like_undo +    } do +      other_user = insert(:user, ap_id: "https://gensokyo.2hu/users/raymoo") + +      bad_actor = +        valid_like_undo +        |> Map.put("actor", other_user.ap_id) + +      {:error, cng} = ObjectValidator.validate(bad_actor, []) + +      assert {:actor, {"not the same as object actor", []}} in cng.errors +    end + +    test "it does not validate if the object is missing", %{valid_like_undo: valid_like_undo} do +      missing_object = +        valid_like_undo +        |> Map.put("object", "https://gensokyo.2hu/objects/1") + +      {:error, cng} = ObjectValidator.validate(missing_object, []) + +      assert {:object, {"can't find object", []}} in cng.errors +      assert length(cng.errors) == 1 +    end +  end +end diff --git a/test/web/activity_pub/object_validators/update_validation_test.exs b/test/web/activity_pub/object_validators/update_validation_test.exs new file mode 100644 index 000000000..5e80cf731 --- /dev/null +++ b/test/web/activity_pub/object_validators/update_validation_test.exs @@ -0,0 +1,44 @@ +# 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.UpdateHandlingTest do +  use Pleroma.DataCase + +  alias Pleroma.Web.ActivityPub.Builder +  alias Pleroma.Web.ActivityPub.ObjectValidator + +  import Pleroma.Factory + +  describe "updates" do +    setup do +      user = insert(:user) + +      object = %{ +        "id" => user.ap_id, +        "name" => "A new name", +        "summary" => "A new bio" +      } + +      {:ok, valid_update, []} = Builder.update(user, object) + +      %{user: user, valid_update: valid_update} +    end + +    test "validates a basic object", %{valid_update: valid_update} do +      assert {:ok, _update, []} = ObjectValidator.validate(valid_update, []) +    end + +    test "returns an error if the object can't be updated by the actor", %{ +      valid_update: valid_update +    } do +      other_user = insert(:user) + +      update = +        valid_update +        |> Map.put("actor", other_user.ap_id) + +      assert {:error, _cng} = ObjectValidator.validate(update, []) +    end +  end +end diff --git a/test/web/activity_pub/relay_test.exs b/test/web/activity_pub/relay_test.exs index b3b573c9b..9d657ac4f 100644 --- a/test/web/activity_pub/relay_test.exs +++ b/test/web/activity_pub/relay_test.exs @@ -7,8 +7,8 @@ defmodule Pleroma.Web.ActivityPub.RelayTest do    alias Pleroma.Activity    alias Pleroma.User -  alias Pleroma.Web.ActivityPub.ActivityPub    alias Pleroma.Web.ActivityPub.Relay +  alias Pleroma.Web.CommonAPI    import ExUnit.CaptureLog    import Pleroma.Factory @@ -53,8 +53,7 @@ defmodule Pleroma.Web.ActivityPub.RelayTest do      test "returns activity" do        user = insert(:user)        service_actor = Relay.get_actor() -      ActivityPub.follow(service_actor, user) -      Pleroma.User.follow(service_actor, user) +      CommonAPI.follow(service_actor, user)        assert "#{user.ap_id}/followers" in User.following(service_actor)        assert {:ok, %Activity{} = activity} = Relay.unfollow(user.ap_id)        assert activity.actor == "#{Pleroma.Web.Endpoint.url()}/relay" @@ -74,6 +73,7 @@ defmodule Pleroma.Web.ActivityPub.RelayTest do        assert Relay.publish(activity) == {:error, "Not implemented"}      end +    @tag capture_log: true      test "returns error when activity not public" do        activity = insert(:direct_note_activity)        assert Relay.publish(activity) == {:error, false} diff --git a/test/web/activity_pub/side_effects_test.exs b/test/web/activity_pub/side_effects_test.exs index 12c9ef1da..2649b060a 100644 --- a/test/web/activity_pub/side_effects_test.exs +++ b/test/web/activity_pub/side_effects_test.exs @@ -64,6 +64,47 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do      end    end +  describe "blocking users" do +    setup do +      user = insert(:user) +      blocked = insert(:user) +      User.follow(blocked, user) +      User.follow(user, blocked) + +      {:ok, block_data, []} = Builder.block(user, blocked) +      {:ok, block, _meta} = ActivityPub.persist(block_data, local: true) + +      %{user: user, blocked: blocked, block: block} +    end + +    test "it unfollows and blocks", %{user: user, blocked: blocked, block: block} do +      assert User.following?(user, blocked) +      assert User.following?(blocked, user) + +      {:ok, _, _} = SideEffects.handle(block) + +      refute User.following?(user, blocked) +      refute User.following?(blocked, user) +      assert User.blocks?(user, blocked) +    end + +    test "it blocks but does not unfollow if the relevant setting is set", %{ +      user: user, +      blocked: blocked, +      block: block +    } do +      clear_config([:activitypub, :unfollow_blocked], false) +      assert User.following?(user, blocked) +      assert User.following?(blocked, user) + +      {:ok, _, _} = SideEffects.handle(block) + +      refute User.following?(user, blocked) +      assert User.following?(blocked, user) +      assert User.blocks?(user, blocked) +    end +  end +    describe "update users" do      setup do        user = insert(:user) @@ -242,8 +283,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do        {:ok, like} = CommonAPI.favorite(user, post.id)        {:ok, reaction} = CommonAPI.react_with_emoji(post.id, user, "👍")        {:ok, announce} = CommonAPI.repeat(post.id, user) -      {:ok, block} = ActivityPub.block(user, poster) -      User.block(user, poster) +      {:ok, block} = CommonAPI.block(user, poster)        {:ok, undo_data, _meta} = Builder.undo(user, like)        {:ok, like_undo, _meta} = ActivityPub.persist(undo_data, local: true) @@ -549,10 +589,29 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do      end      test "it streams out the announce", %{announce: announce} do -      with_mock Pleroma.Web.ActivityPub.ActivityPub, [:passthrough], stream_out: fn _ -> nil end do +      with_mocks([ +        { +          Pleroma.Web.Streamer, +          [], +          [ +            stream: fn _, _ -> nil end +          ] +        }, +        { +          Pleroma.Web.Push, +          [], +          [ +            send: fn _ -> nil end +          ] +        } +      ]) do          {:ok, announce, _} = SideEffects.handle(announce) -        assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out(announce)) +        assert called( +                 Pleroma.Web.Streamer.stream(["user", "list", "public", "public:local"], announce) +               ) + +        assert called(Pleroma.Web.Push.send(:_))        end      end    end diff --git a/test/web/activity_pub/transmogrifier/block_handling_test.exs b/test/web/activity_pub/transmogrifier/block_handling_test.exs new file mode 100644 index 000000000..71f1a0ed5 --- /dev/null +++ b/test/web/activity_pub/transmogrifier/block_handling_test.exs @@ -0,0 +1,63 @@ +# 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.BlockHandlingTest do +  use Pleroma.DataCase + +  alias Pleroma.Activity +  alias Pleroma.User +  alias Pleroma.Web.ActivityPub.Transmogrifier + +  import Pleroma.Factory + +  test "it works for incoming blocks" do +    user = insert(:user) + +    data = +      File.read!("test/fixtures/mastodon-block-activity.json") +      |> Poison.decode!() +      |> Map.put("object", user.ap_id) + +    blocker = insert(:user, ap_id: data["actor"]) + +    {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) + +    assert data["type"] == "Block" +    assert data["object"] == user.ap_id +    assert data["actor"] == "http://mastodon.example.org/users/admin" + +    assert User.blocks?(blocker, user) +  end + +  test "incoming blocks successfully tear down any follow relationship" do +    blocker = insert(:user) +    blocked = insert(:user) + +    data = +      File.read!("test/fixtures/mastodon-block-activity.json") +      |> Poison.decode!() +      |> Map.put("object", blocked.ap_id) +      |> Map.put("actor", blocker.ap_id) + +    {:ok, blocker} = User.follow(blocker, blocked) +    {:ok, blocked} = User.follow(blocked, blocker) + +    assert User.following?(blocker, blocked) +    assert User.following?(blocked, blocker) + +    {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) + +    assert data["type"] == "Block" +    assert data["object"] == blocked.ap_id +    assert data["actor"] == blocker.ap_id + +    blocker = User.get_cached_by_ap_id(data["actor"]) +    blocked = User.get_cached_by_ap_id(data["object"]) + +    assert User.blocks?(blocker, blocked) + +    refute User.following?(blocker, blocked) +    refute User.following?(blocked, blocker) +  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 06c39eed6..17e764ca1 100644 --- a/test/web/activity_pub/transmogrifier/follow_handling_test.exs +++ b/test/web/activity_pub/transmogrifier/follow_handling_test.exs @@ -160,7 +160,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.FollowHandlingTest do          |> Poison.decode!()          |> Map.put("object", user.ap_id) -      with_mock Pleroma.User, [:passthrough], follow: fn _, _ -> {:error, :testing} end do +      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) diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs index 100821056..f7b7d1a9f 100644 --- a/test/web/activity_pub/transmogrifier_test.exs +++ b/test/web/activity_pub/transmogrifier_test.exs @@ -11,7 +11,6 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do    alias Pleroma.Object.Fetcher    alias Pleroma.Tests.ObanHelpers    alias Pleroma.User -  alias Pleroma.Web.ActivityPub.ActivityPub    alias Pleroma.Web.ActivityPub.Transmogrifier    alias Pleroma.Web.AdminAPI.AccountView    alias Pleroma.Web.CommonAPI @@ -445,56 +444,6 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        assert [^pending_follower] = User.get_follow_requests(user)      end -    test "it works for incoming blocks" do -      user = insert(:user) - -      data = -        File.read!("test/fixtures/mastodon-block-activity.json") -        |> Poison.decode!() -        |> Map.put("object", user.ap_id) - -      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - -      assert data["type"] == "Block" -      assert data["object"] == user.ap_id -      assert data["actor"] == "http://mastodon.example.org/users/admin" - -      blocker = User.get_cached_by_ap_id(data["actor"]) - -      assert User.blocks?(blocker, user) -    end - -    test "incoming blocks successfully tear down any follow relationship" do -      blocker = insert(:user) -      blocked = insert(:user) - -      data = -        File.read!("test/fixtures/mastodon-block-activity.json") -        |> Poison.decode!() -        |> Map.put("object", blocked.ap_id) -        |> Map.put("actor", blocker.ap_id) - -      {:ok, blocker} = User.follow(blocker, blocked) -      {:ok, blocked} = User.follow(blocked, blocker) - -      assert User.following?(blocker, blocked) -      assert User.following?(blocked, blocker) - -      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - -      assert data["type"] == "Block" -      assert data["object"] == blocked.ap_id -      assert data["actor"] == blocker.ap_id - -      blocker = User.get_cached_by_ap_id(data["actor"]) -      blocked = User.get_cached_by_ap_id(data["object"]) - -      assert User.blocks?(blocker, blocked) - -      refute User.following?(blocker, blocked) -      refute User.following?(blocked, blocker) -    end -      test "it works for incoming accepts which were pre-accepted" do        follower = insert(:user)        followed = insert(:user) @@ -502,7 +451,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        {:ok, follower} = User.follow(follower, followed)        assert User.following?(follower, followed) == true -      {:ok, follow_activity} = ActivityPub.follow(follower, followed) +      {:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed)        accept_data =          File.read!("test/fixtures/mastodon-accept-activity.json") @@ -532,7 +481,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        follower = insert(:user)        followed = insert(:user, locked: true) -      {:ok, follow_activity} = ActivityPub.follow(follower, followed) +      {:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed)        accept_data =          File.read!("test/fixtures/mastodon-accept-activity.json") @@ -554,7 +503,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        follower = insert(:user)        followed = insert(:user, locked: true) -      {:ok, follow_activity} = ActivityPub.follow(follower, followed) +      {:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed)        accept_data =          File.read!("test/fixtures/mastodon-accept-activity.json") @@ -619,7 +568,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        followed = insert(:user, locked: true)        {:ok, follower} = User.follow(follower, followed) -      {:ok, _follow_activity} = ActivityPub.follow(follower, followed) +      {:ok, _, _, _follow_activity} = CommonAPI.follow(follower, followed)        assert User.following?(follower, followed) == true @@ -645,7 +594,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        followed = insert(:user, locked: true)        {:ok, follower} = User.follow(follower, followed) -      {:ok, follow_activity} = ActivityPub.follow(follower, followed) +      {:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed)        assert User.following?(follower, followed) == true @@ -709,22 +658,44 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do            "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3"          ) -      attachment = %{ -        "type" => "Link", -        "mediaType" => "video/mp4", -        "url" => [ -          %{ -            "href" => -              "https://peertube.moe/static/webseed/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-480.mp4", -            "mediaType" => "video/mp4" -          } -        ] -      } -        assert object.data["url"] ==                 "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3" -      assert object.data["attachment"] == [attachment] +      assert object.data["attachment"] == [ +               %{ +                 "type" => "Link", +                 "mediaType" => "video/mp4", +                 "url" => [ +                   %{ +                     "href" => +                       "https://peertube.moe/static/webseed/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-480.mp4", +                     "mediaType" => "video/mp4" +                   } +                 ] +               } +             ] + +      {:ok, object} = +        Fetcher.fetch_object_from_id( +          "https://framatube.org/videos/watch/6050732a-8a7a-43d4-a6cd-809525a1d206" +        ) + +      assert object.data["attachment"] == [ +               %{ +                 "type" => "Link", +                 "mediaType" => "video/mp4", +                 "url" => [ +                   %{ +                     "href" => +                       "https://framatube.org/static/webseed/6050732a-8a7a-43d4-a6cd-809525a1d206-1080.mp4", +                     "mediaType" => "video/mp4" +                   } +                 ] +               } +             ] + +      assert object.data["url"] == +               "https://framatube.org/videos/watch/6050732a-8a7a-43d4-a6cd-809525a1d206"      end      test "it accepts Flag activities" do diff --git a/test/web/activity_pub/utils_test.exs b/test/web/activity_pub/utils_test.exs index 15f03f193..361dc5a41 100644 --- a/test/web/activity_pub/utils_test.exs +++ b/test/web/activity_pub/utils_test.exs @@ -8,7 +8,6 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do    alias Pleroma.Object    alias Pleroma.Repo    alias Pleroma.User -  alias Pleroma.Web.ActivityPub.ActivityPub    alias Pleroma.Web.ActivityPub.Utils    alias Pleroma.Web.AdminAPI.AccountView    alias Pleroma.Web.CommonAPI @@ -27,16 +26,6 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do      end    end -  describe "fetch the latest Block" do -    test "fetches the latest Block activity" do -      blocker = insert(:user) -      blocked = insert(:user) -      {:ok, activity} = ActivityPub.block(blocker, blocked) - -      assert activity == Utils.fetch_latest_block(blocker, blocked) -    end -  end -    describe "determine_explicit_mentions()" do      test "works with an object that has mentions" do        object = %{ @@ -207,8 +196,8 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do        user = insert(:user, locked: true)        follower = insert(:user) -      {:ok, follow_activity} = ActivityPub.follow(follower, user) -      {:ok, follow_activity_two} = ActivityPub.follow(follower, user) +      {:ok, _, _, follow_activity} = CommonAPI.follow(follower, user) +      {:ok, _, _, follow_activity_two} = CommonAPI.follow(follower, user)        data =          follow_activity_two.data @@ -231,8 +220,8 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do        user = insert(:user, locked: true)        follower = insert(:user) -      {:ok, follow_activity} = ActivityPub.follow(follower, user) -      {:ok, follow_activity_two} = ActivityPub.follow(follower, user) +      {:ok, _, _, follow_activity} = CommonAPI.follow(follower, user) +      {:ok, _, _, follow_activity_two} = CommonAPI.follow(follower, user)        data =          follow_activity_two.data @@ -344,9 +333,9 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do        user1 = insert(:user)        user2 = insert(:user) -      assert {:ok, %Activity{} = _} = ActivityPub.block(user1, user2) -      assert {:ok, %Activity{} = _} = ActivityPub.block(user1, user2) -      assert {:ok, %Activity{} = activity} = ActivityPub.block(user1, user2) +      assert {:ok, %Activity{} = _} = CommonAPI.block(user1, user2) +      assert {:ok, %Activity{} = _} = CommonAPI.block(user1, user2) +      assert {:ok, %Activity{} = activity} = CommonAPI.block(user1, user2)        assert Utils.fetch_latest_block(user1, user2) == activity      end diff --git a/test/web/common_api/common_api_test.exs b/test/web/common_api/common_api_test.exs index 6bd26050e..7e11fede3 100644 --- a/test/web/common_api/common_api_test.exs +++ b/test/web/common_api/common_api_test.exs @@ -25,6 +25,52 @@ defmodule Pleroma.Web.CommonAPITest do    setup do: clear_config([:instance, :limit])    setup do: clear_config([:instance, :max_pinned_statuses]) +  describe "blocking" do +    setup do +      blocker = insert(:user) +      blocked = insert(:user) +      User.follow(blocker, blocked) +      User.follow(blocked, blocker) +      %{blocker: blocker, blocked: blocked} +    end + +    test "it blocks and federates", %{blocker: blocker, blocked: blocked} do +      clear_config([:instance, :federating], true) + +      with_mock Pleroma.Web.Federator, +        publish: fn _ -> nil end do +        assert {:ok, block} = CommonAPI.block(blocker, blocked) + +        assert block.local +        assert User.blocks?(blocker, blocked) +        refute User.following?(blocker, blocked) +        refute User.following?(blocked, blocker) + +        assert called(Pleroma.Web.Federator.publish(block)) +      end +    end + +    test "it blocks and does not federate if outgoing blocks are disabled", %{ +      blocker: blocker, +      blocked: blocked +    } do +      clear_config([:instance, :federating], true) +      clear_config([:activitypub, :outgoing_blocks], false) + +      with_mock Pleroma.Web.Federator, +        publish: fn _ -> nil end do +        assert {:ok, block} = CommonAPI.block(blocker, blocked) + +        assert block.local +        assert User.blocks?(blocker, blocked) +        refute User.following?(blocker, blocked) +        refute User.following?(blocked, blocker) + +        refute called(Pleroma.Web.Federator.publish(block)) +      end +    end +  end +    describe "posting chat messages" do      setup do: clear_config([:instance, :chat_limit]) @@ -445,6 +491,7 @@ defmodule Pleroma.Web.CommonAPITest do        object = Object.normalize(activity)        assert object.data["content"] == "<p><b>2hu</b></p>alert('xss')" +      assert object.data["source"] == post      end      test "it filters out obviously bad tags when accepting a post as Markdown" do @@ -461,6 +508,7 @@ defmodule Pleroma.Web.CommonAPITest do        object = Object.normalize(activity)        assert object.data["content"] == "<p><b>2hu</b></p>alert('xss')" +      assert object.data["source"] == post      end      test "it does not allow replies to direct messages that are not direct messages themselves" do @@ -886,6 +934,15 @@ defmodule Pleroma.Web.CommonAPITest do      end    end +  describe "follow/2" do +    test "directly follows a non-locked local user" do +      [follower, followed] = insert_pair(:user) +      {:ok, follower, followed, _} = CommonAPI.follow(follower, followed) + +      assert User.following?(follower, followed) +    end +  end +    describe "unfollow/2" do      test "also unsubscribes a user" do        [follower, followed] = insert_pair(:user) @@ -950,9 +1007,9 @@ defmodule Pleroma.Web.CommonAPITest do        follower = insert(:user)        follower_two = insert(:user) -      {:ok, follow_activity} = ActivityPub.follow(follower, user) -      {:ok, follow_activity_two} = ActivityPub.follow(follower, user) -      {:ok, follow_activity_three} = ActivityPub.follow(follower_two, user) +      {:ok, _, _, follow_activity} = CommonAPI.follow(follower, user) +      {:ok, _, _, follow_activity_two} = CommonAPI.follow(follower, user) +      {:ok, _, _, follow_activity_three} = CommonAPI.follow(follower_two, user)        assert follow_activity.data["state"] == "pending"        assert follow_activity_two.data["state"] == "pending" @@ -970,9 +1027,9 @@ defmodule Pleroma.Web.CommonAPITest do        follower = insert(:user)        follower_two = insert(:user) -      {:ok, follow_activity} = ActivityPub.follow(follower, user) -      {:ok, follow_activity_two} = ActivityPub.follow(follower, user) -      {:ok, follow_activity_three} = ActivityPub.follow(follower_two, user) +      {:ok, _, _, follow_activity} = CommonAPI.follow(follower, user) +      {:ok, _, _, follow_activity_two} = CommonAPI.follow(follower, user) +      {:ok, _, _, follow_activity_three} = CommonAPI.follow(follower_two, user)        assert follow_activity.data["state"] == "pending"        assert follow_activity_two.data["state"] == "pending" diff --git a/test/web/masto_fe_controller_test.exs b/test/web/masto_fe_controller_test.exs index 1d107d56c..f3b54b5f2 100644 --- a/test/web/masto_fe_controller_test.exs +++ b/test/web/masto_fe_controller_test.exs @@ -24,7 +24,7 @@ defmodule Pleroma.Web.MastodonAPI.MastoFEController do      assert _result = json_response(conn, 200)      user = User.get_cached_by_ap_id(user.ap_id) -    assert user.settings == %{"programming" => "socks"} +    assert user.mastofe_settings == %{"programming" => "socks"}    end    describe "index/2 redirections" do diff --git a/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs b/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs index f67d294ba..b55bb76a7 100644 --- a/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs +++ b/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs @@ -216,10 +216,21 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do          filename: "an_image.jpg"        } -      conn = patch(conn, "/api/v1/accounts/update_credentials", %{"avatar" => new_avatar}) +      assert user.avatar == %{} -      assert user_response = json_response_and_validate_schema(conn, 200) +      res = patch(conn, "/api/v1/accounts/update_credentials", %{"avatar" => new_avatar}) + +      assert user_response = json_response_and_validate_schema(res, 200)        assert user_response["avatar"] != User.avatar_url(user) + +      user = User.get_by_id(user.id) +      refute user.avatar == %{} + +      # Also resets it +      _res = patch(conn, "/api/v1/accounts/update_credentials", %{"avatar" => ""}) + +      user = User.get_by_id(user.id) +      assert user.avatar == nil      end      test "updates the user's banner", %{user: user, conn: conn} do @@ -229,26 +240,39 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do          filename: "an_image.jpg"        } -      conn = patch(conn, "/api/v1/accounts/update_credentials", %{"header" => new_header}) +      res = patch(conn, "/api/v1/accounts/update_credentials", %{"header" => new_header}) -      assert user_response = json_response_and_validate_schema(conn, 200) +      assert user_response = json_response_and_validate_schema(res, 200)        assert user_response["header"] != User.banner_url(user) + +      # Also resets it +      _res = patch(conn, "/api/v1/accounts/update_credentials", %{"header" => ""}) + +      user = User.get_by_id(user.id) +      assert user.banner == nil      end -    test "updates the user's background", %{conn: conn} do +    test "updates the user's background", %{conn: conn, user: user} do        new_header = %Plug.Upload{          content_type: "image/jpg",          path: Path.absname("test/fixtures/image.jpg"),          filename: "an_image.jpg"        } -      conn = +      res =          patch(conn, "/api/v1/accounts/update_credentials", %{            "pleroma_background_image" => new_header          }) -      assert user_response = json_response_and_validate_schema(conn, 200) +      assert user_response = json_response_and_validate_schema(res, 200)        assert user_response["pleroma"]["background_image"] +      # +      # Also resets it +      _res = +        patch(conn, "/api/v1/accounts/update_credentials", %{"pleroma_background_image" => ""}) + +      user = User.get_by_id(user.id) +      assert user.background == nil      end      test "requires 'write:accounts' permission" do diff --git a/test/web/mastodon_api/controllers/account_controller_test.exs b/test/web/mastodon_api/controllers/account_controller_test.exs index fcc1e792b..9c7b5e9b2 100644 --- a/test/web/mastodon_api/controllers/account_controller_test.exs +++ b/test/web/mastodon_api/controllers/account_controller_test.exs @@ -708,7 +708,10 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do        followed = insert(:user)        other_user = insert(:user) -      ret_conn = post(conn, "/api/v1/accounts/#{followed.id}/follow?reblogs=false") +      ret_conn = +        conn +        |> put_req_header("content-type", "application/json") +        |> post("/api/v1/accounts/#{followed.id}/follow", %{reblogs: false})        assert %{"showing_reblogs" => false} = json_response_and_validate_schema(ret_conn, 200) @@ -722,7 +725,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do        assert %{"showing_reblogs" => true} =                 conn -               |> post("/api/v1/accounts/#{followed.id}/follow?reblogs=true") +               |> put_req_header("content-type", "application/json") +               |> post("/api/v1/accounts/#{followed.id}/follow", %{reblogs: true})                 |> json_response_and_validate_schema(200)        assert [%{"id" => ^reblog_id}] = @@ -731,6 +735,35 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do                 |> json_response(200)      end +    test "following with reblogs" do +      %{conn: conn} = oauth_access(["follow", "read:statuses"]) +      followed = insert(:user) +      other_user = insert(:user) + +      ret_conn = post(conn, "/api/v1/accounts/#{followed.id}/follow") + +      assert %{"showing_reblogs" => true} = json_response_and_validate_schema(ret_conn, 200) + +      {:ok, activity} = CommonAPI.post(other_user, %{status: "hey"}) +      {:ok, %{id: reblog_id}} = CommonAPI.repeat(activity.id, followed) + +      assert [%{"id" => ^reblog_id}] = +               conn +               |> get("/api/v1/timelines/home") +               |> json_response(200) + +      assert %{"showing_reblogs" => false} = +               conn +               |> put_req_header("content-type", "application/json") +               |> post("/api/v1/accounts/#{followed.id}/follow", %{reblogs: false}) +               |> json_response_and_validate_schema(200) + +      assert [] == +               conn +               |> get("/api/v1/timelines/home") +               |> json_response(200) +    end +      test "following / unfollowing errors", %{user: user, conn: conn} do        # self follow        conn_res = post(conn, "/api/v1/accounts/#{user.id}/follow") @@ -780,7 +813,6 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do        assert %{"id" => _id, "muting" => true, "muting_notifications" => true} =                 conn -               |> put_req_header("content-type", "application/json")                 |> post("/api/v1/accounts/#{other_user.id}/mute")                 |> json_response_and_validate_schema(200) diff --git a/test/web/mastodon_api/controllers/follow_request_controller_test.exs b/test/web/mastodon_api/controllers/follow_request_controller_test.exs index 44e12d15a..6749e0e83 100644 --- a/test/web/mastodon_api/controllers/follow_request_controller_test.exs +++ b/test/web/mastodon_api/controllers/follow_request_controller_test.exs @@ -6,7 +6,7 @@ defmodule Pleroma.Web.MastodonAPI.FollowRequestControllerTest do    use Pleroma.Web.ConnCase    alias Pleroma.User -  alias Pleroma.Web.ActivityPub.ActivityPub +  alias Pleroma.Web.CommonAPI    import Pleroma.Factory @@ -20,7 +20,7 @@ defmodule Pleroma.Web.MastodonAPI.FollowRequestControllerTest do      test "/api/v1/follow_requests works", %{user: user, conn: conn} do        other_user = insert(:user) -      {:ok, _activity} = ActivityPub.follow(other_user, user) +      {:ok, _, _, _activity} = CommonAPI.follow(other_user, user)        {:ok, other_user} = User.follow(other_user, user, :follow_pending)        assert User.following?(other_user, user) == false @@ -34,7 +34,7 @@ defmodule Pleroma.Web.MastodonAPI.FollowRequestControllerTest do      test "/api/v1/follow_requests/:id/authorize works", %{user: user, conn: conn} do        other_user = insert(:user) -      {:ok, _activity} = ActivityPub.follow(other_user, user) +      {:ok, _, _, _activity} = CommonAPI.follow(other_user, user)        {:ok, other_user} = User.follow(other_user, user, :follow_pending)        user = User.get_cached_by_id(user.id) @@ -56,7 +56,7 @@ defmodule Pleroma.Web.MastodonAPI.FollowRequestControllerTest do      test "/api/v1/follow_requests/:id/reject works", %{user: user, conn: conn} do        other_user = insert(:user) -      {:ok, _activity} = ActivityPub.follow(other_user, user) +      {:ok, _, _, _activity} = CommonAPI.follow(other_user, user)        user = User.get_cached_by_id(user.id) diff --git a/test/web/mastodon_api/controllers/instance_controller_test.exs b/test/web/mastodon_api/controllers/instance_controller_test.exs index 8bdfdddd1..cc880d82c 100644 --- a/test/web/mastodon_api/controllers/instance_controller_test.exs +++ b/test/web/mastodon_api/controllers/instance_controller_test.exs @@ -32,11 +32,15 @@ defmodule Pleroma.Web.MastodonAPI.InstanceControllerTest do               "avatar_upload_limit" => _,               "background_upload_limit" => _,               "banner_upload_limit" => _, -             "background_image" => _ +             "background_image" => _, +             "chat_limit" => _, +             "description_limit" => _             } = result +    assert result["pleroma"]["metadata"]["account_activation_required"] != nil      assert result["pleroma"]["metadata"]["features"]      assert result["pleroma"]["metadata"]["federation"] +    assert result["pleroma"]["metadata"]["fields_limits"]      assert result["pleroma"]["vapid_public_key"]      assert email == from_config_email diff --git a/test/web/mastodon_api/controllers/search_controller_test.exs b/test/web/mastodon_api/controllers/search_controller_test.exs index 826f37fbc..24d1959f8 100644 --- a/test/web/mastodon_api/controllers/search_controller_test.exs +++ b/test/web/mastodon_api/controllers/search_controller_test.exs @@ -79,6 +79,7 @@ defmodule Pleroma.Web.MastodonAPI.SearchControllerTest do        assert status["id"] == to_string(activity.id)      end +    @tag capture_log: true      test "constructs hashtags from search query", %{conn: conn} do        results =          conn @@ -318,11 +319,13 @@ defmodule Pleroma.Web.MastodonAPI.SearchControllerTest do      test "search fetches remote accounts", %{conn: conn} do        user = insert(:user) +      query = URI.encode_query(%{q: "       mike@osada.macgirvin.com          ", resolve: true}) +        results =          conn          |> assign(:user, user)          |> assign(:token, insert(:oauth_token, user: user, scopes: ["read"])) -        |> get("/api/v1/search?q=mike@osada.macgirvin.com&resolve=true") +        |> get("/api/v1/search?#{query}")          |> json_response_and_validate_schema(200)        [account] = results["accounts"] diff --git a/test/web/mastodon_api/controllers/status_controller_test.exs b/test/web/mastodon_api/controllers/status_controller_test.exs index a98e939e8..fd2de8d80 100644 --- a/test/web/mastodon_api/controllers/status_controller_test.exs +++ b/test/web/mastodon_api/controllers/status_controller_test.exs @@ -760,13 +760,18 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do      test "when you created it" do        %{user: author, conn: conn} = oauth_access(["write:statuses"])        activity = insert(:note_activity, user: author) +      object = Object.normalize(activity) -      conn = +      content = object.data["content"] +      source = object.data["source"] + +      result =          conn          |> assign(:user, author)          |> delete("/api/v1/statuses/#{activity.id}") +        |> json_response_and_validate_schema(200) -      assert %{} = json_response_and_validate_schema(conn, 200) +      assert match?(%{"content" => ^content, "text" => ^source}, result)        refute Activity.get_by_id(activity.id)      end @@ -789,7 +794,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do        conn = delete(conn, "/api/v1/statuses/#{activity.id}") -      assert %{"error" => _} = json_response_and_validate_schema(conn, 403) +      assert %{"error" => "Record not found"} == json_response_and_validate_schema(conn, 404)        assert Activity.get_by_id(activity.id) == activity      end diff --git a/test/web/mastodon_api/controllers/timeline_controller_test.exs b/test/web/mastodon_api/controllers/timeline_controller_test.exs index f069390c1..50e0d783d 100644 --- a/test/web/mastodon_api/controllers/timeline_controller_test.exs +++ b/test/web/mastodon_api/controllers/timeline_controller_test.exs @@ -418,4 +418,78 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do        assert [status_none] == json_response_and_validate_schema(all_test, :ok)      end    end + +  describe "hashtag timeline handling of :restrict_unauthenticated setting" do +    setup do +      user = insert(:user) +      {:ok, activity1} = CommonAPI.post(user, %{status: "test #tag1"}) +      {:ok, _activity2} = CommonAPI.post(user, %{status: "test #tag1"}) + +      activity1 +      |> Ecto.Changeset.change(%{local: false}) +      |> Pleroma.Repo.update() + +      base_uri = "/api/v1/timelines/tag/tag1" +      error_response = %{"error" => "authorization required for timeline view"} + +      %{base_uri: base_uri, error_response: error_response} +    end + +    defp ensure_authenticated_access(base_uri) do +      %{conn: auth_conn} = oauth_access(["read:statuses"]) + +      res_conn = get(auth_conn, "#{base_uri}?local=true") +      assert length(json_response(res_conn, 200)) == 1 + +      res_conn = get(auth_conn, "#{base_uri}?local=false") +      assert length(json_response(res_conn, 200)) == 2 +    end + +    test "with `%{local: true, federated: true}`, returns 403 for unauthenticated users", %{ +      conn: conn, +      base_uri: base_uri, +      error_response: error_response +    } do +      clear_config([:restrict_unauthenticated, :timelines, :local], true) +      clear_config([:restrict_unauthenticated, :timelines, :federated], true) + +      for local <- [true, false] do +        res_conn = get(conn, "#{base_uri}?local=#{local}") + +        assert json_response(res_conn, :unauthorized) == error_response +      end + +      ensure_authenticated_access(base_uri) +    end + +    test "with `%{local: false, federated: true}`, forbids unauthenticated access to federated timeline", +         %{conn: conn, base_uri: base_uri, error_response: error_response} do +      clear_config([:restrict_unauthenticated, :timelines, :local], false) +      clear_config([:restrict_unauthenticated, :timelines, :federated], true) + +      res_conn = get(conn, "#{base_uri}?local=true") +      assert length(json_response(res_conn, 200)) == 1 + +      res_conn = get(conn, "#{base_uri}?local=false") +      assert json_response(res_conn, :unauthorized) == error_response + +      ensure_authenticated_access(base_uri) +    end + +    test "with `%{local: true, federated: false}`, forbids unauthenticated access to public timeline" <> +           "(but not to local public activities which are delivered as part of federated timeline)", +         %{conn: conn, base_uri: base_uri, error_response: error_response} do +      clear_config([:restrict_unauthenticated, :timelines, :local], true) +      clear_config([:restrict_unauthenticated, :timelines, :federated], false) + +      res_conn = get(conn, "#{base_uri}?local=true") +      assert json_response(res_conn, :unauthorized) == error_response + +      # Note: local activities get delivered as part of federated timeline +      res_conn = get(conn, "#{base_uri}?local=false") +      assert length(json_response(res_conn, 200)) == 2 + +      ensure_authenticated_access(base_uri) +    end +  end  end diff --git a/test/web/mastodon_api/mastodon_api_test.exs b/test/web/mastodon_api/mastodon_api_test.exs index a7f9c5205..c08be37d4 100644 --- a/test/web/mastodon_api/mastodon_api_test.exs +++ b/test/web/mastodon_api/mastodon_api_test.exs @@ -18,7 +18,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPITest do        follower = insert(:user)        user = insert(:user, local: true, deactivated: true)        {:error, error} = MastodonAPI.follow(follower, user) -      assert error == "Could not follow user: #{user.nickname} is deactivated." +      assert error == :rejected      end      test "following for user" do diff --git a/test/web/mastodon_api/views/account_view_test.exs b/test/web/mastodon_api/views/account_view_test.exs index 80b1f734c..f5bfc9c67 100644 --- a/test/web/mastodon_api/views/account_view_test.exs +++ b/test/web/mastodon_api/views/account_view_test.exs @@ -5,6 +5,7 @@  defmodule Pleroma.Web.MastodonAPI.AccountViewTest do    use Pleroma.DataCase +  alias Pleroma.Config    alias Pleroma.User    alias Pleroma.UserRelationship    alias Pleroma.Web.CommonAPI @@ -18,6 +19,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do      :ok    end +  setup do: clear_config([:instances_favicons, :enabled]) +    test "Represent a user account" do      background_image = %{        "url" => [%{"href" => "https://example.com/images/asuka_hospital.png"}] @@ -75,6 +78,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do        pleroma: %{          ap_id: user.ap_id,          background_image: "https://example.com/images/asuka_hospital.png", +        favicon: +          "https://shitposter.club/plugins/Qvitter/img/gnusocial-favicons/favicon-16x16.png",          confirmation_pending: false,          tags: [],          is_admin: false, @@ -92,6 +97,23 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do      assert expected == AccountView.render("show.json", %{user: user})    end +  test "Favicon is nil when :instances_favicons is disabled" do +    user = insert(:user) + +    Config.put([:instances_favicons, :enabled], true) + +    assert %{ +             pleroma: %{ +               favicon: +                 "https://shitposter.club/plugins/Qvitter/img/gnusocial-favicons/favicon-16x16.png" +             } +           } = AccountView.render("show.json", %{user: user}) + +    Config.put([:instances_favicons, :enabled], false) + +    assert %{pleroma: %{favicon: nil}} = AccountView.render("show.json", %{user: user}) +  end +    test "Represent the user account for the account owner" do      user = insert(:user) @@ -152,6 +174,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do        pleroma: %{          ap_id: user.ap_id,          background_image: nil, +        favicon: +          "https://shitposter.club/plugins/Qvitter/img/gnusocial-favicons/favicon-16x16.png",          confirmation_pending: false,          tags: [],          is_admin: false, @@ -372,6 +396,9 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do        user = insert(:user, hide_followers: true, hide_follows: true)        other_user = insert(:user)        {:ok, user, other_user, _activity} = CommonAPI.follow(user, other_user) + +      assert User.following?(user, other_user) +      assert Pleroma.FollowingRelationship.follower_count(other_user) == 1        {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user)        assert %{ diff --git a/test/web/mastodon_api/views/status_view_test.exs b/test/web/mastodon_api/views/status_view_test.exs index 5cbadf0fc..fa26b3129 100644 --- a/test/web/mastodon_api/views/status_view_test.exs +++ b/test/web/mastodon_api/views/status_view_test.exs @@ -183,6 +183,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do        card: nil,        reblog: nil,        content: HTML.filter_tags(object_data["content"]), +      text: nil,        created_at: created_at,        reblogs_count: 0,        replies_count: 0, @@ -226,7 +227,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do          expires_at: nil,          direct_conversation_id: nil,          thread_muted: false, -        emoji_reactions: [] +        emoji_reactions: [], +        parent_visible: false        }      } @@ -620,4 +622,20 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do      assert status.visibility == "list"    end + +  test "has a field for parent visibility" do +    user = insert(:user) +    poster = insert(:user) + +    {:ok, invisible} = CommonAPI.post(poster, %{status: "hey", visibility: "private"}) + +    {:ok, visible} = +      CommonAPI.post(poster, %{status: "hey", visibility: "private", in_reply_to_id: invisible.id}) + +    status = StatusView.render("show.json", activity: visible, for: user) +    refute status.pleroma.parent_visible + +    status = StatusView.render("show.json", activity: visible, for: poster) +    assert status.pleroma.parent_visible +  end  end diff --git a/test/web/pleroma_api/controllers/account_controller_test.exs b/test/web/pleroma_api/controllers/account_controller_test.exs index 103997c31..07909d48b 100644 --- a/test/web/pleroma_api/controllers/account_controller_test.exs +++ b/test/web/pleroma_api/controllers/account_controller_test.exs @@ -13,8 +13,6 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do    import Pleroma.Factory    import Swoosh.TestAssertions -  @image "data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7" -    describe "POST /api/v1/pleroma/accounts/confirmation_resend" do      setup do        {:ok, user} = @@ -68,103 +66,6 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do      end    end -  describe "PATCH /api/v1/pleroma/accounts/update_avatar" do -    setup do: oauth_access(["write:accounts"]) - -    test "user avatar can be set", %{user: user, conn: conn} do -      avatar_image = File.read!("test/fixtures/avatar_data_uri") - -      conn = -        conn -        |> put_req_header("content-type", "multipart/form-data") -        |> patch("/api/v1/pleroma/accounts/update_avatar", %{img: avatar_image}) - -      user = refresh_record(user) - -      assert %{ -               "name" => _, -               "type" => _, -               "url" => [ -                 %{ -                   "href" => _, -                   "mediaType" => _, -                   "type" => _ -                 } -               ] -             } = user.avatar - -      assert %{"url" => _} = json_response_and_validate_schema(conn, 200) -    end - -    test "user avatar can be reset", %{user: user, conn: conn} do -      conn = -        conn -        |> put_req_header("content-type", "multipart/form-data") -        |> patch("/api/v1/pleroma/accounts/update_avatar", %{img: ""}) - -      user = User.get_cached_by_id(user.id) - -      assert user.avatar == nil - -      assert %{"url" => nil} = json_response_and_validate_schema(conn, 200) -    end -  end - -  describe "PATCH /api/v1/pleroma/accounts/update_banner" do -    setup do: oauth_access(["write:accounts"]) - -    test "can set profile banner", %{user: user, conn: conn} do -      conn = -        conn -        |> put_req_header("content-type", "multipart/form-data") -        |> patch("/api/v1/pleroma/accounts/update_banner", %{"banner" => @image}) - -      user = refresh_record(user) -      assert user.banner["type"] == "Image" - -      assert %{"url" => _} = json_response_and_validate_schema(conn, 200) -    end - -    test "can reset profile banner", %{user: user, conn: conn} do -      conn = -        conn -        |> put_req_header("content-type", "multipart/form-data") -        |> patch("/api/v1/pleroma/accounts/update_banner", %{"banner" => ""}) - -      user = refresh_record(user) -      assert user.banner == %{} - -      assert %{"url" => nil} = json_response_and_validate_schema(conn, 200) -    end -  end - -  describe "PATCH /api/v1/pleroma/accounts/update_background" do -    setup do: oauth_access(["write:accounts"]) - -    test "background image can be set", %{user: user, conn: conn} do -      conn = -        conn -        |> put_req_header("content-type", "multipart/form-data") -        |> patch("/api/v1/pleroma/accounts/update_background", %{"img" => @image}) - -      user = refresh_record(user) -      assert user.background["type"] == "Image" -      # assert %{"url" => _} = json_response(conn, 200) -      assert %{"url" => _} = json_response_and_validate_schema(conn, 200) -    end - -    test "background image can be reset", %{user: user, conn: conn} do -      conn = -        conn -        |> put_req_header("content-type", "multipart/form-data") -        |> patch("/api/v1/pleroma/accounts/update_background", %{"img" => ""}) - -      user = refresh_record(user) -      assert user.background == %{} -      assert %{"url" => nil} = json_response_and_validate_schema(conn, 200) -    end -  end -    describe "getting favorites timeline of specified user" do      setup do        [current_user, user] = insert_pair(:user, hide_favorites: false) diff --git a/test/web/preload/instance_test.exs b/test/web/preload/instance_test.exs index 42a0d87bc..a46f28312 100644 --- a/test/web/preload/instance_test.exs +++ b/test/web/preload/instance_test.exs @@ -8,7 +8,7 @@ defmodule Pleroma.Web.Preload.Providers.InstanceTest do    setup do: {:ok, Instance.generate_terms(nil)} -  test "it renders the info", %{"/api/v1/instance": info} do +  test "it renders the info", %{"/api/v1/instance" => info} do      assert %{               description: description,               email: "admin@example.com", @@ -18,14 +18,25 @@ defmodule Pleroma.Web.Preload.Providers.InstanceTest do      assert String.equivalent?(description, "Pleroma: An efficient and flexible fediverse server")    end -  test "it renders the panel", %{"/instance/panel.html": panel} do +  test "it renders the panel", %{"/instance/panel.html" => panel} do      assert String.contains?(               panel,               "<p>Welcome to <a href=\"https://pleroma.social\" target=\"_blank\">Pleroma!</a></p>"             )    end -  test "it renders the node_info", %{"/nodeinfo/2.0": nodeinfo} do +  test "it works with overrides" do +    clear_config([:instance, :static_dir], "test/fixtures/preload_static") + +    %{"/instance/panel.html" => panel} = Instance.generate_terms(nil) + +    assert String.contains?( +             panel, +             "HEY!" +           ) +  end + +  test "it renders the node_info", %{"/nodeinfo/2.0.json" => nodeinfo} do      %{        metadata: metadata,        version: "2.0" diff --git a/test/web/preload/status_net_test.exs b/test/web/preload/status_net_test.exs deleted file mode 100644 index ab6823a7e..000000000 --- a/test/web/preload/status_net_test.exs +++ /dev/null @@ -1,14 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.Preload.Providers.StatusNetTest do -  use Pleroma.DataCase -  alias Pleroma.Web.Preload.Providers.StatusNet - -  setup do: {:ok, StatusNet.generate_terms(nil)} - -  test "it renders the info", %{"/api/statusnet/config.json": info} do -    assert info =~ "<name>Pleroma</name>" -  end -end diff --git a/test/web/preload/timeline_test.exs b/test/web/preload/timeline_test.exs index da6a3aded..fea95a6a4 100644 --- a/test/web/preload/timeline_test.exs +++ b/test/web/preload/timeline_test.exs @@ -9,7 +9,7 @@ defmodule Pleroma.Web.Preload.Providers.TimelineTest do    alias Pleroma.Web.CommonAPI    alias Pleroma.Web.Preload.Providers.Timelines -  @public_url :"/api/v1/timelines/public" +  @public_url "/api/v1/timelines/public"    describe "unauthenticated timeliness when restricted" do      setup do diff --git a/test/web/preload/user_test.exs b/test/web/preload/user_test.exs index 99232cdfa..83f065e27 100644 --- a/test/web/preload/user_test.exs +++ b/test/web/preload/user_test.exs @@ -9,13 +9,11 @@ defmodule Pleroma.Web.Preload.Providers.UserTest do    describe "returns empty when user doesn't exist" do      test "nil user specified" do -      refute User.generate_terms(%{user: nil}) -             |> Map.has_key?("/api/v1/accounts") +      assert User.generate_terms(%{user: nil}) == %{}      end      test "missing user specified" do -      refute User.generate_terms(%{user: :not_a_user}) -             |> Map.has_key?("/api/v1/accounts") +      assert User.generate_terms(%{user: :not_a_user}) == %{}      end    end @@ -23,11 +21,13 @@ defmodule Pleroma.Web.Preload.Providers.UserTest do      setup do        user = insert(:user) -      {:ok, User.generate_terms(%{user: user})} +      terms = User.generate_terms(%{user: user}) +      %{terms: terms, user: user}      end -    test "account is rendered", %{"/api/v1/accounts": accounts} do -      assert %{acct: user, username: user} = accounts +    test "account is rendered", %{terms: terms, user: user} do +      account = terms["/api/v1/accounts/#{user.id}"] +      assert %{acct: user, username: user} = account      end    end  end diff --git a/test/web/static_fe/static_fe_controller_test.exs b/test/web/static_fe/static_fe_controller_test.exs index a49ab002f..1598bf675 100644 --- a/test/web/static_fe/static_fe_controller_test.exs +++ b/test/web/static_fe/static_fe_controller_test.exs @@ -87,6 +87,20 @@ defmodule Pleroma.Web.StaticFE.StaticFEControllerTest do        assert html =~ "testing a thing!"      end +    test "redirects to json if requested", %{conn: conn, user: user} do +      {:ok, activity} = CommonAPI.post(user, %{status: "testing a thing!"}) + +      conn = +        conn +        |> put_req_header( +          "accept", +          "Accept: application/activity+json, application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\", text/html" +        ) +        |> get("/notice/#{activity.id}") + +      assert redirected_to(conn, 302) =~ activity.data["object"] +    end +      test "filters HTML tags", %{conn: conn} do        user = insert(:user)        {:ok, activity} = CommonAPI.post(user, %{status: "<script>alert('xss')</script>"}) diff --git a/test/web/streamer/streamer_test.exs b/test/web/streamer/streamer_test.exs index 245f6e63f..d56d74464 100644 --- a/test/web/streamer/streamer_test.exs +++ b/test/web/streamer/streamer_test.exs @@ -116,6 +116,35 @@ defmodule Pleroma.Web.StreamerTest do        refute Streamer.filtered_by_user?(user, announce)      end +    test "it does not stream announces of the user's own posts in the 'user' stream", %{ +      user: user +    } do +      Streamer.get_topic_and_add_socket("user", user) + +      other_user = insert(:user) +      {:ok, activity} = CommonAPI.post(user, %{status: "hey"}) +      {:ok, announce} = CommonAPI.repeat(activity.id, other_user) + +      assert Streamer.filtered_by_user?(user, announce) +    end + +    test "it does stream notifications announces of the user's own posts in the 'user' stream", %{ +      user: user +    } do +      Streamer.get_topic_and_add_socket("user", user) + +      other_user = insert(:user) +      {:ok, activity} = CommonAPI.post(user, %{status: "hey"}) +      {:ok, announce} = CommonAPI.repeat(activity.id, other_user) + +      notification = +        Pleroma.Notification +        |> Repo.get_by(%{user_id: user.id, activity_id: announce.id}) +        |> Repo.preload(:activity) + +      refute Streamer.filtered_by_user?(user, notification) +    end +      test "it streams boosts of mastodon user in the 'user' stream", %{user: user} do        Streamer.get_topic_and_add_socket("user", user) diff --git a/test/web/twitter_api/util_controller_test.exs b/test/web/twitter_api/util_controller_test.exs index ad919d341..76e9369f7 100644 --- a/test/web/twitter_api/util_controller_test.exs +++ b/test/web/twitter_api/util_controller_test.exs @@ -224,105 +224,6 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do      end    end -  describe "GET /api/statusnet/config" do -    test "it returns config in xml format", %{conn: conn} do -      instance = Config.get(:instance) - -      response = -        conn -        |> put_req_header("accept", "application/xml") -        |> get("/api/statusnet/config") -        |> response(:ok) - -      assert response == -               "<config>\n<site>\n<name>#{Keyword.get(instance, :name)}</name>\n<site>#{ -                 Pleroma.Web.base_url() -               }</site>\n<textlimit>#{Keyword.get(instance, :limit)}</textlimit>\n<closed>#{ -                 !Keyword.get(instance, :registrations_open) -               }</closed>\n</site>\n</config>\n" -    end - -    test "it returns config in json format", %{conn: conn} do -      instance = Config.get(:instance) -      Config.put([:instance, :managed_config], true) -      Config.put([:instance, :registrations_open], false) -      Config.put([:instance, :invites_enabled], true) -      Config.put([:instance, :public], false) -      Config.put([:frontend_configurations, :pleroma_fe], %{theme: "asuka-hospital"}) - -      response = -        conn -        |> put_req_header("accept", "application/json") -        |> get("/api/statusnet/config") -        |> json_response(:ok) - -      expected_data = %{ -        "site" => %{ -          "accountActivationRequired" => "0", -          "closed" => "1", -          "description" => Keyword.get(instance, :description), -          "invitesEnabled" => "1", -          "name" => Keyword.get(instance, :name), -          "pleromafe" => %{"theme" => "asuka-hospital"}, -          "private" => "1", -          "safeDMMentionsEnabled" => "0", -          "server" => Pleroma.Web.base_url(), -          "textlimit" => to_string(Keyword.get(instance, :limit)), -          "uploadlimit" => %{ -            "avatarlimit" => to_string(Keyword.get(instance, :avatar_upload_limit)), -            "backgroundlimit" => to_string(Keyword.get(instance, :background_upload_limit)), -            "bannerlimit" => to_string(Keyword.get(instance, :banner_upload_limit)), -            "uploadlimit" => to_string(Keyword.get(instance, :upload_limit)) -          }, -          "vapidPublicKey" => Keyword.get(Pleroma.Web.Push.vapid_config(), :public_key) -        } -      } - -      assert response == expected_data -    end - -    test "returns the state of safe_dm_mentions flag", %{conn: conn} do -      Config.put([:instance, :safe_dm_mentions], true) - -      response = -        conn -        |> get("/api/statusnet/config.json") -        |> json_response(:ok) - -      assert response["site"]["safeDMMentionsEnabled"] == "1" - -      Config.put([:instance, :safe_dm_mentions], false) - -      response = -        conn -        |> get("/api/statusnet/config.json") -        |> json_response(:ok) - -      assert response["site"]["safeDMMentionsEnabled"] == "0" -    end - -    test "it returns the managed config", %{conn: conn} do -      Config.put([:instance, :managed_config], false) -      Config.put([:frontend_configurations, :pleroma_fe], %{theme: "asuka-hospital"}) - -      response = -        conn -        |> get("/api/statusnet/config.json") -        |> json_response(:ok) - -      refute response["site"]["pleromafe"] - -      Config.put([:instance, :managed_config], true) - -      response = -        conn -        |> get("/api/statusnet/config.json") -        |> json_response(:ok) - -      assert response["site"]["pleromafe"] == %{"theme" => "asuka-hospital"} -    end -  end -    describe "GET /api/pleroma/frontend_configurations" do      test "returns everything in :pleroma, :frontend_configurations", %{conn: conn} do        config = [ @@ -451,28 +352,6 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do      end    end -  describe "GET /api/statusnet/version" do -    test "it returns version in xml format", %{conn: conn} do -      response = -        conn -        |> put_req_header("accept", "application/xml") -        |> get("/api/statusnet/version") -        |> response(:ok) - -      assert response == "<version>#{Pleroma.Application.named_version()}</version>" -    end - -    test "it returns version in json format", %{conn: conn} do -      response = -        conn -        |> put_req_header("accept", "application/json") -        |> get("/api/statusnet/version") -        |> json_response(:ok) - -      assert response == "#{Pleroma.Application.named_version()}" -    end -  end -    describe "POST /main/ostatus - remote_subscribe/2" do      setup do: clear_config([:instance, :federating], true) | 
