Mastodon API: Fix lists leaking private posts
authorrinpatch <rinpatch@sdf.org>
Fri, 31 May 2019 12:25:17 +0000 (15:25 +0300)
committerrinpatch <rinpatch@sdf.org>
Fri, 31 May 2019 12:25:17 +0000 (15:25 +0300)
Our previous list visibility resolver grabbed posts if either follower
collection of the user in a list who is followed is in `to` or if
follower collection of the user in a list was in `cc`. This not only
missed unlisted posts but also lead to leaking private posts when
`fix_explicit_addressing` mistakingly started putting follower collections
to `cc` (also fixed in this MR).

Reported by @kurisu@iscute.moe via a DM

CHANGELOG.md
lib/pleroma/web/activity_pub/activity_pub.ex
test/web/activity_pub/activity_pub_test.exs

index f689160e90635114d2c53ca14aa135b4f3242d8e..716cf2a46e08505a14ae0ffb129117dd0baa05c3 100644 (file)
@@ -118,6 +118,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 ## Removed
 - Configuration: `config :pleroma, :fe` in favor of the more flexible `config :pleroma, :frontend_configurations`
 
+## [0.9.99999] - 2019-05-31
+### Security
+- Mastodon API: Fix lists leaking private posts
+
 ## [0.9.9999] - 2019-04-05
 ### Security
 - Mastodon API: Fix content warnings skipping HTML sanitization
index aa0229db7f3e77d89620c6f329d6ed3cb2acbb0e..498b1a342f594fc6c8096ccaa20b3b88a0746bc6 100644 (file)
@@ -653,20 +653,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
 
   defp restrict_tag(query, _), do: query
 
-  defp restrict_to_cc(query, recipients_to, recipients_cc) do
-    from(
-      activity in query,
-      where:
-        fragment(
-          "(?->'to' \\?| ?) or (?->'cc' \\?| ?)",
-          activity.data,
-          ^recipients_to,
-          activity.data,
-          ^recipients_cc
-        )
-    )
-  end
-
   defp restrict_recipients(query, [], _user), do: query
 
   defp restrict_recipients(query, recipients, nil) do
@@ -889,9 +875,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
     |> Enum.reverse()
   end
 
-  def fetch_activities_bounded(recipients_to, recipients_cc, opts \\ %{}) do
+  def fetch_activities_bounded_query(query, recipients, recipients_with_public) do
+    from(activity in query,
+      where:
+        fragment("? && ?", activity.recipients, ^recipients) or
+          (fragment("? && ?", activity.recipients, ^recipients_with_public) and
+             "https://www.w3.org/ns/activitystreams#Public" in activity.recipients)
+    )
+  end
+
+  def fetch_activities_bounded(recipients, recipients_with_public, opts \\ %{}) do
     fetch_activities_query([], opts)
-    |> restrict_to_cc(recipients_to, recipients_cc)
+    |> fetch_activities_bounded_query(recipients, recipients_with_public)
     |> Pagination.fetch_paginated(opts)
     |> Enum.reverse()
   end
index f743f380beb42ce3056e3762cb0d81ab0a95de79..76586ee4ada3977ea2d6d5bb665568d7377f8814 100644 (file)
@@ -1186,4 +1186,33 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
   def data_uri do
     File.read!("test/fixtures/avatar_data_uri")
   end
+
+  describe "fetch_activities_bounded" do
+    test "fetches private posts for followed users" do
+      user = insert(:user)
+
+      {:ok, activity} =
+        CommonAPI.post(user, %{
+          "status" => "thought I looked cute might delete later :3",
+          "visibility" => "private"
+        })
+
+      [result] = ActivityPub.fetch_activities_bounded([user.follower_address], [])
+      assert result.id == activity.id
+    end
+
+    test "fetches only public posts for other users" do
+      user = insert(:user)
+      {:ok, activity} = CommonAPI.post(user, %{"status" => "#cofe", "visibility" => "public"})
+
+      {:ok, _private_activity} =
+        CommonAPI.post(user, %{
+          "status" => "why is tenshi eating a corndog so cute?",
+          "visibility" => "private"
+        })
+
+      [result] = ActivityPub.fetch_activities_bounded([], [user.follower_address])
+      assert result.id == activity.id
+    end
+  end
 end