From: Egor Kislitsyn Date: Tue, 14 May 2019 12:00:07 +0000 (+0700) Subject: Merge remote-tracking branch 'pleroma/develop' into feature/addressable-lists X-Git-Url: https://git.squeep.com/?a=commitdiff_plain;h=e82e73478e577782407bc8452d17925675d99d10;p=akkoma Merge remote-tracking branch 'pleroma/develop' into feature/addressable-lists --- e82e73478e577782407bc8452d17925675d99d10 diff --cc lib/pleroma/web/activity_pub/activity_pub.ex index 3b71e0369,11777c220..eba8f8018 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@@ -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) diff --cc lib/pleroma/web/activity_pub/publisher.ex index 000000000,8e3af0a81..036ac892e mode 000000,100644..100644 --- a/lib/pleroma/web/activity_pub/publisher.ex +++ b/lib/pleroma/web/activity_pub/publisher.ex @@@ -1,0 -1,152 +1,201 @@@ + # Pleroma: A lightweight social networking server + # Copyright © 2017-2019 Pleroma Authors + # 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 + - @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) ++ ++ 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) + - (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"] + 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 diff --cc lib/pleroma/web/common_api/common_api.ex index d47d5788c,b53869c75..ed2c0017f --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@@ -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( @@@ -174,21 -170,21 +175,18 @@@ 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