diff --git a/docs/API/differences_in_mastoapi_responses.md b/docs/API/differences_in_mastoapi_responses.md index 38865dc68..3cb2183bd 100644 --- a/docs/API/differences_in_mastoapi_responses.md +++ b/docs/API/differences_in_mastoapi_responses.md @@ -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. diff --git a/docs/API/pleroma_api.md b/docs/API/pleroma_api.md index c1aa4d204..4e97d26c0 100644 --- a/docs/API/pleroma_api.md +++ b/docs/API/pleroma_api.md @@ -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 diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index ad7a04f62..57e06bd5a 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -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 diff --git a/lib/pleroma/web/api_spec/operations/account_operation.ex b/lib/pleroma/web/api_spec/operations/account_operation.ex index aaebc9b5c..91b4d0c80 100644 --- a/lib/pleroma/web/api_spec/operations/account_operation.ex +++ b/lib/pleroma/web/api_spec/operations/account_operation.ex @@ -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" } diff --git a/lib/pleroma/web/api_spec/operations/pleroma_account_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_account_operation.ex index 1040f6e20..97836b2eb 100644 --- a/lib/pleroma/web/api_spec/operations/pleroma_account_operation.ex +++ b/lib/pleroma/web/api_spec/operations/pleroma_account_operation.ex @@ -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 diff --git a/lib/pleroma/web/api_spec/schemas/account.ex b/lib/pleroma/web/api_spec/schemas/account.ex index 4fd27edf5..cf743932c 100644 --- a/lib/pleroma/web/api_spec/schemas/account.ex +++ b/lib/pleroma/web/api_spec/schemas/account.ex @@ -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" diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex index f45678184..b0ec97d87 100644 --- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex @@ -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: # diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index 4f29a80fb..f78b04565 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -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, diff --git a/lib/pleroma/web/pleroma_api/controllers/account_controller.ex b/lib/pleroma/web/pleroma_api/controllers/account_controller.ex index 03e5781a3..563edded7 100644 --- a/lib/pleroma/web/pleroma_api/controllers/account_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/account_controller.ex @@ -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 diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index fbab0fc27..c6433cc53 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -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) diff --git a/lib/pleroma/web/web_finger/web_finger.ex b/lib/pleroma/web/web_finger/web_finger.ex index fb142ce8d..b0df356a3 100644 --- a/lib/pleroma/web/web_finger/web_finger.ex +++ b/lib/pleroma/web/web_finger/web_finger.ex @@ -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 index a6ace6e0f..000000000 --- a/priv/repo/migrations/20200717025041_add_aliases_to_users.exs +++ /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 diff --git a/test/user_test.exs b/test/user_test.exs index 941e48408..b47405895 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -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 diff --git a/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs b/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs index b888e4c71..467110f3b 100644 --- a/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs +++ b/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs @@ -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", diff --git a/test/web/mastodon_api/views/account_view_test.exs b/test/web/mastodon_api/views/account_view_test.exs index a55b5a06e..bbf7b33a8 100644 --- a/test/web/mastodon_api/views/account_view_test.exs +++ b/test/web/mastodon_api/views/account_view_test.exs @@ -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", diff --git a/test/web/pleroma_api/controllers/account_controller_test.exs b/test/web/pleroma_api/controllers/account_controller_test.exs index da01a8218..07909d48b 100644 --- a/test/web/pleroma_api/controllers/account_controller_test.exs +++ b/test/web/pleroma_api/controllers/account_controller_test.exs @@ -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 diff --git a/test/web/web_finger/web_finger_controller_test.exs b/test/web/web_finger/web_finger_controller_test.exs index 50b6c4b3e..ce9eb0650 100644 --- a/test/web/web_finger/web_finger_controller_test.exs +++ b/test/web/web_finger/web_finger_controller_test.exs @@ -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 =~ "https://hyrule.world/users/zelda" + assert response =~ "https://mushroom.kingdom/users/toad" end test "it returns 404 when user isn't found (XML)" do