Resolve merge conflicts
This commit is contained in:
commit
196cad46f3
114 changed files with 3178 additions and 914 deletions
|
|
@ -8,6 +8,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
alias Pleroma.Conversation
|
||||
alias Pleroma.Notification
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.Object.Containment
|
||||
alias Pleroma.Object.Fetcher
|
||||
alias Pleroma.Pagination
|
||||
alias Pleroma.Repo
|
||||
|
|
@ -26,19 +27,16 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
# 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 = data["to"] || []
|
||||
cc = data["cc"] || []
|
||||
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 =
|
||||
(to ++ cc)
|
||||
|> Enum.filter(fn recipient ->
|
||||
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)
|
||||
nil -> true
|
||||
user -> User.following?(user, actor)
|
||||
end
|
||||
end)
|
||||
|
||||
|
|
@ -46,17 +44,19 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
end
|
||||
|
||||
defp get_recipients(%{"type" => "Create"} = data) do
|
||||
to = data["to"] || []
|
||||
cc = data["cc"] || []
|
||||
actor = data["actor"] || []
|
||||
recipients = (to ++ cc ++ [actor]) |> Enum.uniq()
|
||||
to = Map.get(data, "to", [])
|
||||
cc = Map.get(data, "cc", [])
|
||||
bcc = Map.get(data, "bcc", [])
|
||||
actor = Map.get(data, "actor", [])
|
||||
recipients = [to, cc, bcc, [actor]] |> Enum.concat() |> Enum.uniq()
|
||||
{recipients, to, cc}
|
||||
end
|
||||
|
||||
defp get_recipients(data) do
|
||||
to = data["to"] || []
|
||||
cc = data["cc"] || []
|
||||
recipients = to ++ cc
|
||||
to = Map.get(data, "to", [])
|
||||
cc = Map.get(data, "cc", [])
|
||||
bcc = Map.get(data, "bcc", [])
|
||||
recipients = Enum.concat([to, cc, bcc])
|
||||
{recipients, to, cc}
|
||||
end
|
||||
|
||||
|
|
@ -126,6 +126,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
{:ok, map} <- MRF.filter(map),
|
||||
{recipients, _, _} = get_recipients(map),
|
||||
{:fake, false, map, recipients} <- {:fake, fake, map, recipients},
|
||||
:ok <- Containment.contain_child(map),
|
||||
{:ok, map, object} <- insert_full_object(map) do
|
||||
{:ok, activity} =
|
||||
Repo.insert(%Activity{
|
||||
|
|
@ -896,13 +897,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
defp maybe_order(query, _), do: query
|
||||
|
||||
def fetch_activities_query(recipients, opts \\ %{}) do
|
||||
base_query = from(activity in Activity)
|
||||
|
||||
config = %{
|
||||
skip_thread_containment: Config.get([:instance, :skip_thread_containment])
|
||||
}
|
||||
|
||||
base_query
|
||||
Activity
|
||||
|> maybe_preload_objects(opts)
|
||||
|> maybe_preload_bookmarks(opts)
|
||||
|> maybe_set_thread_muted_field(opts)
|
||||
|
|
@ -931,11 +930,31 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
end
|
||||
|
||||
def fetch_activities(recipients, opts \\ %{}) do
|
||||
fetch_activities_query(recipients, opts)
|
||||
list_memberships = Pleroma.List.memberships(opts["user"])
|
||||
|
||||
fetch_activities_query(recipients ++ list_memberships, opts)
|
||||
|> Pagination.fetch_paginated(opts)
|
||||
|> Enum.reverse()
|
||||
|> maybe_update_cc(list_memberships, opts["user"])
|
||||
end
|
||||
|
||||
defp maybe_update_cc(activities, list_memberships, %User{ap_id: user_ap_id})
|
||||
when is_list(list_memberships) and length(list_memberships) > 0 do
|
||||
Enum.map(activities, fn
|
||||
%{data: %{"bcc" => bcc}} = activity when is_list(bcc) and length(bcc) > 0 ->
|
||||
if Enum.any?(bcc, &(&1 in list_memberships)) do
|
||||
update_in(activity.data["cc"], &[user_ap_id | &1])
|
||||
else
|
||||
activity
|
||||
end
|
||||
|
||||
activity ->
|
||||
activity
|
||||
end)
|
||||
end
|
||||
|
||||
defp maybe_update_cc(activities, _, _), do: activities
|
||||
|
||||
def fetch_activities_bounded_query(query, recipients, recipients_with_public) do
|
||||
from(activity in query,
|
||||
where:
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|
|||
alias Pleroma.Object.Fetcher
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||
alias Pleroma.Web.ActivityPub.InternalFetchActor
|
||||
alias Pleroma.Web.ActivityPub.ObjectView
|
||||
alias Pleroma.Web.ActivityPub.Relay
|
||||
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||
|
|
@ -206,9 +207,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|
|||
json(conn, dgettext("errors", "error"))
|
||||
end
|
||||
|
||||
def relay(conn, _params) do
|
||||
with %User{} = user <- Relay.get_actor(),
|
||||
{:ok, user} <- User.ensure_keys_present(user) do
|
||||
defp represent_service_actor(%User{} = user, conn) do
|
||||
with {:ok, user} <- User.ensure_keys_present(user) do
|
||||
conn
|
||||
|> put_resp_header("content-type", "application/activity+json")
|
||||
|> json(UserView.render("user.json", %{user: user}))
|
||||
|
|
@ -217,6 +217,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|
|||
end
|
||||
end
|
||||
|
||||
defp represent_service_actor(nil, _), do: {:error, :not_found}
|
||||
|
||||
def relay(conn, _params) do
|
||||
Relay.get_actor()
|
||||
|> represent_service_actor(conn)
|
||||
end
|
||||
|
||||
def internal_fetch(conn, _params) do
|
||||
InternalFetchActor.get_actor()
|
||||
|> represent_service_actor(conn)
|
||||
end
|
||||
|
||||
def whoami(%{assigns: %{user: %User{} = user}} = conn, _params) do
|
||||
conn
|
||||
|> put_resp_header("content-type", "application/activity+json")
|
||||
|
|
|
|||
20
lib/pleroma/web/activity_pub/internal_fetch_actor.ex
Normal file
20
lib/pleroma/web/activity_pub/internal_fetch_actor.ex
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.ActivityPub.InternalFetchActor do
|
||||
alias Pleroma.User
|
||||
|
||||
require Logger
|
||||
|
||||
def init do
|
||||
# Wait for everything to settle.
|
||||
Process.sleep(1000 * 5)
|
||||
get_actor()
|
||||
end
|
||||
|
||||
def get_actor do
|
||||
"#{Pleroma.Web.Endpoint.url()}/internal/fetch"
|
||||
|> User.get_or_create_service_actor_by_ap_id("internal.fetch")
|
||||
end
|
||||
end
|
||||
24
lib/pleroma/web/activity_pub/mrf/mention_policy.ex
Normal file
24
lib/pleroma/web/activity_pub/mrf/mention_policy.ex
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.ActivityPub.MRF.MentionPolicy do
|
||||
@moduledoc "Block messages which mention a user"
|
||||
|
||||
@behaviour Pleroma.Web.ActivityPub.MRF
|
||||
|
||||
@impl true
|
||||
def filter(%{"type" => "Create"} = message) do
|
||||
reject_actors = Pleroma.Config.get([:mrf_mention, :actors], [])
|
||||
recipients = (message["to"] || []) ++ (message["cc"] || [])
|
||||
|
||||
if Enum.any?(recipients, fn recipient -> Enum.member?(reject_actors, recipient) end) do
|
||||
{:reject, nil}
|
||||
else
|
||||
{:ok, message}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def filter(message), do: {:ok, message}
|
||||
end
|
||||
|
|
@ -92,18 +92,68 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
|
|||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Publishes an activity to all relevant peers.
|
||||
"""
|
||||
def publish(%User{} = actor, %Activity{} = activity) do
|
||||
remote_followers =
|
||||
defp recipients(actor, activity) do
|
||||
followers =
|
||||
if actor.follower_address in activity.recipients do
|
||||
{:ok, followers} = User.get_followers(actor)
|
||||
followers |> Enum.filter(&(!&1.local))
|
||||
Enum.filter(followers, &(!&1.local))
|
||||
else
|
||||
[]
|
||||
end
|
||||
|
||||
Pleroma.Web.Salmon.remote_users(actor, activity) ++ followers
|
||||
end
|
||||
|
||||
defp get_cc_ap_ids(ap_id, recipients) do
|
||||
host = Map.get(URI.parse(ap_id), :host)
|
||||
|
||||
recipients
|
||||
|> Enum.filter(fn %User{ap_id: ap_id} -> Map.get(URI.parse(ap_id), :host) == host end)
|
||||
|> Enum.map(& &1.ap_id)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Publishes an activity with BCC to all relevant peers.
|
||||
"""
|
||||
|
||||
def publish(actor, %{data: %{"bcc" => bcc}} = activity) when is_list(bcc) and bcc != [] do
|
||||
public = is_public?(activity)
|
||||
{:ok, data} = Transmogrifier.prepare_outgoing(activity.data)
|
||||
|
||||
recipients = recipients(actor, activity)
|
||||
|
||||
recipients
|
||||
|> Enum.filter(&User.ap_enabled?/1)
|
||||
|> Enum.map(fn %{info: %{source_data: data}} -> data["inbox"] end)
|
||||
|> Enum.filter(fn inbox -> should_federate?(inbox, public) end)
|
||||
|> Instances.filter_reachable()
|
||||
|> Enum.each(fn {inbox, unreachable_since} ->
|
||||
%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)
|
||||
|> Jason.encode!()
|
||||
|
||||
Pleroma.Web.Federator.Publisher.enqueue_one(__MODULE__, %{
|
||||
inbox: inbox,
|
||||
json: json,
|
||||
actor: actor,
|
||||
id: activity.data["id"],
|
||||
unreachable_since: unreachable_since
|
||||
})
|
||||
end)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Publishes an activity to all relevant peers.
|
||||
"""
|
||||
def publish(%User{} = actor, %Activity{} = activity) do
|
||||
public = is_public?(activity)
|
||||
|
||||
if public && Config.get([:instance, :allow_relay]) do
|
||||
|
|
@ -114,7 +164,7 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
|
|||
{:ok, data} = Transmogrifier.prepare_outgoing(activity.data)
|
||||
json = Jason.encode!(data)
|
||||
|
||||
(Pleroma.Web.Salmon.remote_users(activity) ++ remote_followers)
|
||||
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"]
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@ defmodule Pleroma.Web.ActivityPub.Relay do
|
|||
require Logger
|
||||
|
||||
def get_actor do
|
||||
User.get_or_create_instance_user()
|
||||
"#{Pleroma.Web.Endpoint.url()}/relay"
|
||||
|> User.get_or_create_service_actor_by_ap_id()
|
||||
end
|
||||
|
||||
def follow(target_instance) do
|
||||
|
|
|
|||
|
|
@ -814,13 +814,16 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
|
||||
def prepare_outgoing(%{"type" => "Create", "object" => object_id} = data) do
|
||||
object =
|
||||
Object.normalize(object_id).data
|
||||
object_id
|
||||
|> Object.normalize()
|
||||
|> Map.get(:data)
|
||||
|> prepare_object
|
||||
|
||||
data =
|
||||
data
|
||||
|> Map.put("object", object)
|
||||
|> Map.merge(Utils.make_json_ld_header())
|
||||
|> Map.delete("bcc")
|
||||
|
||||
{:ok, data}
|
||||
end
|
||||
|
|
|
|||
|
|
@ -25,12 +25,8 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|
|||
|
||||
# Some implementations send the actor URI as the actor field, others send the entire actor object,
|
||||
# so figure out what the actor's URI is based on what we have.
|
||||
def get_ap_id(object) do
|
||||
case object do
|
||||
%{"id" => id} -> id
|
||||
id -> id
|
||||
end
|
||||
end
|
||||
def get_ap_id(%{"id" => id} = _), do: id
|
||||
def get_ap_id(id), do: id
|
||||
|
||||
def normalize_params(params) do
|
||||
Map.put(params, "actor", get_ap_id(params["actor"]))
|
||||
|
|
|
|||
|
|
@ -31,8 +31,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do
|
|||
|
||||
def render("endpoints.json", _), do: %{}
|
||||
|
||||
# the instance itself is not a Person, but instead an Application
|
||||
def render("user.json", %{user: %{nickname: nil} = user}) do
|
||||
def render("service.json", %{user: user}) do
|
||||
{:ok, user} = User.ensure_keys_present(user)
|
||||
{:ok, _, public_key} = Keys.keys_from_pem(user.info.keys)
|
||||
public_key = :public_key.pem_entry_encode(:SubjectPublicKeyInfo, public_key)
|
||||
|
|
@ -47,7 +46,8 @@ defmodule Pleroma.Web.ActivityPub.UserView do
|
|||
"followers" => "#{user.ap_id}/followers",
|
||||
"inbox" => "#{user.ap_id}/inbox",
|
||||
"name" => "Pleroma",
|
||||
"summary" => "Virtual actor for Pleroma relay",
|
||||
"summary" =>
|
||||
"An internal service actor for this Pleroma instance. No user-serviceable parts inside.",
|
||||
"url" => user.ap_id,
|
||||
"manuallyApprovesFollowers" => false,
|
||||
"publicKey" => %{
|
||||
|
|
@ -60,6 +60,13 @@ defmodule Pleroma.Web.ActivityPub.UserView do
|
|||
|> Map.merge(Utils.make_json_ld_header())
|
||||
end
|
||||
|
||||
# the instance itself is not a Person, but instead an Application
|
||||
def render("user.json", %{user: %User{nickname: nil} = user}),
|
||||
do: render("service.json", %{user: user})
|
||||
|
||||
def render("user.json", %{user: %User{nickname: "internal." <> _} = user}),
|
||||
do: render("service.json", %{user: user})
|
||||
|
||||
def render("user.json", %{user: user}) do
|
||||
{:ok, user} = User.ensure_keys_present(user)
|
||||
{:ok, _, public_key} = Keys.keys_from_pem(user.info.keys)
|
||||
|
|
|
|||
|
|
@ -34,6 +34,20 @@ defmodule Pleroma.Web.ActivityPub.Visibility do
|
|||
!is_public?(activity) && !is_private?(activity)
|
||||
end
|
||||
|
||||
def is_list?(%{data: %{"listMessage" => _}}), do: true
|
||||
def is_list?(_), do: false
|
||||
|
||||
def visible_for_user?(%{actor: ap_id}, %User{ap_id: ap_id}), do: true
|
||||
|
||||
def visible_for_user?(%{data: %{"listMessage" => list_ap_id}} = activity, %User{} = user) do
|
||||
user.ap_id in activity.data["to"] ||
|
||||
list_ap_id
|
||||
|> Pleroma.List.get_by_ap_id()
|
||||
|> Pleroma.List.member?(user)
|
||||
end
|
||||
|
||||
def visible_for_user?(%{data: %{"listMessage" => _}}, nil), do: false
|
||||
|
||||
def visible_for_user?(activity, nil) do
|
||||
is_public?(activity)
|
||||
end
|
||||
|
|
@ -73,6 +87,9 @@ defmodule Pleroma.Web.ActivityPub.Visibility do
|
|||
object.data["directMessage"] == true ->
|
||||
"direct"
|
||||
|
||||
is_binary(object.data["listMessage"]) ->
|
||||
"list"
|
||||
|
||||
length(cc) > 0 ->
|
||||
"private"
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue