Merge branch 'features/sec-websocket-protocol-header' into 'develop'
authorkaniini <nenolod@gmail.com>
Tue, 9 Jul 2019 16:52:22 +0000 (16:52 +0000)
committerkaniini <nenolod@gmail.com>
Tue, 9 Jul 2019 16:52:22 +0000 (16:52 +0000)
Features: MastoAPI streaming Sec-WebSocket-Protocol header

See merge request pleroma/pleroma!1381

29 files changed:
CHANGELOG.md
config/config.exs
config/test.exs
docs/config.md
lib/pleroma/object.ex
lib/pleroma/object/fetcher.ex
lib/pleroma/user/search.ex
lib/pleroma/web/activity_pub/transmogrifier.ex
lib/pleroma/web/activity_pub/utils.ex
lib/pleroma/web/federator/federator.ex
lib/pleroma/web/mastodon_api/views/status_view.ex
lib/pleroma/web/media_proxy/media_proxy.ex
lib/pleroma/web/metadata/opengraph.ex
lib/pleroma/web/metadata/twitter_card.ex
lib/pleroma/web/ostatus/handlers/note_handler.ex
lib/pleroma/web/ostatus/ostatus.ex
lib/pleroma/web/router.ex
test/conversation_test.exs
test/media_proxy_test.exs
test/user_search_test.exs
test/web/activity_pub/activity_pub_controller_test.exs
test/web/activity_pub/transmogrifier_test.exs
test/web/federator_test.exs
test/web/mastodon_api/status_view_test.exs
test/web/ostatus/ostatus_controller_test.exs
test/web/ostatus/ostatus_test.exs
test/web/plugs/federating_plug_test.exs
test/web/web_finger/web_finger_controller_test.exs
test/web/websub/websub_controller_test.exs

index 408085335ff2cc3782be923f87097f180fb1e856..75fa50e000e7fbf69099e5ae5388556e8b1ea2a0 100644 (file)
@@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 ## [Unreleased]
 ### Added
 - MRF: Support for priming the mediaproxy cache (`Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy`)
+Configuration: `federation_incoming_replies_max_depth` option
 - Mastodon API: Support for the [`tagged` filter](https://github.com/tootsuite/mastodon/pull/9755) in [`GET /api/v1/accounts/:id/statuses`](https://docs.joinmastodon.org/api/rest/accounts/#get-api-v1-accounts-id-statuses)
 - Admin API: Return users' tags when querying reports
 - Admin API: Return avatar and display name when querying users
@@ -13,9 +14,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 
 ### Fixed
 - Not being able to pin unlisted posts
+- Metadata rendering errors resulting in the entire page being inaccessible
 - Mastodon API: Handling of search timeouts (`/api/v1/search` and `/api/v2/search`)
+- Mastodon API: Embedded relationships not being properly rendered in the Account entity of Status entity
 
 ### Changed
+- Configuration: OpenGraph and TwitterCard providers enabled by default
 - Configuration: Filter.AnonymizeFilename added ability to retain file extension with custom text
 
 ### Changed
index e337f00aaa02a65d46d73b21741db7bfb6f3bfdd..675fbb5515996acf356845cda3264805581f6fcd 100644 (file)
@@ -218,6 +218,7 @@ config :pleroma, :instance,
   },
   registrations_open: true,
   federating: true,
+  federation_incoming_replies_max_depth: 100,
   federation_reachability_timeout_days: 7,
   federation_publisher_modules: [
     Pleroma.Web.ActivityPub.Publisher,
@@ -358,7 +359,11 @@ config :pleroma, :gopher,
   port: 9999
 
 config :pleroma, Pleroma.Web.Metadata,
-  providers: [Pleroma.Web.Metadata.Providers.RelMe],
+  providers: [
+    Pleroma.Web.Metadata.Providers.OpenGraph,
+    Pleroma.Web.Metadata.Providers.TwitterCard,
+    Pleroma.Web.Metadata.Providers.RelMe
+  ],
   unfurl_nsfw: false
 
 config :pleroma, :suggestions,
index 9d441a7f5e5123ebb80af51eca4544dcd3116d23..012021f2a137269feb71b08624388a825f3946cd 100644 (file)
@@ -28,7 +28,8 @@ config :pleroma, Pleroma.Emails.Mailer, adapter: Swoosh.Adapters.Test
 config :pleroma, :instance,
   email: "admin@example.com",
   notify_email: "noreply@example.com",
-  skip_thread_containment: false
+  skip_thread_containment: false,
+  federating: false
 
 # Configure your database
 config :pleroma, Pleroma.Repo,
index 8afccb228d7ca9991fd4998d365a2b71102eada8..822c34c515a3e7cfbf301dcfe20d8914a3f60d4b 100644 (file)
@@ -87,6 +87,7 @@ config :pleroma, Pleroma.Emails.Mailer,
 * `invites_enabled`: Enable user invitations for admins (depends on `registrations_open: false`).
 * `account_activation_required`: Require users to confirm their emails before signing in.
 * `federating`: Enable federation with other instances
+* `federation_incoming_replies_max_depth`: Max. depth of reply-to activities fetching on incoming federation, to prevent out-of-memory situations while fetching very long threads. If set to `nil`, threads of any depth will be fetched. Lower this value if you experience out-of-memory crashes.
 * `federation_reachability_timeout_days`: Timeout (in days) of each external federation target being unreachable prior to pausing federating to it.
 * `allow_relay`: Enable Pleroma’s Relay, which makes it possible to follow a whole instance
 * `rewrite_policy`: Message Rewrite Policy, either one or a list. Here are the ones available by default:
index 4b181ec59f0ab225d3c1c44add562587036cf226..b8647dd26ed9f8aa9bc9a2f661e8eee34a28525c 100644 (file)
@@ -44,20 +44,20 @@ defmodule Pleroma.Object do
     Repo.one(from(object in Object, where: fragment("(?)->>'id' = ?", object.data, ^ap_id)))
   end
 
-  def normalize(_, fetch_remote \\ true)
+  def normalize(_, fetch_remote \\ true, options \\ [])
   # If we pass an Activity to Object.normalize(), we can try to use the preloaded object.
   # Use this whenever possible, especially when walking graphs in an O(N) loop!
-  def normalize(%Object{} = object, _), do: object
-  def normalize(%Activity{object: %Object{} = object}, _), do: object
+  def normalize(%Object{} = object, _, _), do: object
+  def normalize(%Activity{object: %Object{} = object}, _, _), do: object
 
   # A hack for fake activities
-  def normalize(%Activity{data: %{"object" => %{"fake" => true} = data}}, _) do
+  def normalize(%Activity{data: %{"object" => %{"fake" => true} = data}}, _, _) do
     %Object{id: "pleroma:fake_object_id", data: data}
   end
 
   # Catch and log Object.normalize() calls where the Activity's child object is not
   # preloaded.
-  def normalize(%Activity{data: %{"object" => %{"id" => ap_id}}}, fetch_remote) do
+  def normalize(%Activity{data: %{"object" => %{"id" => ap_id}}}, fetch_remote, _) do
     Logger.debug(
       "Object.normalize() called without preloaded object (#{ap_id}).  Consider preloading the object!"
     )
@@ -67,7 +67,7 @@ defmodule Pleroma.Object do
     normalize(ap_id, fetch_remote)
   end
 
-  def normalize(%Activity{data: %{"object" => ap_id}}, fetch_remote) do
+  def normalize(%Activity{data: %{"object" => ap_id}}, fetch_remote, _) do
     Logger.debug(
       "Object.normalize() called without preloaded object (#{ap_id}).  Consider preloading the object!"
     )
@@ -78,10 +78,14 @@ defmodule Pleroma.Object do
   end
 
   # Old way, try fetching the object through cache.
-  def normalize(%{"id" => ap_id}, fetch_remote), do: normalize(ap_id, fetch_remote)
-  def normalize(ap_id, false) when is_binary(ap_id), do: get_cached_by_ap_id(ap_id)
-  def normalize(ap_id, true) when is_binary(ap_id), do: Fetcher.fetch_object_from_id!(ap_id)
-  def normalize(_, _), do: nil
+  def normalize(%{"id" => ap_id}, fetch_remote, _), do: normalize(ap_id, fetch_remote)
+  def normalize(ap_id, false, _) when is_binary(ap_id), do: get_cached_by_ap_id(ap_id)
+
+  def normalize(ap_id, true, options) when is_binary(ap_id) do
+    Fetcher.fetch_object_from_id!(ap_id, options)
+  end
+
+  def normalize(_, _, _), do: nil
 
   # Owned objects can only be mutated by their owner
   def authorize_mutation(%Object{data: %{"actor" => actor}}, %User{ap_id: ap_id}),
index c422490ac4ae922399589d7ee842e5eb21a4a434..fffbf2bbb23062bdb983e922d95bf0e6f1aed069 100644 (file)
@@ -22,7 +22,7 @@ defmodule Pleroma.Object.Fetcher do
 
   # TODO:
   # This will create a Create activity, which we need internally at the moment.
-  def fetch_object_from_id(id) do
+  def fetch_object_from_id(id, options \\ []) do
     if object = Object.get_cached_by_ap_id(id) do
       {:ok, object}
     else
@@ -38,7 +38,7 @@ defmodule Pleroma.Object.Fetcher do
              "object" => data
            },
            :ok <- Containment.contain_origin(id, params),
-           {:ok, activity} <- Transmogrifier.handle_incoming(params),
+           {:ok, activity} <- Transmogrifier.handle_incoming(params, options),
            {:object, _data, %Object{} = object} <-
              {:object, data, Object.normalize(activity, false)} do
         {:ok, object}
@@ -63,8 +63,8 @@ defmodule Pleroma.Object.Fetcher do
     end
   end
 
-  def fetch_object_from_id!(id) do
-    with {:ok, object} <- fetch_object_from_id(id) do
+  def fetch_object_from_id!(id, options \\ []) do
+    with {:ok, object} <- fetch_object_from_id(id, options) do
       object
     else
       _e ->
index 7680c2afd1c60ab05e46ac8394da7b90f79ac7f0..64eb6d2bc484df842a22562b7468d80d807aba86 100644 (file)
@@ -150,7 +150,7 @@ defmodule Pleroma.User.Search do
   @spec fts_search_subquery(User.t() | Ecto.Query.t(), String.t()) :: Ecto.Query.t()
   defp fts_search_subquery(query, term) do
     processed_query =
-      term
+      String.trim_trailing(term, "@" <> local_domain())
       |> String.replace(~r/\W+/, " ")
       |> String.trim()
       |> String.split()
@@ -192,6 +192,8 @@ defmodule Pleroma.User.Search do
 
   @spec trigram_search_subquery(User.t() | Ecto.Query.t(), String.t()) :: Ecto.Query.t()
   defp trigram_search_subquery(query, term) do
+    term = String.trim_trailing(term, "@" <> local_domain())
+
     from(
       u in query,
       select_merge: %{
@@ -209,4 +211,6 @@ defmodule Pleroma.User.Search do
     )
     |> User.restrict_deactivated()
   end
+
+  defp local_domain, do: Pleroma.Config.get([Pleroma.Web.Endpoint, :url, :host])
 end
index 3bb8b40b5c0284024ba2558950e1fee312ac965b..543d4bb7d1dd89c7e03ec0df027bb4a78ba769fd 100644 (file)
@@ -14,6 +14,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
   alias Pleroma.Web.ActivityPub.ActivityPub
   alias Pleroma.Web.ActivityPub.Utils
   alias Pleroma.Web.ActivityPub.Visibility
+  alias Pleroma.Web.Federator
 
   import Ecto.Query
 
@@ -22,20 +23,20 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
   @doc """
   Modifies an incoming AP object (mastodon format) to our internal format.
   """
-  def fix_object(object) do
+  def fix_object(object, options \\ []) do
     object
     |> fix_actor
     |> fix_url
     |> fix_attachments
     |> fix_context
-    |> fix_in_reply_to
+    |> fix_in_reply_to(options)
     |> fix_emoji
     |> fix_tag
     |> fix_content_map
     |> fix_likes
     |> fix_addressing
     |> fix_summary
-    |> fix_type
+    |> fix_type(options)
   end
 
   def fix_summary(%{"summary" => nil} = object) do
@@ -164,7 +165,9 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
     object
   end
 
-  def fix_in_reply_to(%{"inReplyTo" => in_reply_to} = object)
+  def fix_in_reply_to(object, options \\ [])
+
+  def fix_in_reply_to(%{"inReplyTo" => in_reply_to} = object, options)
       when not is_nil(in_reply_to) do
     in_reply_to_id =
       cond do
@@ -182,28 +185,34 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
           ""
       end
 
-    case get_obj_helper(in_reply_to_id) do
-      {:ok, replied_object} ->
-        with %Activity{} = _activity <-
-               Activity.get_create_by_object_ap_id(replied_object.data["id"]) do
-          object
-          |> Map.put("inReplyTo", replied_object.data["id"])
-          |> Map.put("inReplyToAtomUri", object["inReplyToAtomUri"] || in_reply_to_id)
-          |> Map.put("conversation", replied_object.data["context"] || object["conversation"])
-          |> Map.put("context", replied_object.data["context"] || object["conversation"])
-        else
-          e ->
-            Logger.error("Couldn't fetch \"#{inspect(in_reply_to_id)}\", error: #{inspect(e)}")
+    object = Map.put(object, "inReplyToAtomUri", in_reply_to_id)
+
+    if Federator.allowed_incoming_reply_depth?(options[:depth]) do
+      case get_obj_helper(in_reply_to_id, options) do
+        {:ok, replied_object} ->
+          with %Activity{} = _activity <-
+                 Activity.get_create_by_object_ap_id(replied_object.data["id"]) do
             object
-        end
+            |> Map.put("inReplyTo", replied_object.data["id"])
+            |> Map.put("inReplyToAtomUri", object["inReplyToAtomUri"] || in_reply_to_id)
+            |> Map.put("conversation", replied_object.data["context"] || object["conversation"])
+            |> Map.put("context", replied_object.data["context"] || object["conversation"])
+          else
+            e ->
+              Logger.error("Couldn't fetch \"#{inspect(in_reply_to_id)}\", error: #{inspect(e)}")
+              object
+          end
 
-      e ->
-        Logger.error("Couldn't fetch \"#{inspect(in_reply_to_id)}\", error: #{inspect(e)}")
-        object
+        e ->
+          Logger.error("Couldn't fetch \"#{inspect(in_reply_to_id)}\", error: #{inspect(e)}")
+          object
+      end
+    else
+      object
     end
   end
 
-  def fix_in_reply_to(object), do: object
+  def fix_in_reply_to(object, _options), do: object
 
   def fix_context(object) do
     context = object["context"] || object["conversation"] || Utils.generate_context_id()
@@ -336,8 +345,13 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
 
   def fix_content_map(object), do: object
 
-  def fix_type(%{"inReplyTo" => reply_id} = object) when is_binary(reply_id) do
-    reply = Object.normalize(reply_id)
+  def fix_type(object, options \\ [])
+
+  def fix_type(%{"inReplyTo" => reply_id} = object, options) when is_binary(reply_id) do
+    reply =
+      if Federator.allowed_incoming_reply_depth?(options[:depth]) do
+        Object.normalize(reply_id, true)
+      end
 
     if reply && (reply.data["type"] == "Question" and object["name"]) do
       Map.put(object, "type", "Answer")
@@ -346,7 +360,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
     end
   end
 
-  def fix_type(object), do: object
+  def fix_type(object, _), do: object
 
   defp mastodon_follow_hack(%{"id" => id, "actor" => follower_id}, followed) do
     with true <- id =~ "follows",
@@ -374,9 +388,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
     end
   end
 
+  def handle_incoming(data, options \\ [])
+
   # Flag objects are placed ahead of the ID check because Mastodon 2.8 and earlier send them
   # with nil ID.
-  def handle_incoming(%{"type" => "Flag", "object" => objects, "actor" => actor} = data) do
+  def handle_incoming(%{"type" => "Flag", "object" => objects, "actor" => actor} = data, _options) do
     with context <- data["context"] || Utils.generate_context_id(),
          content <- data["content"] || "",
          %User{} = actor <- User.get_cached_by_ap_id(actor),
@@ -409,15 +425,19 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
   end
 
   # disallow objects with bogus IDs
-  def handle_incoming(%{"id" => nil}), do: :error
-  def handle_incoming(%{"id" => ""}), do: :error
+  def handle_incoming(%{"id" => nil}, _options), do: :error
+  def handle_incoming(%{"id" => ""}, _options), do: :error
   # length of https:// = 8, should validate better, but good enough for now.
-  def handle_incoming(%{"id" => id}) when not (is_binary(id) and length(id) > 8), do: :error
+  def handle_incoming(%{"id" => id}, _options) when not (is_binary(id) and length(id) > 8),
+    do: :error
 
   # TODO: validate those with a Ecto scheme
   # - tags
   # - emoji
-  def handle_incoming(%{"type" => "Create", "object" => %{"type" => objtype} = object} = data)
+  def handle_incoming(
+        %{"type" => "Create", "object" => %{"type" => objtype} = object} = data,
+        options
+      )
       when objtype in ["Article", "Note", "Video", "Page", "Question", "Answer"] do
     actor = Containment.get_actor(data)
 
@@ -427,7 +447,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
 
     with nil <- Activity.get_create_by_object_ap_id(object["id"]),
          {:ok, %User{} = user} <- User.get_or_fetch_by_ap_id(data["actor"]) do
-      object = fix_object(data["object"])
+      options = Keyword.put(options, :depth, (options[:depth] || 0) + 1)
+      object = fix_object(data["object"], options)
 
       params = %{
         to: data["to"],
@@ -452,7 +473,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
   end
 
   def handle_incoming(
-        %{"type" => "Follow", "object" => followed, "actor" => follower, "id" => id} = data
+        %{"type" => "Follow", "object" => followed, "actor" => follower, "id" => id} = data,
+        _options
       ) do
     with %User{local: true} = followed <- User.get_cached_by_ap_id(followed),
          {:ok, %User{} = follower} <- User.get_or_fetch_by_ap_id(follower),
@@ -503,7 +525,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
   end
 
   def handle_incoming(
-        %{"type" => "Accept", "object" => follow_object, "actor" => _actor, "id" => _id} = data
+        %{"type" => "Accept", "object" => follow_object, "actor" => _actor, "id" => _id} = data,
+        _options
       ) do
     with actor <- Containment.get_actor(data),
          {:ok, %User{} = followed} <- User.get_or_fetch_by_ap_id(actor),
@@ -524,7 +547,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
   end
 
   def handle_incoming(
-        %{"type" => "Reject", "object" => follow_object, "actor" => _actor, "id" => _id} = data
+        %{"type" => "Reject", "object" => follow_object, "actor" => _actor, "id" => _id} = data,
+        _options
       ) do
     with actor <- Containment.get_actor(data),
          {:ok, %User{} = followed} <- User.get_or_fetch_by_ap_id(actor),
@@ -548,7 +572,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
   end
 
   def handle_incoming(
-        %{"type" => "Like", "object" => object_id, "actor" => _actor, "id" => id} = data
+        %{"type" => "Like", "object" => object_id, "actor" => _actor, "id" => id} = data,
+        _options
       ) do
     with actor <- Containment.get_actor(data),
          {:ok, %User{} = actor} <- User.get_or_fetch_by_ap_id(actor),
@@ -561,7 +586,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
   end
 
   def handle_incoming(
-        %{"type" => "Announce", "object" => object_id, "actor" => _actor, "id" => id} = data
+        %{"type" => "Announce", "object" => object_id, "actor" => _actor, "id" => id} = data,
+        _options
       ) do
     with actor <- Containment.get_actor(data),
          {:ok, %User{} = actor} <- User.get_or_fetch_by_ap_id(actor),
@@ -576,7 +602,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
 
   def handle_incoming(
         %{"type" => "Update", "object" => %{"type" => object_type} = object, "actor" => actor_id} =
-          data
+          data,
+        _options
       )
       when object_type in ["Person", "Application", "Service", "Organization"] do
     with %User{ap_id: ^actor_id} = actor <- User.get_cached_by_ap_id(object["id"]) do
@@ -614,7 +641,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
   # an error or a tombstone.  This would allow us to verify that a deletion actually took
   # place.
   def handle_incoming(
-        %{"type" => "Delete", "object" => object_id, "actor" => _actor, "id" => _id} = data
+        %{"type" => "Delete", "object" => object_id, "actor" => _actor, "id" => _id} = data,
+        _options
       ) do
     object_id = Utils.get_ap_id(object_id)
 
@@ -635,7 +663,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
           "object" => %{"type" => "Announce", "object" => object_id},
           "actor" => _actor,
           "id" => id
-        } = data
+        } = data,
+        _options
       ) do
     with actor <- Containment.get_actor(data),
          {:ok, %User{} = actor} <- User.get_or_fetch_by_ap_id(actor),
@@ -653,7 +682,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
           "object" => %{"type" => "Follow", "object" => followed},
           "actor" => follower,
           "id" => id
-        } = _data
+        } = _data,
+        _options
       ) do
     with %User{local: true} = followed <- User.get_cached_by_ap_id(followed),
          {:ok, %User{} = follower} <- User.get_or_fetch_by_ap_id(follower),
@@ -671,7 +701,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
           "object" => %{"type" => "Block", "object" => blocked},
           "actor" => blocker,
           "id" => id
-        } = _data
+        } = _data,
+        _options
       ) do
     with true <- Pleroma.Config.get([:activitypub, :accept_blocks]),
          %User{local: true} = blocked <- User.get_cached_by_ap_id(blocked),
@@ -685,7 +716,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
   end
 
   def handle_incoming(
-        %{"type" => "Block", "object" => blocked, "actor" => blocker, "id" => id} = _data
+        %{"type" => "Block", "object" => blocked, "actor" => blocker, "id" => id} = _data,
+        _options
       ) do
     with true <- Pleroma.Config.get([:activitypub, :accept_blocks]),
          %User{local: true} = blocked = User.get_cached_by_ap_id(blocked),
@@ -705,7 +737,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
           "object" => %{"type" => "Like", "object" => object_id},
           "actor" => _actor,
           "id" => id
-        } = data
+        } = data,
+        _options
       ) do
     with actor <- Containment.get_actor(data),
          {:ok, %User{} = actor} <- User.get_or_fetch_by_ap_id(actor),
@@ -717,10 +750,10 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
     end
   end
 
-  def handle_incoming(_), do: :error
+  def handle_incoming(_, _), do: :error
 
-  def get_obj_helper(id) do
-    if object = Object.normalize(id), do: {:ok, object}, else: nil
+  def get_obj_helper(id, options \\ []) do
+    if object = Object.normalize(id, true, options), do: {:ok, object}, else: nil
   end
 
   def set_reply_to_uri(%{"inReplyTo" => in_reply_to} = object) when is_binary(in_reply_to) do
index 514266ceefaa314484dbf9d840a51a1525195725..4288ea4c838a8cf291394663291246bea3d7c9bd 100644 (file)
@@ -170,14 +170,17 @@ defmodule Pleroma.Web.ActivityPub.Utils do
   Enqueues an activity for federation if it's local
   """
   def maybe_federate(%Activity{local: true} = activity) do
-    priority =
-      case activity.data["type"] do
-        "Delete" -> 10
-        "Create" -> 1
-        _ -> 5
-      end
+    if Pleroma.Config.get!([:instance, :federating]) do
+      priority =
+        case activity.data["type"] do
+          "Delete" -> 10
+          "Create" -> 1
+          _ -> 5
+        end
+
+      Pleroma.Web.Federator.publish(activity, priority)
+    end
 
-    Pleroma.Web.Federator.publish(activity, priority)
     :ok
   end
 
index f4c9fe28403d4991f6569b7bc91897529fbcd155..f4f9e83e06ab55f71b715301631865bc46b11c00 100644 (file)
@@ -22,6 +22,18 @@ defmodule Pleroma.Web.Federator do
     refresh_subscriptions()
   end
 
+  @doc "Addresses [memory leaks on recursive replies fetching](https://git.pleroma.social/pleroma/pleroma/issues/161)"
+  # credo:disable-for-previous-line Credo.Check.Readability.MaxLineLength
+  def allowed_incoming_reply_depth?(depth) do
+    max_replies_depth = Pleroma.Config.get([:instance, :federation_incoming_replies_max_depth])
+
+    if max_replies_depth do
+      (depth || 1) <= max_replies_depth
+    else
+      true
+    end
+  end
+
   # Client API
 
   def incoming_doc(doc) do
index 6836d331a7ae89c5d2e58102f68ae55a26c5f698..ec582b919c626aa5c8f1e9330a03c0d1afafac8d 100644 (file)
@@ -104,7 +104,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
       id: to_string(activity.id),
       uri: activity_object.data["id"],
       url: activity_object.data["id"],
-      account: AccountView.render("account.json", %{user: user}),
+      account: AccountView.render("account.json", %{user: user, for: opts[:for]}),
       in_reply_to_id: nil,
       in_reply_to_account_id: nil,
       reblog: reblogged,
@@ -221,7 +221,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
       id: to_string(activity.id),
       uri: object.data["id"],
       url: url,
-      account: AccountView.render("account.json", %{user: user}),
+      account: AccountView.render("account.json", %{user: user, for: opts[:for]}),
       in_reply_to_id: reply_to && to_string(reply_to.id),
       in_reply_to_account_id: reply_to_user && to_string(reply_to_user.id),
       reblog: nil,
index cee6d8481a33942d1d41d51a0cb16ba6fb98ac0b..dd8888a021635357b4fe88c1bb2748517c7c6062 100644 (file)
@@ -33,20 +33,7 @@ defmodule Pleroma.Web.MediaProxy do
 
   def encode_url(url) do
     secret = Pleroma.Config.get([Pleroma.Web.Endpoint, :secret_key_base])
-
-    # Must preserve `%2F` for compatibility with S3
-    # https://git.pleroma.social/pleroma/pleroma/issues/580
-    replacement = get_replacement(url, ":2F:")
-
-    # The URL is url-decoded and encoded again to ensure it is correctly encoded and not twice.
-    base64 =
-      url
-      |> String.replace("%2F", replacement)
-      |> URI.decode()
-      |> URI.encode()
-      |> String.replace(replacement, "%2F")
-      |> Base.url_encode64(@base64_opts)
-
+    base64 = Base.url_encode64(url, @base64_opts)
     sig = :crypto.hmac(:sha, secret, base64)
     sig64 = sig |> Base.url_encode64(@base64_opts)
 
@@ -80,12 +67,4 @@ defmodule Pleroma.Web.MediaProxy do
     |> Enum.filter(fn value -> value end)
     |> Path.join()
   end
-
-  defp get_replacement(url, replacement) do
-    if String.contains?(url, replacement) do
-      get_replacement(url, replacement <> replacement)
-    else
-      replacement
-    end
-  end
 end
index 357b80a2d50e7959bd8d5b8dfe36d2468f25def9..4033ec38ff17d2592777565c47c8dc9c62686cb8 100644 (file)
@@ -121,4 +121,6 @@ defmodule Pleroma.Web.Metadata.Providers.OpenGraph do
       acc ++ rendered_tags
     end)
   end
+
+  defp build_attachments(_), do: []
 end
index 040b872e7034d840705ffb324628d223a9f197b3..8dd01e0d5f33ff55391dc4cd77ac1c52ff2b157e 100644 (file)
@@ -117,6 +117,8 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCard do
     end)
   end
 
+  defp build_attachments(_id, _object), do: []
+
   defp player_url(id) do
     Pleroma.Web.Router.Helpers.o_status_url(Pleroma.Web.Endpoint, :notice_player, id)
   end
index ec6e5cfaf3226cdb61e4ba7b1e72d3bba161a532..8e0adad91f38b7c87008f37b932e426934eb0dd8 100644 (file)
@@ -10,6 +10,7 @@ defmodule Pleroma.Web.OStatus.NoteHandler do
   alias Pleroma.Web.ActivityPub.ActivityPub
   alias Pleroma.Web.ActivityPub.Utils
   alias Pleroma.Web.CommonAPI
+  alias Pleroma.Web.Federator
   alias Pleroma.Web.OStatus
   alias Pleroma.Web.XML
 
@@ -88,14 +89,15 @@ defmodule Pleroma.Web.OStatus.NoteHandler do
     Map.put(note, "external_url", url)
   end
 
-  def fetch_replied_to_activity(entry, in_reply_to) do
+  def fetch_replied_to_activity(entry, in_reply_to, options \\ []) do
     with %Activity{} = activity <- Activity.get_create_by_object_ap_id(in_reply_to) do
       activity
     else
       _e ->
-        with in_reply_to_href when not is_nil(in_reply_to_href) <-
+        with true <- Federator.allowed_incoming_reply_depth?(options[:depth]),
+             in_reply_to_href when not is_nil(in_reply_to_href) <-
                XML.string_from_xpath("//thr:in-reply-to[1]/@href", entry),
-             {:ok, [activity | _]} <- OStatus.fetch_activity_from_url(in_reply_to_href) do
+             {:ok, [activity | _]} <- OStatus.fetch_activity_from_url(in_reply_to_href, options) do
           activity
         else
           _e -> nil
@@ -104,7 +106,7 @@ defmodule Pleroma.Web.OStatus.NoteHandler do
   end
 
   # TODO: Clean this up a bit.
-  def handle_note(entry, doc \\ nil) do
+  def handle_note(entry, doc \\ nil, options \\ []) do
     with id <- XML.string_from_xpath("//id", entry),
          activity when is_nil(activity) <- Activity.get_create_by_object_ap_id_with_object(id),
          [author] <- :xmerl_xpath.string('//author[1]', doc),
@@ -112,7 +114,8 @@ defmodule Pleroma.Web.OStatus.NoteHandler do
          content_html <- OStatus.get_content(entry),
          cw <- OStatus.get_cw(entry),
          in_reply_to <- XML.string_from_xpath("//thr:in-reply-to[1]/@ref", entry),
-         in_reply_to_activity <- fetch_replied_to_activity(entry, in_reply_to),
+         options <- Keyword.put(options, :depth, (options[:depth] || 0) + 1),
+         in_reply_to_activity <- fetch_replied_to_activity(entry, in_reply_to, options),
          in_reply_to_object <-
            (in_reply_to_activity && Object.normalize(in_reply_to_activity)) || nil,
          in_reply_to <- (in_reply_to_object && in_reply_to_object.data["id"]) || in_reply_to,
index 6ed089d8458f6e51aacf0ca3da25462559340faf..502410c83cfd7ed0bf7620970f10f1f996bfd021 100644 (file)
@@ -54,7 +54,7 @@ defmodule Pleroma.Web.OStatus do
     "#{Web.base_url()}/ostatus_subscribe?acct={uri}"
   end
 
-  def handle_incoming(xml_string) do
+  def handle_incoming(xml_string, options \\ []) do
     with doc when doc != :error <- parse_document(xml_string) do
       with {:ok, actor_user} <- find_make_or_update_user(doc),
            do: Pleroma.Instances.set_reachable(actor_user.ap_id)
@@ -91,10 +91,12 @@ defmodule Pleroma.Web.OStatus do
               _ ->
                 case object_type do
                   'http://activitystrea.ms/schema/1.0/note' ->
-                    with {:ok, activity} <- NoteHandler.handle_note(entry, doc), do: activity
+                    with {:ok, activity} <- NoteHandler.handle_note(entry, doc, options),
+                         do: activity
 
                   'http://activitystrea.ms/schema/1.0/comment' ->
-                    with {:ok, activity} <- NoteHandler.handle_note(entry, doc), do: activity
+                    with {:ok, activity} <- NoteHandler.handle_note(entry, doc, options),
+                         do: activity
 
                   _ ->
                     Logger.error("Couldn't parse incoming document")
@@ -359,7 +361,7 @@ defmodule Pleroma.Web.OStatus do
     end
   end
 
-  def fetch_activity_from_atom_url(url) do
+  def fetch_activity_from_atom_url(url, options \\ []) do
     with true <- String.starts_with?(url, "http"),
          {:ok, %{body: body, status: code}} when code in 200..299 <-
            HTTP.get(
@@ -367,7 +369,7 @@ defmodule Pleroma.Web.OStatus do
              [{:Accept, "application/atom+xml"}]
            ) do
       Logger.debug("Got document from #{url}, handling...")
-      handle_incoming(body)
+      handle_incoming(body, options)
     else
       e ->
         Logger.debug("Couldn't get #{url}: #{inspect(e)}")
@@ -375,13 +377,13 @@ defmodule Pleroma.Web.OStatus do
     end
   end
 
-  def fetch_activity_from_html_url(url) do
+  def fetch_activity_from_html_url(url, options \\ []) do
     Logger.debug("Trying to fetch #{url}")
 
     with true <- String.starts_with?(url, "http"),
          {:ok, %{body: body}} <- HTTP.get(url, []),
          {:ok, atom_url} <- get_atom_url(body) do
-      fetch_activity_from_atom_url(atom_url)
+      fetch_activity_from_atom_url(atom_url, options)
     else
       e ->
         Logger.debug("Couldn't get #{url}: #{inspect(e)}")
@@ -389,11 +391,11 @@ defmodule Pleroma.Web.OStatus do
     end
   end
 
-  def fetch_activity_from_url(url) do
-    with {:ok, [_ | _] = activities} <- fetch_activity_from_atom_url(url) do
+  def fetch_activity_from_url(url, options \\ []) do
+    with {:ok, [_ | _] = activities} <- fetch_activity_from_atom_url(url, options) do
       {:ok, activities}
     else
-      _e -> fetch_activity_from_html_url(url)
+      _e -> fetch_activity_from_html_url(url, options)
     end
   rescue
     e ->
index 055289dc56bfbfb31d336f9096fb7c06877d72b8..ff9ed1640c069b9a032560be9124e5a291eac439 100644 (file)
@@ -724,6 +724,7 @@ end
 
 defmodule Fallback.RedirectController do
   use Pleroma.Web, :controller
+  require Logger
   alias Pleroma.User
   alias Pleroma.Web.Metadata
 
@@ -750,7 +751,20 @@ defmodule Fallback.RedirectController do
 
   def redirector_with_meta(conn, params) do
     {:ok, index_content} = File.read(index_file_path())
-    tags = Metadata.build_tags(params)
+
+    tags =
+      try do
+        Metadata.build_tags(params)
+      rescue
+        e ->
+          Logger.error(
+            "Metadata rendering for #{conn.request_path} failed.\n" <>
+              Exception.format(:error, e, __STACKTRACE__)
+          )
+
+          ""
+      end
+
     response = String.replace(index_content, "<!--server-generated-meta-->", tags)
 
     conn
index 5903d10ff05b1ffd94b4d4594952a1b393283b6f..aa193e0d40dadf907f974ef2cfa378ee7788844e 100644 (file)
@@ -11,6 +11,16 @@ defmodule Pleroma.ConversationTest do
 
   import Pleroma.Factory
 
+  setup_all do
+    config_path = [:instance, :federating]
+    initial_setting = Pleroma.Config.get(config_path)
+
+    Pleroma.Config.put(config_path, true)
+    on_exit(fn -> Pleroma.Config.put(config_path, initial_setting) end)
+
+    :ok
+  end
+
   test "it goes through old direct conversations" do
     user = insert(:user)
     other_user = insert(:user)
index b23aeb88be580c9642dd6675a55ded62d1af951a..1d6d170b72e02d4986ad087fb3a090c7cb59a391 100644 (file)
@@ -70,14 +70,6 @@ defmodule Pleroma.MediaProxyTest do
       assert decode_result(encoded) == url
     end
 
-    test "ensures urls are url-encoded" do
-      assert decode_result(url("https://pleroma.social/Hello world.jpg")) ==
-               "https://pleroma.social/Hello%20world.jpg"
-
-      assert decode_result(url("https://pleroma.social/Hello%20world.jpg")) ==
-               "https://pleroma.social/Hello%20world.jpg"
-    end
-
     test "validates signature" do
       secret_key_base = Pleroma.Config.get([Pleroma.Web.Endpoint, :secret_key_base])
 
@@ -141,10 +133,31 @@ defmodule Pleroma.MediaProxyTest do
       assert String.starts_with?(encoded, Pleroma.Config.get([:media_proxy, :base_url]))
     end
 
-    # https://git.pleroma.social/pleroma/pleroma/issues/580
-    test "encoding S3 links (must preserve `%2F`)" do
+    # Some sites expect ASCII encoded characters in the URL to be preserved even if
+    # unnecessary.
+    # Issues: https://git.pleroma.social/pleroma/pleroma/issues/580
+    #         https://git.pleroma.social/pleroma/pleroma/issues/1055
+    test "preserve ASCII encoding" do
+      url =
+        "https://pleroma.com/%20/%21/%22/%23/%24/%25/%26/%27/%28/%29/%2A/%2B/%2C/%2D/%2E/%2F/%30/%31/%32/%33/%34/%35/%36/%37/%38/%39/%3A/%3B/%3C/%3D/%3E/%3F/%40/%41/%42/%43/%44/%45/%46/%47/%48/%49/%4A/%4B/%4C/%4D/%4E/%4F/%50/%51/%52/%53/%54/%55/%56/%57/%58/%59/%5A/%5B/%5C/%5D/%5E/%5F/%60/%61/%62/%63/%64/%65/%66/%67/%68/%69/%6A/%6B/%6C/%6D/%6E/%6F/%70/%71/%72/%73/%74/%75/%76/%77/%78/%79/%7A/%7B/%7C/%7D/%7E/%7F/%80/%81/%82/%83/%84/%85/%86/%87/%88/%89/%8A/%8B/%8C/%8D/%8E/%8F/%90/%91/%92/%93/%94/%95/%96/%97/%98/%99/%9A/%9B/%9C/%9D/%9E/%9F/%C2%A0/%A1/%A2/%A3/%A4/%A5/%A6/%A7/%A8/%A9/%AA/%AB/%AC/%C2%AD/%AE/%AF/%B0/%B1/%B2/%B3/%B4/%B5/%B6/%B7/%B8/%B9/%BA/%BB/%BC/%BD/%BE/%BF/%C0/%C1/%C2/%C3/%C4/%C5/%C6/%C7/%C8/%C9/%CA/%CB/%CC/%CD/%CE/%CF/%D0/%D1/%D2/%D3/%D4/%D5/%D6/%D7/%D8/%D9/%DA/%DB/%DC/%DD/%DE/%DF/%E0/%E1/%E2/%E3/%E4/%E5/%E6/%E7/%E8/%E9/%EA/%EB/%EC/%ED/%EE/%EF/%F0/%F1/%F2/%F3/%F4/%F5/%F6/%F7/%F8/%F9/%FA/%FB/%FC/%FD/%FE/%FF"
+
+      encoded = url(url)
+      assert decode_result(encoded) == url
+    end
+
+    # This includes unsafe/reserved characters which are not interpreted as part of the URL
+    # and would otherwise have to be ASCII encoded. It is our role to ensure the proxied URL
+    # is unmodified, so we are testing these characters anyway.
+    test "preserve non-unicode characters per RFC3986" do
       url =
-        "https://s3.amazonaws.com/example/test.png?X-Amz-Credential=your-access-key-id%2F20130721%2Fus-east-1%2Fs3%2Faws4_request"
+        "https://pleroma.com/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890-._~:/?#[]@!$&'()*+,;=|^`{}"
+
+      encoded = url(url)
+      assert decode_result(encoded) == url
+    end
+
+    test "preserve unicode characters" do
+      url = "https://ko.wikipedia.org/wiki/위키백과:대문"
 
       encoded = url(url)
       assert decode_result(encoded) == url
index 8f8472aaef2aa853c7031c42678705c4dc2e836c..1f0162486034104fa43568cebb9eff09e565b1e2 100644 (file)
@@ -217,5 +217,36 @@ defmodule Pleroma.UserSearchTest do
       refute Enum.member?(account_ids, blocked_user2.id)
       assert length(account_ids) == 3
     end
+
+    test "local user has the same search_rank as for users with the same nickname, but another domain" do
+      user = insert(:user)
+      insert(:user, nickname: "lain@mastodon.social")
+      insert(:user, nickname: "lain")
+      insert(:user, nickname: "lain@pleroma.social")
+
+      assert User.search("lain@localhost", resolve: true, for_user: user)
+             |> Enum.each(fn u -> u.search_rank == 0.5 end)
+    end
+
+    test "localhost is the part of the domain" do
+      user = insert(:user)
+      insert(:user, nickname: "another@somedomain")
+      insert(:user, nickname: "lain")
+      insert(:user, nickname: "lain@examplelocalhost")
+
+      result = User.search("lain@examplelocalhost", resolve: true, for_user: user)
+      assert Enum.each(result, fn u -> u.search_rank == 0.5 end)
+      assert length(result) == 2
+    end
+
+    test "local user search with users" do
+      user = insert(:user)
+      local_user = insert(:user, nickname: "lain")
+      insert(:user, nickname: "another@localhost.com")
+      insert(:user, nickname: "localhost@localhost.com")
+
+      [result] = User.search("lain@localhost", resolve: true, for_user: user)
+      assert Map.put(result, :search_rank, nil) |> Map.put(:search_type, nil) == local_user
+    end
   end
 end
index 8b323372954bf9be125ac1658631a39c02fe2183..5a8a671552f18cf9bc218e4da47791e613ae49f3 100644 (file)
@@ -15,6 +15,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
 
   setup_all do
     Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
+
+    config_path = [:instance, :federating]
+    initial_setting = Pleroma.Config.get(config_path)
+
+    Pleroma.Config.put(config_path, true)
+    on_exit(fn -> Pleroma.Config.put(config_path, initial_setting) end)
+
     :ok
   end
 
index 68ec03c339616b5a4d2730c0194ca0c0fa2563ba..a914d3c4c77065462384820c36d7bf01003cb2c4 100644 (file)
@@ -11,12 +11,13 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
   alias Pleroma.User
   alias Pleroma.Web.ActivityPub.ActivityPub
   alias Pleroma.Web.ActivityPub.Transmogrifier
+  alias Pleroma.Web.CommonAPI
   alias Pleroma.Web.OStatus
   alias Pleroma.Web.Websub.WebsubClientSubscription
 
+  import Mock
   import Pleroma.Factory
   import ExUnit.CaptureLog
-  alias Pleroma.Web.CommonAPI
 
   setup_all do
     Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
@@ -46,12 +47,10 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
         data["object"]
         |> Map.put("inReplyTo", "https://shitposter.club/notice/2827873")
 
-      data =
-        data
-        |> Map.put("object", object)
-
+      data = Map.put(data, "object", object)
       {:ok, returned_activity} = Transmogrifier.handle_incoming(data)
-      returned_object = Object.normalize(returned_activity.data["object"])
+
+      returned_object = Object.normalize(returned_activity.data["object"], false)
 
       assert activity =
                Activity.get_create_by_object_ap_id(
@@ -61,6 +60,32 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
       assert returned_object.data["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873"
     end
 
+    test "it does not fetch replied-to activities beyond max_replies_depth" do
+      data =
+        File.read!("test/fixtures/mastodon-post-activity.json")
+        |> Poison.decode!()
+
+      object =
+        data["object"]
+        |> Map.put("inReplyTo", "https://shitposter.club/notice/2827873")
+
+      data = Map.put(data, "object", object)
+
+      with_mock Pleroma.Web.Federator,
+        allowed_incoming_reply_depth?: fn _ -> false end do
+        {:ok, returned_activity} = Transmogrifier.handle_incoming(data)
+
+        returned_object = Object.normalize(returned_activity.data["object"], false)
+
+        refute Activity.get_create_by_object_ap_id(
+                 "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"
+               )
+
+        assert returned_object.data["inReplyToAtomUri"] ==
+                 "https://shitposter.club/notice/2827873"
+      end
+    end
+
     test "it does not crash if the object in inReplyTo can't be fetched" do
       data =
         File.read!("test/fixtures/mastodon-post-activity.json")
index 0f43bc8f24e6d93c3857a9b265a66b80fcc365fc..69dd4d7473c4df10d78e638bb22537db48f03c0b 100644 (file)
@@ -12,6 +12,13 @@ defmodule Pleroma.Web.FederatorTest do
 
   setup_all do
     Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
+
+    config_path = [:instance, :federating]
+    initial_setting = Pleroma.Config.get(config_path)
+
+    Pleroma.Config.put(config_path, true)
+    on_exit(fn -> Pleroma.Config.put(config_path, initial_setting) end)
+
     :ok
   end
 
index ec75150ab88c377099eaa7aefed0cef5a69ad732..73791a95b5f4fcfede475d03a13089ebd2647cc6 100644 (file)
@@ -444,4 +444,39 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
       assert Enum.at(result[:options], 2)[:votes_count] == 1
     end
   end
+
+  test "embeds a relationship in the account" do
+    user = insert(:user)
+    other_user = insert(:user)
+
+    {:ok, activity} =
+      CommonAPI.post(user, %{
+        "status" => "drink more water"
+      })
+
+    result = StatusView.render("status.json", %{activity: activity, for: other_user})
+
+    assert result[:account][:pleroma][:relationship] ==
+             AccountView.render("relationship.json", %{user: other_user, target: user})
+  end
+
+  test "embeds a relationship in the account in reposts" do
+    user = insert(:user)
+    other_user = insert(:user)
+
+    {:ok, activity} =
+      CommonAPI.post(user, %{
+        "status" => "˙˙ɐʎns"
+      })
+
+    {:ok, activity, _object} = CommonAPI.repeat(activity.id, other_user)
+
+    result = StatusView.render("status.json", %{activity: activity, for: user})
+
+    assert result[:account][:pleroma][:relationship] ==
+             AccountView.render("relationship.json", %{user: user, target: other_user})
+
+    assert result[:reblog][:account][:pleroma][:relationship] ==
+             AccountView.render("relationship.json", %{user: user, target: user})
+  end
 end
index 7441e5fce9d5ab87ee10651750c96eed68e4d785..eae44dba5125e734841e96a8f0f865d369c58a74 100644 (file)
@@ -12,6 +12,13 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do
 
   setup_all do
     Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
+
+    config_path = [:instance, :federating]
+    initial_setting = Pleroma.Config.get(config_path)
+
+    Pleroma.Config.put(config_path, true)
+    on_exit(fn -> Pleroma.Config.put(config_path, initial_setting) end)
+
     :ok
   end
 
index f6be16862e34bb6864b2780390b1fa0625176189..acce330080dc394b05f81fe5785d49105ebaf672 100644 (file)
@@ -11,8 +11,10 @@ defmodule Pleroma.Web.OStatusTest do
   alias Pleroma.User
   alias Pleroma.Web.OStatus
   alias Pleroma.Web.XML
-  import Pleroma.Factory
+
   import ExUnit.CaptureLog
+  import Mock
+  import Pleroma.Factory
 
   setup_all do
     Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
@@ -266,10 +268,13 @@ defmodule Pleroma.Web.OStatusTest do
     assert favorited_activity.local
   end
 
-  test "handle incoming replies" do
+  test_with_mock "handle incoming replies, fetching replied-to activities if we don't have them",
+                 OStatus,
+                 [:passthrough],
+                 [] do
     incoming = File.read!("test/fixtures/incoming_note_activity_answer.xml")
     {:ok, [activity]} = OStatus.handle_incoming(incoming)
-    object = Object.normalize(activity.data["object"])
+    object = Object.normalize(activity.data["object"], false)
 
     assert activity.data["type"] == "Create"
     assert object.data["type"] == "Note"
@@ -282,6 +287,23 @@ defmodule Pleroma.Web.OStatusTest do
     assert object.data["id"] == "tag:gs.example.org:4040,2017-04-25:noticeId=55:objectType=note"
 
     assert "https://www.w3.org/ns/activitystreams#Public" in activity.data["to"]
+
+    assert called(OStatus.fetch_activity_from_url(object.data["inReplyTo"], :_))
+  end
+
+  test_with_mock "handle incoming replies, not fetching replied-to activities beyond max_replies_depth",
+                 OStatus,
+                 [:passthrough],
+                 [] do
+    incoming = File.read!("test/fixtures/incoming_note_activity_answer.xml")
+
+    with_mock Pleroma.Web.Federator,
+      allowed_incoming_reply_depth?: fn _ -> false end do
+      {:ok, [activity]} = OStatus.handle_incoming(incoming)
+      object = Object.normalize(activity.data["object"], false)
+
+      refute called(OStatus.fetch_activity_from_url(object.data["inReplyTo"], :_))
+    end
   end
 
   test "handle incoming follows" do
index 530562325f7a99664c48d6d2cfc9879448505987..c01e0112460b38397c8c554cae5e50117b694015 100644 (file)
@@ -5,6 +5,15 @@
 defmodule Pleroma.Web.FederatingPlugTest do
   use Pleroma.Web.ConnCase
 
+  setup_all do
+    config_path = [:instance, :federating]
+    initial_setting = Pleroma.Config.get(config_path)
+
+    on_exit(fn -> Pleroma.Config.put(config_path, initial_setting) end)
+
+    :ok
+  end
+
   test "returns and halt the conn when federating is disabled" do
     Pleroma.Config.put([:instance, :federating], false)
 
@@ -14,11 +23,11 @@ defmodule Pleroma.Web.FederatingPlugTest do
 
     assert conn.status == 404
     assert conn.halted
-
-    Pleroma.Config.put([:instance, :federating], true)
   end
 
   test "does nothing when federating is enabled" do
+    Pleroma.Config.put([:instance, :federating], true)
+
     conn =
       build_conn()
       |> Pleroma.Web.FederatingPlug.call(%{})
index 43fccfc7ab5241f948027589d807d9b66c821a94..a14ed3126d43395e298b95df87125ef79574e333 100644 (file)
@@ -10,6 +10,12 @@ defmodule Pleroma.Web.WebFinger.WebFingerControllerTest do
 
   setup do
     mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
+
+    config_path = [:instance, :federating]
+    initial_setting = Pleroma.Config.get(config_path)
+
+    Pleroma.Config.put(config_path, true)
+    on_exit(fn -> Pleroma.Config.put(config_path, initial_setting) end)
     :ok
   end
 
index f79745d58ce340dd0691beafe84bf5f033e05d34..aa7262beb1eb3c6d2a0cec2dabdead769e2523c2 100644 (file)
@@ -9,6 +9,16 @@ defmodule Pleroma.Web.Websub.WebsubControllerTest do
   alias Pleroma.Web.Websub
   alias Pleroma.Web.Websub.WebsubClientSubscription
 
+  setup_all do
+    config_path = [:instance, :federating]
+    initial_setting = Pleroma.Config.get(config_path)
+
+    Pleroma.Config.put(config_path, true)
+    on_exit(fn -> Pleroma.Config.put(config_path, initial_setting) end)
+
+    :ok
+  end
+
   test "websub subscription request", %{conn: conn} do
     user = insert(:user)