http signatures: derive actor ID from key ID.

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.
This commit is contained in:
Ariadne Conill 2019-07-17 19:18:19 +00:00
parent 1e3aff6ef1
commit f84fb340b7
2 changed files with 20 additions and 9 deletions

View file

@ -8,10 +8,16 @@ defmodule Pleroma.Signature do
alias Pleroma.Keys alias Pleroma.Keys
alias Pleroma.User alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub 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 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} <- User.get_public_key_for_ap_id(actor_id) do
{:ok, public_key} {:ok, public_key}
else else
@ -21,7 +27,8 @@ def fetch_public_key(conn) do
end end
def refetch_public_key(conn) do 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, _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} <- User.get_public_key_for_ap_id(actor_id) do
{:ok, public_key} {:ok, public_key}

View file

@ -31,25 +31,29 @@ defmodule Pleroma.SignatureTest do
65_537 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 describe "fetch_public_key/1" do
test "it returns key" do test "it returns key" do
expected_result = {:ok, @rsa_public_key} expected_result = {:ok, @rsa_public_key}
user = insert(:user, %{info: %{source_data: %{"publicKey" => @public_key}}}) user = insert(:user, %{info: %{source_data: %{"publicKey" => @public_key}}})
assert Signature.fetch_public_key(%Plug.Conn{params: %{"actor" => user.ap_id}}) == assert Signature.fetch_public_key(make_fake_conn(user.ap_id)) == expected_result
expected_result
end end
test "it returns error when not found user" do 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} {:error, :error}
end end
test "it returns error if public key is empty" do test "it returns error if public key is empty" do
user = insert(:user, %{info: %{source_data: %{"publicKey" => %{}}}}) 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} {:error, :error}
end end
end end
@ -58,12 +62,12 @@ test "it returns error if public key is empty" do
test "it returns key" do test "it returns key" do
ap_id = "https://mastodon.social/users/lambadalambda" 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} {:ok, @rsa_public_key}
end end
test "it returns error when not found user" do 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}} {:error, {:error, :ok}}
end end
end end