alias Pleroma.Web.ActivityPub.Relay
alias Pleroma.Web.ActivityPub.Transmogrifier
+ require Pleroma.Constants
+
import Pleroma.Web.ActivityPub.Visibility
@behaviour Pleroma.Web.Federator.Publisher
"""
def publish_one(%{inbox: inbox, json: json, actor: %User{} = actor, id: id} = params) do
Logger.info("Federating #{id} to #{inbox}")
- host = URI.parse(inbox).host
+ %{host: host, path: path} = URI.parse(inbox)
digest = "SHA-256=" <> (:crypto.hash(:sha256, json) |> Base.encode64())
signature =
Pleroma.Signature.sign(actor, %{
+ "(request-target)": "post #{path}",
host: host,
"content-length": byte_size(json),
digest: digest,
if public do
true
else
- inbox_info = URI.parse(inbox)
- !Enum.member?(Config.get([:instance, :quarantined_instances], []), inbox_info.host)
+ %{host: host} = URI.parse(inbox)
+
+ quarantined_instances =
+ Config.get([:instance, :quarantined_instances], [])
+ |> Pleroma.Web.ActivityPub.MRF.subdomains_regex()
+
+ !Pleroma.Web.ActivityPub.MRF.subdomain_match?(quarantined_instances, host)
end
end
+ @spec recipients(User.t(), Activity.t()) :: list(User.t()) | []
defp recipients(actor, activity) do
- followers =
+ {:ok, followers} =
if actor.follower_address in activity.recipients do
- {:ok, followers} = User.get_followers(actor)
- Enum.filter(followers, &(!&1.local))
+ User.get_external_followers(actor)
else
- []
+ {:ok, []}
end
Pleroma.Web.Salmon.remote_users(actor, activity) ++ followers
|> Enum.map(& &1.ap_id)
end
+ 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)
+
+ Pleroma.Constants.as_public() in to || Pleroma.Constants.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.
"""
%User{ap_id: ap_id} =
Enum.find(recipients, fn %{info: %{source_data: data}} -> data["inbox"] == inbox end)
+ # Get all the recipients on the same host and add them to cc. Otherwise, a remote
+ # instance would only accept a first message for the first recipient and ignore the rest.
cc = get_cc_ap_ids(ap_id, recipients)
json =
data
|> Map.put("cc", cc)
- |> Map.put("directMessage", true)
|> Jason.encode!()
Pleroma.Web.Federator.Publisher.enqueue_one(__MODULE__, %{
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)