Merge remote-tracking branch 'pleroma/develop' into feature/addressable-lists
authorEgor Kislitsyn <egor@kislitsyn.com>
Tue, 14 May 2019 12:00:07 +0000 (19:00 +0700)
committerEgor Kislitsyn <egor@kislitsyn.com>
Tue, 14 May 2019 12:00:07 +0000 (19:00 +0700)
1  2 
lib/pleroma/web/activity_pub/activity_pub.ex
lib/pleroma/web/activity_pub/publisher.ex
lib/pleroma/web/activity_pub/transmogrifier.ex
lib/pleroma/web/common_api/common_api.ex
lib/pleroma/web/common_api/utils.ex
lib/pleroma/web/salmon/salmon.ex

index 3b71e03698d241ed55c2fbbfac63fbabb20982d3,11777c220cf522318a5150b70386c8f310bfcbef..eba8f80184018d61c83b3b538a0b2f1686378007
@@@ -782,9 -811,32 +810,30 @@@ defmodule Pleroma.Web.ActivityPub.Activ
      |> Activity.with_preloaded_object()
    end
  
+   defp maybe_preload_bookmarks(query, %{"skip_preload" => true}), do: query
+   defp maybe_preload_bookmarks(query, opts) do
+     query
+     |> Activity.with_preloaded_bookmark(opts["user"])
+   end
+   defp maybe_order(query, %{order: :desc}) do
+     query
+     |> order_by(desc: :id)
+   end
+   defp maybe_order(query, %{order: :asc}) do
+     query
+     |> order_by(asc: :id)
+   end
+   defp maybe_order(query, _), do: query
    def fetch_activities_query(recipients, opts \\ %{}) do
 -    base_query = from(activity in Activity)
 -
 -    base_query
 +    Activity
      |> maybe_preload_objects(opts)
+     |> maybe_preload_bookmarks(opts)
+     |> maybe_order(opts)
      |> restrict_recipients(recipients, opts["user"])
      |> restrict_tag(opts)
      |> restrict_tag_reject(opts)
index 0000000000000000000000000000000000000000,8e3af0a813868b91df3e839dd518e8d67d244162..036ac892e0d613efa9597828d3e7f6c14c923764
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,152 +1,201 @@@
 -  @doc """
 -  Publishes an activity to all relevant peers.
 -  """
 -  def publish(%User{} = actor, %Activity{} = activity) do
 -    remote_followers =
+ # 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.Publisher do
+   alias Pleroma.Activity
+   alias Pleroma.Config
+   alias Pleroma.Instances
+   alias Pleroma.User
+   alias Pleroma.Web.ActivityPub.Relay
+   alias Pleroma.Web.ActivityPub.Transmogrifier
+   import Pleroma.Web.ActivityPub.Visibility
+   @behaviour Pleroma.Web.Federator.Publisher
+   require Logger
+   @httpoison Application.get_env(:pleroma, :httpoison)
+   @moduledoc """
+   ActivityPub outgoing federation module.
+   """
+   @doc """
+   Determine if an activity can be represented by running it through Transmogrifier.
+   """
+   def is_representable?(%Activity{} = activity) do
+     with {:ok, _data} <- Transmogrifier.prepare_outgoing(activity.data) do
+       true
+     else
+       _e ->
+         false
+     end
+   end
+   @doc """
+   Publish a single message to a peer.  Takes a struct with the following
+   parameters set:
+   * `inbox`: the inbox to publish to
+   * `json`: the JSON message body representing the ActivityPub message
+   * `actor`: the actor which is signing the message
+   * `id`: the ActivityStreams URI of the message
+   """
+   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
+     digest = "SHA-256=" <> (:crypto.hash(:sha256, json) |> Base.encode64())
+     date =
+       NaiveDateTime.utc_now()
+       |> Timex.format!("{WDshort}, {0D} {Mshort} {YYYY} {h24}:{m}:{s} GMT")
+     signature =
+       Pleroma.Web.HTTPSignatures.sign(actor, %{
+         host: host,
+         "content-length": byte_size(json),
+         digest: digest,
+         date: date
+       })
+     with {:ok, %{status: code}} when code in 200..299 <-
+            result =
+              @httpoison.post(
+                inbox,
+                json,
+                [
+                  {"Content-Type", "application/activity+json"},
+                  {"Date", date},
+                  {"signature", signature},
+                  {"digest", digest}
+                ]
+              ) do
+       if !Map.has_key?(params, :unreachable_since) || params[:unreachable_since],
+         do: Instances.set_reachable(inbox)
+       result
+     else
+       {_post_result, response} ->
+         unless params[:unreachable_since], do: Instances.set_unreachable(inbox)
+         {:error, response}
+     end
+   end
+   defp should_federate?(inbox, public) do
+     if public do
+       true
+     else
+       inbox_info = URI.parse(inbox)
+       !Enum.member?(Pleroma.Config.get([:instance, :quarantined_instances], []), inbox_info.host)
+     end
+   end
 -        followers |> Enum.filter(&(!&1.local))
++  defp recipients(actor, activity) do
++    followers =
+       if actor.follower_address in activity.recipients do
+         {:ok, followers} = User.get_followers(actor)
 -    (Pleroma.Web.Salmon.remote_users(activity) ++ remote_followers)
++        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)
++
++      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__, %{
++        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
+       Logger.info(fn -> "Relaying #{activity.data["id"]} out" end)
+       Relay.publish(activity)
+     end
+     {:ok, data} = Transmogrifier.prepare_outgoing(activity.data)
+     json = Jason.encode!(data)
++    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"]
+     end)
+     |> Enum.uniq()
+     |> Enum.filter(fn inbox -> should_federate?(inbox, public) end)
+     |> Instances.filter_reachable()
+     |> Enum.each(fn {inbox, unreachable_since} ->
+       Pleroma.Web.Federator.Publisher.enqueue_one(
+         __MODULE__,
+         %{
+           inbox: inbox,
+           json: json,
+           actor: actor,
+           id: activity.data["id"],
+           unreachable_since: unreachable_since
+         }
+       )
+     end)
+   end
+   def gather_webfinger_links(%User{} = user) do
+     [
+       %{"rel" => "self", "type" => "application/activity+json", "href" => user.ap_id},
+       %{
+         "rel" => "self",
+         "type" => "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"",
+         "href" => user.ap_id
+       }
+     ]
+   end
+   def gather_nodeinfo_protocol_names, do: ["activitypub"]
+ end
index d47d5788ced936adc09b09d822c6fde726d02318,b53869c7582899eebfbad8bc188a4f2bcb47a730..ed2c0017f0fb86638dc4f83f8331b9233c4e07bb
@@@ -153,10 -150,9 +154,10 @@@ defmodule Pleroma.Web.CommonAPI d
               visibility
             ),
           {to, cc} <- to_for_user_and_mentions(user, mentions, in_reply_to, visibility),
 +         bcc <- bcc_for_list(user, visibility),
           context <- make_context(in_reply_to),
-          cw <- data["spoiler_text"],
-          full_payload <- String.trim(status <> (data["spoiler_text"] || "")),
+          cw <- data["spoiler_text"] || "",
+          full_payload <- String.trim(status <> cw),
           length when length in 1..limit <- String.length(full_payload),
           object <-
             make_note_data(
             Map.put(
               object,
               "emoji",
-              (Formatter.get_emoji(status) ++ Formatter.get_emoji(data["spoiler_text"]))
-              |> Enum.reduce(%{}, fn {name, file, _}, acc ->
-                Map.put(acc, name, "#{Pleroma.Web.Endpoint.static_url()}#{file}")
-              end)
+              Formatter.get_emoji_map(full_payload)
             ) do
 -      res =
 -        ActivityPub.create(
 -          %{
 -            to: to,
 -            actor: user,
 -            context: context,
 -            object: object,
 -            additional: %{"cc" => cc, "directMessage" => visibility == "direct"}
 -          },
 -          Pleroma.Web.ControllerHelper.truthy_param?(data["preview"]) || false
 -        )
 -
 -      res
 +      ActivityPub.create(
 +        %{
 +          to: to,
 +          actor: user,
 +          context: context,
 +          object: object,
 +          additional: %{"cc" => cc, "bcc" => bcc, "directMessage" => visibility == "direct"}
 +        },
 +        Pleroma.Web.ControllerHelper.truthy_param?(data["preview"]) || false
 +      )
      end
    end
  
Simple merge
Simple merge