Mastodon API: Fix lists leaking private posts

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
This commit is contained in:
rinpatch 2019-05-31 15:25:17 +03:00
parent a9eaa55885
commit d9c0650ff9
3 changed files with 44 additions and 16 deletions

View File

@ -118,6 +118,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## Removed ## Removed
- Configuration: `config :pleroma, :fe` in favor of the more flexible `config :pleroma, :frontend_configurations` - 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 ## [0.9.9999] - 2019-04-05
### Security ### Security
- Mastodon API: Fix content warnings skipping HTML sanitization - Mastodon API: Fix content warnings skipping HTML sanitization

View File

@ -653,20 +653,6 @@ defp restrict_tag(query, %{"tag" => tag}) when is_binary(tag) do
defp restrict_tag(query, _), do: query 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, [], _user), do: query
defp restrict_recipients(query, recipients, nil) do defp restrict_recipients(query, recipients, nil) do
@ -889,9 +875,18 @@ def fetch_activities(recipients, opts \\ %{}) do
|> Enum.reverse() |> Enum.reverse()
end 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) fetch_activities_query([], opts)
|> restrict_to_cc(recipients_to, recipients_cc) |> fetch_activities_bounded_query(recipients, recipients_with_public)
|> Pagination.fetch_paginated(opts) |> Pagination.fetch_paginated(opts)
|> Enum.reverse() |> Enum.reverse()
end end

View File

@ -1186,4 +1186,33 @@ test "it can create a Flag activity" do
def data_uri do def data_uri do
File.read!("test/fixtures/avatar_data_uri") File.read!("test/fixtures/avatar_data_uri")
end 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 end