http signatures: derive actor ID from key ID.
authorAriadne Conill <ariadne@dereferenced.org>
Wed, 17 Jul 2019 19:18:19 +0000 (19:18 +0000)
committerAriadne Conill <ariadne@dereferenced.org>
Wed, 17 Jul 2019 19:18:19 +0000 (19:18 +0000)
Almost all AP servers return their key ID as the actor URI with #main-key
added.  Hubzilla, which doesn't, uses a URL which refers to the actor
anyway, so worst case, Hubzilla users get refetched.

lib/pleroma/signature.ex
test/signature_test.exs

index 1a4d54c62ce030534429a0b6b493121461118200..a45c70a9dcfdb8a7443bff9912fe5083c1da06c3 100644 (file)
@@ -8,10 +8,16 @@ defmodule Pleroma.Signature do
   alias Pleroma.Keys
   alias Pleroma.User
   alias Pleroma.Web.ActivityPub.ActivityPub
-  alias Pleroma.Web.ActivityPub.Utils
+
+  defp key_id_to_actor_id(key_id) do
+    URI.parse(key_id)
+    |> Map.put(:fragment, nil)
+    |> URI.to_string()
+  end
 
   def fetch_public_key(conn) do
-    with actor_id <- Utils.get_ap_id(conn.params["actor"]),
+    with %{"keyId" => kid} <- HTTPSignatures.signature_for_conn(conn),
+         actor_id <- key_id_to_actor_id(kid),
          {:ok, public_key} <- User.get_public_key_for_ap_id(actor_id) do
       {:ok, public_key}
     else
@@ -21,7 +27,8 @@ defmodule Pleroma.Signature do
   end
 
   def refetch_public_key(conn) do
-    with actor_id <- Utils.get_ap_id(conn.params["actor"]),
+    with %{"keyId" => kid} <- HTTPSignatures.signature_for_conn(conn),
+         actor_id <- key_id_to_actor_id(kid),
          {:ok, _user} <- ActivityPub.make_user_from_ap_id(actor_id),
          {:ok, public_key} <- User.get_public_key_for_ap_id(actor_id) do
       {:ok, public_key}
index 4920196c76984eb76c290d54be69349cfce12f73..840987cd6bacc46b0f4ced6fbe6bf2ee6454a52a 100644 (file)
@@ -31,25 +31,29 @@ defmodule Pleroma.SignatureTest do
     65_537
   }
 
+  defp make_fake_signature(key_id), do: "keyId=\"#{key_id}\""
+
+  defp make_fake_conn(key_id),
+    do: %Plug.Conn{req_headers: %{"signature" => make_fake_signature(key_id <> "#main-key")}}
+
   describe "fetch_public_key/1" do
     test "it returns key" do
       expected_result = {:ok, @rsa_public_key}
 
       user = insert(:user, %{info: %{source_data: %{"publicKey" => @public_key}}})
 
-      assert Signature.fetch_public_key(%Plug.Conn{params: %{"actor" => user.ap_id}}) ==
-               expected_result
+      assert Signature.fetch_public_key(make_fake_conn(user.ap_id)) == expected_result
     end
 
     test "it returns error when not found user" do
-      assert Signature.fetch_public_key(%Plug.Conn{params: %{"actor" => "test-ap_id"}}) ==
+      assert Signature.fetch_public_key(make_fake_conn("test-ap_id")) ==
                {:error, :error}
     end
 
     test "it returns error if public key is empty" do
       user = insert(:user, %{info: %{source_data: %{"publicKey" => %{}}}})
 
-      assert Signature.fetch_public_key(%Plug.Conn{params: %{"actor" => user.ap_id}}) ==
+      assert Signature.fetch_public_key(make_fake_conn(user.ap_id)) ==
                {:error, :error}
     end
   end
@@ -58,12 +62,12 @@ defmodule Pleroma.SignatureTest do
     test "it returns key" do
       ap_id = "https://mastodon.social/users/lambadalambda"
 
-      assert Signature.refetch_public_key(%Plug.Conn{params: %{"actor" => ap_id}}) ==
+      assert Signature.refetch_public_key(make_fake_conn(ap_id)) ==
                {:ok, @rsa_public_key}
     end
 
     test "it returns error when not found user" do
-      assert Signature.refetch_public_key(%Plug.Conn{params: %{"actor" => "test-ap_id"}}) ==
+      assert Signature.refetch_public_key(make_fake_conn("test-ap_id")) ==
                {:error, {:error, :ok}}
     end
   end