diff options
Diffstat (limited to 'lib/pleroma/web/activity_pub')
-rw-r--r-- | lib/pleroma/web/activity_pub/activity_pub.ex | 49 | ||||
-rw-r--r-- | lib/pleroma/web/activity_pub/activity_pub_controller.ex | 4 | ||||
-rw-r--r-- | lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex | 82 | ||||
-rw-r--r-- | lib/pleroma/web/activity_pub/transmogrifier.ex | 26 | ||||
-rw-r--r-- | lib/pleroma/web/activity_pub/utils.ex | 2 | ||||
-rw-r--r-- | lib/pleroma/web/activity_pub/views/user_view.ex | 75 |
6 files changed, 164 insertions, 74 deletions
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index c46d8233e..8d3116839 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -172,9 +172,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do # only accept false as false value local = !(params[:local] == false) - with data <- %{"to" => to, "type" => "Accept", "actor" => actor, "object" => object}, + with data <- %{"to" => to, "type" => "Accept", "actor" => actor.ap_id, "object" => object}, {:ok, activity} <- insert(data, local), - :ok <- maybe_federate(activity) do + :ok <- maybe_federate(activity), + _ <- User.update_follow_request_count(actor) do {:ok, activity} end end @@ -183,9 +184,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do # only accept false as false value local = !(params[:local] == false) - with data <- %{"to" => to, "type" => "Reject", "actor" => actor, "object" => object}, + with data <- %{"to" => to, "type" => "Reject", "actor" => actor.ap_id, "object" => object}, {:ok, activity} <- insert(data, local), - :ok <- maybe_federate(activity) do + :ok <- maybe_federate(activity), + _ <- User.update_follow_request_count(actor) do {:ok, activity} end end @@ -283,7 +285,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do def follow(follower, followed, activity_id \\ nil, local \\ true) do with data <- make_follow_data(follower, followed, activity_id), {:ok, activity} <- insert(data, local), - :ok <- maybe_federate(activity) do + :ok <- maybe_federate(activity), + _ <- User.update_follow_request_count(followed) do {:ok, activity} end end @@ -293,7 +296,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do {:ok, follow_activity} <- update_follow_state(follow_activity, "cancelled"), unfollow_data <- make_unfollow_data(follower, followed, follow_activity, activity_id), {:ok, activity} <- insert(unfollow_data, local), - :ok <- maybe_federate(activity) do + :ok <- maybe_federate(activity), + _ <- User.update_follow_request_count(followed) do {:ok, activity} end end @@ -753,21 +757,19 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do public = is_public?(activity) - reachable_inboxes_metadata = - (Pleroma.Web.Salmon.remote_users(activity) ++ remote_followers) - |> 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"] - end) - |> Enum.uniq() - |> Enum.filter(fn inbox -> should_federate?(inbox, public) end) - |> Instances.filter_reachable() - {:ok, data} = Transmogrifier.prepare_outgoing(activity.data) json = Jason.encode!(data) - Enum.each(reachable_inboxes_metadata, fn {inbox, unreachable_since} -> - Federator.enqueue(:publish_single_ap, %{ + (Pleroma.Web.Salmon.remote_users(activity) ++ remote_followers) + |> 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"] + end) + |> Enum.uniq() + |> Enum.filter(fn inbox -> should_federate?(inbox, public) end) + |> Instances.filter_reachable() + |> Enum.each(fn {inbox, unreachable_since} -> + Federator.publish_single_ap(%{ inbox: inbox, json: json, actor: actor, @@ -818,8 +820,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do if object = Object.get_cached_by_ap_id(id) do {:ok, object} else - Logger.info("Fetching #{id} via AP") - with {:ok, data} <- fetch_and_contain_remote_object_from_id(id), nil <- Object.normalize(data), params <- %{ @@ -851,7 +851,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do end def fetch_and_contain_remote_object_from_id(id) do - Logger.info("Fetching #{id} via AP") + Logger.info("Fetching object #{id} via AP") with true <- String.starts_with?(id, "http"), {:ok, %{body: body, status: code}} when code in 200..299 <- @@ -878,7 +878,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do end def is_private?(activity) do - !is_public?(activity) && Enum.any?(activity.data["to"], &String.contains?(&1, "/followers")) + unless is_public?(activity) do + follower_address = User.get_cached_by_ap_id(activity.data["actor"]).follower_address + Enum.any?(activity.data["to"], &(&1 == follower_address)) + else + false + end end def is_direct?(%Activity{data: %{"directMessage" => true}}), do: true diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex index 69879476e..2bea51311 100644 --- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex +++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex @@ -155,13 +155,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do with %User{} = user <- User.get_cached_by_nickname(nickname), true <- Utils.recipient_in_message(user.ap_id, params), params <- Utils.maybe_splice_recipient(user.ap_id, params) do - Federator.enqueue(:incoming_ap_doc, params) + Federator.incoming_ap_doc(params) json(conn, "ok") end end def inbox(%{assigns: %{valid_signature: true}} = conn, params) do - Federator.enqueue(:incoming_ap_doc, params) + Federator.incoming_ap_doc(params) json(conn, "ok") end diff --git a/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex b/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex index 4c6e612b2..6736f3cb9 100644 --- a/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex @@ -6,40 +6,80 @@ defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicy do alias Pleroma.User @behaviour Pleroma.Web.ActivityPub.MRF - defp delist_message(message) do + defp delist_message(message, threshold) when threshold > 0 do follower_collection = User.get_cached_by_ap_id(message["actor"]).follower_address - message - |> Map.put("to", [follower_collection]) - |> Map.put("cc", ["https://www.w3.org/ns/activitystreams#Public"]) + follower_collection? = Enum.member?(message["to"] ++ message["cc"], follower_collection) + + message = + case get_recipient_count(message) do + {:public, recipients} + when follower_collection? and recipients > threshold -> + message + |> Map.put("to", [follower_collection]) + |> Map.put("cc", ["https://www.w3.org/ns/activitystreams#Public"]) + + {:public, recipients} when recipients > threshold -> + message + |> Map.put("to", []) + |> Map.put("cc", ["https://www.w3.org/ns/activitystreams#Public"]) + + _ -> + message + end + + {:ok, message} + end + + defp delist_message(message, _threshold), do: {:ok, message} + + defp reject_message(message, threshold) when threshold > 0 do + with {_, recipients} <- get_recipient_count(message) do + if recipients > threshold do + {:reject, nil} + else + {:ok, message} + end + end + end + + defp reject_message(message, _threshold), do: {:ok, message} + + defp get_recipient_count(message) do + recipients = (message["to"] || []) ++ (message["cc"] || []) + follower_collection = User.get_cached_by_ap_id(message["actor"]).follower_address + + if Enum.member?(recipients, "https://www.w3.org/ns/activitystreams#Public") do + recipients = + recipients + |> List.delete("https://www.w3.org/ns/activitystreams#Public") + |> List.delete(follower_collection) + + {:public, length(recipients)} + else + recipients = + recipients + |> List.delete(follower_collection) + + {:not_public, length(recipients)} + end end @impl true def filter(%{"type" => "Create"} = message) do - delist_threshold = Pleroma.Config.get([:mrf_hellthread, :delist_threshold]) - reject_threshold = Pleroma.Config.get( [:mrf_hellthread, :reject_threshold], Pleroma.Config.get([:mrf_hellthread, :threshold]) ) - recipients = (message["to"] || []) ++ (message["cc"] || []) - - cond do - length(recipients) > reject_threshold and reject_threshold > 0 -> - {:reject, nil} - - length(recipients) > delist_threshold and delist_threshold > 0 -> - if Enum.member?(message["to"], "https://www.w3.org/ns/activitystreams#Public") or - Enum.member?(message["cc"], "https://www.w3.org/ns/activitystreams#Public") do - {:ok, delist_message(message)} - else - {:ok, message} - end + delist_threshold = Pleroma.Config.get([:mrf_hellthread, :delist_threshold]) - true -> - {:ok, message} + with {:ok, message} <- reject_message(message, reject_threshold), + {:ok, message} <- delist_message(message, delist_threshold) do + {:ok, message} + else + _e -> {:reject, nil} end end diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 98a2af819..41d89a02b 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -406,7 +406,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do if not User.locked?(followed) do ActivityPub.accept(%{ to: [follower.ap_id], - actor: followed.ap_id, + actor: followed, object: data, local: true }) @@ -432,7 +432,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do ActivityPub.accept(%{ to: follow_activity.data["to"], type: "Accept", - actor: followed.ap_id, + actor: followed, object: follow_activity.data["id"], local: false }) do @@ -458,7 +458,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do ActivityPub.reject(%{ to: follow_activity.data["to"], type: "Reject", - actor: followed.ap_id, + actor: followed, object: follow_activity.data["id"], local: false }) do @@ -649,7 +649,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do if object = Object.normalize(id), do: {:ok, object}, else: nil end - def set_reply_to_uri(%{"inReplyTo" => inReplyTo} = object) do + def set_reply_to_uri(%{"inReplyTo" => inReplyTo} = object) when is_binary(inReplyTo) do with false <- String.starts_with?(inReplyTo, "http"), {:ok, %{data: replied_to_object}} <- get_obj_helper(inReplyTo) do Map.put(object, "inReplyTo", replied_to_object["external_url"] || inReplyTo) @@ -765,12 +765,18 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do def add_hashtags(object) do tags = (object["tag"] || []) - |> Enum.map(fn tag -> - %{ - "href" => Pleroma.Web.Endpoint.url() <> "/tags/#{tag}", - "name" => "##{tag}", - "type" => "Hashtag" - } + |> Enum.map(fn + # Expand internal representation tags into AS2 tags. + tag when is_binary(tag) -> + %{ + "href" => Pleroma.Web.Endpoint.url() <> "/tags/#{tag}", + "name" => "##{tag}", + "type" => "Hashtag" + } + + # Do not process tags which are already AS2 tag objects. + tag when is_map(tag) -> + tag end) object diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 964e11c9d..6a89374d0 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -164,7 +164,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do _ -> 5 end - Pleroma.Web.Federator.enqueue(:publish, activity, priority) + Pleroma.Web.Federator.publish(activity, priority) :ok end diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex index 15e6c1f68..c8e154989 100644 --- a/lib/pleroma/web/activity_pub/views/user_view.ex +++ b/lib/pleroma/web/activity_pub/views/user_view.ex @@ -12,9 +12,26 @@ defmodule Pleroma.Web.ActivityPub.UserView do alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.Transmogrifier alias Pleroma.Web.ActivityPub.Utils + alias Pleroma.Web.Router.Helpers + alias Pleroma.Web.Endpoint import Ecto.Query + def render("endpoints.json", %{user: %User{nickname: nil, local: true} = _user}) do + %{"sharedInbox" => Helpers.activity_pub_url(Endpoint, :inbox)} + end + + def render("endpoints.json", %{user: %User{local: true} = _user}) do + %{ + "oauthAuthorizationEndpoint" => Helpers.o_auth_url(Endpoint, :authorize), + "oauthRegistrationEndpoint" => Helpers.mastodon_api_url(Endpoint, :create_app), + "oauthTokenEndpoint" => Helpers.o_auth_url(Endpoint, :token_exchange), + "sharedInbox" => Helpers.activity_pub_url(Endpoint, :inbox) + } + end + + 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 {:ok, user} = WebFinger.ensure_keys_present(user) @@ -22,6 +39,8 @@ defmodule Pleroma.Web.ActivityPub.UserView do public_key = :public_key.pem_entry_encode(:SubjectPublicKeyInfo, public_key) public_key = :public_key.pem_encode([public_key]) + endpoints = render("endpoints.json", %{user: user}) + %{ "id" => user.ap_id, "type" => "Application", @@ -37,9 +56,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do "owner" => user.ap_id, "publicKeyPem" => public_key }, - "endpoints" => %{ - "sharedInbox" => "#{Pleroma.Web.Endpoint.url()}/inbox" - } + "endpoints" => endpoints } |> Map.merge(Utils.make_json_ld_header()) end @@ -50,6 +67,8 @@ defmodule Pleroma.Web.ActivityPub.UserView do public_key = :public_key.pem_entry_encode(:SubjectPublicKeyInfo, public_key) public_key = :public_key.pem_encode([public_key]) + endpoints = render("endpoints.json", %{user: user}) + %{ "id" => user.ap_id, "type" => "Person", @@ -67,9 +86,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do "owner" => user.ap_id, "publicKeyPem" => public_key }, - "endpoints" => %{ - "sharedInbox" => "#{Pleroma.Web.Endpoint.url()}/inbox" - }, + "endpoints" => endpoints, "icon" => %{ "type" => "Image", "url" => User.avatar_url(user) @@ -88,7 +105,14 @@ defmodule Pleroma.Web.ActivityPub.UserView do query = from(user in query, select: [:ap_id]) following = Repo.all(query) - collection(following, "#{user.ap_id}/following", page, !user.info.hide_follows) + total = + if !user.info.hide_follows do + length(following) + else + 0 + end + + collection(following, "#{user.ap_id}/following", page, !user.info.hide_follows, total) |> Map.merge(Utils.make_json_ld_header()) end @@ -97,10 +121,17 @@ defmodule Pleroma.Web.ActivityPub.UserView do query = from(user in query, select: [:ap_id]) following = Repo.all(query) + total = + if !user.info.hide_follows do + length(following) + else + 0 + end + %{ "id" => "#{user.ap_id}/following", "type" => "OrderedCollection", - "totalItems" => length(following), + "totalItems" => total, "first" => collection(following, "#{user.ap_id}/following", 1, !user.info.hide_follows) } |> Map.merge(Utils.make_json_ld_header()) @@ -111,7 +142,14 @@ defmodule Pleroma.Web.ActivityPub.UserView do query = from(user in query, select: [:ap_id]) followers = Repo.all(query) - collection(followers, "#{user.ap_id}/followers", page, !user.info.hide_followers) + total = + if !user.info.hide_followers do + length(followers) + else + 0 + end + + collection(followers, "#{user.ap_id}/followers", page, !user.info.hide_followers, total) |> Map.merge(Utils.make_json_ld_header()) end @@ -120,19 +158,24 @@ defmodule Pleroma.Web.ActivityPub.UserView do query = from(user in query, select: [:ap_id]) followers = Repo.all(query) + total = + if !user.info.hide_followers do + length(followers) + else + 0 + end + %{ "id" => "#{user.ap_id}/followers", "type" => "OrderedCollection", - "totalItems" => length(followers), - "first" => collection(followers, "#{user.ap_id}/followers", 1, !user.info.hide_followers) + "totalItems" => total, + "first" => + collection(followers, "#{user.ap_id}/followers", 1, !user.info.hide_followers, total) } |> Map.merge(Utils.make_json_ld_header()) end def render("outbox.json", %{user: user, max_id: max_qid}) do - # XXX: technically note_count is wrong for this, but it's better than nothing - info = User.user_info(user) - params = %{ "limit" => "10" } @@ -160,7 +203,6 @@ defmodule Pleroma.Web.ActivityPub.UserView do "id" => "#{iri}?max_id=#{max_id}", "type" => "OrderedCollectionPage", "partOf" => iri, - "totalItems" => info.note_count, "orderedItems" => collection, "next" => "#{iri}?max_id=#{min_id}" } @@ -169,7 +211,6 @@ defmodule Pleroma.Web.ActivityPub.UserView do %{ "id" => iri, "type" => "OrderedCollection", - "totalItems" => info.note_count, "first" => page } |> Map.merge(Utils.make_json_ld_header()) @@ -207,7 +248,6 @@ defmodule Pleroma.Web.ActivityPub.UserView do "id" => "#{iri}?max_id=#{max_id}", "type" => "OrderedCollectionPage", "partOf" => iri, - "totalItems" => -1, "orderedItems" => collection, "next" => "#{iri}?max_id=#{min_id}" } @@ -216,7 +256,6 @@ defmodule Pleroma.Web.ActivityPub.UserView do %{ "id" => iri, "type" => "OrderedCollection", - "totalItems" => -1, "first" => page } |> Map.merge(Utils.make_json_ld_header()) |