Fork of Pleroma with site-specific changes and feature branches https://git.pleroma.social/pleroma/pleroma
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

121 lines
3.7KB

  1. # Pleroma: A lightweight social networking server
  2. # Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
  3. # SPDX-License-Identifier: AGPL-3.0-only
  4. defmodule Pleroma.Web.Federator do
  5. alias Pleroma.Activity
  6. alias Pleroma.Object.Containment
  7. alias Pleroma.User
  8. alias Pleroma.Web.ActivityPub.ActivityPub
  9. alias Pleroma.Web.ActivityPub.Transmogrifier
  10. alias Pleroma.Web.ActivityPub.Utils
  11. alias Pleroma.Web.Federator.Publisher
  12. alias Pleroma.Workers.PublisherWorker
  13. alias Pleroma.Workers.ReceiverWorker
  14. require Logger
  15. @behaviour Pleroma.Web.Federator.Publishing
  16. @doc """
  17. Returns `true` if the distance to target object does not exceed max configured value.
  18. Serves to prevent fetching of very long threads, especially useful on smaller instances.
  19. Addresses [memory leaks on recursive replies fetching](https://git.pleroma.social/pleroma/pleroma/issues/161).
  20. Applies to fetching of both ancestor (reply-to) and child (reply) objects.
  21. """
  22. # credo:disable-for-previous-line Credo.Check.Readability.MaxLineLength
  23. def allowed_thread_distance?(distance) do
  24. max_distance = Pleroma.Config.get([:instance, :federation_incoming_replies_max_depth])
  25. if max_distance && max_distance >= 0 do
  26. # Default depth is 0 (an object has zero distance from itself in its thread)
  27. (distance || 0) <= max_distance
  28. else
  29. true
  30. end
  31. end
  32. # Client API
  33. def incoming_ap_doc(params) do
  34. ReceiverWorker.enqueue("incoming_ap_doc", %{"params" => params})
  35. end
  36. @impl true
  37. def publish(%{id: "pleroma:fakeid"} = activity) do
  38. perform(:publish, activity)
  39. end
  40. @impl true
  41. def publish(activity) do
  42. PublisherWorker.enqueue("publish", %{"activity_id" => activity.id})
  43. end
  44. # Job Worker Callbacks
  45. @spec perform(atom(), module(), any()) :: {:ok, any()} | {:error, any()}
  46. def perform(:publish_one, module, params) do
  47. apply(module, :publish_one, [params])
  48. end
  49. def perform(:publish, activity) do
  50. Logger.debug(fn -> "Running publish for #{activity.data["id"]}" end)
  51. with %User{} = actor <- User.get_cached_by_ap_id(activity.data["actor"]),
  52. {:ok, actor} <- User.ensure_keys_present(actor) do
  53. Publisher.publish(actor, activity)
  54. end
  55. end
  56. def perform(:incoming_ap_doc, params) do
  57. Logger.debug("Handling incoming AP activity")
  58. actor =
  59. params
  60. |> Map.get("actor")
  61. |> Utils.get_ap_id()
  62. # NOTE: we use the actor ID to do the containment, this is fine because an
  63. # actor shouldn't be acting on objects outside their own AP server.
  64. with {_, {:ok, _user}} <- {:actor, ap_enabled_actor(actor)},
  65. nil <- Activity.normalize(params["id"]),
  66. {_, :ok} <-
  67. {:correct_origin?, Containment.contain_origin_from_id(actor, params)},
  68. {:ok, activity} <- Transmogrifier.handle_incoming(params) do
  69. {:ok, activity}
  70. else
  71. {:correct_origin?, _} ->
  72. Logger.debug("Origin containment failure for #{params["id"]}")
  73. {:error, :origin_containment_failed}
  74. %Activity{} ->
  75. Logger.debug("Already had #{params["id"]}")
  76. {:error, :already_present}
  77. {:actor, e} ->
  78. Logger.debug("Unhandled actor #{actor}, #{inspect(e)}")
  79. {:error, e}
  80. {:error, {:validate_object, _}} = e ->
  81. Logger.error("Incoming AP doc validation error: #{inspect(e)}")
  82. Logger.debug(Jason.encode!(params, pretty: true))
  83. e
  84. e ->
  85. # Just drop those for now
  86. Logger.debug(fn -> "Unhandled activity\n" <> Jason.encode!(params, pretty: true) end)
  87. {:error, e}
  88. end
  89. end
  90. def ap_enabled_actor(id) do
  91. user = User.get_cached_by_ap_id(id)
  92. if User.ap_enabled?(user) do
  93. {:ok, user}
  94. else
  95. ActivityPub.make_user_from_ap_id(id)
  96. end
  97. end
  98. end