ActivityPub: Don't show announces of your own objects in timeline.
authorlain <lain@soykaf.club>
Wed, 10 Jun 2020 10:10:09 +0000 (12:10 +0200)
committerlain <lain@soykaf.club>
Wed, 10 Jun 2020 10:10:09 +0000 (12:10 +0200)
lib/pleroma/web/activity_pub/activity_pub.ex
lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex
test/web/activity_pub/activity_pub_test.exs

index eb73c95fe6cc8452ee38c51411e7fa3cdf1fad3b..4182275bcdfe62f424c86ae3b7b6cb6a6f911233 100644 (file)
@@ -31,25 +31,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
   require Logger
   require Pleroma.Constants
 
-  # For Announce activities, we filter the recipients based on following status for any actors
-  # that match actual users.  See issue #164 for more information about why this is necessary.
-  defp get_recipients(%{"type" => "Announce"} = data) do
-    to = Map.get(data, "to", [])
-    cc = Map.get(data, "cc", [])
-    bcc = Map.get(data, "bcc", [])
-    actor = User.get_cached_by_ap_id(data["actor"])
-
-    recipients =
-      Enum.filter(Enum.concat([to, cc, bcc]), fn recipient ->
-        case User.get_cached_by_ap_id(recipient) do
-          nil -> true
-          user -> User.following?(user, actor)
-        end
-      end)
-
-    {recipients, to, cc}
-  end
-
   defp get_recipients(%{"type" => "Create"} = data) do
     to = Map.get(data, "to", [])
     cc = Map.get(data, "cc", [])
@@ -702,6 +683,26 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
     end
   end
 
+  defp restrict_announce_object_actor(_query, %{announce_filtering_user: _, skip_preload: true}) do
+    raise "Can't use the child object without preloading!"
+  end
+
+  defp restrict_announce_object_actor(query, %{announce_filtering_user: %{ap_id: actor}}) do
+    from(
+      [activity, object] in query,
+      where:
+        fragment(
+          "?->>'type' != ? or ?->>'actor' != ?",
+          activity.data,
+          "Announce",
+          object.data,
+          ^actor
+        )
+    )
+  end
+
+  defp restrict_announce_object_actor(query, _), do: query
+
   defp restrict_since(query, %{since_id: ""}), do: query
 
   defp restrict_since(query, %{since_id: since_id}) do
@@ -1113,6 +1114,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
     |> restrict_pinned(opts)
     |> restrict_muted_reblogs(restrict_muted_reblogs_opts)
     |> restrict_instance(opts)
+    |> restrict_announce_object_actor(opts)
     |> Activity.restrict_deactivated_users()
     |> exclude_poll_votes(opts)
     |> exclude_invisible_actors(opts)
index 9270ca267a75f27704646f261a3a5c2150dd1191..4bdd46d7e97f99a5d0ad6f5c52938ff7a2ca7eca 100644 (file)
@@ -48,6 +48,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
       |> Map.put(:blocking_user, user)
       |> Map.put(:muting_user, user)
       |> Map.put(:reply_filtering_user, user)
+      |> Map.put(:announce_filtering_user, user)
       |> Map.put(:user, user)
 
     activities =
index 2f65dfc8e2881e48cbc003070ef2ba2d67394e82..e17cc4ab14f5d395abd6504d558e76fc6f233386 100644 (file)
@@ -1643,6 +1643,30 @@ 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"],
+        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