X-Git-Url: http://git.squeep.com/?a=blobdiff_plain;f=lib%2Fpleroma%2Fweb%2Fsalmon%2Fsalmon.ex;h=9e91a5a4061e9b769d3c90f0eb670d5ae3899442;hb=f1890d2cacfa09dd22b06a8d041c04dbeba9e138;hp=0e2cfddd0ab7d7ec8b267ea311871f423ff0c2e0;hpb=88f92693f25c34f8ab82d4ed809b266bf5fb9ff8;p=akkoma diff --git a/lib/pleroma/web/salmon/salmon.ex b/lib/pleroma/web/salmon/salmon.ex index 0e2cfddd0..9e91a5a40 100644 --- a/lib/pleroma/web/salmon/salmon.ex +++ b/lib/pleroma/web/salmon/salmon.ex @@ -1,10 +1,23 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + defmodule Pleroma.Web.Salmon do - @httpoison Application.get_env(:pleroma, :httpoison) + @behaviour Pleroma.Web.Federator.Publisher use Bitwise - alias Pleroma.Web.XML - alias Pleroma.Web.OStatus.ActivityRepresenter + + alias Pleroma.Activity + alias Pleroma.HTTP + alias Pleroma.Instances + alias Pleroma.Keys alias Pleroma.User + alias Pleroma.Web.ActivityPub.Visibility + alias Pleroma.Web.Federator.Publisher + alias Pleroma.Web.OStatus + alias Pleroma.Web.OStatus.ActivityRepresenter + alias Pleroma.Web.XML + require Logger def decode(salmon) do @@ -76,45 +89,6 @@ defmodule Pleroma.Web.Salmon do "RSA.#{modulus_enc}.#{exponent_enc}" end - # Native generation of RSA keys is only available since OTP 20+ and in default build conditions - # We try at compile time to generate natively an RSA key otherwise we fallback on the old way. - try do - _ = :public_key.generate_key({:rsa, 2048, 65537}) - - def generate_rsa_pem do - key = :public_key.generate_key({:rsa, 2048, 65537}) - entry = :public_key.pem_entry_encode(:RSAPrivateKey, key) - pem = :public_key.pem_encode([entry]) |> String.trim_trailing() - {:ok, pem} - end - rescue - _ -> - def generate_rsa_pem do - port = Port.open({:spawn, "openssl genrsa"}, [:binary]) - - {:ok, pem} = - receive do - {^port, {:data, pem}} -> {:ok, pem} - end - - Port.close(port) - - if Regex.match?(~r/RSA PRIVATE KEY/, pem) do - {:ok, pem} - else - :error - end - end - end - - def keys_from_pem(pem) do - [private_key_code] = :public_key.pem_decode(pem) - private_key = :public_key.pem_entry_decode(private_key_code) - {:RSAPrivateKey, _, modulus, exponent, _, _, _, _, _, _, _} = private_key - public_key = {:RSAPublicKey, modulus, exponent} - {:ok, private_key, public_key} - end - def encode(private_key, doc) do type = "application/atom+xml" encoding = "base64url" @@ -157,20 +131,31 @@ defmodule Pleroma.Web.Salmon do |> Enum.filter(fn user -> user && !user.local end) end - defp send_to_user(%{info: %{salmon: salmon}}, feed, poster) do - with {:ok, %{status: code}} <- - poster.( - salmon, + @doc "Pushes an activity to remote account." + def publish_one(%{recipient: %{info: %{salmon: salmon}}} = params), + do: publish_one(Map.put(params, :recipient, salmon)) + + def publish_one(%{recipient: url, feed: feed} = params) when is_binary(url) do + with {:ok, %{status: code}} when code in 200..299 <- + HTTP.post( + url, feed, [{"Content-Type", "application/magic-envelope+xml"}] ) do - Logger.debug(fn -> "Pushed to #{salmon}, code #{code}" end) + if !Map.has_key?(params, :unreachable_since) || params[:unreachable_since], + do: Instances.set_reachable(url) + + Logger.debug(fn -> "Pushed to #{url}, code #{code}" end) + :ok else - e -> Logger.debug(fn -> "Pushing Salmon to #{salmon} failed, #{inspect(e)}" end) + e -> + unless params[:unreachable_since], do: Instances.set_reachable(url) + Logger.debug(fn -> "Pushing Salmon to #{url} failed, #{inspect(e)}" end) + {:error, "Unreachable instance"} end end - defp send_to_user(_, _, _), do: nil + def publish_one(_), do: :noop @supported_activities [ "Create", @@ -180,9 +165,20 @@ defmodule Pleroma.Web.Salmon do "Undo", "Delete" ] - def publish(user, activity, poster \\ &@httpoison.post/4) - def publish(%{info: %{keys: keys}} = user, %{data: %{"type" => type}} = activity, poster) + def is_representable?(%Activity{data: %{"type" => type}} = activity) + when type in @supported_activities, + do: Visibility.is_public?(activity) + + def is_representable?(_), do: false + + @doc """ + Publishes an activity to remote accounts + """ + @spec publish(User.t(), Pleroma.Activity.t()) :: none + def publish(user, activity) + + def publish(%{info: %{keys: keys}} = user, %{data: %{"type" => type}} = activity) when type in @supported_activities do feed = ActivityRepresenter.to_simple_form(activity, user, true) @@ -192,18 +188,43 @@ defmodule Pleroma.Web.Salmon do |> :xmerl.export_simple(:xmerl_xml) |> to_string - {:ok, private, _} = keys_from_pem(keys) + {:ok, private, _} = Keys.keys_from_pem(keys) {:ok, feed} = encode(private, feed) - remote_users(activity) + remote_users = remote_users(activity) + + salmon_urls = Enum.map(remote_users, & &1.info.salmon) + reachable_urls_metadata = Instances.filter_reachable(salmon_urls) + reachable_urls = Map.keys(reachable_urls_metadata) + + remote_users + |> Enum.filter(&(&1.info.salmon in reachable_urls)) |> Enum.each(fn remote_user -> - Task.start(fn -> - Logger.debug(fn -> "Sending Salmon to #{remote_user.ap_id}" end) - send_to_user(remote_user, feed, poster) - end) + Logger.debug(fn -> "Sending Salmon to #{remote_user.ap_id}" end) + + Publisher.enqueue_one(__MODULE__, %{ + recipient: remote_user, + feed: feed, + unreachable_since: reachable_urls_metadata[remote_user.info.salmon] + }) end) end end - def publish(%{id: id}, _, _), do: Logger.debug(fn -> "Keys missing for user #{id}" end) + def publish(%{id: id}, _), do: Logger.debug(fn -> "Keys missing for user #{id}" end) + + def gather_webfinger_links(%User{} = user) do + {:ok, _private, public} = Keys.keys_from_pem(user.info.keys) + magic_key = encode_key(public) + + [ + %{"rel" => "salmon", "href" => OStatus.salmon_path(user)}, + %{ + "rel" => "magic-public-key", + "href" => "data:application/magic-public-key,#{magic_key}" + } + ] + end + + def gather_nodeinfo_protocol_names, do: [] end