move key generation functions into Pleroma.Keys module
authorWilliam Pitcock <nenolod@dereferenced.org>
Wed, 22 May 2019 03:58:15 +0000 (03:58 +0000)
committerWilliam Pitcock <nenolod@dereferenced.org>
Wed, 22 May 2019 03:58:15 +0000 (03:58 +0000)
14 files changed:
lib/pleroma/keys.ex [new file with mode: 0644]
lib/pleroma/signature.ex
lib/pleroma/user.ex
lib/pleroma/web/activity_pub/activity_pub_controller.ex
lib/pleroma/web/activity_pub/views/user_view.ex
lib/pleroma/web/federator/federator.ex
lib/pleroma/web/salmon/salmon.ex
lib/pleroma/web/web_finger/web_finger.ex
test/keys_test.exs [new file with mode: 0644]
test/user_test.exs
test/web/activity_pub/activity_pub_test.exs
test/web/activity_pub/views/user_view_test.exs
test/web/salmon/salmon_test.exs
test/web/web_finger/web_finger_test.exs

diff --git a/lib/pleroma/keys.ex b/lib/pleroma/keys.ex
new file mode 100644 (file)
index 0000000..b7bc7a4
--- /dev/null
@@ -0,0 +1,44 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Keys do
+  # 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, 65_537})
+
+    def generate_rsa_pem do
+      key = :public_key.generate_key({:rsa, 2048, 65_537})
+      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
+end
index b7ecf00a0e456a69d0a2e5b2eb7a03d07d1423f1..1a4d54c62ce030534429a0b6b493121461118200 100644 (file)
@@ -5,11 +5,10 @@
 defmodule Pleroma.Signature do
   @behaviour HTTPSignatures.Adapter
 
+  alias Pleroma.Keys
   alias Pleroma.User
   alias Pleroma.Web.ActivityPub.ActivityPub
   alias Pleroma.Web.ActivityPub.Utils
-  alias Pleroma.Web.Salmon
-  alias Pleroma.Web.WebFinger
 
   def fetch_public_key(conn) do
     with actor_id <- Utils.get_ap_id(conn.params["actor"]),
@@ -33,8 +32,8 @@ defmodule Pleroma.Signature do
   end
 
   def sign(%User{} = user, headers) do
-    with {:ok, %{info: %{keys: keys}}} <- WebFinger.ensure_keys_present(user),
-         {:ok, private_key, _} <- Salmon.keys_from_pem(keys) do
+    with {:ok, %{info: %{keys: keys}}} <- User.ensure_keys_present(user),
+         {:ok, private_key, _} <- Keys.keys_from_pem(keys) do
       HTTPSignatures.sign(private_key, user.ap_id <> "#main-key", headers)
     end
   end
index 05fe58f7ca07cd30e1e0b1441b8f6425b9201a93..653dec95f2b5d0515e2267008cf1eb7efe1851fe 100644 (file)
@@ -10,6 +10,7 @@ defmodule Pleroma.User do
 
   alias Comeonin.Pbkdf2
   alias Pleroma.Activity
+  alias Pleroma.Keys
   alias Pleroma.Notification
   alias Pleroma.Object
   alias Pleroma.Registration
@@ -1422,4 +1423,24 @@ defmodule Pleroma.User do
       }
     }
   end
+
+  def ensure_keys_present(user) do
+    info = user.info
+
+    if info.keys do
+      {:ok, user}
+    else
+      {:ok, pem} = Keys.generate_rsa_pem()
+
+      info_cng =
+        info
+        |> User.Info.set_keys(pem)
+
+      cng =
+        Ecto.Changeset.change(user)
+        |> Ecto.Changeset.put_embed(:info, info_cng)
+
+      update_and_set_cache(cng)
+    end
+  end
 end
index c967ab7a9fdc4430a7414598e27eac1ffbbb45d8..ad2ca1e5487511dfaf1bc8409766608a842ddc08 100644 (file)
@@ -39,7 +39,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
 
   def user(conn, %{"nickname" => nickname}) do
     with %User{} = user <- User.get_cached_by_nickname(nickname),
-         {:ok, user} <- Pleroma.Web.WebFinger.ensure_keys_present(user) do
+         {:ok, user} <- User.ensure_keys_present(user) do
       conn
       |> put_resp_header("content-type", "application/activity+json")
       |> json(UserView.render("user.json", %{user: user}))
@@ -106,7 +106,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
 
   def following(conn, %{"nickname" => nickname, "page" => page}) do
     with %User{} = user <- User.get_cached_by_nickname(nickname),
-         {:ok, user} <- Pleroma.Web.WebFinger.ensure_keys_present(user) do
+         {:ok, user} <- User.ensure_keys_present(user) do
       {page, _} = Integer.parse(page)
 
       conn
@@ -117,7 +117,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
 
   def following(conn, %{"nickname" => nickname}) do
     with %User{} = user <- User.get_cached_by_nickname(nickname),
-         {:ok, user} <- Pleroma.Web.WebFinger.ensure_keys_present(user) do
+         {:ok, user} <- User.ensure_keys_present(user) do
       conn
       |> put_resp_header("content-type", "application/activity+json")
       |> json(UserView.render("following.json", %{user: user}))
@@ -126,7 +126,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
 
   def followers(conn, %{"nickname" => nickname, "page" => page}) do
     with %User{} = user <- User.get_cached_by_nickname(nickname),
-         {:ok, user} <- Pleroma.Web.WebFinger.ensure_keys_present(user) do
+         {:ok, user} <- User.ensure_keys_present(user) do
       {page, _} = Integer.parse(page)
 
       conn
@@ -137,7 +137,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
 
   def followers(conn, %{"nickname" => nickname}) do
     with %User{} = user <- User.get_cached_by_nickname(nickname),
-         {:ok, user} <- Pleroma.Web.WebFinger.ensure_keys_present(user) do
+         {:ok, user} <- User.ensure_keys_present(user) do
       conn
       |> put_resp_header("content-type", "application/activity+json")
       |> json(UserView.render("followers.json", %{user: user}))
@@ -146,7 +146,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
 
   def outbox(conn, %{"nickname" => nickname} = params) do
     with %User{} = user <- User.get_cached_by_nickname(nickname),
-         {:ok, user} <- Pleroma.Web.WebFinger.ensure_keys_present(user) do
+         {:ok, user} <- User.ensure_keys_present(user) do
       conn
       |> put_resp_header("content-type", "application/activity+json")
       |> json(UserView.render("outbox.json", %{user: user, max_id: params["max_id"]}))
@@ -195,7 +195,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
 
   def relay(conn, _params) do
     with %User{} = user <- Relay.get_actor(),
-         {:ok, user} <- Pleroma.Web.WebFinger.ensure_keys_present(user) do
+         {:ok, user} <- User.ensure_keys_present(user) do
       conn
       |> put_resp_header("content-type", "application/activity+json")
       |> json(UserView.render("user.json", %{user: user}))
index 1254fdf6cfdf94352ff1eba73f927f638ef0978f..327e0e05bbca5a373a28dc15eb301c4b6148e102 100644 (file)
@@ -5,6 +5,7 @@
 defmodule Pleroma.Web.ActivityPub.UserView do
   use Pleroma.Web, :view
 
+  alias Pleroma.Keys
   alias Pleroma.Repo
   alias Pleroma.User
   alias Pleroma.Web.ActivityPub.ActivityPub
@@ -12,8 +13,6 @@ defmodule Pleroma.Web.ActivityPub.UserView do
   alias Pleroma.Web.ActivityPub.Utils
   alias Pleroma.Web.Endpoint
   alias Pleroma.Web.Router.Helpers
-  alias Pleroma.Web.Salmon
-  alias Pleroma.Web.WebFinger
 
   import Ecto.Query
 
@@ -34,8 +33,8 @@ defmodule Pleroma.Web.ActivityPub.UserView do
 
   # the instance itself is not a Person, but instead an Application
   def render("user.json", %{user: %{nickname: nil} = user}) do
-    {:ok, user} = WebFinger.ensure_keys_present(user)
-    {:ok, _, public_key} = Salmon.keys_from_pem(user.info.keys)
+    {:ok, user} = User.ensure_keys_present(user)
+    {:ok, _, public_key} = Keys.keys_from_pem(user.info.keys)
     public_key = :public_key.pem_entry_encode(:SubjectPublicKeyInfo, public_key)
     public_key = :public_key.pem_encode([public_key])
 
@@ -62,8 +61,8 @@ defmodule Pleroma.Web.ActivityPub.UserView do
   end
 
   def render("user.json", %{user: user}) do
-    {:ok, user} = WebFinger.ensure_keys_present(user)
-    {:ok, _, public_key} = Salmon.keys_from_pem(user.info.keys)
+    {:ok, user} = User.ensure_keys_present(user)
+    {:ok, _, public_key} = Keys.keys_from_pem(user.info.keys)
     public_key = :public_key.pem_entry_encode(:SubjectPublicKeyInfo, public_key)
     public_key = :public_key.pem_encode([public_key])
 
index 169fdf4dc13ed2c88cd8c6befb50a8d54d647fa9..6b0b75284e2dd70871df3bac6e7c381aa181f8b0 100644 (file)
@@ -11,7 +11,6 @@ defmodule Pleroma.Web.Federator do
   alias Pleroma.Web.ActivityPub.Utils
   alias Pleroma.Web.Federator.Publisher
   alias Pleroma.Web.Federator.RetryQueue
-  alias Pleroma.Web.WebFinger
   alias Pleroma.Web.Websub
 
   require Logger
@@ -77,9 +76,8 @@ defmodule Pleroma.Web.Federator do
   def perform(:publish, activity) do
     Logger.debug(fn -> "Running publish for #{activity.data["id"]}" end)
 
-    with actor when not is_nil(actor) <- User.get_cached_by_ap_id(activity.data["actor"]) do
-      {:ok, actor} = WebFinger.ensure_keys_present(actor)
-
+    with %User{} = actor <- User.get_cached_by_ap_id(activity.data["actor"]),
+         {:ok, actor} <- User.ensure_keys_present(actor) do
       Publisher.publish(actor, activity)
     end
   end
index 42709ab47251531d594cdf7938b68d089a7a729e..fa30f73cdf0b7b7944d879639227cf68235042f1 100644 (file)
@@ -10,6 +10,7 @@ defmodule Pleroma.Web.Salmon do
   use Bitwise
 
   alias Pleroma.Activity
+  alias Pleroma.Keys
   alias Pleroma.Instances
   alias Pleroma.User
   alias Pleroma.Web.ActivityPub.Visibility
@@ -89,45 +90,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, 65_537})
-
-    def generate_rsa_pem do
-      key = :public_key.generate_key({:rsa, 2048, 65_537})
-      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"
@@ -227,7 +189,7 @@ 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 = remote_users(activity)
@@ -253,7 +215,7 @@ defmodule Pleroma.Web.Salmon do
   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_from_pem(user.info.keys)
+    {:ok, _private, public} = Keys.keys_from_pem(user.info.keys)
     magic_key = encode_key(public)
 
     [
index 1239b962ad3fd8e9f05a0f4f85d7377884eb195f..c5b7d4acb1a59fcb59a9e1edef95a7c91888a04e 100644 (file)
@@ -8,7 +8,6 @@ defmodule Pleroma.Web.WebFinger do
   alias Pleroma.User
   alias Pleroma.Web
   alias Pleroma.Web.Federator.Publisher
-  alias Pleroma.Web.Salmon
   alias Pleroma.Web.XML
   alias Pleroma.XmlBuilder
   require Jason
@@ -61,7 +60,7 @@ defmodule Pleroma.Web.WebFinger do
   end
 
   def represent_user(user, "JSON") do
-    {:ok, user} = ensure_keys_present(user)
+    {:ok, user} = User.ensure_keys_present(user)
 
     %{
       "subject" => "acct:#{user.nickname}@#{Pleroma.Web.Endpoint.host()}",
@@ -71,7 +70,7 @@ defmodule Pleroma.Web.WebFinger do
   end
 
   def represent_user(user, "XML") do
-    {:ok, user} = ensure_keys_present(user)
+    {:ok, user} = User.ensure_keys_present(user)
 
     links =
       gather_links(user)
@@ -88,27 +87,6 @@ defmodule Pleroma.Web.WebFinger do
     |> XmlBuilder.to_doc()
   end
 
-  # This seems a better fit in Salmon
-  def ensure_keys_present(user) do
-    info = user.info
-
-    if info.keys do
-      {:ok, user}
-    else
-      {:ok, pem} = Salmon.generate_rsa_pem()
-
-      info_cng =
-        info
-        |> User.Info.set_keys(pem)
-
-      cng =
-        Ecto.Changeset.change(user)
-        |> Ecto.Changeset.put_embed(:info, info_cng)
-
-      User.update_and_set_cache(cng)
-    end
-  end
-
   defp get_magic_key(magic_key) do
     "data:application/magic-public-key," <> magic_key = magic_key
     {:ok, magic_key}
diff --git a/test/keys_test.exs b/test/keys_test.exs
new file mode 100644 (file)
index 0000000..776fdea
--- /dev/null
@@ -0,0 +1,20 @@
+defmodule Pleroma.KeysTest do
+  use Pleroma.DataCase
+
+  alias Pleroma.Keys
+
+  test "generates an RSA private key pem" do
+    {:ok, key} = Keys.generate_rsa_pem()
+
+    assert is_binary(key)
+    assert Regex.match?(~r/RSA/, key)
+  end
+
+  test "returns a public and private key from a pem" do
+    pem = File.read!("test/fixtures/private_key.pem")
+    {:ok, private, public} = Keys.keys_from_pem(pem)
+
+    assert elem(private, 0) == :RSAPrivateKey
+    assert elem(public, 0) == :RSAPublicKey
+  end
+end
index cb6afbe07352cde5f1d7a7844c3c8c7853a71b8c..019f2b56d1fb648aff531e5a4916211be5cdf3a1 100644 (file)
@@ -1251,4 +1251,19 @@ defmodule Pleroma.UserTest do
       refute user.info.confirmation_token
     end
   end
+
+  describe "ensure_keys_present" do
+    test "it creates keys for a user and stores them in info" do
+      user = insert(:user)
+      refute is_binary(user.info.keys)
+      {:ok, user} = User.ensure_keys_present(user)
+      assert is_binary(user.info.keys)
+    end
+
+    test "it doesn't create keys if there already are some" do
+      user = insert(:user, %{info: %{keys: "xxx"}})
+      {:ok, user} = User.ensure_keys_present(user)
+      assert user.info.keys == "xxx"
+    end
+  end
 end
index c18e0ab5f4e98fbbe1dfde8f115bcfc8ee227e43..f743f380beb42ce3056e3762cb0d81ab0a95de79 100644 (file)
@@ -1005,7 +1005,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
   describe "update" do
     test "it creates an update activity with the new user data" do
       user = insert(:user)
-      {:ok, user} = Pleroma.Web.WebFinger.ensure_keys_present(user)
+      {:ok, user} = User.ensure_keys_present(user)
       user_data = Pleroma.Web.ActivityPub.UserView.render("user.json", %{user: user})
 
       {:ok, update} =
index 9fb9455d2c6693c95900d4c10ec869a3d4b6caa1..e6483db8bdc8f9dde223425fa6f3951332ffd9d7 100644 (file)
@@ -2,11 +2,12 @@ defmodule Pleroma.Web.ActivityPub.UserViewTest do
   use Pleroma.DataCase
   import Pleroma.Factory
 
+  alias Pleroma.User
   alias Pleroma.Web.ActivityPub.UserView
 
   test "Renders a user, including the public key" do
     user = insert(:user)
-    {:ok, user} = Pleroma.Web.WebFinger.ensure_keys_present(user)
+    {:ok, user} = User.ensure_keys_present(user)
 
     result = UserView.render("user.json", %{user: user})
 
@@ -18,7 +19,7 @@ defmodule Pleroma.Web.ActivityPub.UserViewTest do
 
   test "Does not add an avatar image if the user hasn't set one" do
     user = insert(:user)
-    {:ok, user} = Pleroma.Web.WebFinger.ensure_keys_present(user)
+    {:ok, user} = User.ensure_keys_present(user)
 
     result = UserView.render("user.json", %{user: user})
     refute result["icon"]
@@ -32,7 +33,7 @@ defmodule Pleroma.Web.ActivityPub.UserViewTest do
         }
       )
 
-    {:ok, user} = Pleroma.Web.WebFinger.ensure_keys_present(user)
+    {:ok, user} = User.ensure_keys_present(user)
 
     result = UserView.render("user.json", %{user: user})
     assert result["icon"]["url"] == "https://someurl"
@@ -42,7 +43,7 @@ defmodule Pleroma.Web.ActivityPub.UserViewTest do
   describe "endpoints" do
     test "local users have a usable endpoints structure" do
       user = insert(:user)
-      {:ok, user} = Pleroma.Web.WebFinger.ensure_keys_present(user)
+      {:ok, user} = User.ensure_keys_present(user)
 
       result = UserView.render("user.json", %{user: user})
 
@@ -58,7 +59,7 @@ defmodule Pleroma.Web.ActivityPub.UserViewTest do
 
     test "remote users have an empty endpoints structure" do
       user = insert(:user, local: false)
-      {:ok, user} = Pleroma.Web.WebFinger.ensure_keys_present(user)
+      {:ok, user} = User.ensure_keys_present(user)
 
       result = UserView.render("user.json", %{user: user})
 
@@ -68,7 +69,7 @@ defmodule Pleroma.Web.ActivityPub.UserViewTest do
 
     test "instance users do not expose oAuth endpoints" do
       user = insert(:user, nickname: nil, local: true)
-      {:ok, user} = Pleroma.Web.WebFinger.ensure_keys_present(user)
+      {:ok, user} = User.ensure_keys_present(user)
 
       result = UserView.render("user.json", %{user: user})
 
index 232082779fd8f13de9768c8363efbcbb0779b2b6..e86e76fe931efdf6220cb46773da8cc60af8d772 100644 (file)
@@ -5,6 +5,7 @@
 defmodule Pleroma.Web.Salmon.SalmonTest do
   use Pleroma.DataCase
   alias Pleroma.Activity
+  alias Pleroma.Keys
   alias Pleroma.Repo
   alias Pleroma.User
   alias Pleroma.Web.Federator.Publisher
@@ -34,12 +35,6 @@ defmodule Pleroma.Web.Salmon.SalmonTest do
     assert Salmon.decode_and_validate(@wrong_magickey, salmon) == :error
   end
 
-  test "generates an RSA private key pem" do
-    {:ok, key} = Salmon.generate_rsa_pem()
-    assert is_binary(key)
-    assert Regex.match?(~r/RSA/, key)
-  end
-
   test "it encodes a magic key from a public key" do
     key = Salmon.decode_key(@magickey)
     magic_key = Salmon.encode_key(key)
@@ -51,18 +46,10 @@ defmodule Pleroma.Web.Salmon.SalmonTest do
     _key = Salmon.decode_key(@magickey_friendica)
   end
 
-  test "returns a public and private key from a pem" do
-    pem = File.read!("test/fixtures/private_key.pem")
-    {:ok, private, public} = Salmon.keys_from_pem(pem)
-
-    assert elem(private, 0) == :RSAPrivateKey
-    assert elem(public, 0) == :RSAPublicKey
-  end
-
   test "encodes an xml payload with a private key" do
     doc = File.read!("test/fixtures/incoming_note_activity.xml")
     pem = File.read!("test/fixtures/private_key.pem")
-    {:ok, private, public} = Salmon.keys_from_pem(pem)
+    {:ok, private, public} = Keys.keys_from_pem(pem)
 
     # Let's try a roundtrip.
     {:ok, salmon} = Salmon.encode(private, doc)
@@ -105,7 +92,7 @@ defmodule Pleroma.Web.Salmon.SalmonTest do
 
     {:ok, activity} = Repo.insert(%Activity{data: activity_data, recipients: activity_data["to"]})
     user = User.get_cached_by_ap_id(activity.data["actor"])
-    {:ok, user} = Pleroma.Web.WebFinger.ensure_keys_present(user)
+    {:ok, user} = User.ensure_keys_present(user)
 
     Salmon.publish(user, activity)
 
index 6b20d8d569d5a8e33e5ef48f03c64961f92d03aa..335c95b18ba14e8fa10433aa220b0b14c5c17d86 100644 (file)
@@ -105,19 +105,4 @@ defmodule Pleroma.Web.WebFingerTest do
       assert template == "http://status.alpicola.com/main/xrd?uri={uri}"
     end
   end
-
-  describe "ensure_keys_present" do
-    test "it creates keys for a user and stores them in info" do
-      user = insert(:user)
-      refute is_binary(user.info.keys)
-      {:ok, user} = WebFinger.ensure_keys_present(user)
-      assert is_binary(user.info.keys)
-    end
-
-    test "it doesn't create keys if there already are some" do
-      user = insert(:user, %{info: %{keys: "xxx"}})
-      {:ok, user} = WebFinger.ensure_keys_present(user)
-      assert user.info.keys == "xxx"
-    end
-  end
 end