diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 3998f6226..a70c2e616 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -2070,7 +2070,7 @@ defmodule Pleroma.User do |> set_cache() end - defdelegate public_key(user), to: SigningKey + defdelegate public_key(user), to: SigningKey, as: :public_key_pem @doc "Gets or fetch a user by uri or nickname." @spec get_or_fetch(String.t()) :: {:ok, User.t()} | {:error, String.t()} diff --git a/lib/pleroma/user/signing_key.ex b/lib/pleroma/user/signing_key.ex index dd7ef1813..f99ad1679 100644 --- a/lib/pleroma/user/signing_key.ex +++ b/lib/pleroma/user/signing_key.ex @@ -110,7 +110,7 @@ defmodule Pleroma.User.SigningKey do {:ok, :public_key.pem_encode([public_key])} end - @spec public_key(__MODULE__) :: {:ok, binary()} | {:error, String.t()} + @spec public_key_decoded(__MODULE__) :: {:ok, binary()} | {:error, String.t()} @doc """ Return public key data in binary format. """ @@ -124,8 +124,12 @@ defmodule Pleroma.User.SigningKey do {:ok, decoded} end - def public_key(_), do: {:error, "key not found"} + def public_key_decoded(_), do: {:error, "key not found"} + @spec public_key_pem(__MODULE__) :: {:ok, binary()} | {:error, String.t()} + @doc """ + Return public key data for user in PEM format + """ def public_key_pem(%User{} = user) do case Repo.preload(user, :signing_key) do %User{signing_key: %__MODULE__{public_key: public_key_pem}} -> {:ok, public_key_pem} diff --git a/test/pleroma/user/signing_key_test.exs b/test/pleroma/user/signing_key_test.exs index c46a2d2ea..52b6db202 100644 --- a/test/pleroma/user/signing_key_test.exs +++ b/test/pleroma/user/signing_key_test.exs @@ -15,7 +15,7 @@ defmodule Pleroma.User.SigningKeyTests do defp maybe_put(map, _, nil), do: map defp maybe_put(map, key, val), do: Kernel.put_in(map, key, val) - defp get_body_actor(key_id \\ nil, user_id \\ nil, owner_id \\ nil) do + defp get_body_actor(key_id, user_id, owner_id \\ nil) do owner_id = owner_id || user_id File.read!("test/fixtures/tesla_mock/admin@mastdon.example.org.json") @@ -233,7 +233,6 @@ defmodule Pleroma.User.SigningKeyTests do assert user.signing_key.key_id == refreshed_org_key.key_id end - @tag :skip test "remote users sharing signing key ID don't break our database" do # in principle a valid setup using this can be cosntructed, # but so far not observed in practice and our db scheme cannot handle it. @@ -245,6 +244,7 @@ defmodule Pleroma.User.SigningKeyTests do |> with_signing_key(%{key_id: key_id}) key_owner = "https://mastodon.example.org/#" + key_owner_doc = get_body_actor(key_id, key_owner) user2_ap_id = user1.ap_id <> "22" user2_doc = get_body_actor(user1.signing_key.key_id, user2_ap_id, key_owner) @@ -253,7 +253,7 @@ defmodule Pleroma.User.SigningKeyTests do user3_doc = get_body_actor(user1.signing_key.key_id, user2_ap_id) standalone_key_doc = - get_body_rawkey(key_id, "https://mastodon.example.org/#", user1.signing_key.public_key) + get_body_rawkey(key_id, key_owner, user1.signing_key.public_key) ap_headers = [ {"content-type", "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""} @@ -268,6 +268,14 @@ defmodule Pleroma.User.SigningKeyTests do headers: ap_headers } + %{method: :get, url: ^key_owner} -> + %Tesla.Env{ + status: 200, + body: key_owner_doc, + url: key_owner, + headers: ap_headers + } + %{method: :get, url: ^user2_ap_id} -> %Tesla.Env{ status: 200, @@ -285,7 +293,11 @@ defmodule Pleroma.User.SigningKeyTests do } end) - {:error, _} = SigningKey.fetch_remote_key(key_id) + assert match?({:ok, _}, SigningKey.public_key_pem(user1)) + + # No further associations for the same key id can be inserted, + # but new users still fetched (without signing keys) + assert_raise Ecto.ConstraintError, fn -> SigningKey.fetch_remote_key(key_id) end {:ok, user2} = User.get_or_fetch_by_ap_id(user2_ap_id) {:ok, user3} = User.get_or_fetch_by_ap_id(user3_ap_id) @@ -299,8 +311,8 @@ defmodule Pleroma.User.SigningKeyTests do assert match?([%SigningKey{}], keys) assert [db_key] == keys assert db_key.user_id == user1.id - assert match?({:ok, _}, SigningKey.public_key(user1)) - assert {:error, "key not found"} == SigningKey.public_key(user2) - assert {:error, "key not found"} == SigningKey.public_key(user3) + assert match?({:ok, _}, SigningKey.public_key_pem(user1)) + assert {:error, "key not found"} == SigningKey.public_key_pem(user2) + assert {:error, "key not found"} == SigningKey.public_key_pem(user3) end end