diff options
| -rw-r--r-- | docs/API/pleroma_api.md | 20 | ||||
| -rw-r--r-- | lib/pleroma/user.ex | 24 | ||||
| -rw-r--r-- | lib/pleroma/web/api_spec/operations/pleroma_account_operation.ex | 46 | ||||
| -rw-r--r-- | lib/pleroma/web/api_spec/schemas/account.ex | 2 | ||||
| -rw-r--r-- | lib/pleroma/web/mastodon_api/views/account_view.ex | 1 | ||||
| -rw-r--r-- | lib/pleroma/web/pleroma_api/controllers/account_controller.ex | 25 | ||||
| -rw-r--r-- | lib/pleroma/web/router.ex | 3 | ||||
| -rw-r--r-- | lib/pleroma/web/web_finger/web_finger.ex | 9 | ||||
| -rw-r--r-- | priv/repo/migrations/20200717025041_add_aliases_to_users.exs | 9 | ||||
| -rw-r--r-- | test/user_test.exs | 37 | ||||
| -rw-r--r-- | test/web/mastodon_api/views/account_view_test.exs | 5 | ||||
| -rw-r--r-- | test/web/pleroma_api/controllers/account_controller_test.exs | 29 | ||||
| -rw-r--r-- | test/web/web_finger/web_finger_controller_test.exs | 14 | 
13 files changed, 220 insertions, 4 deletions
diff --git a/docs/API/pleroma_api.md b/docs/API/pleroma_api.md index 5bd38ad36..8a937fdfd 100644 --- a/docs/API/pleroma_api.md +++ b/docs/API/pleroma_api.md @@ -570,3 +570,23 @@ 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 9240e912d..9b756c9a0 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -89,6 +89,7 @@ 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) @@ -2268,4 +2269,27 @@ defmodule Pleroma.User do      |> Map.put(:bio, HTML.filter_tags(user.bio, filter))      |> 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}) +    |> 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}) +    |> Repo.update() +  end  end 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 97836b2eb..1040f6e20 100644 --- a/lib/pleroma/web/api_spec/operations/pleroma_account_operation.ex +++ b/lib/pleroma/web/api_spec/operations/pleroma_account_operation.ex @@ -4,6 +4,8 @@  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 @@ -87,10 +89,54 @@ 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 ca79f0747..4fd27edf5 100644 --- a/lib/pleroma/web/api_spec/schemas/account.ex +++ b/lib/pleroma/web/api_spec/schemas/account.ex @@ -40,6 +40,8 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Account do        pleroma: %Schema{          type: :object,          properties: %{ +          ap_id: %Schema{type: :string}, +          ap_aliases: %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/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index bc9745044..e2912031a 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -248,6 +248,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do        # Pleroma extension        pleroma: %{          ap_id: user.ap_id, +        ap_aliases: user.ap_aliases,          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 563edded7..03e5781a3 100644 --- a/lib/pleroma/web/pleroma_api/controllers/account_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/account_controller.ex @@ -39,6 +39,11 @@ 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]) @@ -107,4 +112,24 @@ 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 386308362..dea95cd77 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -344,6 +344,9 @@ 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 71ccf251a..fb142ce8d 100644 --- a/lib/pleroma/web/web_finger/web_finger.ex +++ b/lib/pleroma/web/web_finger/web_finger.ex @@ -58,12 +58,19 @@ defmodule Pleroma.Web.WebFinger do      ] ++ Publisher.gather_webfinger_links(user)    end +  defp gather_aliases(%User{} = user) do +    user.ap_aliases +    |> MapSet.new() +    |> MapSet.put(user.ap_id) +    |> MapSet.to_list() +  end +    def represent_user(user, "JSON") do      {:ok, user} = User.ensure_keys_present(user)      %{        "subject" => "acct:#{user.nickname}@#{Pleroma.Web.Endpoint.host()}", -      "aliases" => [user.ap_id], +      "aliases" => gather_aliases(user),        "links" => gather_links(user)      }    end diff --git a/priv/repo/migrations/20200717025041_add_aliases_to_users.exs b/priv/repo/migrations/20200717025041_add_aliases_to_users.exs new file mode 100644 index 000000000..a6ace6e0f --- /dev/null +++ b/priv/repo/migrations/20200717025041_add_aliases_to_users.exs @@ -0,0 +1,9 @@ +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 9788e09d9..db6e4872e 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -1858,4 +1858,41 @@ 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 "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/views/account_view_test.exs b/test/web/mastodon_api/views/account_view_test.exs index a83bf90a3..4a0512e68 100644 --- a/test/web/mastodon_api/views/account_view_test.exs +++ b/test/web/mastodon_api/views/account_view_test.exs @@ -37,7 +37,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do            "<script src=\"invalid-html\"></script><span>valid html</span>. a<br>b<br/>c<br >d<br />f '&<>\"",          inserted_at: ~N[2017-08-15 15:47:06.597036],          emoji: %{"karjalanpiirakka" => "/file.png"}, -        raw_bio: "valid html. a\nb\nc\nd\nf '&<>\"" +        raw_bio: "valid html. a\nb\nc\nd\nf '&<>\"", +        ap_aliases: ["https://shitposter.zone/users/shp"]        })      expected = %{ @@ -77,6 +78,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do        },        pleroma: %{          ap_id: user.ap_id, +        ap_aliases: ["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", @@ -171,6 +173,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do        },        pleroma: %{          ap_id: user.ap_id, +        ap_aliases: [],          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 07909d48b..da01a8218 100644 --- a/test/web/pleroma_api/controllers/account_controller_test.exs +++ b/test/web/pleroma_api/controllers/account_controller_test.exs @@ -281,4 +281,33 @@ 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 0023f1e81..50b6c4b3e 100644 --- a/test/web/web_finger/web_finger_controller_test.exs +++ b/test/web/web_finger/web_finger_controller_test.exs @@ -30,14 +30,24 @@ defmodule Pleroma.Web.WebFinger.WebFingerControllerTest do    end    test "Webfinger JRD" do -    user = insert(:user) +    user = +      insert(:user, +        ap_id: "https://hyrule.world/users/zelda", +        ap_aliases: ["https://mushroom.kingdom/users/toad"] +      )      response =        build_conn()        |> put_req_header("accept", "application/jrd+json")        |> get("/.well-known/webfinger?resource=acct:#{user.nickname}@localhost") +      |> json_response(200) + +    assert response["subject"] == "acct:#{user.nickname}@localhost" -    assert json_response(response, 200)["subject"] == "acct:#{user.nickname}@localhost" +    assert response["aliases"] == [ +             "https://hyrule.world/users/zelda", +             "https://mushroom.kingdom/users/toad" +           ]    end    test "it returns 404 when user isn't found (JSON)" do  | 
