Clean up account aliases
authorAlex Gleason <alex@alexgleason.me>
Fri, 7 Aug 2020 21:48:03 +0000 (16:48 -0500)
committerAlex Gleason <alex@alexgleason.me>
Fri, 7 Aug 2020 22:37:15 +0000 (17:37 -0500)
17 files changed:
docs/API/differences_in_mastoapi_responses.md
docs/API/pleroma_api.md
lib/pleroma/user.ex
lib/pleroma/web/api_spec/operations/account_operation.ex
lib/pleroma/web/api_spec/operations/pleroma_account_operation.ex
lib/pleroma/web/api_spec/schemas/account.ex
lib/pleroma/web/mastodon_api/controllers/account_controller.ex
lib/pleroma/web/mastodon_api/views/account_view.ex
lib/pleroma/web/pleroma_api/controllers/account_controller.ex
lib/pleroma/web/router.ex
lib/pleroma/web/web_finger/web_finger.ex
priv/repo/migrations/20200717025041_add_aliases_to_users.exs [deleted file]
test/user_test.exs
test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs
test/web/mastodon_api/views/account_view_test.exs
test/web/pleroma_api/controllers/account_controller_test.exs
test/web/web_finger/web_finger_controller_test.exs

index 38865dc68a8b4393a7c40d23eceacebf1a7bf434..3cb2183bdda74f0dcaeaf894fab1d2587622b98c 100644 (file)
@@ -184,6 +184,7 @@ Additional parameters can be added to the JSON body/Form data:
 - `pleroma_settings_store` - Opaque user settings to be saved on the backend.
 - `skip_thread_containment` - if true, skip filtering out broken threads
 - `allow_following_move` - if true, allows automatically follow moved following accounts
+- `also_known_as` - array of ActivityPub IDs, needed for following move
 - `pleroma_background_image` - sets the background image of the user. Can be set to "" (an empty string) to reset.
 - `discoverable` - if true, discovery of this account in search results and other services is allowed.
 - `actor_type` - the type of this account.
index c1aa4d204148b536141cbf1ec11ef6f5de88e336..4e97d26c052d0e0969cbe33f21db507139a9880e 100644 (file)
@@ -570,23 +570,3 @@ Emoji reactions work a lot like favourites do. They make it possible to react to
   {"name": "😀", "count": 2, "me": true, "accounts": [{"id" => "xyz.."...}, {"id" => "zyx..."}]}
 ]
 ```
-
-# Account aliases
-
-Set and delete ActivityPub aliases for follower move.
-
-## `POST /api/v1/pleroma/accounts/ap_aliases`
-### Add account aliases
-* Method: `POST`
-* Authentication: required
-* Params:
-  * `aliases`: array of ActivityPub IDs to add
-* Response: JSON, the user's account
-
-## `DELETE /api/v1/pleroma/accounts/ap_aliases`
-### Delete account aliases
-* Method: `DELETE`
-* Authentication: required
-* Params:
-  * `aliases`: array of ActivityPub IDs to delete
-* Response: JSON, the user's account
index ad7a04f62cd3db05181adf7d66e335038650846a..57e06bd5a704e7082f2d096bb06626905fb731a4 100644 (file)
@@ -96,7 +96,6 @@ defmodule Pleroma.User do
     field(:keys, :string)
     field(:public_key, :string)
     field(:ap_id, :string)
-    field(:ap_aliases, {:array, :string}, default: [])
     field(:avatar, :map, default: %{})
     field(:local, :boolean, default: true)
     field(:follower_address, :string)
@@ -486,6 +485,7 @@ defmodule Pleroma.User do
         :hide_follows_count,
         :hide_favorites,
         :allow_following_move,
+        :also_known_as,
         :background,
         :show_role,
         :skip_thread_containment,
@@ -494,12 +494,12 @@ defmodule Pleroma.User do
         :pleroma_settings_store,
         :discoverable,
         :actor_type,
-        :also_known_as,
         :accepts_chat_messages
       ]
     )
     |> unique_constraint(:nickname)
     |> validate_format(:nickname, local_nickname_regex())
+    |> validate_also_known_as()
     |> validate_length(:bio, max: bio_limit)
     |> validate_length(:name, min: 1, max: name_limit)
     |> validate_inclusion(:actor_type, ["Person", "Service"])
@@ -2387,36 +2387,11 @@ defmodule Pleroma.User do
     |> Map.put(:fields, fields)
   end
 
-  def add_aliases(%User{} = user, aliases) when is_list(aliases) do
-    alias_set =
-      (user.ap_aliases ++ aliases)
-      |> MapSet.new()
-      |> MapSet.to_list()
-
-    user
-    |> change(%{ap_aliases: alias_set})
-    |> validate_ap_aliases()
-    |> Repo.update()
-  end
-
-  def delete_aliases(%User{} = user, aliases) when is_list(aliases) do
-    alias_set =
-      user.ap_aliases
-      |> MapSet.new()
-      |> MapSet.difference(MapSet.new(aliases))
-      |> MapSet.to_list()
-
-    user
-    |> change(%{ap_aliases: alias_set})
-    |> validate_ap_aliases()
-    |> Repo.update()
-  end
-
-  defp validate_ap_aliases(changeset) do
-    validate_change(changeset, :ap_aliases, fn :ap_aliases, ap_aliases ->
-      case Enum.all?(ap_aliases, fn a -> Regex.match?(@url_regex, a) end) do
+  defp validate_also_known_as(changeset) do
+    validate_change(changeset, :also_known_as, fn :also_known_as, also_known_as ->
+      case Enum.all?(also_known_as, fn a -> Regex.match?(@url_regex, a) end) do
         true -> []
-        false -> [ap_aliases: "Invalid ap_id format. Must be a URL."]
+        false -> [also_known_as: "Invalid ap_id format. Must be a URL."]
       end
     end)
   end
index aaebc9b5cb72c3e3f991f64eb14c6dc6f16fca41..91b4d0c80ec0b8eb1c803f8d2c0310c99b25b95f 100644 (file)
@@ -597,6 +597,12 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
           nullable: true,
           description: "Allows automatically follow moved following accounts"
         },
+        also_known_as: %Schema{
+          type: :array,
+          items: %Schema{type: :string},
+          nullable: true,
+          description: "List of alternate ActivityPub IDs"
+        },
         pleroma_background_image: %Schema{
           type: :string,
           nullable: true,
@@ -627,6 +633,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
         pleroma_settings_store: %{"pleroma-fe" => %{"key" => "val"}},
         skip_thread_containment: false,
         allow_following_move: false,
+        also_known_as: ["https://foo.bar/users/foo"],
         discoverable: false,
         actor_type: "Person"
       }
index 1040f6e205c53f6ab8f9a1c1a845aed2e9e6c9da..97836b2eb570023531c63c7be7ccebeb19940b43 100644 (file)
@@ -4,8 +4,6 @@
 
 defmodule Pleroma.Web.ApiSpec.PleromaAccountOperation do
   alias OpenApiSpex.Operation
-  alias OpenApiSpex.Schema
-  alias Pleroma.Web.ApiSpec.Schemas.Account
   alias Pleroma.Web.ApiSpec.Schemas.AccountRelationship
   alias Pleroma.Web.ApiSpec.Schemas.ApiError
   alias Pleroma.Web.ApiSpec.Schemas.FlakeID
@@ -89,54 +87,10 @@ defmodule Pleroma.Web.ApiSpec.PleromaAccountOperation do
     }
   end
 
-  def add_aliases_operation do
-    %Operation{
-      tags: ["Accounts"],
-      summary: "Add ActivityPub aliases",
-      operationId: "PleromaAPI.AccountController.add_aliases",
-      requestBody: request_body("Parameters", alias_request(), required: true),
-      security: [%{"oAuth" => ["write:accounts"]}],
-      responses: %{
-        200 => Operation.response("Account", "application/json", Account),
-        403 => Operation.response("Forbidden", "application/json", ApiError)
-      }
-    }
-  end
-
-  def delete_aliases_operation do
-    %Operation{
-      tags: ["Accounts"],
-      summary: "Delete ActivityPub aliases",
-      operationId: "PleromaAPI.AccountController.delete_aliases",
-      requestBody: request_body("Parameters", alias_request(), required: true),
-      security: [%{"oAuth" => ["write:accounts"]}],
-      responses: %{
-        200 => Operation.response("Account", "application/json", Account)
-      }
-    }
-  end
-
   defp id_param do
     Operation.parameter(:id, :path, FlakeID, "Account ID",
       example: "9umDrYheeY451cQnEe",
       required: true
     )
   end
-
-  defp alias_request do
-    %Schema{
-      title: "AccountAliasRequest",
-      description: "POST body for adding/deleting AP aliases",
-      type: :object,
-      properties: %{
-        aliases: %Schema{
-          type: :array,
-          items: %Schema{type: :string}
-        }
-      },
-      example: %{
-        "aliases" => ["https://beepboop.social/users/beep", "https://mushroom.kingdom/users/toad"]
-      }
-    }
-  end
 end
index 4fd27edf58e5c0e4da2162e9a60143f09f80e897..cf743932cae8561028a1fabf89d8209e6a7e18e2 100644 (file)
@@ -41,7 +41,7 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Account do
         type: :object,
         properties: %{
           ap_id: %Schema{type: :string},
-          ap_aliases: %Schema{type: :array, items: %Schema{type: :string}},
+          also_known_as: %Schema{type: :array, items: %Schema{type: :string}},
           allow_following_move: %Schema{
             type: :boolean,
             description: "whether the user allows automatically follow moved following accounts"
index f45678184eeee58985fbddc30f3d5e9d24e38bca..b0ec97d878d0a0e97dd76d399bf794cf0d2271bb 100644 (file)
@@ -186,6 +186,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
         :show_role,
         :skip_thread_containment,
         :allow_following_move,
+        :also_known_as,
         :discoverable,
         :accepts_chat_messages
       ]
@@ -210,6 +211,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
         if bot, do: {:ok, "Service"}, else: {:ok, "Person"}
       end)
       |> Maps.put_if_present(:actor_type, params[:actor_type])
+      |> Maps.put_if_present(:also_known_as, params[:also_known_as])
 
     # What happens here:
     #
index 4f29a80fbf66374dea1a2db6a2fc5f7a60364bb9..f78b0456534c140dbfc02dc568878d916edf1f0d 100644 (file)
@@ -267,7 +267,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
       # Pleroma extension
       pleroma: %{
         ap_id: user.ap_id,
-        ap_aliases: user.ap_aliases,
+        also_known_as: user.also_known_as,
         confirmation_pending: user.confirmation_pending,
         tags: user.tags,
         hide_followers_count: user.hide_followers_count,
index 03e5781a31532d4ab2da7a8e176dbc915a073e89..563edded70d0bcf32513fbbaab293faa3488e844 100644 (file)
@@ -39,11 +39,6 @@ defmodule Pleroma.Web.PleromaAPI.AccountController do
     %{scopes: ["read:favourites"], fallback: :proceed_unauthenticated} when action == :favourites
   )
 
-  plug(
-    OAuthScopesPlug,
-    %{scopes: ["write:accounts"]} when action in [:add_aliases, :delete_aliases]
-  )
-
   plug(RateLimiter, [name: :account_confirmation_resend] when action == :confirmation_resend)
 
   plug(:assign_account_by_id when action in [:favourites, :subscribe, :unsubscribe])
@@ -112,24 +107,4 @@ defmodule Pleroma.Web.PleromaAPI.AccountController do
       {:error, message} -> json_response(conn, :forbidden, %{error: message})
     end
   end
-
-  @doc "POST /api/v1/pleroma/accounts/ap_aliases"
-  def add_aliases(%{assigns: %{user: user}, body_params: %{aliases: aliases}} = conn, _params)
-      when is_list(aliases) do
-    with {:ok, user} <- User.add_aliases(user, aliases) do
-      render(conn, "show.json", user: user)
-    else
-      {:error, message} -> json_response(conn, :forbidden, %{error: message})
-    end
-  end
-
-  @doc "DELETE /api/v1/pleroma/accounts/ap_aliases"
-  def delete_aliases(%{assigns: %{user: user}, body_params: %{aliases: aliases}} = conn, _params)
-      when is_list(aliases) do
-    with {:ok, user} <- User.delete_aliases(user, aliases) do
-      render(conn, "show.json", user: user)
-    else
-      {:error, message} -> json_response(conn, :forbidden, %{error: message})
-    end
-  end
 end
index fbab0fc272abd43da8fc3d7b28d97755113469da..c6433cc5325f3e923dc9150632c82ec5945d7d5a 100644 (file)
@@ -345,9 +345,6 @@ defmodule Pleroma.Web.Router do
 
       post("/accounts/:id/subscribe", AccountController, :subscribe)
       post("/accounts/:id/unsubscribe", AccountController, :unsubscribe)
-
-      post("/accounts/ap_aliases", AccountController, :add_aliases)
-      delete("/accounts/ap_aliases", AccountController, :delete_aliases)
     end
 
     post("/accounts/confirmation_resend", AccountController, :confirmation_resend)
index fb142ce8d819a53299960ae6cff4ac12523560a3..b0df356a30889685a55f3193dcc4dc0f715cdd34 100644 (file)
@@ -59,10 +59,7 @@ defmodule Pleroma.Web.WebFinger do
   end
 
   defp gather_aliases(%User{} = user) do
-    user.ap_aliases
-    |> MapSet.new()
-    |> MapSet.put(user.ap_id)
-    |> MapSet.to_list()
+    [user.ap_id] ++ user.also_known_as
   end
 
   def represent_user(user, "JSON") do
@@ -78,6 +75,10 @@ defmodule Pleroma.Web.WebFinger do
   def represent_user(user, "XML") do
     {:ok, user} = User.ensure_keys_present(user)
 
+    aliases =
+      gather_aliases(user)
+      |> Enum.map(fn the_alias -> {:Alias, the_alias} end)
+
     links =
       gather_links(user)
       |> Enum.map(fn link -> {:Link, link} end)
@@ -86,9 +87,8 @@ defmodule Pleroma.Web.WebFinger do
       :XRD,
       %{xmlns: "http://docs.oasis-open.org/ns/xri/xrd-1.0"},
       [
-        {:Subject, "acct:#{user.nickname}@#{Pleroma.Web.Endpoint.host()}"},
-        {:Alias, user.ap_id}
-      ] ++ links
+        {:Subject, "acct:#{user.nickname}@#{Pleroma.Web.Endpoint.host()}"}
+      ] ++ aliases ++ links
     }
     |> XmlBuilder.to_doc()
   end
diff --git a/priv/repo/migrations/20200717025041_add_aliases_to_users.exs b/priv/repo/migrations/20200717025041_add_aliases_to_users.exs
deleted file mode 100644 (file)
index a6ace6e..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-defmodule Pleroma.Repo.Migrations.AddAliasesToUsers do
-  use Ecto.Migration
-
-  def change do
-    alter table(:users) do
-      add(:ap_aliases, {:array, :string}, default: [])
-    end
-  end
-end
index 941e484086887c767809a1c822838b83f0987b2f..b4740589593bb8e673b6914ac63e51102ba4e566 100644 (file)
@@ -2024,48 +2024,4 @@ defmodule Pleroma.UserTest do
 
     assert User.avatar_url(user, no_default: true) == nil
   end
-
-  test "add_aliases/2" do
-    user = insert(:user)
-
-    aliases = [
-      "https://gleasonator.com/users/alex",
-      "https://gleasonator.com/users/alex",
-      "https://animalliberation.social/users/alex"
-    ]
-
-    {:ok, user} = User.add_aliases(user, aliases)
-
-    assert user.ap_aliases == [
-             "https://animalliberation.social/users/alex",
-             "https://gleasonator.com/users/alex"
-           ]
-  end
-
-  test "add_aliases/2 with invalid alias" do
-    user = insert(:user)
-    {:error, _} = User.add_aliases(user, ["invalid_alias"])
-    {:error, _} = User.add_aliases(user, ["http://still_invalid"])
-    {:error, _} = User.add_aliases(user, ["http://validalias.com/users/dude", "invalid_alias"])
-  end
-
-  test "delete_aliases/2" do
-    user =
-      insert(:user,
-        ap_aliases: [
-          "https://animalliberation.social/users/alex",
-          "https://benis.social/users/benis",
-          "https://gleasonator.com/users/alex"
-        ]
-      )
-
-    aliases = ["https://benis.social/users/benis"]
-
-    {:ok, user} = User.delete_aliases(user, aliases)
-
-    assert user.ap_aliases == [
-             "https://animalliberation.social/users/alex",
-             "https://gleasonator.com/users/alex"
-           ]
-  end
 end
index b888e4c7110100e8135c1ef60d403c4355e47d05..467110f3b5654eb28db577c994914c2945ea92ae 100644 (file)
@@ -216,6 +216,16 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do
       assert user_data["display_name"] == "markorepairs"
     end
 
+    test "updates the user's AKAs", %{conn: conn} do
+      conn =
+        patch(conn, "/api/v1/accounts/update_credentials", %{
+          "also_known_as" => ["https://mushroom.kingdom/users/mario"]
+        })
+
+      assert user_data = json_response_and_validate_schema(conn, 200)
+      assert user_data["pleroma"]["also_known_as"] == ["https://mushroom.kingdom/users/mario"]
+    end
+
     test "updates the user's avatar", %{user: user, conn: conn} do
       new_avatar = %Plug.Upload{
         content_type: "image/jpg",
index a55b5a06e429686645513cf9e94c0c5a9a012513..bbf7b33a8ae39600c13ea4fdb05125b7562a06df 100644 (file)
@@ -38,7 +38,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
         inserted_at: ~N[2017-08-15 15:47:06.597036],
         emoji: %{"karjalanpiirakka" => "/file.png"},
         raw_bio: "valid html. a\nb\nc\nd\nf '&<>\"",
-        ap_aliases: ["https://shitposter.zone/users/shp"]
+        also_known_as: ["https://shitposter.zone/users/shp"]
       })
 
     expected = %{
@@ -78,7 +78,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
       },
       pleroma: %{
         ap_id: user.ap_id,
-        ap_aliases: ["https://shitposter.zone/users/shp"],
+        also_known_as: ["https://shitposter.zone/users/shp"],
         background_image: "https://example.com/images/asuka_hospital.png",
         favicon:
           "https://shitposter.club/plugins/Qvitter/img/gnusocial-favicons/favicon-16x16.png",
@@ -174,7 +174,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
       },
       pleroma: %{
         ap_id: user.ap_id,
-        ap_aliases: [],
+        also_known_as: [],
         background_image: nil,
         favicon:
           "https://shitposter.club/plugins/Qvitter/img/gnusocial-favicons/favicon-16x16.png",
index da01a8218acb7bc15f97adcc192653b9ca314816..07909d48bd806f8c2c1b65e88cabe8563326f665 100644 (file)
@@ -281,33 +281,4 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do
       assert %{"error" => "Record not found"} = json_response_and_validate_schema(conn, 404)
     end
   end
-
-  describe "aliases controllers" do
-    setup do: oauth_access(["write:accounts"])
-
-    test "adds aliases", %{conn: conn} do
-      aliases = ["https://gleasonator.com/users/alex"]
-
-      conn =
-        conn
-        |> put_req_header("content-type", "application/json")
-        |> post("/api/v1/pleroma/accounts/ap_aliases", %{"aliases" => aliases})
-
-      assert %{"pleroma" => %{"ap_aliases" => res}} = json_response_and_validate_schema(conn, 200)
-      assert Enum.count(res) == 1
-    end
-
-    test "deletes aliases", %{conn: conn, user: user} do
-      aliases = ["https://gleasonator.com/users/alex"]
-      User.add_aliases(user, aliases)
-
-      conn =
-        conn
-        |> put_req_header("content-type", "application/json")
-        |> delete("/api/v1/pleroma/accounts/ap_aliases", %{"aliases" => aliases})
-
-      assert %{"pleroma" => %{"ap_aliases" => res}} = json_response_and_validate_schema(conn, 200)
-      assert Enum.count(res) == 0
-    end
-  end
 end
index 50b6c4b3e657e83f3752f53dcc24e4ba7b260f40..ce9eb0650a7d05050847da2f0df4f02a8a25392b 100644 (file)
@@ -33,7 +33,7 @@ defmodule Pleroma.Web.WebFinger.WebFingerControllerTest do
     user =
       insert(:user,
         ap_id: "https://hyrule.world/users/zelda",
-        ap_aliases: ["https://mushroom.kingdom/users/toad"]
+        also_known_as: ["https://mushroom.kingdom/users/toad"]
       )
 
     response =
@@ -61,14 +61,20 @@ defmodule Pleroma.Web.WebFinger.WebFingerControllerTest do
   end
 
   test "Webfinger XML" do
-    user = insert(:user)
+    user =
+      insert(:user,
+        ap_id: "https://hyrule.world/users/zelda",
+        also_known_as: ["https://mushroom.kingdom/users/toad"]
+      )
 
     response =
       build_conn()
       |> put_req_header("accept", "application/xrd+xml")
       |> get("/.well-known/webfinger?resource=acct:#{user.nickname}@localhost")
+      |> response(200)
 
-    assert response(response, 200)
+    assert response =~ "<Alias>https://hyrule.world/users/zelda</Alias>"
+    assert response =~ "<Alias>https://mushroom.kingdom/users/toad</Alias>"
   end
 
   test "it returns 404 when user isn't found (XML)" do