plugs: add MappedSignatureToIdentityPlug
authorAriadne Conill <ariadne@dereferenced.org>
Thu, 18 Jul 2019 15:38:45 +0000 (15:38 +0000)
committerAriadne Conill <ariadne@dereferenced.org>
Thu, 18 Jul 2019 15:38:45 +0000 (15:38 +0000)
lib/pleroma/plugs/mapped_signature_to_identity_plug.ex [new file with mode: 0644]
lib/pleroma/web/router.ex

diff --git a/lib/pleroma/plugs/mapped_signature_to_identity_plug.ex b/lib/pleroma/plugs/mapped_signature_to_identity_plug.ex
new file mode 100644 (file)
index 0000000..ae93395
--- /dev/null
@@ -0,0 +1,64 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.Plugs.MappedSignatureToIdentityPlug do
+  alias Pleroma.Signature
+  alias Pleroma.User
+  alias Pleroma.Web.ActivityPub.Utils
+
+  import Plug.Conn
+  require Logger
+
+  def init(options), do: options
+
+  defp key_id_from_conn(conn) do
+    with %{"keyId" => key_id} <- HTTPSignatures.signature_for_conn(conn) do
+      Signature.key_id_to_actor_id(key_id)
+    else
+      _ ->
+        nil
+    end
+  end
+
+  defp user_from_key_id(conn) do
+    with key_actor_id when is_binary(key_actor_id) <- key_id_from_conn(conn),
+         %User{} = user <- User.get_or_fetch_by_ap_id(key_actor_id) do
+      user
+    else
+      _ ->
+        nil
+    end
+  end
+
+  def call(%{assigns: %{mapped_identity: _}} = conn, _opts), do: conn
+
+  # if this has payload make sure it is signed by the same actor that made it
+  def call(%{assigns: %{valid_signature: true}, params: %{"actor" => actor}} = conn, _opts) do
+    with actor_id <- Utils.get_ap_id(actor),
+         %User{} = user <- user_from_key_id(conn),
+         true <- user.ap_id == actor_id do
+      assign(conn, :mapped_identity, user)
+    else
+      _ ->
+        Logger.debug("Failed to map identity from signature (payload actor mismatch?)")
+        Logger.debug("key_id=#{key_id_from_conn(conn)}, actor=#{actor}")
+        conn
+    end
+  end
+
+  # no payload, probably a signed fetch
+  def call(%{assigns: %{valid_signature: true}} = conn, _opts) do
+    with %User{} = user <- user_from_key_id(conn) do
+      assign(conn, :mapped_identity, user)
+    else
+      _ ->
+        Logger.debug("Failed to map identity from signature (no payload actor mismatch)")
+        Logger.debug("key_id=#{key_id_from_conn(conn)}")
+        conn
+    end
+  end
+
+  # no signature at all
+  def call(conn, _opts), do: conn
+end
index 8095ac4b19728f23c7e65c714b9cca88844fcf57..518720d38c05f5af68abcc5f95c093150ff1d0eb 100644 (file)
@@ -617,6 +617,7 @@ defmodule Pleroma.Web.Router do
   pipeline :activitypub do
     plug(:accepts, ["activity+json", "json"])
     plug(Pleroma.Web.Plugs.HTTPSignaturePlug)
+    plug(Pleroma.Web.Plugs.MappedSignatureToIdentityPlug)
   end
 
   scope "/", Pleroma.Web.ActivityPub do