diff options
Diffstat (limited to 'test/web/activity_pub')
25 files changed, 2026 insertions, 781 deletions
| diff --git a/test/web/activity_pub/activity_pub_controller_test.exs b/test/web/activity_pub/activity_pub_controller_test.exs index c432c90e3..e722f7c04 100644 --- a/test/web/activity_pub/activity_pub_controller_test.exs +++ b/test/web/activity_pub/activity_pub_controller_test.exs @@ -6,7 +6,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do    use Pleroma.Web.ConnCase    use Oban.Testing, repo: Pleroma.Repo -  import Pleroma.Factory    alias Pleroma.Activity    alias Pleroma.Config    alias Pleroma.Delivery @@ -14,13 +13,19 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do    alias Pleroma.Object    alias Pleroma.Tests.ObanHelpers    alias Pleroma.User +  alias Pleroma.Web.ActivityPub.ActivityPub    alias Pleroma.Web.ActivityPub.ObjectView    alias Pleroma.Web.ActivityPub.Relay    alias Pleroma.Web.ActivityPub.UserView    alias Pleroma.Web.ActivityPub.Utils    alias Pleroma.Web.CommonAPI +  alias Pleroma.Web.Endpoint    alias Pleroma.Workers.ReceiverWorker +  import Pleroma.Factory + +  require Pleroma.Constants +    setup_all do      Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)      :ok @@ -168,6 +173,60 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do      end    end +  describe "mastodon compatibility routes" do +    test "it returns a json representation of the object with accept application/json", %{ +      conn: conn +    } do +      {:ok, object} = +        %{ +          "type" => "Note", +          "content" => "hey", +          "id" => Endpoint.url() <> "/users/raymoo/statuses/999999999", +          "actor" => Endpoint.url() <> "/users/raymoo", +          "to" => [Pleroma.Constants.as_public()] +        } +        |> Object.create() + +      conn = +        conn +        |> put_req_header("accept", "application/json") +        |> get("/users/raymoo/statuses/999999999") + +      assert json_response(conn, 200) == ObjectView.render("object.json", %{object: object}) +    end + +    test "it returns a json representation of the activity with accept application/json", %{ +      conn: conn +    } do +      {:ok, object} = +        %{ +          "type" => "Note", +          "content" => "hey", +          "id" => Endpoint.url() <> "/users/raymoo/statuses/999999999", +          "actor" => Endpoint.url() <> "/users/raymoo", +          "to" => [Pleroma.Constants.as_public()] +        } +        |> Object.create() + +      {:ok, activity, _} = +        %{ +          "id" => object.data["id"] <> "/activity", +          "type" => "Create", +          "object" => object.data["id"], +          "actor" => object.data["actor"], +          "to" => object.data["to"] +        } +        |> ActivityPub.persist(local: true) + +      conn = +        conn +        |> put_req_header("accept", "application/json") +        |> get("/users/raymoo/statuses/999999999/activity") + +      assert json_response(conn, 200) == ObjectView.render("object.json", %{object: activity}) +    end +  end +    describe "/objects/:uuid" do      test "it returns a json representation of the object with accept application/json", %{        conn: conn @@ -392,6 +451,36 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do        assert Activity.get_by_ap_id(data["id"])      end +    @tag capture_log: true +    test "it inserts an incoming activity into the database" <> +           "even if we can't fetch the user but have it in our db", +         %{conn: conn} do +      user = +        insert(:user, +          ap_id: "https://mastodon.example.org/users/raymoo", +          ap_enabled: true, +          local: false, +          last_refreshed_at: nil +        ) + +      data = +        File.read!("test/fixtures/mastodon-post-activity.json") +        |> Poison.decode!() +        |> Map.put("actor", user.ap_id) +        |> put_in(["object", "attridbutedTo"], user.ap_id) + +      conn = +        conn +        |> assign(:valid_signature, true) +        |> put_req_header("content-type", "application/activity+json") +        |> post("/inbox", data) + +      assert "ok" == json_response(conn, 200) + +      ObanHelpers.perform(all_enqueued(worker: ReceiverWorker)) +      assert Activity.get_by_ap_id(data["id"]) +    end +      test "it clears `unreachable` federation status of the sender", %{conn: conn} do        data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!() @@ -447,6 +536,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do        assert_receive {:mix_shell, :info, ["relay.mastodon.host"]}      end +    @tag capture_log: true      test "without valid signature, " <>             "it only accepts Create activities and requires enabled federation",           %{conn: conn} do @@ -559,11 +649,14 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do      test "it accepts announces with to as string instead of array", %{conn: conn} do        user = insert(:user) +      {:ok, post} = CommonAPI.post(user, %{status: "hey"}) +      announcer = insert(:user, local: false) +        data = %{          "@context" => "https://www.w3.org/ns/activitystreams", -        "actor" => "http://mastodon.example.org/users/admin", -        "id" => "http://mastodon.example.org/users/admin/statuses/19512778738411822/activity", -        "object" => "https://mastodon.social/users/emelie/statuses/101849165031453009", +        "actor" => announcer.ap_id, +        "id" => "#{announcer.ap_id}/statuses/19512778738411822/activity", +        "object" => post.data["object"],          "to" => "https://www.w3.org/ns/activitystreams#Public",          "cc" => [user.ap_id],          "type" => "Announce" @@ -715,17 +808,63 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do    end    describe "GET /users/:nickname/outbox" do +    test "it paginates correctly", %{conn: conn} do +      user = insert(:user) +      conn = assign(conn, :user, user) +      outbox_endpoint = user.ap_id <> "/outbox" + +      _posts = +        for i <- 0..25 do +          {:ok, activity} = CommonAPI.post(user, %{status: "post #{i}"}) +          activity +        end + +      result = +        conn +        |> put_req_header("accept", "application/activity+json") +        |> get(outbox_endpoint <> "?page=true") +        |> json_response(200) + +      result_ids = Enum.map(result["orderedItems"], fn x -> x["id"] end) +      assert length(result["orderedItems"]) == 20 +      assert length(result_ids) == 20 +      assert result["next"] +      assert String.starts_with?(result["next"], outbox_endpoint) + +      result_next = +        conn +        |> put_req_header("accept", "application/activity+json") +        |> get(result["next"]) +        |> json_response(200) + +      result_next_ids = Enum.map(result_next["orderedItems"], fn x -> x["id"] end) +      assert length(result_next["orderedItems"]) == 6 +      assert length(result_next_ids) == 6 +      refute Enum.find(result_next_ids, fn x -> x in result_ids end) +      refute Enum.find(result_ids, fn x -> x in result_next_ids end) +      assert String.starts_with?(result["id"], outbox_endpoint) + +      result_next_again = +        conn +        |> put_req_header("accept", "application/activity+json") +        |> get(result_next["id"]) +        |> json_response(200) + +      assert result_next == result_next_again +    end +      test "it returns 200 even if there're no activities", %{conn: conn} do        user = insert(:user) +      outbox_endpoint = user.ap_id <> "/outbox"        conn =          conn          |> assign(:user, user)          |> put_req_header("accept", "application/activity+json") -        |> get("/users/#{user.nickname}/outbox") +        |> get(outbox_endpoint)        result = json_response(conn, 200) -      assert user.ap_id <> "/outbox" == result["id"] +      assert outbox_endpoint == result["id"]      end      test "it returns a note activity in a collection", %{conn: conn} do diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs index 77bd07edf..575e0c5db 100644 --- a/test/web/activity_pub/activity_pub_test.exs +++ b/test/web/activity_pub/activity_pub_test.exs @@ -82,30 +82,28 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        {:ok, private_activity} = CommonAPI.post(user, %{status: ".", visibility: "private"}) -      activities = -        ActivityPub.fetch_activities([], %{:visibility => "direct", "actor_id" => user.ap_id}) +      activities = ActivityPub.fetch_activities([], %{visibility: "direct", actor_id: user.ap_id})        assert activities == [direct_activity]        activities = -        ActivityPub.fetch_activities([], %{:visibility => "unlisted", "actor_id" => user.ap_id}) +        ActivityPub.fetch_activities([], %{visibility: "unlisted", actor_id: user.ap_id})        assert activities == [unlisted_activity]        activities = -        ActivityPub.fetch_activities([], %{:visibility => "private", "actor_id" => user.ap_id}) +        ActivityPub.fetch_activities([], %{visibility: "private", actor_id: user.ap_id})        assert activities == [private_activity] -      activities = -        ActivityPub.fetch_activities([], %{:visibility => "public", "actor_id" => user.ap_id}) +      activities = ActivityPub.fetch_activities([], %{visibility: "public", actor_id: user.ap_id})        assert activities == [public_activity]        activities =          ActivityPub.fetch_activities([], %{ -          :visibility => ~w[private public], -          "actor_id" => user.ap_id +          visibility: ~w[private public], +          actor_id: user.ap_id          })        assert activities == [public_activity, private_activity] @@ -126,8 +124,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        activities =          ActivityPub.fetch_activities([], %{ -          "exclude_visibilities" => "direct", -          "actor_id" => user.ap_id +          exclude_visibilities: "direct", +          actor_id: user.ap_id          })        assert public_activity in activities @@ -137,8 +135,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        activities =          ActivityPub.fetch_activities([], %{ -          "exclude_visibilities" => "unlisted", -          "actor_id" => user.ap_id +          exclude_visibilities: "unlisted", +          actor_id: user.ap_id          })        assert public_activity in activities @@ -148,8 +146,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        activities =          ActivityPub.fetch_activities([], %{ -          "exclude_visibilities" => "private", -          "actor_id" => user.ap_id +          exclude_visibilities: "private", +          actor_id: user.ap_id          })        assert public_activity in activities @@ -159,8 +157,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        activities =          ActivityPub.fetch_activities([], %{ -          "exclude_visibilities" => "public", -          "actor_id" => user.ap_id +          exclude_visibilities: "public", +          actor_id: user.ap_id          })        refute public_activity in activities @@ -193,23 +191,22 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        {:ok, status_two} = CommonAPI.post(user, %{status: ". #essais"})        {:ok, status_three} = CommonAPI.post(user, %{status: ". #test #reject"}) -      fetch_one = ActivityPub.fetch_activities([], %{"type" => "Create", "tag" => "test"}) +      fetch_one = ActivityPub.fetch_activities([], %{type: "Create", tag: "test"}) -      fetch_two = -        ActivityPub.fetch_activities([], %{"type" => "Create", "tag" => ["test", "essais"]}) +      fetch_two = ActivityPub.fetch_activities([], %{type: "Create", tag: ["test", "essais"]})        fetch_three =          ActivityPub.fetch_activities([], %{ -          "type" => "Create", -          "tag" => ["test", "essais"], -          "tag_reject" => ["reject"] +          type: "Create", +          tag: ["test", "essais"], +          tag_reject: ["reject"]          })        fetch_four =          ActivityPub.fetch_activities([], %{ -          "type" => "Create", -          "tag" => ["test"], -          "tag_all" => ["test", "reject"] +          type: "Create", +          tag: ["test"], +          tag_all: ["test", "reject"]          })        assert fetch_one == [status_one, status_three] @@ -375,7 +372,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        _listen_activity_2 = insert(:listen)        _listen_activity_3 = insert(:listen) -      timeline = ActivityPub.fetch_activities([], %{"type" => ["Listen"]}) +      timeline = ActivityPub.fetch_activities([], %{type: ["Listen"]})        assert length(timeline) == 3      end @@ -507,7 +504,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        {:ok, _user_relationship} = User.block(user, %{ap_id: activity_five.data["actor"]}) -      activities = ActivityPub.fetch_activities_for_context("2hu", %{"blocking_user" => user}) +      activities = ActivityPub.fetch_activities_for_context("2hu", %{blocking_user: user})        assert activities == [activity_two, activity]      end    end @@ -520,8 +517,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      booster = insert(:user)      {:ok, _user_relationship} = User.block(user, %{ap_id: activity_one.data["actor"]}) -    activities = -      ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true}) +    activities = ActivityPub.fetch_activities([], %{blocking_user: user, skip_preload: true})      assert Enum.member?(activities, activity_two)      assert Enum.member?(activities, activity_three) @@ -529,28 +525,25 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      {:ok, _user_block} = User.unblock(user, %{ap_id: activity_one.data["actor"]}) -    activities = -      ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true}) +    activities = ActivityPub.fetch_activities([], %{blocking_user: user, skip_preload: true})      assert Enum.member?(activities, activity_two)      assert Enum.member?(activities, activity_three)      assert Enum.member?(activities, activity_one)      {:ok, _user_relationship} = User.block(user, %{ap_id: activity_three.data["actor"]}) -    {:ok, _announce, %{data: %{"id" => id}}} = CommonAPI.repeat(activity_three.id, booster) +    {:ok, %{data: %{"object" => id}}} = CommonAPI.repeat(activity_three.id, booster)      %Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id)      activity_three = Activity.get_by_id(activity_three.id) -    activities = -      ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true}) +    activities = ActivityPub.fetch_activities([], %{blocking_user: user, skip_preload: true})      assert Enum.member?(activities, activity_two)      refute Enum.member?(activities, activity_three)      refute Enum.member?(activities, boost_activity)      assert Enum.member?(activities, activity_one) -    activities = -      ActivityPub.fetch_activities([], %{"blocking_user" => nil, "skip_preload" => true}) +    activities = ActivityPub.fetch_activities([], %{blocking_user: nil, skip_preload: true})      assert Enum.member?(activities, activity_two)      assert Enum.member?(activities, activity_three) @@ -573,7 +566,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      {:ok, activity_four} = CommonAPI.post(blockee, %{status: "hey! @#{blocker.nickname}"}) -    activities = ActivityPub.fetch_activities([], %{"blocking_user" => blocker}) +    activities = ActivityPub.fetch_activities([], %{blocking_user: blocker})      assert Enum.member?(activities, activity_one)      refute Enum.member?(activities, activity_two) @@ -581,7 +574,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      refute Enum.member?(activities, activity_four)    end -  test "doesn't return announce activities concerning blocked users" do +  test "doesn't return announce activities with blocked users in 'to'" do      blocker = insert(:user)      blockee = insert(:user)      friend = insert(:user) @@ -592,10 +585,43 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      {:ok, activity_two} = CommonAPI.post(blockee, %{status: "hey! @#{friend.nickname}"}) -    {:ok, activity_three, _} = CommonAPI.repeat(activity_two.id, friend) +    {:ok, activity_three} = CommonAPI.repeat(activity_two.id, friend)      activities = -      ActivityPub.fetch_activities([], %{"blocking_user" => blocker}) +      ActivityPub.fetch_activities([], %{blocking_user: blocker}) +      |> Enum.map(fn act -> act.id end) + +    assert Enum.member?(activities, activity_one.id) +    refute Enum.member?(activities, activity_two.id) +    refute Enum.member?(activities, activity_three.id) +  end + +  test "doesn't return announce activities with blocked users in 'cc'" do +    blocker = insert(:user) +    blockee = insert(:user) +    friend = insert(:user) + +    {:ok, _user_relationship} = User.block(blocker, blockee) + +    {:ok, activity_one} = CommonAPI.post(friend, %{status: "hey!"}) + +    {:ok, activity_two} = CommonAPI.post(blockee, %{status: "hey! @#{friend.nickname}"}) + +    assert object = Pleroma.Object.normalize(activity_two) + +    data = %{ +      "actor" => friend.ap_id, +      "object" => object.data["id"], +      "context" => object.data["context"], +      "type" => "Announce", +      "to" => ["https://www.w3.org/ns/activitystreams#Public"], +      "cc" => [blockee.ap_id] +    } + +    assert {:ok, activity_three} = ActivityPub.insert(data) + +    activities = +      ActivityPub.fetch_activities([], %{blocking_user: blocker})        |> Enum.map(fn act -> act.id end)      assert Enum.member?(activities, activity_one.id) @@ -611,17 +637,15 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      user = insert(:user)      {:ok, user} = User.block_domain(user, domain) -    activities = -      ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true}) +    activities = ActivityPub.fetch_activities([], %{blocking_user: user, skip_preload: true})      refute activity in activities      followed_user = insert(:user)      ActivityPub.follow(user, followed_user) -    {:ok, repeat_activity, _} = CommonAPI.repeat(activity.id, followed_user) +    {:ok, repeat_activity} = CommonAPI.repeat(activity.id, followed_user) -    activities = -      ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true}) +    activities = ActivityPub.fetch_activities([], %{blocking_user: user, skip_preload: true})      refute repeat_activity in activities    end @@ -641,8 +665,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      note = insert(:note, %{data: %{"actor" => domain_user.ap_id}})      activity = insert(:note_activity, %{note: note}) -    activities = -      ActivityPub.fetch_activities([], %{"blocking_user" => blocker, "skip_preload" => true}) +    activities = ActivityPub.fetch_activities([], %{blocking_user: blocker, skip_preload: true})      assert activity in activities @@ -651,10 +674,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      another_user = insert(:user, %{ap_id: "https://#{domain}/@meanie2"})      bad_note = insert(:note, %{data: %{"actor" => another_user.ap_id}})      bad_activity = insert(:note_activity, %{note: bad_note}) -    {:ok, repeat_activity, _} = CommonAPI.repeat(bad_activity.id, domain_user) +    {:ok, repeat_activity} = CommonAPI.repeat(bad_activity.id, domain_user) -    activities = -      ActivityPub.fetch_activities([], %{"blocking_user" => blocker, "skip_preload" => true}) +    activities = ActivityPub.fetch_activities([], %{blocking_user: blocker, skip_preload: true})      refute repeat_activity in activities    end @@ -669,8 +691,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      activity_one_actor = User.get_by_ap_id(activity_one.data["actor"])      {:ok, _user_relationships} = User.mute(user, activity_one_actor) -    activities = -      ActivityPub.fetch_activities([], %{"muting_user" => user, "skip_preload" => true}) +    activities = ActivityPub.fetch_activities([], %{muting_user: user, skip_preload: true})      assert Enum.member?(activities, activity_two)      assert Enum.member?(activities, activity_three) @@ -679,9 +700,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      # Calling with 'with_muted' will deliver muted activities, too.      activities =        ActivityPub.fetch_activities([], %{ -        "muting_user" => user, -        "with_muted" => true, -        "skip_preload" => true +        muting_user: user, +        with_muted: true, +        skip_preload: true        })      assert Enum.member?(activities, activity_two) @@ -690,8 +711,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      {:ok, _user_mute} = User.unmute(user, activity_one_actor) -    activities = -      ActivityPub.fetch_activities([], %{"muting_user" => user, "skip_preload" => true}) +    activities = ActivityPub.fetch_activities([], %{muting_user: user, skip_preload: true})      assert Enum.member?(activities, activity_two)      assert Enum.member?(activities, activity_three) @@ -699,19 +719,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      activity_three_actor = User.get_by_ap_id(activity_three.data["actor"])      {:ok, _user_relationships} = User.mute(user, activity_three_actor) -    {:ok, _announce, %{data: %{"id" => id}}} = CommonAPI.repeat(activity_three.id, booster) +    {:ok, %{data: %{"object" => id}}} = CommonAPI.repeat(activity_three.id, booster)      %Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id)      activity_three = Activity.get_by_id(activity_three.id) -    activities = -      ActivityPub.fetch_activities([], %{"muting_user" => user, "skip_preload" => true}) +    activities = ActivityPub.fetch_activities([], %{muting_user: user, skip_preload: true})      assert Enum.member?(activities, activity_two)      refute Enum.member?(activities, activity_three)      refute Enum.member?(activities, boost_activity)      assert Enum.member?(activities, activity_one) -    activities = ActivityPub.fetch_activities([], %{"muting_user" => nil, "skip_preload" => true}) +    activities = ActivityPub.fetch_activities([], %{muting_user: nil, skip_preload: true})      assert Enum.member?(activities, activity_two)      assert Enum.member?(activities, activity_three) @@ -727,7 +746,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      {:ok, _activity_two} = CommonAPI.add_mute(user, activity_two) -    assert [_activity_one] = ActivityPub.fetch_activities([], %{"muting_user" => user}) +    assert [_activity_one] = ActivityPub.fetch_activities([], %{muting_user: user})    end    test "returns thread muted activities when with_muted is set" do @@ -739,7 +758,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      {:ok, _activity_two} = CommonAPI.add_mute(user, activity_two)      assert [_activity_two, _activity_one] = -             ActivityPub.fetch_activities([], %{"muting_user" => user, "with_muted" => true}) +             ActivityPub.fetch_activities([], %{muting_user: user, with_muted: true})    end    test "does include announces on request" do @@ -749,7 +768,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      {:ok, user} = User.follow(user, booster) -    {:ok, announce, _object} = CommonAPI.repeat(activity_three.id, booster) +    {:ok, announce} = CommonAPI.repeat(activity_three.id, booster)      [announce_activity] = ActivityPub.fetch_activities([user.ap_id | User.following(user)]) @@ -761,7 +780,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      {:ok, expected_activity} = ActivityBuilder.insert(%{"type" => "Create"}, %{:user => user})      {:ok, _} = ActivityBuilder.insert(%{"type" => "Announce"}, %{:user => user}) -    [activity] = ActivityPub.fetch_user_activities(user, nil, %{"exclude_reblogs" => "true"}) +    [activity] = ActivityPub.fetch_user_activities(user, nil, %{exclude_reblogs: true})      assert activity == expected_activity    end @@ -804,7 +823,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        expected_activities = ActivityBuilder.insert_list(10)        since_id = List.last(activities).id -      activities = ActivityPub.fetch_public_activities(%{"since_id" => since_id}) +      activities = ActivityPub.fetch_public_activities(%{since_id: since_id})        assert collect_ids(activities) == collect_ids(expected_activities)        assert length(activities) == 10 @@ -819,7 +838,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do          |> ActivityBuilder.insert_list()          |> List.first() -      activities = ActivityPub.fetch_public_activities(%{"max_id" => max_id}) +      activities = ActivityPub.fetch_public_activities(%{max_id: max_id})        assert length(activities) == 20        assert collect_ids(activities) == collect_ids(expected_activities) @@ -831,8 +850,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        later_activities = ActivityBuilder.insert_list(10) -      activities = -        ActivityPub.fetch_public_activities(%{"page" => "2", "page_size" => "20"}, :offset) +      activities = ActivityPub.fetch_public_activities(%{page: "2", page_size: "20"}, :offset)        assert length(activities) == 20 @@ -846,9 +864,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        booster = insert(:user)        {:ok, _reblog_mute} = CommonAPI.hide_reblogs(user, booster) -      {:ok, activity, _} = CommonAPI.repeat(activity.id, booster) +      {:ok, activity} = CommonAPI.repeat(activity.id, booster) -      activities = ActivityPub.fetch_activities([], %{"muting_user" => user}) +      activities = ActivityPub.fetch_activities([], %{muting_user: user})        refute Enum.any?(activities, fn %{id: id} -> id == activity.id end)      end @@ -860,83 +878,14 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        {:ok, _reblog_mute} = CommonAPI.hide_reblogs(user, booster)        {:ok, _reblog_mute} = CommonAPI.show_reblogs(user, booster) -      {:ok, activity, _} = CommonAPI.repeat(activity.id, booster) +      {:ok, activity} = CommonAPI.repeat(activity.id, booster) -      activities = ActivityPub.fetch_activities([], %{"muting_user" => user}) +      activities = ActivityPub.fetch_activities([], %{muting_user: user})        assert Enum.any?(activities, fn %{id: id} -> id == activity.id end)      end    end -  describe "announcing an object" do -    test "adds an announce activity to the db" do -      note_activity = insert(:note_activity) -      object = Object.normalize(note_activity) -      user = insert(:user) - -      {:ok, announce_activity, object} = ActivityPub.announce(user, object) -      assert object.data["announcement_count"] == 1 -      assert object.data["announcements"] == [user.ap_id] - -      assert announce_activity.data["to"] == [ -               User.ap_followers(user), -               note_activity.data["actor"] -             ] - -      assert announce_activity.data["object"] == object.data["id"] -      assert announce_activity.data["actor"] == user.ap_id -      assert announce_activity.data["context"] == object.data["context"] -    end - -    test "reverts annouce from object on error" do -      note_activity = insert(:note_activity) -      object = Object.normalize(note_activity) -      user = insert(:user) - -      with_mock(Utils, [:passthrough], maybe_federate: fn _ -> {:error, :reverted} end) do -        assert {:error, :reverted} = ActivityPub.announce(user, object) -      end - -      reloaded_object = Object.get_by_ap_id(object.data["id"]) -      assert reloaded_object == object -      refute reloaded_object.data["announcement_count"] -      refute reloaded_object.data["announcements"] -    end -  end - -  describe "announcing a private object" do -    test "adds an announce activity to the db if the audience is not widened" do -      user = insert(:user) -      {:ok, note_activity} = CommonAPI.post(user, %{status: ".", visibility: "private"}) -      object = Object.normalize(note_activity) - -      {:ok, announce_activity, object} = ActivityPub.announce(user, object, nil, true, false) - -      assert announce_activity.data["to"] == [User.ap_followers(user)] - -      assert announce_activity.data["object"] == object.data["id"] -      assert announce_activity.data["actor"] == user.ap_id -      assert announce_activity.data["context"] == object.data["context"] -    end - -    test "does not add an announce activity to the db if the audience is widened" do -      user = insert(:user) -      {:ok, note_activity} = CommonAPI.post(user, %{status: ".", visibility: "private"}) -      object = Object.normalize(note_activity) - -      assert {:error, _} = ActivityPub.announce(user, object, nil, true, true) -    end - -    test "does not add an announce activity to the db if the announcer is not the author" do -      user = insert(:user) -      announcer = insert(:user) -      {:ok, note_activity} = CommonAPI.post(user, %{status: ".", visibility: "private"}) -      object = Object.normalize(note_activity) - -      assert {:error, _} = ActivityPub.announce(announcer, object, nil, true, false) -    end -  end -    describe "uploading files" do      test "copies the file to the configured folder" do        file = %Plug.Upload{ @@ -1043,54 +992,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) @@ -1135,7 +1036,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        assert length(activities) == 3        activities = -        ActivityPub.fetch_activities([user1.ap_id | User.following(user1)], %{"user" => user1}) +        ActivityPub.fetch_activities([user1.ap_id | User.following(user1)], %{user: user1})          |> Enum.map(fn a -> a.id end)        assert [public_activity.id, private_activity_1.id] == activities @@ -1143,52 +1044,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      end    end -  describe "update" do -    setup do: clear_config([:instance, :max_pinned_statuses]) - -    test "it creates an update activity with the new user data" do -      user = insert(:user) -      {:ok, user} = User.ensure_keys_present(user) -      user_data = Pleroma.Web.ActivityPub.UserView.render("user.json", %{user: user}) - -      {:ok, update} = -        ActivityPub.update(%{ -          actor: user_data["id"], -          to: [user.follower_address], -          cc: [], -          object: user_data -        }) - -      assert update.data["actor"] == user.ap_id -      assert update.data["to"] == [user.follower_address] -      assert embedded_object = update.data["object"] -      assert embedded_object["id"] == user_data["id"] -      assert embedded_object["type"] == user_data["type"] -    end -  end - -  test "returned pinned statuses" do -    Config.put([:instance, :max_pinned_statuses], 3) -    user = insert(:user) - -    {:ok, activity_one} = CommonAPI.post(user, %{status: "HI!!!"}) -    {:ok, activity_two} = CommonAPI.post(user, %{status: "HI!!!"}) -    {:ok, activity_three} = CommonAPI.post(user, %{status: "HI!!!"}) - -    CommonAPI.pin(activity_one.id, user) -    user = refresh_record(user) - -    CommonAPI.pin(activity_two.id, user) -    user = refresh_record(user) - -    CommonAPI.pin(activity_three.id, user) -    user = refresh_record(user) - -    activities = ActivityPub.fetch_user_activities(user, nil, %{"pinned" => "true"}) - -    assert 3 = length(activities) -  end -    describe "flag/1" do      setup do        reporter = insert(:user) @@ -1295,7 +1150,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      activity = Repo.preload(activity, :bookmark)      activity = %Activity{activity | thread_muted?: !!activity.thread_muted?} -    assert ActivityPub.fetch_activities([], %{"user" => user}) == [activity] +    assert ActivityPub.fetch_activities([], %{user: user}) == [activity]    end    def data_uri do @@ -1469,7 +1324,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        assert Enum.map(result, & &1.id) == [a1.id, a5.id, a3.id, a4.id] -      result = ActivityPub.fetch_favourites(user, %{"limit" => 2}) +      result = ActivityPub.fetch_favourites(user, %{limit: 2})        assert Enum.map(result, & &1.id) == [a1.id, a5.id]      end    end @@ -1539,7 +1394,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      {:ok, _reply} = CommonAPI.post(user, %{status: "yeah", in_reply_to_status_id: activity.id}) -    [result] = ActivityPub.fetch_public_activities(%{"exclude_replies" => "true"}) +    [result] = ActivityPub.fetch_public_activities(%{exclude_replies: true})      assert result.id == activity.id @@ -1552,11 +1407,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      test "public timeline", %{users: %{u1: user}} do        activities_ids =          %{} -        |> Map.put("type", ["Create", "Announce"]) -        |> Map.put("local_only", false) -        |> Map.put("blocking_user", user) -        |> Map.put("muting_user", user) -        |> Map.put("reply_filtering_user", user) +        |> Map.put(:type, ["Create", "Announce"]) +        |> Map.put(:local_only, false) +        |> Map.put(:blocking_user, user) +        |> Map.put(:muting_user, user) +        |> Map.put(:reply_filtering_user, user)          |> ActivityPub.fetch_public_activities()          |> Enum.map(& &1.id) @@ -1573,12 +1428,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      } do        activities_ids =          %{} -        |> Map.put("type", ["Create", "Announce"]) -        |> Map.put("local_only", false) -        |> Map.put("blocking_user", user) -        |> Map.put("muting_user", user) -        |> Map.put("reply_visibility", "following") -        |> Map.put("reply_filtering_user", user) +        |> Map.put(:type, ["Create", "Announce"]) +        |> Map.put(:local_only, false) +        |> Map.put(:blocking_user, user) +        |> Map.put(:muting_user, user) +        |> Map.put(:reply_visibility, "following") +        |> Map.put(:reply_filtering_user, user)          |> ActivityPub.fetch_public_activities()          |> Enum.map(& &1.id) @@ -1600,12 +1455,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      } do        activities_ids =          %{} -        |> Map.put("type", ["Create", "Announce"]) -        |> Map.put("local_only", false) -        |> Map.put("blocking_user", user) -        |> Map.put("muting_user", user) -        |> Map.put("reply_visibility", "self") -        |> Map.put("reply_filtering_user", user) +        |> Map.put(:type, ["Create", "Announce"]) +        |> Map.put(:local_only, false) +        |> Map.put(:blocking_user, user) +        |> Map.put(:muting_user, user) +        |> Map.put(:reply_visibility, "self") +        |> Map.put(:reply_filtering_user, user)          |> ActivityPub.fetch_public_activities()          |> Enum.map(& &1.id) @@ -1624,11 +1479,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      } do        params =          %{} -        |> Map.put("type", ["Create", "Announce"]) -        |> Map.put("blocking_user", user) -        |> Map.put("muting_user", user) -        |> Map.put("user", user) -        |> Map.put("reply_filtering_user", user) +        |> Map.put(:type, ["Create", "Announce"]) +        |> Map.put(:blocking_user, user) +        |> Map.put(:muting_user, user) +        |> Map.put(:user, user) +        |> Map.put(:reply_filtering_user, user)        activities_ids =          ActivityPub.fetch_activities([user.ap_id | User.following(user)], params) @@ -1662,12 +1517,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      } do        params =          %{} -        |> Map.put("type", ["Create", "Announce"]) -        |> Map.put("blocking_user", user) -        |> Map.put("muting_user", user) -        |> Map.put("user", user) -        |> Map.put("reply_visibility", "following") -        |> Map.put("reply_filtering_user", user) +        |> Map.put(:type, ["Create", "Announce"]) +        |> Map.put(:blocking_user, user) +        |> Map.put(:muting_user, user) +        |> Map.put(:user, user) +        |> Map.put(:reply_visibility, "following") +        |> Map.put(:reply_filtering_user, user)        activities_ids =          ActivityPub.fetch_activities([user.ap_id | User.following(user)], params) @@ -1701,12 +1556,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      } do        params =          %{} -        |> Map.put("type", ["Create", "Announce"]) -        |> Map.put("blocking_user", user) -        |> Map.put("muting_user", user) -        |> Map.put("user", user) -        |> Map.put("reply_visibility", "self") -        |> Map.put("reply_filtering_user", user) +        |> Map.put(:type, ["Create", "Announce"]) +        |> Map.put(:blocking_user, user) +        |> Map.put(:muting_user, user) +        |> Map.put(:user, user) +        |> Map.put(:reply_visibility, "self") +        |> Map.put(:reply_filtering_user, user)        activities_ids =          ActivityPub.fetch_activities([user.ap_id | User.following(user)], params) @@ -1727,6 +1582,40 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do        assert Enum.all?(visible_ids, &(&1 in activities_ids))      end + +    test "filtering out announces where the user is the actor of the announced message" do +      user = insert(:user) +      other_user = insert(:user) +      third_user = insert(:user) +      User.follow(user, other_user) + +      {:ok, post} = CommonAPI.post(user, %{status: "yo"}) +      {:ok, other_post} = CommonAPI.post(third_user, %{status: "yo"}) +      {:ok, _announce} = CommonAPI.repeat(post.id, other_user) +      {:ok, _announce} = CommonAPI.repeat(post.id, third_user) +      {:ok, announce} = CommonAPI.repeat(other_post.id, other_user) + +      params = %{ +        type: ["Announce"] +      } + +      results = +        [user.ap_id | User.following(user)] +        |> ActivityPub.fetch_activities(params) + +      assert length(results) == 3 + +      params = %{ +        type: ["Announce"], +        announce_filtering_user: user +      } + +      [result] = +        [user.ap_id | User.following(user)] +        |> ActivityPub.fetch_activities(params) + +      assert result.id == announce.id +    end    end    describe "replies filtering with private messages" do @@ -1735,11 +1624,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      test "public timeline", %{users: %{u1: user}} do        activities_ids =          %{} -        |> Map.put("type", ["Create", "Announce"]) -        |> Map.put("local_only", false) -        |> Map.put("blocking_user", user) -        |> Map.put("muting_user", user) -        |> Map.put("user", user) +        |> Map.put(:type, ["Create", "Announce"]) +        |> Map.put(:local_only, false) +        |> Map.put(:blocking_user, user) +        |> Map.put(:muting_user, user) +        |> Map.put(:user, user)          |> ActivityPub.fetch_public_activities()          |> Enum.map(& &1.id) @@ -1749,13 +1638,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      test "public timeline with default reply_visibility `following`", %{users: %{u1: user}} do        activities_ids =          %{} -        |> Map.put("type", ["Create", "Announce"]) -        |> Map.put("local_only", false) -        |> Map.put("blocking_user", user) -        |> Map.put("muting_user", user) -        |> Map.put("reply_visibility", "following") -        |> Map.put("reply_filtering_user", user) -        |> Map.put("user", user) +        |> Map.put(:type, ["Create", "Announce"]) +        |> Map.put(:local_only, false) +        |> Map.put(:blocking_user, user) +        |> Map.put(:muting_user, user) +        |> Map.put(:reply_visibility, "following") +        |> Map.put(:reply_filtering_user, user) +        |> Map.put(:user, user)          |> ActivityPub.fetch_public_activities()          |> Enum.map(& &1.id) @@ -1765,13 +1654,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      test "public timeline with default reply_visibility `self`", %{users: %{u1: user}} do        activities_ids =          %{} -        |> Map.put("type", ["Create", "Announce"]) -        |> Map.put("local_only", false) -        |> Map.put("blocking_user", user) -        |> Map.put("muting_user", user) -        |> Map.put("reply_visibility", "self") -        |> Map.put("reply_filtering_user", user) -        |> Map.put("user", user) +        |> Map.put(:type, ["Create", "Announce"]) +        |> Map.put(:local_only, false) +        |> Map.put(:blocking_user, user) +        |> Map.put(:muting_user, user) +        |> Map.put(:reply_visibility, "self") +        |> Map.put(:reply_filtering_user, user) +        |> Map.put(:user, user)          |> ActivityPub.fetch_public_activities()          |> Enum.map(& &1.id) @@ -1781,10 +1670,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      test "home timeline", %{users: %{u1: user}} do        params =          %{} -        |> Map.put("type", ["Create", "Announce"]) -        |> Map.put("blocking_user", user) -        |> Map.put("muting_user", user) -        |> Map.put("user", user) +        |> Map.put(:type, ["Create", "Announce"]) +        |> Map.put(:blocking_user, user) +        |> Map.put(:muting_user, user) +        |> Map.put(:user, user)        activities_ids =          ActivityPub.fetch_activities([user.ap_id | User.following(user)], params) @@ -1796,12 +1685,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      test "home timeline with default reply_visibility `following`", %{users: %{u1: user}} do        params =          %{} -        |> Map.put("type", ["Create", "Announce"]) -        |> Map.put("blocking_user", user) -        |> Map.put("muting_user", user) -        |> Map.put("user", user) -        |> Map.put("reply_visibility", "following") -        |> Map.put("reply_filtering_user", user) +        |> Map.put(:type, ["Create", "Announce"]) +        |> Map.put(:blocking_user, user) +        |> Map.put(:muting_user, user) +        |> Map.put(:user, user) +        |> Map.put(:reply_visibility, "following") +        |> Map.put(:reply_filtering_user, user)        activities_ids =          ActivityPub.fetch_activities([user.ap_id | User.following(user)], params) @@ -1820,12 +1709,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      } do        params =          %{} -        |> Map.put("type", ["Create", "Announce"]) -        |> Map.put("blocking_user", user) -        |> Map.put("muting_user", user) -        |> Map.put("user", user) -        |> Map.put("reply_visibility", "self") -        |> Map.put("reply_filtering_user", user) +        |> Map.put(:type, ["Create", "Announce"]) +        |> Map.put(:blocking_user, user) +        |> Map.put(:muting_user, user) +        |> Map.put(:user, user) +        |> Map.put(:reply_visibility, "self") +        |> Map.put(:reply_filtering_user, user)        activities_ids =          ActivityPub.fetch_activities([user.ap_id | User.following(user)], params) @@ -2070,4 +1959,20 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do               end) =~ "Follower/Following counter update for #{user.ap_id} failed"      end    end + +  describe "global activity expiration" do +    setup do: clear_config([:mrf, :policies]) + +    test "creates an activity expiration for local Create activities" do +      Pleroma.Config.put( +        [:mrf, :policies], +        Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicy +      ) + +      {:ok, %{id: id_create}} = ActivityBuilder.insert(%{"type" => "Create", "context" => "3hu"}) +      {:ok, _follow} = ActivityBuilder.insert(%{"type" => "Follow", "context" => "3hu"}) + +      assert [%{activity_id: ^id_create}] = Pleroma.ActivityExpiration |> Repo.all() +    end +  end  end diff --git a/test/web/activity_pub/mrf/activity_expiration_policy_test.exs b/test/web/activity_pub/mrf/activity_expiration_policy_test.exs new file mode 100644 index 000000000..8babf49e7 --- /dev/null +++ b/test/web/activity_pub/mrf/activity_expiration_policy_test.exs @@ -0,0 +1,77 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicyTest do +  use ExUnit.Case, async: true +  alias Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicy + +  @id Pleroma.Web.Endpoint.url() <> "/activities/cofe" + +  test "adds `expires_at` property" do +    assert {:ok, %{"type" => "Create", "expires_at" => expires_at}} = +             ActivityExpirationPolicy.filter(%{ +               "id" => @id, +               "type" => "Create", +               "object" => %{"type" => "Note"} +             }) + +    assert Timex.diff(expires_at, NaiveDateTime.utc_now(), :days) == 364 +  end + +  test "keeps existing `expires_at` if it less than the config setting" do +    expires_at = NaiveDateTime.utc_now() |> Timex.shift(days: 1) + +    assert {:ok, %{"type" => "Create", "expires_at" => ^expires_at}} = +             ActivityExpirationPolicy.filter(%{ +               "id" => @id, +               "type" => "Create", +               "expires_at" => expires_at, +               "object" => %{"type" => "Note"} +             }) +  end + +  test "overwrites existing `expires_at` if it greater than the config setting" do +    too_distant_future = NaiveDateTime.utc_now() |> Timex.shift(years: 2) + +    assert {:ok, %{"type" => "Create", "expires_at" => expires_at}} = +             ActivityExpirationPolicy.filter(%{ +               "id" => @id, +               "type" => "Create", +               "expires_at" => too_distant_future, +               "object" => %{"type" => "Note"} +             }) + +    assert Timex.diff(expires_at, NaiveDateTime.utc_now(), :days) == 364 +  end + +  test "ignores remote activities" do +    assert {:ok, activity} = +             ActivityExpirationPolicy.filter(%{ +               "id" => "https://example.com/123", +               "type" => "Create", +               "object" => %{"type" => "Note"} +             }) + +    refute Map.has_key?(activity, "expires_at") +  end + +  test "ignores non-Create/Note activities" do +    assert {:ok, activity} = +             ActivityExpirationPolicy.filter(%{ +               "id" => "https://example.com/123", +               "type" => "Follow" +             }) + +    refute Map.has_key?(activity, "expires_at") + +    assert {:ok, activity} = +             ActivityExpirationPolicy.filter(%{ +               "id" => "https://example.com/123", +               "type" => "Create", +               "object" => %{"type" => "Cofe"} +             }) + +    refute Map.has_key?(activity, "expires_at") +  end +end diff --git a/test/web/activity_pub/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/mrf/hellthread_policy_test.exs b/test/web/activity_pub/mrf/hellthread_policy_test.exs index 95ef0b168..6e9daa7f9 100644 --- a/test/web/activity_pub/mrf/hellthread_policy_test.exs +++ b/test/web/activity_pub/mrf/hellthread_policy_test.exs @@ -8,6 +8,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicyTest do    import Pleroma.Web.ActivityPub.MRF.HellthreadPolicy +  alias Pleroma.Web.CommonAPI +    setup do      user = insert(:user) @@ -20,7 +22,10 @@ defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicyTest do          "https://instance.tld/users/user1",          "https://instance.tld/users/user2",          "https://instance.tld/users/user3" -      ] +      ], +      "object" => %{ +        "type" => "Note" +      }      }      [user: user, message: message] @@ -28,6 +33,17 @@ defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicyTest do    setup do: clear_config(:mrf_hellthread) +  test "doesn't die on chat messages" do +    Pleroma.Config.put([:mrf_hellthread], %{delist_threshold: 2, reject_threshold: 0}) + +    user = insert(:user) +    other_user = insert(:user) + +    {:ok, activity} = CommonAPI.post_chat_message(user, other_user, "moin") + +    assert {:ok, _} = filter(activity.data) +  end +    describe "reject" do      test "rejects the message if the recipient count is above reject_threshold", %{        message: message diff --git a/test/web/activity_pub/mrf/mrf_test.exs b/test/web/activity_pub/mrf/mrf_test.exs index c941066f2..a63b25423 100644 --- a/test/web/activity_pub/mrf/mrf_test.exs +++ b/test/web/activity_pub/mrf/mrf_test.exs @@ -60,8 +60,6 @@ defmodule Pleroma.Web.ActivityPub.MRFTest do    end    describe "describe/0" do -    setup do: clear_config([:instance, :rewrite_policy]) -      test "it works as expected with noop policy" do        expected = %{          mrf_policies: ["NoOpPolicy"], @@ -72,7 +70,7 @@ defmodule Pleroma.Web.ActivityPub.MRFTest do      end      test "it works as expected with mock policy" do -      Pleroma.Config.put([:instance, :rewrite_policy], [MRFModuleMock]) +      clear_config([:mrf, :policies], [MRFModuleMock])        expected = %{          mrf_policies: ["MRFModuleMock"], diff --git a/test/web/activity_pub/mrf/steal_emoji_policy_test.exs b/test/web/activity_pub/mrf/steal_emoji_policy_test.exs new file mode 100644 index 000000000..3f8222736 --- /dev/null +++ b/test/web/activity_pub/mrf/steal_emoji_policy_test.exs @@ -0,0 +1,68 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.MRF.StealEmojiPolicyTest do +  use Pleroma.DataCase + +  alias Pleroma.Config +  alias Pleroma.Web.ActivityPub.MRF.StealEmojiPolicy + +  setup_all do +    Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) +    :ok +  end + +  setup do +    emoji_path = Path.join(Config.get([:instance, :static_dir]), "emoji/stolen") +    File.rm_rf!(emoji_path) +    File.mkdir!(emoji_path) + +    Pleroma.Emoji.reload() + +    on_exit(fn -> +      File.rm_rf!(emoji_path) +    end) + +    :ok +  end + +  test "does nothing by default" do +    installed_emoji = Pleroma.Emoji.get_all() |> Enum.map(fn {k, _} -> k end) +    refute "firedfox" in installed_emoji + +    message = %{ +      "type" => "Create", +      "object" => %{ +        "emoji" => [{"firedfox", "https://example.org/emoji/firedfox.png"}], +        "actor" => "https://example.org/users/admin" +      } +    } + +    assert {:ok, message} == StealEmojiPolicy.filter(message) + +    installed_emoji = Pleroma.Emoji.get_all() |> Enum.map(fn {k, _} -> k end) +    refute "firedfox" in installed_emoji +  end + +  test "Steals emoji on unknown shortcode from allowed remote host" do +    installed_emoji = Pleroma.Emoji.get_all() |> Enum.map(fn {k, _} -> k end) +    refute "firedfox" in installed_emoji + +    message = %{ +      "type" => "Create", +      "object" => %{ +        "emoji" => [{"firedfox", "https://example.org/emoji/firedfox.png"}], +        "actor" => "https://example.org/users/admin" +      } +    } + +    clear_config([:mrf_steal_emoji, :hosts], ["example.org"]) +    clear_config([:mrf_steal_emoji, :size_limit], 284_468) + +    assert {:ok, message} == StealEmojiPolicy.filter(message) + +    installed_emoji = Pleroma.Emoji.get_all() |> Enum.map(fn {k, _} -> k end) +    assert "firedfox" in installed_emoji +  end +end diff --git a/test/web/activity_pub/mrf/user_allowlist_policy_test.exs b/test/web/activity_pub/mrf/user_allowlist_policy_test.exs index 724bae058..ba1b69658 100644 --- a/test/web/activity_pub/mrf/user_allowlist_policy_test.exs +++ b/test/web/activity_pub/mrf/user_allowlist_policy_test.exs @@ -7,7 +7,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.UserAllowListPolicyTest do    alias Pleroma.Web.ActivityPub.MRF.UserAllowListPolicy -  setup do: clear_config([:mrf_user_allowlist, :localhost]) +  setup do: clear_config(:mrf_user_allowlist)    test "pass filter if allow list is empty" do      actor = insert(:user) @@ -17,14 +17,14 @@ defmodule Pleroma.Web.ActivityPub.MRF.UserAllowListPolicyTest do    test "pass filter if allow list isn't empty and user in allow list" do      actor = insert(:user) -    Pleroma.Config.put([:mrf_user_allowlist, :localhost], [actor.ap_id, "test-ap-id"]) +    Pleroma.Config.put([:mrf_user_allowlist], %{"localhost" => [actor.ap_id, "test-ap-id"]})      message = %{"actor" => actor.ap_id}      assert UserAllowListPolicy.filter(message) == {:ok, message}    end    test "rejected if allow list isn't empty and user not in allow list" do      actor = insert(:user) -    Pleroma.Config.put([:mrf_user_allowlist, :localhost], ["test-ap-id"]) +    Pleroma.Config.put([:mrf_user_allowlist], %{"localhost" => ["test-ap-id"]})      message = %{"actor" => actor.ap_id}      assert UserAllowListPolicy.filter(message) == {:reject, nil}    end diff --git a/test/web/activity_pub/object_validator_test.exs b/test/web/activity_pub/object_validator_test.exs index 96eff1c30..f38bf7e08 100644 --- a/test/web/activity_pub/object_validator_test.exs +++ b/test/web/activity_pub/object_validator_test.exs @@ -2,14 +2,264 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidatorTest do    use Pleroma.DataCase    alias Pleroma.Object +  alias Pleroma.Web.ActivityPub.ActivityPub    alias Pleroma.Web.ActivityPub.Builder    alias Pleroma.Web.ActivityPub.ObjectValidator +  alias Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidator    alias Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator    alias Pleroma.Web.ActivityPub.Utils    alias Pleroma.Web.CommonAPI    import Pleroma.Factory +  describe "attachments" do +    test "works with honkerific attachments" do +      attachment = %{ +        "mediaType" => "", +        "name" => "", +        "summary" => "298p3RG7j27tfsZ9RQ.jpg", +        "type" => "Document", +        "url" => "https://honk.tedunangst.com/d/298p3RG7j27tfsZ9RQ.jpg" +      } + +      assert {:ok, attachment} = +               AttachmentValidator.cast_and_validate(attachment) +               |> Ecto.Changeset.apply_action(:insert) + +      assert attachment.mediaType == "application/octet-stream" +    end + +    test "it turns mastodon attachments into our attachments" do +      attachment = %{ +        "url" => +          "http://mastodon.example.org/system/media_attachments/files/000/000/002/original/334ce029e7bfb920.jpg", +        "type" => "Document", +        "name" => nil, +        "mediaType" => "image/jpeg" +      } + +      {:ok, attachment} = +        AttachmentValidator.cast_and_validate(attachment) +        |> Ecto.Changeset.apply_action(:insert) + +      assert [ +               %{ +                 href: +                   "http://mastodon.example.org/system/media_attachments/files/000/000/002/original/334ce029e7bfb920.jpg", +                 type: "Link", +                 mediaType: "image/jpeg" +               } +             ] = attachment.url + +      assert attachment.mediaType == "image/jpeg" +    end + +    test "it handles our own uploads" do +      user = insert(:user) + +      file = %Plug.Upload{ +        content_type: "image/jpg", +        path: Path.absname("test/fixtures/image.jpg"), +        filename: "an_image.jpg" +      } + +      {:ok, attachment} = ActivityPub.upload(file, actor: user.ap_id) + +      {:ok, attachment} = +        attachment.data +        |> AttachmentValidator.cast_and_validate() +        |> Ecto.Changeset.apply_action(:insert) + +      assert attachment.mediaType == "image/jpeg" +    end +  end + +  describe "chat message create activities" do +    test "it is invalid if the object already exists" do +      user = insert(:user) +      recipient = insert(:user) +      {:ok, activity} = CommonAPI.post_chat_message(user, recipient, "hey") +      object = Object.normalize(activity, false) + +      {:ok, create_data, _} = Builder.create(user, object.data, [recipient.ap_id]) + +      {:error, cng} = ObjectValidator.validate(create_data, []) + +      assert {:object, {"The object to create already exists", []}} in cng.errors +    end + +    test "it is invalid if the object data has a different `to` or `actor` field" do +      user = insert(:user) +      recipient = insert(:user) +      {:ok, object_data, _} = Builder.chat_message(recipient, user.ap_id, "Hey") + +      {:ok, create_data, _} = Builder.create(user, object_data, [recipient.ap_id]) + +      {:error, cng} = ObjectValidator.validate(create_data, []) + +      assert {:to, {"Recipients don't match with object recipients", []}} in cng.errors +      assert {:actor, {"Actor doesn't match with object actor", []}} in cng.errors +    end +  end + +  describe "chat messages" do +    setup do +      clear_config([:instance, :remote_limit]) +      user = insert(:user) +      recipient = insert(:user, local: false) + +      {:ok, valid_chat_message, _} = Builder.chat_message(user, recipient.ap_id, "hey :firefox:") + +      %{user: user, recipient: recipient, valid_chat_message: valid_chat_message} +    end + +    test "let's through some basic html", %{user: user, recipient: recipient} do +      {:ok, valid_chat_message, _} = +        Builder.chat_message( +          user, +          recipient.ap_id, +          "hey <a href='https://example.org'>example</a> <script>alert('uguu')</script>" +        ) + +      assert {:ok, object, _meta} = ObjectValidator.validate(valid_chat_message, []) + +      assert object["content"] == +               "hey <a href=\"https://example.org\">example</a> alert('uguu')" +    end + +    test "validates for a basic object we build", %{valid_chat_message: valid_chat_message} do +      assert {:ok, object, _meta} = ObjectValidator.validate(valid_chat_message, []) + +      assert Map.put(valid_chat_message, "attachment", nil) == object +    end + +    test "validates for a basic object with an attachment", %{ +      valid_chat_message: valid_chat_message, +      user: user +    } do +      file = %Plug.Upload{ +        content_type: "image/jpg", +        path: Path.absname("test/fixtures/image.jpg"), +        filename: "an_image.jpg" +      } + +      {:ok, attachment} = ActivityPub.upload(file, actor: user.ap_id) + +      valid_chat_message = +        valid_chat_message +        |> Map.put("attachment", attachment.data) + +      assert {:ok, object, _meta} = ObjectValidator.validate(valid_chat_message, []) + +      assert object["attachment"] +    end + +    test "validates for a basic object with an attachment in an array", %{ +      valid_chat_message: valid_chat_message, +      user: user +    } do +      file = %Plug.Upload{ +        content_type: "image/jpg", +        path: Path.absname("test/fixtures/image.jpg"), +        filename: "an_image.jpg" +      } + +      {:ok, attachment} = ActivityPub.upload(file, actor: user.ap_id) + +      valid_chat_message = +        valid_chat_message +        |> Map.put("attachment", [attachment.data]) + +      assert {:ok, object, _meta} = ObjectValidator.validate(valid_chat_message, []) + +      assert object["attachment"] +    end + +    test "validates for a basic object with an attachment but without content", %{ +      valid_chat_message: valid_chat_message, +      user: user +    } do +      file = %Plug.Upload{ +        content_type: "image/jpg", +        path: Path.absname("test/fixtures/image.jpg"), +        filename: "an_image.jpg" +      } + +      {:ok, attachment} = ActivityPub.upload(file, actor: user.ap_id) + +      valid_chat_message = +        valid_chat_message +        |> Map.put("attachment", attachment.data) +        |> Map.delete("content") + +      assert {:ok, object, _meta} = ObjectValidator.validate(valid_chat_message, []) + +      assert object["attachment"] +    end + +    test "does not validate if the message has no content", %{ +      valid_chat_message: valid_chat_message +    } do +      contentless = +        valid_chat_message +        |> Map.delete("content") + +      refute match?({:ok, _object, _meta}, ObjectValidator.validate(contentless, [])) +    end + +    test "does not validate if the message is longer than the remote_limit", %{ +      valid_chat_message: valid_chat_message +    } do +      Pleroma.Config.put([:instance, :remote_limit], 2) +      refute match?({:ok, _object, _meta}, ObjectValidator.validate(valid_chat_message, [])) +    end + +    test "does not validate if the recipient is blocking the actor", %{ +      valid_chat_message: valid_chat_message, +      user: user, +      recipient: recipient +    } do +      Pleroma.User.block(recipient, user) +      refute match?({:ok, _object, _meta}, ObjectValidator.validate(valid_chat_message, [])) +    end + +    test "does not validate if the actor or the recipient is not in our system", %{ +      valid_chat_message: valid_chat_message +    } do +      chat_message = +        valid_chat_message +        |> Map.put("actor", "https://raymoo.com/raymoo") + +      {:error, _} = ObjectValidator.validate(chat_message, []) + +      chat_message = +        valid_chat_message +        |> Map.put("to", ["https://raymoo.com/raymoo"]) + +      {:error, _} = ObjectValidator.validate(chat_message, []) +    end + +    test "does not validate for a message with multiple recipients", %{ +      valid_chat_message: valid_chat_message, +      user: user, +      recipient: recipient +    } do +      chat_message = +        valid_chat_message +        |> Map.put("to", [user.ap_id, recipient.ap_id]) + +      assert {:error, _} = ObjectValidator.validate(chat_message, []) +    end + +    test "does not validate if it doesn't concern local users" do +      user = insert(:user, local: false) +      recipient = insert(:user, local: false) + +      {:ok, valid_chat_message, _} = Builder.chat_message(user, recipient.ap_id, "hey") +      assert {:error, _} = ObjectValidator.validate(valid_chat_message, []) +    end +  end +    describe "EmojiReacts" do      setup do        user = insert(:user) @@ -280,4 +530,155 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidatorTest do        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 + +  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/types/date_time_test.exs b/test/web/activity_pub/object_validators/types/date_time_test.exs index 3e17a9497..43be8e936 100644 --- a/test/web/activity_pub/object_validators/types/date_time_test.exs +++ b/test/web/activity_pub/object_validators/types/date_time_test.exs @@ -1,5 +1,5 @@  defmodule Pleroma.Web.ActivityPub.ObjectValidators.Types.DateTimeTest do -  alias Pleroma.Web.ActivityPub.ObjectValidators.Types.DateTime +  alias Pleroma.EctoType.ActivityPub.ObjectValidators.DateTime    use Pleroma.DataCase    test "it validates an xsd:Datetime" do diff --git a/test/web/activity_pub/object_validators/types/object_id_test.exs b/test/web/activity_pub/object_validators/types/object_id_test.exs index 834213182..e0ab76379 100644 --- a/test/web/activity_pub/object_validators/types/object_id_test.exs +++ b/test/web/activity_pub/object_validators/types/object_id_test.exs @@ -1,5 +1,9 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only +  defmodule Pleroma.Web.ObjectValidators.Types.ObjectIDTest do -  alias Pleroma.Web.ActivityPub.ObjectValidators.Types.ObjectID +  alias Pleroma.EctoType.ActivityPub.ObjectValidators.ObjectID    use Pleroma.DataCase    @uris [ diff --git a/test/web/activity_pub/object_validators/types/recipients_test.exs b/test/web/activity_pub/object_validators/types/recipients_test.exs index f278f039b..053916bdd 100644 --- a/test/web/activity_pub/object_validators/types/recipients_test.exs +++ b/test/web/activity_pub/object_validators/types/recipients_test.exs @@ -1,5 +1,5 @@  defmodule Pleroma.Web.ObjectValidators.Types.RecipientsTest do -  alias Pleroma.Web.ActivityPub.ObjectValidators.Types.Recipients +  alias Pleroma.EctoType.ActivityPub.ObjectValidators.Recipients    use Pleroma.DataCase    test "it asserts that all elements of the list are object ids" do diff --git a/test/web/activity_pub/object_validators/types/safe_text_test.exs b/test/web/activity_pub/object_validators/types/safe_text_test.exs new file mode 100644 index 000000000..9c08606f6 --- /dev/null +++ b/test/web/activity_pub/object_validators/types/safe_text_test.exs @@ -0,0 +1,30 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.ObjectValidators.Types.SafeTextTest do +  use Pleroma.DataCase + +  alias Pleroma.EctoType.ActivityPub.ObjectValidators.SafeText + +  test "it lets normal text go through" do +    text = "hey how are you" +    assert {:ok, text} == SafeText.cast(text) +  end + +  test "it removes html tags from text" do +    text = "hey look xss <script>alert('foo')</script>" +    assert {:ok, "hey look xss alert('foo')"} == SafeText.cast(text) +  end + +  test "it keeps basic html tags" do +    text = "hey <a href='http://gensokyo.2hu'>look</a> xss <script>alert('foo')</script>" + +    assert {:ok, "hey <a href=\"http://gensokyo.2hu\">look</a> xss alert('foo')"} == +             SafeText.cast(text) +  end + +  test "errors for non-text" do +    assert :error == SafeText.cast(1) +  end +end diff --git a/test/web/activity_pub/pipeline_test.exs b/test/web/activity_pub/pipeline_test.exs index f3c437498..8deb64501 100644 --- a/test/web/activity_pub/pipeline_test.exs +++ b/test/web/activity_pub/pipeline_test.exs @@ -9,6 +9,11 @@ defmodule Pleroma.Web.ActivityPub.PipelineTest do    import Pleroma.Factory    describe "common_pipeline/2" do +    setup do +      clear_config([:instance, :federating], true) +      :ok +    end +      test "it goes through validation, filtering, persisting, side effects and federation for local activities" do        activity = insert(:note_activity)        meta = [local: true] @@ -28,7 +33,10 @@ defmodule Pleroma.Web.ActivityPub.PipelineTest do          {            Pleroma.Web.ActivityPub.SideEffects,            [], -          [handle: fn o, m -> {:ok, o, m} end] +          [ +            handle: fn o, m -> {:ok, o, m} end, +            handle_after_transaction: fn m -> m end +          ]          },          {            Pleroma.Web.Federator, @@ -66,7 +74,46 @@ defmodule Pleroma.Web.ActivityPub.PipelineTest do          {            Pleroma.Web.ActivityPub.SideEffects,            [], -          [handle: fn o, m -> {:ok, o, m} end] +          [handle: fn o, m -> {:ok, o, m} end, handle_after_transaction: fn m -> m end] +        }, +        { +          Pleroma.Web.Federator, +          [], +          [] +        } +      ]) do +        assert {:ok, ^activity, ^meta} = +                 Pleroma.Web.ActivityPub.Pipeline.common_pipeline(activity, meta) + +        assert_called(Pleroma.Web.ActivityPub.ObjectValidator.validate(activity, meta)) +        assert_called(Pleroma.Web.ActivityPub.MRF.filter(activity)) +        assert_called(Pleroma.Web.ActivityPub.ActivityPub.persist(activity, meta)) +        assert_called(Pleroma.Web.ActivityPub.SideEffects.handle(activity, meta)) +      end +    end + +    test "it goes through validation, filtering, persisting, side effects without federation for local activities if federation is deactivated" do +      clear_config([:instance, :federating], false) + +      activity = insert(:note_activity) +      meta = [local: true] + +      with_mocks([ +        {Pleroma.Web.ActivityPub.ObjectValidator, [], [validate: fn o, m -> {:ok, o, m} end]}, +        { +          Pleroma.Web.ActivityPub.MRF, +          [], +          [filter: fn o -> {:ok, o} end] +        }, +        { +          Pleroma.Web.ActivityPub.ActivityPub, +          [], +          [persist: fn o, m -> {:ok, o, m} end] +        }, +        { +          Pleroma.Web.ActivityPub.SideEffects, +          [], +          [handle: fn o, m -> {:ok, o, m} end, handle_after_transaction: fn m -> m end]          },          {            Pleroma.Web.Federator, diff --git a/test/web/activity_pub/relay_test.exs b/test/web/activity_pub/relay_test.exs index 9e16e39c4..b3b573c9b 100644 --- a/test/web/activity_pub/relay_test.exs +++ b/test/web/activity_pub/relay_test.exs @@ -6,7 +6,6 @@ defmodule Pleroma.Web.ActivityPub.RelayTest do    use Pleroma.DataCase    alias Pleroma.Activity -  alias Pleroma.Object    alias Pleroma.User    alias Pleroma.Web.ActivityPub.ActivityPub    alias Pleroma.Web.ActivityPub.Relay @@ -95,21 +94,21 @@ defmodule Pleroma.Web.ActivityPub.RelayTest do        end)        assert capture_log(fn -> -               assert Relay.publish(activity) == {:error, nil} -             end) =~ "[error] error: nil" +               assert Relay.publish(activity) == {:error, false} +             end) =~ "[error] error: false"      end      test_with_mock "returns announce activity and publish to federate",                     Pleroma.Web.Federator,                     [:passthrough],                     [] do -      Pleroma.Config.put([:instance, :federating], true) +      clear_config([:instance, :federating], true)        service_actor = Relay.get_actor()        note = insert(:note_activity) -      assert {:ok, %Activity{} = activity, %Object{} = obj} = Relay.publish(note) +      assert {:ok, %Activity{} = activity} = Relay.publish(note)        assert activity.data["type"] == "Announce"        assert activity.data["actor"] == service_actor.ap_id -      assert activity.data["object"] == obj.data["id"] +      assert activity.data["to"] == [service_actor.follower_address]        assert called(Pleroma.Web.Federator.publish(activity))      end @@ -117,13 +116,12 @@ defmodule Pleroma.Web.ActivityPub.RelayTest do                     Pleroma.Web.Federator,                     [:passthrough],                     [] do -      Pleroma.Config.put([:instance, :federating], false) +      clear_config([:instance, :federating], false)        service_actor = Relay.get_actor()        note = insert(:note_activity) -      assert {:ok, %Activity{} = activity, %Object{} = obj} = Relay.publish(note) +      assert {:ok, %Activity{} = activity} = Relay.publish(note)        assert activity.data["type"] == "Announce"        assert activity.data["actor"] == service_actor.ap_id -      assert activity.data["object"] == obj.data["id"]        refute called(Pleroma.Web.Federator.publish(activity))      end    end diff --git a/test/web/activity_pub/side_effects_test.exs b/test/web/activity_pub/side_effects_test.exs index 797f00d08..af27c34b4 100644 --- a/test/web/activity_pub/side_effects_test.exs +++ b/test/web/activity_pub/side_effects_test.exs @@ -7,6 +7,8 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do    use Pleroma.DataCase    alias Pleroma.Activity +  alias Pleroma.Chat +  alias Pleroma.Chat.MessageReference    alias Pleroma.Notification    alias Pleroma.Object    alias Pleroma.Repo @@ -20,6 +22,114 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do    import Pleroma.Factory    import Mock +  describe "handle_after_transaction" do +    test "it streams out notifications and streams" do +      author = insert(:user, local: true) +      recipient = insert(:user, local: true) + +      {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey") + +      {:ok, create_activity_data, _meta} = +        Builder.create(author, chat_message_data["id"], [recipient.ap_id]) + +      {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false) + +      {:ok, _create_activity, meta} = +        SideEffects.handle(create_activity, local: false, object_data: chat_message_data) + +      assert [notification] = meta[:notifications] + +      with_mocks([ +        { +          Pleroma.Web.Streamer, +          [], +          [ +            stream: fn _, _ -> nil end +          ] +        }, +        { +          Pleroma.Web.Push, +          [], +          [ +            send: fn _ -> nil end +          ] +        } +      ]) do +        SideEffects.handle_after_transaction(meta) + +        assert called(Pleroma.Web.Streamer.stream(["user", "user:notification"], notification)) +        assert called(Pleroma.Web.Streamer.stream(["user", "user:pleroma_chat"], :_)) +        assert called(Pleroma.Web.Push.send(notification)) +      end +    end +  end + +  describe "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) +      {:ok, update_data, []} = Builder.update(user, %{"id" => user.ap_id, "name" => "new name!"}) +      {:ok, update, _meta} = ActivityPub.persist(update_data, local: true) + +      %{user: user, update_data: update_data, update: update} +    end + +    test "it updates the user", %{user: user, update: update} do +      {:ok, _, _} = SideEffects.handle(update) +      user = User.get_by_id(user.id) +      assert user.name == "new name!" +    end + +    test "it uses a given changeset to update", %{user: user, update: update} do +      changeset = Ecto.Changeset.change(user, %{default_scope: "direct"}) + +      assert user.default_scope == "public" +      {:ok, _, _} = SideEffects.handle(update, user_update_changeset: changeset) +      user = User.get_by_id(user.id) +      assert user.default_scope == "direct" +    end +  end +    describe "delete objects" do      setup do        user = insert(:user) @@ -140,6 +250,31 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do      end    end +  describe "delete users with confirmation pending" do +    setup do +      user = insert(:user, confirmation_pending: true) +      {:ok, delete_user_data, _meta} = Builder.delete(user, user.ap_id) +      {:ok, delete_user, _meta} = ActivityPub.persist(delete_user_data, local: true) +      {:ok, delete: delete_user, user: user} +    end + +    test "when activation is not required", %{delete: delete, user: user} do +      clear_config([:instance, :account_activation_required], false) +      {:ok, _, _} = SideEffects.handle(delete) +      ObanHelpers.perform_all() + +      assert User.get_cached_by_id(user.id).deactivated +    end + +    test "when activation is required", %{delete: delete, user: user} do +      clear_config([:instance, :account_activation_required], true) +      {:ok, _, _} = SideEffects.handle(delete) +      ObanHelpers.perform_all() + +      refute User.get_cached_by_id(user.id) +    end +  end +    describe "Undo objects" do      setup do        poster = insert(:user) @@ -147,9 +282,8 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do        {:ok, post} = CommonAPI.post(poster, %{status: "hey"})        {: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, announce} = CommonAPI.repeat(post.id, user) +      {:ok, block} = CommonAPI.block(user, poster)        {:ok, undo_data, _meta} = Builder.undo(user, like)        {:ok, like_undo, _meta} = ActivityPub.persist(undo_data, local: true) @@ -264,4 +398,202 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do        assert Repo.get_by(Notification, user_id: poster.id, activity_id: like.id)      end    end + +  describe "creation of ChatMessages" do +    test "notifies the recipient" do +      author = insert(:user, local: false) +      recipient = insert(:user, local: true) + +      {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey") + +      {:ok, create_activity_data, _meta} = +        Builder.create(author, chat_message_data["id"], [recipient.ap_id]) + +      {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false) + +      {:ok, _create_activity, _meta} = +        SideEffects.handle(create_activity, local: false, object_data: chat_message_data) + +      assert Repo.get_by(Notification, user_id: recipient.id, activity_id: create_activity.id) +    end + +    test "it streams the created ChatMessage" do +      author = insert(:user, local: true) +      recipient = insert(:user, local: true) + +      {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey") + +      {:ok, create_activity_data, _meta} = +        Builder.create(author, chat_message_data["id"], [recipient.ap_id]) + +      {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false) + +      {:ok, _create_activity, meta} = +        SideEffects.handle(create_activity, local: false, object_data: chat_message_data) + +      assert [_, _] = meta[:streamables] +    end + +    test "it creates a Chat and MessageReferences for the local users and bumps the unread count, except for the author" do +      author = insert(:user, local: true) +      recipient = insert(:user, local: true) + +      {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey") + +      {:ok, create_activity_data, _meta} = +        Builder.create(author, chat_message_data["id"], [recipient.ap_id]) + +      {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false) + +      with_mocks([ +        { +          Pleroma.Web.Streamer, +          [], +          [ +            stream: fn _, _ -> nil end +          ] +        }, +        { +          Pleroma.Web.Push, +          [], +          [ +            send: fn _ -> nil end +          ] +        } +      ]) do +        {:ok, _create_activity, meta} = +          SideEffects.handle(create_activity, local: false, object_data: chat_message_data) + +        # The notification gets created +        assert [notification] = meta[:notifications] +        assert notification.activity_id == create_activity.id + +        # But it is not sent out +        refute called(Pleroma.Web.Streamer.stream(["user", "user:notification"], notification)) +        refute called(Pleroma.Web.Push.send(notification)) + +        # Same for the user chat stream +        assert [{topics, _}, _] = meta[:streamables] +        assert topics == ["user", "user:pleroma_chat"] +        refute called(Pleroma.Web.Streamer.stream(["user", "user:pleroma_chat"], :_)) + +        chat = Chat.get(author.id, recipient.ap_id) + +        [cm_ref] = MessageReference.for_chat_query(chat) |> Repo.all() + +        assert cm_ref.object.data["content"] == "hey" +        assert cm_ref.unread == false + +        chat = Chat.get(recipient.id, author.ap_id) + +        [cm_ref] = MessageReference.for_chat_query(chat) |> Repo.all() + +        assert cm_ref.object.data["content"] == "hey" +        assert cm_ref.unread == true +      end +    end + +    test "it creates a Chat for the local users and bumps the unread count" do +      author = insert(:user, local: false) +      recipient = insert(:user, local: true) + +      {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey") + +      {:ok, create_activity_data, _meta} = +        Builder.create(author, chat_message_data["id"], [recipient.ap_id]) + +      {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false) + +      {:ok, _create_activity, _meta} = +        SideEffects.handle(create_activity, local: false, object_data: chat_message_data) + +      # An object is created +      assert Object.get_by_ap_id(chat_message_data["id"]) + +      # The remote user won't get a chat +      chat = Chat.get(author.id, recipient.ap_id) +      refute chat + +      # The local user will get a chat +      chat = Chat.get(recipient.id, author.ap_id) +      assert chat + +      author = insert(:user, local: true) +      recipient = insert(:user, local: true) + +      {:ok, chat_message_data, _meta} = Builder.chat_message(author, recipient.ap_id, "hey") + +      {:ok, create_activity_data, _meta} = +        Builder.create(author, chat_message_data["id"], [recipient.ap_id]) + +      {:ok, create_activity, _meta} = ActivityPub.persist(create_activity_data, local: false) + +      {:ok, _create_activity, _meta} = +        SideEffects.handle(create_activity, local: false, object_data: chat_message_data) + +      # Both users are local and get the chat +      chat = Chat.get(author.id, recipient.ap_id) +      assert chat + +      chat = Chat.get(recipient.id, author.ap_id) +      assert chat +    end +  end + +  describe "announce objects" do +    setup do +      poster = insert(:user) +      user = insert(:user) +      {:ok, post} = CommonAPI.post(poster, %{status: "hey"}) +      {:ok, private_post} = CommonAPI.post(poster, %{status: "hey", visibility: "private"}) + +      {:ok, announce_data, _meta} = Builder.announce(user, post.object, public: true) + +      {:ok, private_announce_data, _meta} = +        Builder.announce(user, private_post.object, public: false) + +      {:ok, relay_announce_data, _meta} = +        Builder.announce(Pleroma.Web.ActivityPub.Relay.get_actor(), post.object, public: true) + +      {:ok, announce, _meta} = ActivityPub.persist(announce_data, local: true) +      {:ok, private_announce, _meta} = ActivityPub.persist(private_announce_data, local: true) +      {:ok, relay_announce, _meta} = ActivityPub.persist(relay_announce_data, local: true) + +      %{ +        announce: announce, +        user: user, +        poster: poster, +        private_announce: private_announce, +        relay_announce: relay_announce +      } +    end + +    test "adds the announce to the original object", %{announce: announce, user: user} do +      {:ok, announce, _} = SideEffects.handle(announce) +      object = Object.get_by_ap_id(announce.data["object"]) +      assert object.data["announcement_count"] == 1 +      assert user.ap_id in object.data["announcements"] +    end + +    test "does not add the announce to the original object if the actor is a service actor", %{ +      relay_announce: announce +    } do +      {:ok, announce, _} = SideEffects.handle(announce) +      object = Object.get_by_ap_id(announce.data["object"]) +      assert object.data["announcement_count"] == nil +    end + +    test "creates a notification", %{announce: announce, poster: poster} do +      {:ok, announce, _} = SideEffects.handle(announce) +      assert Repo.get_by(Notification, user_id: poster.id, activity_id: announce.id) +    end + +    test "it streams out the announce", %{announce: announce} do +      with_mock Pleroma.Web.ActivityPub.ActivityPub, [:passthrough], stream_out: fn _ -> nil end do +        {:ok, announce, _} = SideEffects.handle(announce) + +        assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out(announce)) +      end +    end +  end  end diff --git a/test/web/activity_pub/transmogrifier/announce_handling_test.exs b/test/web/activity_pub/transmogrifier/announce_handling_test.exs new file mode 100644 index 000000000..e895636b5 --- /dev/null +++ b/test/web/activity_pub/transmogrifier/announce_handling_test.exs @@ -0,0 +1,172 @@ +# 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.AnnounceHandlingTest do +  use Pleroma.DataCase + +  alias Pleroma.Activity +  alias Pleroma.Object +  alias Pleroma.Web.ActivityPub.Transmogrifier +  alias Pleroma.Web.CommonAPI + +  import Pleroma.Factory + +  test "it works for incoming honk announces" do +    user = insert(:user, ap_id: "https://honktest/u/test", local: false) +    other_user = insert(:user) +    {:ok, post} = CommonAPI.post(other_user, %{status: "bonkeronk"}) + +    announce = %{ +      "@context" => "https://www.w3.org/ns/activitystreams", +      "actor" => "https://honktest/u/test", +      "id" => "https://honktest/u/test/bonk/1793M7B9MQ48847vdx", +      "object" => post.data["object"], +      "published" => "2019-06-25T19:33:58Z", +      "to" => "https://www.w3.org/ns/activitystreams#Public", +      "type" => "Announce" +    } + +    {:ok, %Activity{local: false}} = Transmogrifier.handle_incoming(announce) + +    object = Object.get_by_ap_id(post.data["object"]) + +    assert length(object.data["announcements"]) == 1 +    assert user.ap_id in object.data["announcements"] +  end + +  test "it works for incoming announces with actor being inlined (kroeg)" do +    data = File.read!("test/fixtures/kroeg-announce-with-inline-actor.json") |> Poison.decode!() + +    _user = insert(:user, local: false, ap_id: data["actor"]["id"]) +    other_user = insert(:user) + +    {:ok, post} = CommonAPI.post(other_user, %{status: "kroegeroeg"}) + +    data = +      data +      |> put_in(["object", "id"], post.data["object"]) + +    {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) + +    assert data["actor"] == "https://puckipedia.com/" +  end + +  test "it works for incoming announces, fetching the announced object" do +    data = +      File.read!("test/fixtures/mastodon-announce.json") +      |> Poison.decode!() +      |> Map.put("object", "http://mastodon.example.org/users/admin/statuses/99541947525187367") + +    Tesla.Mock.mock(fn +      %{method: :get} -> +        %Tesla.Env{status: 200, body: File.read!("test/fixtures/mastodon-note-object.json")} +    end) + +    _user = insert(:user, local: false, ap_id: data["actor"]) + +    {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) + +    assert data["actor"] == "http://mastodon.example.org/users/admin" +    assert data["type"] == "Announce" + +    assert data["id"] == +             "http://mastodon.example.org/users/admin/statuses/99542391527669785/activity" + +    assert data["object"] == +             "http://mastodon.example.org/users/admin/statuses/99541947525187367" + +    assert(Activity.get_create_by_object_ap_id(data["object"])) +  end + +  @tag capture_log: true +  test "it works for incoming announces with an existing activity" do +    user = insert(:user) +    {:ok, activity} = CommonAPI.post(user, %{status: "hey"}) + +    data = +      File.read!("test/fixtures/mastodon-announce.json") +      |> Poison.decode!() +      |> Map.put("object", activity.data["object"]) + +    _user = insert(:user, local: false, ap_id: data["actor"]) + +    {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) + +    assert data["actor"] == "http://mastodon.example.org/users/admin" +    assert data["type"] == "Announce" + +    assert data["id"] == +             "http://mastodon.example.org/users/admin/statuses/99542391527669785/activity" + +    assert data["object"] == activity.data["object"] + +    assert Activity.get_create_by_object_ap_id(data["object"]).id == activity.id +  end + +  # Ignore inlined activities for now +  @tag skip: true +  test "it works for incoming announces with an inlined activity" do +    data = +      File.read!("test/fixtures/mastodon-announce-private.json") +      |> Poison.decode!() + +    _user = +      insert(:user, +        local: false, +        ap_id: data["actor"], +        follower_address: data["actor"] <> "/followers" +      ) + +    {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) + +    assert data["actor"] == "http://mastodon.example.org/users/admin" +    assert data["type"] == "Announce" + +    assert data["id"] == +             "http://mastodon.example.org/users/admin/statuses/99542391527669785/activity" + +    object = Object.normalize(data["object"]) + +    assert object.data["id"] == "http://mastodon.example.org/@admin/99541947525187368" +    assert object.data["content"] == "this is a private toot" +  end + +  @tag capture_log: true +  test "it rejects incoming announces with an inlined activity from another origin" do +    Tesla.Mock.mock(fn +      %{method: :get} -> %Tesla.Env{status: 404, body: ""} +    end) + +    data = +      File.read!("test/fixtures/bogus-mastodon-announce.json") +      |> Poison.decode!() + +    _user = insert(:user, local: false, ap_id: data["actor"]) + +    assert {:error, e} = Transmogrifier.handle_incoming(data) +  end + +  test "it does not clobber the addressing on announce activities" do +    user = insert(:user) +    {:ok, activity} = CommonAPI.post(user, %{status: "hey"}) + +    data = +      File.read!("test/fixtures/mastodon-announce.json") +      |> Poison.decode!() +      |> Map.put("object", Object.normalize(activity).data["id"]) +      |> Map.put("to", ["http://mastodon.example.org/users/admin/followers"]) +      |> Map.put("cc", []) + +    _user = +      insert(:user, +        local: false, +        ap_id: data["actor"], +        follower_address: "http://mastodon.example.org/users/admin/followers" +      ) + +    {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) + +    assert data["to"] == ["http://mastodon.example.org/users/admin/followers"] +  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/chat_message_test.exs b/test/web/activity_pub/transmogrifier/chat_message_test.exs new file mode 100644 index 000000000..d6736dc3e --- /dev/null +++ b/test/web/activity_pub/transmogrifier/chat_message_test.exs @@ -0,0 +1,153 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.Transmogrifier.ChatMessageTest do +  use Pleroma.DataCase + +  import Pleroma.Factory + +  alias Pleroma.Activity +  alias Pleroma.Chat +  alias Pleroma.Object +  alias Pleroma.Web.ActivityPub.Transmogrifier + +  describe "handle_incoming" do +    test "handles chonks with attachment" do +      data = %{ +        "@context" => "https://www.w3.org/ns/activitystreams", +        "actor" => "https://honk.tedunangst.com/u/tedu", +        "id" => "https://honk.tedunangst.com/u/tedu/honk/x6gt8X8PcyGkQcXxzg1T", +        "object" => %{ +          "attachment" => [ +            %{ +              "mediaType" => "image/jpeg", +              "name" => "298p3RG7j27tfsZ9RQ.jpg", +              "summary" => "298p3RG7j27tfsZ9RQ.jpg", +              "type" => "Document", +              "url" => "https://honk.tedunangst.com/d/298p3RG7j27tfsZ9RQ.jpg" +            } +          ], +          "attributedTo" => "https://honk.tedunangst.com/u/tedu", +          "content" => "", +          "id" => "https://honk.tedunangst.com/u/tedu/chonk/26L4wl5yCbn4dr4y1b", +          "published" => "2020-05-18T01:13:03Z", +          "to" => [ +            "https://dontbulling.me/users/lain" +          ], +          "type" => "ChatMessage" +        }, +        "published" => "2020-05-18T01:13:03Z", +        "to" => [ +          "https://dontbulling.me/users/lain" +        ], +        "type" => "Create" +      } + +      _user = insert(:user, ap_id: data["actor"]) +      _user = insert(:user, ap_id: hd(data["to"])) + +      assert {:ok, _activity} = Transmogrifier.handle_incoming(data) +    end + +    test "it rejects messages that don't contain content" do +      data = +        File.read!("test/fixtures/create-chat-message.json") +        |> Poison.decode!() + +      object = +        data["object"] +        |> Map.delete("content") + +      data = +        data +        |> Map.put("object", object) + +      _author = +        insert(:user, ap_id: data["actor"], local: false, last_refreshed_at: DateTime.utc_now()) + +      _recipient = +        insert(:user, +          ap_id: List.first(data["to"]), +          local: true, +          last_refreshed_at: DateTime.utc_now() +        ) + +      {:error, _} = Transmogrifier.handle_incoming(data) +    end + +    test "it rejects messages that don't concern local users" do +      data = +        File.read!("test/fixtures/create-chat-message.json") +        |> Poison.decode!() + +      _author = +        insert(:user, ap_id: data["actor"], local: false, last_refreshed_at: DateTime.utc_now()) + +      _recipient = +        insert(:user, +          ap_id: List.first(data["to"]), +          local: false, +          last_refreshed_at: DateTime.utc_now() +        ) + +      {:error, _} = Transmogrifier.handle_incoming(data) +    end + +    test "it rejects messages where the `to` field of activity and object don't match" do +      data = +        File.read!("test/fixtures/create-chat-message.json") +        |> Poison.decode!() + +      author = insert(:user, ap_id: data["actor"]) +      _recipient = insert(:user, ap_id: List.first(data["to"])) + +      data = +        data +        |> Map.put("to", author.ap_id) + +      assert match?({:error, _}, Transmogrifier.handle_incoming(data)) +      refute Object.get_by_ap_id(data["object"]["id"]) +    end + +    test "it fetches the actor if they aren't in our system" do +      Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end) + +      data = +        File.read!("test/fixtures/create-chat-message.json") +        |> Poison.decode!() +        |> Map.put("actor", "http://mastodon.example.org/users/admin") +        |> put_in(["object", "actor"], "http://mastodon.example.org/users/admin") + +      _recipient = insert(:user, ap_id: List.first(data["to"]), local: true) + +      {:ok, %Activity{} = _activity} = Transmogrifier.handle_incoming(data) +    end + +    test "it inserts it and creates a chat" do +      data = +        File.read!("test/fixtures/create-chat-message.json") +        |> Poison.decode!() + +      author = +        insert(:user, ap_id: data["actor"], local: false, last_refreshed_at: DateTime.utc_now()) + +      recipient = insert(:user, ap_id: List.first(data["to"]), local: true) + +      {:ok, %Activity{} = activity} = Transmogrifier.handle_incoming(data) +      assert activity.local == false + +      assert activity.actor == author.ap_id +      assert activity.recipients == [recipient.ap_id, author.ap_id] + +      %Object{} = object = Object.get_by_ap_id(activity.data["object"]) + +      assert object +      assert object.data["content"] == "You expected a cute girl? Too bad. alert('XSS')" +      assert match?(%{"firefox" => _}, object.data["emoji"]) + +      refute Chat.get(author.id, recipient.ap_id) +      assert Chat.get(recipient.id, author.ap_id) +    end +  end +end diff --git a/test/web/activity_pub/transmogrifier/follow_handling_test.exs b/test/web/activity_pub/transmogrifier/follow_handling_test.exs index 967389fae..06c39eed6 100644 --- a/test/web/activity_pub/transmogrifier/follow_handling_test.exs +++ b/test/web/activity_pub/transmogrifier/follow_handling_test.exs @@ -5,6 +5,7 @@  defmodule Pleroma.Web.ActivityPub.Transmogrifier.FollowHandlingTest do    use Pleroma.DataCase    alias Pleroma.Activity +  alias Pleroma.Notification    alias Pleroma.Repo    alias Pleroma.User    alias Pleroma.Web.ActivityPub.Transmogrifier @@ -12,6 +13,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.FollowHandlingTest do    import Pleroma.Factory    import Ecto.Query +  import Mock    setup_all do      Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) @@ -57,9 +59,12 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.FollowHandlingTest do        activity = Repo.get(Activity, activity.id)        assert activity.data["state"] == "accept"        assert User.following?(User.get_cached_by_ap_id(data["actor"]), user) + +      [notification] = Notification.for_user(user) +      assert notification.type == "follow"      end -    test "with locked accounts, it does not create a follow or an accept" do +    test "with locked accounts, it does create a Follow, but not an Accept" do        user = insert(:user, locked: true)        data = @@ -81,6 +86,9 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.FollowHandlingTest do          |> Repo.all()        assert Enum.empty?(accepts) + +      [notification] = Notification.for_user(user) +      assert notification.type == "follow_request"      end      test "it works for follow requests when you are already followed, creating a new accept activity" do @@ -144,6 +152,23 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.FollowHandlingTest do        assert activity.data["state"] == "reject"      end +    test "it rejects incoming follow requests if the following errors for some reason" do +      user = insert(:user) + +      data = +        File.read!("test/fixtures/mastodon-follow-activity.json") +        |> Poison.decode!() +        |> Map.put("object", user.ap_id) + +      with_mock Pleroma.User, [:passthrough], follow: fn _, _ -> {:error, :testing} end do +        {:ok, %Activity{data: %{"id" => id}}} = Transmogrifier.handle_incoming(data) + +        %Activity{} = activity = Activity.get_by_ap_id(id) + +        assert activity.data["state"] == "reject" +      end +    end +      test "it works for incoming follow requests from hubzilla" do        user = insert(:user) diff --git a/test/web/activity_pub/transmogrifier/user_update_handling_test.exs b/test/web/activity_pub/transmogrifier/user_update_handling_test.exs new file mode 100644 index 000000000..64636656c --- /dev/null +++ b/test/web/activity_pub/transmogrifier/user_update_handling_test.exs @@ -0,0 +1,159 @@ +# 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.UserUpdateHandlingTest do +  use Pleroma.DataCase + +  alias Pleroma.Activity +  alias Pleroma.User +  alias Pleroma.Web.ActivityPub.Transmogrifier + +  import Pleroma.Factory + +  test "it works for incoming update activities" do +    user = insert(:user, local: false) + +    update_data = File.read!("test/fixtures/mastodon-update.json") |> Poison.decode!() + +    object = +      update_data["object"] +      |> Map.put("actor", user.ap_id) +      |> Map.put("id", user.ap_id) + +    update_data = +      update_data +      |> Map.put("actor", user.ap_id) +      |> Map.put("object", object) + +    {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(update_data) + +    assert data["id"] == update_data["id"] + +    user = User.get_cached_by_ap_id(data["actor"]) +    assert user.name == "gargle" + +    assert user.avatar["url"] == [ +             %{ +               "href" => +                 "https://cd.niu.moe/accounts/avatars/000/033/323/original/fd7f8ae0b3ffedc9.jpeg" +             } +           ] + +    assert user.banner["url"] == [ +             %{ +               "href" => +                 "https://cd.niu.moe/accounts/headers/000/033/323/original/850b3448fa5fd477.png" +             } +           ] + +    assert user.bio == "<p>Some bio</p>" +  end + +  test "it works with alsoKnownAs" do +    %{ap_id: actor} = insert(:user, local: false) + +    assert User.get_cached_by_ap_id(actor).also_known_as == [] + +    {:ok, _activity} = +      "test/fixtures/mastodon-update.json" +      |> File.read!() +      |> Poison.decode!() +      |> Map.put("actor", actor) +      |> Map.update!("object", fn object -> +        object +        |> Map.put("actor", actor) +        |> Map.put("id", actor) +        |> Map.put("alsoKnownAs", [ +          "http://mastodon.example.org/users/foo", +          "http://example.org/users/bar" +        ]) +      end) +      |> Transmogrifier.handle_incoming() + +    assert User.get_cached_by_ap_id(actor).also_known_as == [ +             "http://mastodon.example.org/users/foo", +             "http://example.org/users/bar" +           ] +  end + +  test "it works with custom profile fields" do +    user = insert(:user, local: false) + +    assert user.fields == [] + +    update_data = File.read!("test/fixtures/mastodon-update.json") |> Poison.decode!() + +    object = +      update_data["object"] +      |> Map.put("actor", user.ap_id) +      |> Map.put("id", user.ap_id) + +    update_data = +      update_data +      |> Map.put("actor", user.ap_id) +      |> Map.put("object", object) + +    {:ok, _update_activity} = Transmogrifier.handle_incoming(update_data) + +    user = User.get_cached_by_ap_id(user.ap_id) + +    assert user.fields == [ +             %{"name" => "foo", "value" => "updated"}, +             %{"name" => "foo1", "value" => "updated"} +           ] + +    Pleroma.Config.put([:instance, :max_remote_account_fields], 2) + +    update_data = +      update_data +      |> put_in(["object", "attachment"], [ +        %{"name" => "foo", "type" => "PropertyValue", "value" => "bar"}, +        %{"name" => "foo11", "type" => "PropertyValue", "value" => "bar11"}, +        %{"name" => "foo22", "type" => "PropertyValue", "value" => "bar22"} +      ]) +      |> Map.put("id", update_data["id"] <> ".") + +    {:ok, _} = Transmogrifier.handle_incoming(update_data) + +    user = User.get_cached_by_ap_id(user.ap_id) + +    assert user.fields == [ +             %{"name" => "foo", "value" => "updated"}, +             %{"name" => "foo1", "value" => "updated"} +           ] + +    update_data = +      update_data +      |> put_in(["object", "attachment"], []) +      |> Map.put("id", update_data["id"] <> ".") + +    {:ok, _} = Transmogrifier.handle_incoming(update_data) + +    user = User.get_cached_by_ap_id(user.ap_id) + +    assert user.fields == [] +  end + +  test "it works for incoming update activities which lock the account" do +    user = insert(:user, local: false) + +    update_data = File.read!("test/fixtures/mastodon-update.json") |> Poison.decode!() + +    object = +      update_data["object"] +      |> Map.put("actor", user.ap_id) +      |> Map.put("id", user.ap_id) +      |> Map.put("manuallyApprovesFollowers", true) + +    update_data = +      update_data +      |> Map.put("actor", user.ap_id) +      |> Map.put("object", object) + +    {:ok, %Activity{local: false}} = Transmogrifier.handle_incoming(update_data) + +    user = User.get_cached_by_ap_id(user.ap_id) +    assert user.locked == true +  end +end diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs index 0a54e3bb9..6a53fd3f0 100644 --- a/test/web/activity_pub/transmogrifier_test.exs +++ b/test/web/activity_pub/transmogrifier_test.exs @@ -28,6 +28,63 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do    setup do: clear_config([:instance, :max_remote_account_fields])    describe "handle_incoming" do +    test "it works for incoming notices with tag not being an array (kroeg)" do +      data = File.read!("test/fixtures/kroeg-array-less-emoji.json") |> Poison.decode!() + +      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) +      object = Object.normalize(data["object"]) + +      assert object.data["emoji"] == %{ +               "icon_e_smile" => "https://puckipedia.com/forum/images/smilies/icon_e_smile.png" +             } + +      data = File.read!("test/fixtures/kroeg-array-less-hashtag.json") |> Poison.decode!() + +      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) +      object = Object.normalize(data["object"]) + +      assert "test" in object.data["tag"] +    end + +    test "it works for incoming notices with url not being a string (prismo)" do +      data = File.read!("test/fixtures/prismo-url-map.json") |> Poison.decode!() + +      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) +      object = Object.normalize(data["object"]) + +      assert object.data["url"] == "https://prismo.news/posts/83" +    end + +    test "it cleans up incoming notices which are not really DMs" do +      user = insert(:user) +      other_user = insert(:user) + +      to = [user.ap_id, other_user.ap_id] + +      data = +        File.read!("test/fixtures/mastodon-post-activity.json") +        |> Poison.decode!() +        |> Map.put("to", to) +        |> Map.put("cc", []) + +      object = +        data["object"] +        |> Map.put("to", to) +        |> Map.put("cc", []) + +      data = Map.put(data, "object", object) + +      {:ok, %Activity{data: data, local: false} = activity} = Transmogrifier.handle_incoming(data) + +      assert data["to"] == [] +      assert data["cc"] == to + +      object_data = Object.normalize(activity).data + +      assert object_data["to"] == [] +      assert object_data["cc"] == to +    end +      test "it ignores an incoming notice if we already have it" do        activity = insert(:note_activity) @@ -260,172 +317,6 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do                 "<p>henlo from my Psion netBook</p><p>message sent from my Psion netBook</p>"      end -    test "it works for incoming honk announces" do -      _user = insert(:user, ap_id: "https://honktest/u/test", local: false) -      other_user = insert(:user) -      {:ok, post} = CommonAPI.post(other_user, %{status: "bonkeronk"}) - -      announce = %{ -        "@context" => "https://www.w3.org/ns/activitystreams", -        "actor" => "https://honktest/u/test", -        "id" => "https://honktest/u/test/bonk/1793M7B9MQ48847vdx", -        "object" => post.data["object"], -        "published" => "2019-06-25T19:33:58Z", -        "to" => "https://www.w3.org/ns/activitystreams#Public", -        "type" => "Announce" -      } - -      {:ok, %Activity{local: false}} = Transmogrifier.handle_incoming(announce) -    end - -    test "it works for incoming announces with actor being inlined (kroeg)" do -      data = File.read!("test/fixtures/kroeg-announce-with-inline-actor.json") |> Poison.decode!() - -      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - -      assert data["actor"] == "https://puckipedia.com/" -    end - -    test "it works for incoming notices with tag not being an array (kroeg)" do -      data = File.read!("test/fixtures/kroeg-array-less-emoji.json") |> Poison.decode!() - -      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) -      object = Object.normalize(data["object"]) - -      assert object.data["emoji"] == %{ -               "icon_e_smile" => "https://puckipedia.com/forum/images/smilies/icon_e_smile.png" -             } - -      data = File.read!("test/fixtures/kroeg-array-less-hashtag.json") |> Poison.decode!() - -      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) -      object = Object.normalize(data["object"]) - -      assert "test" in object.data["tag"] -    end - -    test "it works for incoming notices with url not being a string (prismo)" do -      data = File.read!("test/fixtures/prismo-url-map.json") |> Poison.decode!() - -      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) -      object = Object.normalize(data["object"]) - -      assert object.data["url"] == "https://prismo.news/posts/83" -    end - -    test "it cleans up incoming notices which are not really DMs" do -      user = insert(:user) -      other_user = insert(:user) - -      to = [user.ap_id, other_user.ap_id] - -      data = -        File.read!("test/fixtures/mastodon-post-activity.json") -        |> Poison.decode!() -        |> Map.put("to", to) -        |> Map.put("cc", []) - -      object = -        data["object"] -        |> Map.put("to", to) -        |> Map.put("cc", []) - -      data = Map.put(data, "object", object) - -      {:ok, %Activity{data: data, local: false} = activity} = Transmogrifier.handle_incoming(data) - -      assert data["to"] == [] -      assert data["cc"] == to - -      object_data = Object.normalize(activity).data - -      assert object_data["to"] == [] -      assert object_data["cc"] == to -    end - -    test "it works for incoming announces" do -      data = File.read!("test/fixtures/mastodon-announce.json") |> Poison.decode!() - -      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - -      assert data["actor"] == "http://mastodon.example.org/users/admin" -      assert data["type"] == "Announce" - -      assert data["id"] == -               "http://mastodon.example.org/users/admin/statuses/99542391527669785/activity" - -      assert data["object"] == -               "http://mastodon.example.org/users/admin/statuses/99541947525187367" - -      assert Activity.get_create_by_object_ap_id(data["object"]) -    end - -    test "it works for incoming announces with an existing activity" do -      user = insert(:user) -      {:ok, activity} = CommonAPI.post(user, %{status: "hey"}) - -      data = -        File.read!("test/fixtures/mastodon-announce.json") -        |> Poison.decode!() -        |> Map.put("object", activity.data["object"]) - -      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - -      assert data["actor"] == "http://mastodon.example.org/users/admin" -      assert data["type"] == "Announce" - -      assert data["id"] == -               "http://mastodon.example.org/users/admin/statuses/99542391527669785/activity" - -      assert data["object"] == activity.data["object"] - -      assert Activity.get_create_by_object_ap_id(data["object"]).id == activity.id -    end - -    test "it works for incoming announces with an inlined activity" do -      data = -        File.read!("test/fixtures/mastodon-announce-private.json") -        |> Poison.decode!() - -      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - -      assert data["actor"] == "http://mastodon.example.org/users/admin" -      assert data["type"] == "Announce" - -      assert data["id"] == -               "http://mastodon.example.org/users/admin/statuses/99542391527669785/activity" - -      object = Object.normalize(data["object"]) - -      assert object.data["id"] == "http://mastodon.example.org/@admin/99541947525187368" -      assert object.data["content"] == "this is a private toot" -    end - -    @tag capture_log: true -    test "it rejects incoming announces with an inlined activity from another origin" do -      data = -        File.read!("test/fixtures/bogus-mastodon-announce.json") -        |> Poison.decode!() - -      assert :error = Transmogrifier.handle_incoming(data) -    end - -    test "it does not clobber the addressing on announce activities" do -      user = insert(:user) -      {:ok, activity} = CommonAPI.post(user, %{status: "hey"}) - -      data = -        File.read!("test/fixtures/mastodon-announce.json") -        |> Poison.decode!() -        |> Map.put("object", Object.normalize(activity).data["id"]) -        |> Map.put("to", ["http://mastodon.example.org/users/admin/followers"]) -        |> Map.put("cc", []) - -      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) - -      assert data["to"] == ["http://mastodon.example.org/users/admin/followers"] -    end -      test "it ensures that as:Public activities make it to their followers collection" do        user = insert(:user) @@ -510,162 +401,6 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        refute Map.has_key?(object_data, "reaction_count")      end -    test "it works for incoming update activities" do -      data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!() - -      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) -      update_data = File.read!("test/fixtures/mastodon-update.json") |> Poison.decode!() - -      object = -        update_data["object"] -        |> Map.put("actor", data["actor"]) -        |> Map.put("id", data["actor"]) - -      update_data = -        update_data -        |> Map.put("actor", data["actor"]) -        |> Map.put("object", object) - -      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(update_data) - -      assert data["id"] == update_data["id"] - -      user = User.get_cached_by_ap_id(data["actor"]) -      assert user.name == "gargle" - -      assert user.avatar["url"] == [ -               %{ -                 "href" => -                   "https://cd.niu.moe/accounts/avatars/000/033/323/original/fd7f8ae0b3ffedc9.jpeg" -               } -             ] - -      assert user.banner["url"] == [ -               %{ -                 "href" => -                   "https://cd.niu.moe/accounts/headers/000/033/323/original/850b3448fa5fd477.png" -               } -             ] - -      assert user.bio == "<p>Some bio</p>" -    end - -    test "it works with alsoKnownAs" do -      {:ok, %Activity{data: %{"actor" => actor}}} = -        "test/fixtures/mastodon-post-activity.json" -        |> File.read!() -        |> Poison.decode!() -        |> Transmogrifier.handle_incoming() - -      assert User.get_cached_by_ap_id(actor).also_known_as == ["http://example.org/users/foo"] - -      {:ok, _activity} = -        "test/fixtures/mastodon-update.json" -        |> File.read!() -        |> Poison.decode!() -        |> Map.put("actor", actor) -        |> Map.update!("object", fn object -> -          object -          |> Map.put("actor", actor) -          |> Map.put("id", actor) -          |> Map.put("alsoKnownAs", [ -            "http://mastodon.example.org/users/foo", -            "http://example.org/users/bar" -          ]) -        end) -        |> Transmogrifier.handle_incoming() - -      assert User.get_cached_by_ap_id(actor).also_known_as == [ -               "http://mastodon.example.org/users/foo", -               "http://example.org/users/bar" -             ] -    end - -    test "it works with custom profile fields" do -      {:ok, activity} = -        "test/fixtures/mastodon-post-activity.json" -        |> File.read!() -        |> Poison.decode!() -        |> Transmogrifier.handle_incoming() - -      user = User.get_cached_by_ap_id(activity.actor) - -      assert user.fields == [ -               %{"name" => "foo", "value" => "bar"}, -               %{"name" => "foo1", "value" => "bar1"} -             ] - -      update_data = File.read!("test/fixtures/mastodon-update.json") |> Poison.decode!() - -      object = -        update_data["object"] -        |> Map.put("actor", user.ap_id) -        |> Map.put("id", user.ap_id) - -      update_data = -        update_data -        |> Map.put("actor", user.ap_id) -        |> Map.put("object", object) - -      {:ok, _update_activity} = Transmogrifier.handle_incoming(update_data) - -      user = User.get_cached_by_ap_id(user.ap_id) - -      assert user.fields == [ -               %{"name" => "foo", "value" => "updated"}, -               %{"name" => "foo1", "value" => "updated"} -             ] - -      Pleroma.Config.put([:instance, :max_remote_account_fields], 2) - -      update_data = -        put_in(update_data, ["object", "attachment"], [ -          %{"name" => "foo", "type" => "PropertyValue", "value" => "bar"}, -          %{"name" => "foo11", "type" => "PropertyValue", "value" => "bar11"}, -          %{"name" => "foo22", "type" => "PropertyValue", "value" => "bar22"} -        ]) - -      {:ok, _} = Transmogrifier.handle_incoming(update_data) - -      user = User.get_cached_by_ap_id(user.ap_id) - -      assert user.fields == [ -               %{"name" => "foo", "value" => "updated"}, -               %{"name" => "foo1", "value" => "updated"} -             ] - -      update_data = put_in(update_data, ["object", "attachment"], []) - -      {:ok, _} = Transmogrifier.handle_incoming(update_data) - -      user = User.get_cached_by_ap_id(user.ap_id) - -      assert user.fields == [] -    end - -    test "it works for incoming update activities which lock the account" do -      data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!() - -      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) -      update_data = File.read!("test/fixtures/mastodon-update.json") |> Poison.decode!() - -      object = -        update_data["object"] -        |> Map.put("actor", data["actor"]) -        |> Map.put("id", data["actor"]) -        |> Map.put("manuallyApprovesFollowers", true) - -      update_data = -        update_data -        |> Map.put("actor", data["actor"]) -        |> Map.put("object", object) - -      {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(update_data) - -      user = User.get_cached_by_ap_id(data["actor"]) -      assert user.locked == true -    end -      test "it works for incomming unfollows with an existing follow" do        user = insert(:user) @@ -710,56 +445,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) @@ -1188,7 +873,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        {:ok, activity} = CommonAPI.post(user, %{status: "hey", visibility: "private"}) -      {:ok, announce_activity, _} = CommonAPI.repeat(activity.id, user) +      {:ok, announce_activity} = CommonAPI.repeat(activity.id, user)        {:ok, modified} = Transmogrifier.prepare_outgoing(announce_activity.data) @@ -1203,23 +888,28 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        {:ok, activity} =          CommonAPI.post(user, %{status: "hey, @#{other_user.nickname}, how are ya? #2hu"}) -      {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) -      object = modified["object"] +      with_mock Pleroma.Notification, +        get_notified_from_activity: fn _, _ -> [] end do +        {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data) -      expected_mention = %{ -        "href" => other_user.ap_id, -        "name" => "@#{other_user.nickname}", -        "type" => "Mention" -      } +        object = modified["object"] -      expected_tag = %{ -        "href" => Pleroma.Web.Endpoint.url() <> "/tags/2hu", -        "type" => "Hashtag", -        "name" => "#2hu" -      } +        expected_mention = %{ +          "href" => other_user.ap_id, +          "name" => "@#{other_user.nickname}", +          "type" => "Mention" +        } -      assert Enum.member?(object["tag"], expected_tag) -      assert Enum.member?(object["tag"], expected_mention) +        expected_tag = %{ +          "href" => Pleroma.Web.Endpoint.url() <> "/tags/2hu", +          "type" => "Hashtag", +          "name" => "#2hu" +        } + +        refute called(Pleroma.Notification.get_notified_from_activity(:_, :_)) +        assert Enum.member?(object["tag"], expected_tag) +        assert Enum.member?(object["tag"], expected_mention) +      end      end      test "it adds the sensitive property" do @@ -1438,7 +1128,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        }        assert capture_log(fn -> -               :error = Transmogrifier.handle_incoming(data) +               {:error, _} = Transmogrifier.handle_incoming(data)               end) =~ "Object containment failed"      end @@ -1453,7 +1143,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        }        assert capture_log(fn -> -               :error = Transmogrifier.handle_incoming(data) +               {:error, _} = Transmogrifier.handle_incoming(data)               end) =~ "Object containment failed"      end @@ -1468,7 +1158,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        }        assert capture_log(fn -> -               :error = Transmogrifier.handle_incoming(data) +               {:error, _} = Transmogrifier.handle_incoming(data)               end) =~ "Object containment failed"      end    end @@ -1675,9 +1365,6 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        assert modified_object["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873" -      assert modified_object["conversation"] == -               "tag:shitposter.club,2017-05-05:objectType=thread:nonce=3c16e9c2681f6d26" -        assert modified_object["context"] ==                 "tag:shitposter.club,2017-05-05:objectType=thread:nonce=3c16e9c2681f6d26"      end diff --git a/test/web/activity_pub/utils_test.exs b/test/web/activity_pub/utils_test.exs index 9e0a0f1c4..2f9ecb5a3 100644 --- a/test/web/activity_pub/utils_test.exs +++ b/test/web/activity_pub/utils_test.exs @@ -27,16 +27,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 = %{ @@ -334,7 +324,7 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do        assert object = Object.normalize(note_activity)        actor = insert(:user) -      {:ok, announce, _object} = ActivityPub.announce(actor, object) +      {:ok, announce} = CommonAPI.repeat(note_activity.id, actor)        assert Utils.get_existing_announce(actor.ap_id, object) == announce      end    end @@ -344,9 +334,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/activity_pub/views/object_view_test.exs b/test/web/activity_pub/views/object_view_test.exs index 43f0617f0..f0389845d 100644 --- a/test/web/activity_pub/views/object_view_test.exs +++ b/test/web/activity_pub/views/object_view_test.exs @@ -73,7 +73,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectViewTest do      object = Object.normalize(note)      user = insert(:user) -    {:ok, announce_activity, _} = CommonAPI.repeat(note.id, user) +    {:ok, announce_activity} = CommonAPI.repeat(note.id, user)      result = ObjectView.render("object.json", %{object: announce_activity}) diff --git a/test/web/activity_pub/views/user_view_test.exs b/test/web/activity_pub/views/user_view_test.exs index 20b0f223c..bec15a996 100644 --- a/test/web/activity_pub/views/user_view_test.exs +++ b/test/web/activity_pub/views/user_view_test.exs @@ -158,35 +158,4 @@ defmodule Pleroma.Web.ActivityPub.UserViewTest do        assert %{"totalItems" => 1} = UserView.render("following.json", %{user: user})      end    end - -  test "activity collection page aginates correctly" do -    user = insert(:user) - -    posts = -      for i <- 0..25 do -        {:ok, activity} = CommonAPI.post(user, %{status: "post #{i}"}) -        activity -      end - -    # outbox sorts chronologically, newest first, with ten per page -    posts = Enum.reverse(posts) - -    %{"next" => next_url} = -      UserView.render("activity_collection_page.json", %{ -        iri: "#{user.ap_id}/outbox", -        activities: Enum.take(posts, 10) -      }) - -    next_id = Enum.at(posts, 9).id -    assert next_url =~ next_id - -    %{"next" => next_url} = -      UserView.render("activity_collection_page.json", %{ -        iri: "#{user.ap_id}/outbox", -        activities: Enum.take(Enum.drop(posts, 10), 10) -      }) - -    next_id = Enum.at(posts, 19).id -    assert next_url =~ next_id -  end  end | 
