Browse Source

Merge branch 'hardening/stop-misusing-sharedinbox' into 'develop'

activitypub: publisher: align sharedinbox usage with AP specification rules

See merge request pleroma/pleroma!1464
tags/v1.1.4
Haelwenn 5 years ago
parent
commit
674ad5e1df
3 changed files with 154 additions and 2 deletions
  1. +1
    -0
      CHANGELOG.md
  2. +41
    -2
      lib/pleroma/web/activity_pub/publisher.ex
  3. +112
    -0
      test/web/activity_pub/publisher_test.exs

+ 1
- 0
CHANGELOG.md View File

@@ -23,6 +23,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- ActivityPub C2S: follower/following collection pages being inaccessible even when authentifucated if `hide_followers`/ `hide_follows` was set
- Existing user id not being preserved on insert conflict
- Rich Media: Parser failing when no TTL can be found by image TTL setters
- ActivityPub S2S: sharedInbox usage has been mostly aligned with the rules in the AP specification.

### Added
- MRF: Support for priming the mediaproxy cache (`Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy`)


+ 41
- 2
lib/pleroma/web/activity_pub/publisher.ex View File

@@ -112,6 +112,45 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
|> Enum.map(& &1.ap_id)
end

@as_public "https://www.w3.org/ns/activitystreams#Public"

defp maybe_use_sharedinbox(%User{info: %{source_data: data}}),
do: (is_map(data["endpoints"]) && Map.get(data["endpoints"], "sharedInbox")) || data["inbox"]

@doc """
Determine a user inbox to use based on heuristics. These heuristics
are based on an approximation of the ``sharedInbox`` rules in the
[ActivityPub specification][ap-sharedinbox].

Please do not edit this function (or its children) without reading
the spec, as editing the code is likely to introduce some breakage
without some familiarity.

[ap-sharedinbox]: https://www.w3.org/TR/activitypub/#shared-inbox-delivery
"""
def determine_inbox(
%Activity{data: activity_data},
%User{info: %{source_data: data}} = user
) do
to = activity_data["to"] || []
cc = activity_data["cc"] || []
type = activity_data["type"]

cond do
type == "Delete" ->
maybe_use_sharedinbox(user)

@as_public in to || @as_public in cc ->
maybe_use_sharedinbox(user)

length(to) + length(cc) > 1 ->
maybe_use_sharedinbox(user)

true ->
data["inbox"]
end
end

@doc """
Publishes an activity with BCC to all relevant peers.
"""
@@ -166,8 +205,8 @@ defmodule Pleroma.Web.ActivityPub.Publisher do

recipients(actor, activity)
|> Enum.filter(fn user -> User.ap_enabled?(user) end)
|> Enum.map(fn %{info: %{source_data: data}} ->
(is_map(data["endpoints"]) && Map.get(data["endpoints"], "sharedInbox")) || data["inbox"]
|> Enum.map(fn %User{} = user ->
determine_inbox(activity, user)
end)
|> Enum.uniq()
|> Enum.filter(fn inbox -> should_federate?(inbox, public) end)


+ 112
- 0
test/web/activity_pub/publisher_test.exs View File

@@ -0,0 +1,112 @@
# Pleroma: A lightweight social networking server
# Copyright © 2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only

defmodule Pleroma.Web.ActivityPub.PublisherTest do
use Pleroma.DataCase

import Pleroma.Factory

alias Pleroma.Activity
alias Pleroma.Web.ActivityPub.Publisher

@as_public "https://www.w3.org/ns/activitystreams#Public"

describe "determine_inbox/2" do
test "it returns sharedInbox for messages involving as:Public in to" do
user =
insert(:user, %{
info: %{source_data: %{"endpoints" => %{"sharedInbox" => "http://example.com/inbox"}}}
})

activity = %Activity{
data: %{"to" => [@as_public], "cc" => [user.follower_address]}
}

assert Publisher.determine_inbox(activity, user) == "http://example.com/inbox"
end

test "it returns sharedInbox for messages involving as:Public in cc" do
user =
insert(:user, %{
info: %{source_data: %{"endpoints" => %{"sharedInbox" => "http://example.com/inbox"}}}
})

activity = %Activity{
data: %{"cc" => [@as_public], "to" => [user.follower_address]}
}

assert Publisher.determine_inbox(activity, user) == "http://example.com/inbox"
end

test "it returns sharedInbox for messages involving multiple recipients in to" do
user =
insert(:user, %{
info: %{source_data: %{"endpoints" => %{"sharedInbox" => "http://example.com/inbox"}}}
})

user_two = insert(:user)
user_three = insert(:user)

activity = %Activity{
data: %{"cc" => [], "to" => [user.ap_id, user_two.ap_id, user_three.ap_id]}
}

assert Publisher.determine_inbox(activity, user) == "http://example.com/inbox"
end

test "it returns sharedInbox for messages involving multiple recipients in cc" do
user =
insert(:user, %{
info: %{source_data: %{"endpoints" => %{"sharedInbox" => "http://example.com/inbox"}}}
})

user_two = insert(:user)
user_three = insert(:user)

activity = %Activity{
data: %{"to" => [], "cc" => [user.ap_id, user_two.ap_id, user_three.ap_id]}
}

assert Publisher.determine_inbox(activity, user) == "http://example.com/inbox"
end

test "it returns sharedInbox for messages involving multiple recipients in total" do
user =
insert(:user, %{
info: %{
source_data: %{
"inbox" => "http://example.com/personal-inbox",
"endpoints" => %{"sharedInbox" => "http://example.com/inbox"}
}
}
})

user_two = insert(:user)

activity = %Activity{
data: %{"to" => [user_two.ap_id], "cc" => [user.ap_id]}
}

assert Publisher.determine_inbox(activity, user) == "http://example.com/inbox"
end

test "it returns inbox for messages involving single recipients in total" do
user =
insert(:user, %{
info: %{
source_data: %{
"inbox" => "http://example.com/personal-inbox",
"endpoints" => %{"sharedInbox" => "http://example.com/inbox"}
}
}
})

activity = %Activity{
data: %{"to" => [user.ap_id], "cc" => []}
}

assert Publisher.determine_inbox(activity, user) == "http://example.com/personal-inbox"
end
end
end

Loading…
Cancel
Save