Merge branch '1526-account-aliases' into 'develop'

Resolve "account move from mastodon to pleroma"

Closes #1526

See merge request pleroma/pleroma!3233
This commit is contained in:
lain 2021-01-05 12:31:33 +00:00
commit 7a03b112f2
13 changed files with 79 additions and 12 deletions

View file

@ -30,6 +30,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Mix tasks to help with displaying and removing ConfigDB entries. See `mix pleroma.config`. - Mix tasks to help with displaying and removing ConfigDB entries. See `mix pleroma.config`.
- OAuth form improvements: users are remembered by their cookie, the CSS is overridable by the admin, and the style has been improved. - OAuth form improvements: users are remembered by their cookie, the CSS is overridable by the admin, and the style has been improved.
- OAuth improvements and fixes: more secure session-based authentication (by token that could be revoked anytime), ability to revoke belonging OAuth token from any client etc. - OAuth improvements and fixes: more secure session-based authentication (by token that could be revoked anytime), ability to revoke belonging OAuth token from any client etc.
- Ability to set ActivityPub aliases for follower migration.
<details> <details>
<summary>API Changes</summary> <summary>API Changes</summary>

View file

@ -206,6 +206,7 @@ Additional parameters can be added to the JSON body/Form data:
- `pleroma_settings_store` - Opaque user settings to be saved on the backend. - `pleroma_settings_store` - Opaque user settings to be saved on the backend.
- `skip_thread_containment` - if true, skip filtering out broken threads - `skip_thread_containment` - if true, skip filtering out broken threads
- `allow_following_move` - if true, allows automatically follow moved following accounts - `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. - `pleroma_background_image` - sets the background image of the user. Can be set to "" (an empty string) to reset.
- `discoverable` - if true, external services (search bots) etc. are allowed to index / list the account (regardless of this setting, user will still appear in regular search results). - `discoverable` - if true, external services (search bots) etc. are allowed to index / list the account (regardless of this setting, user will still appear in regular search results).
- `actor_type` - the type of this account. - `actor_type` - the type of this account.

View file

@ -142,7 +142,7 @@ defmodule Pleroma.User do
field(:allow_following_move, :boolean, default: true) field(:allow_following_move, :boolean, default: true)
field(:skip_thread_containment, :boolean, default: false) field(:skip_thread_containment, :boolean, default: false)
field(:actor_type, :string, default: "Person") field(:actor_type, :string, default: "Person")
field(:also_known_as, {:array, :string}, default: []) field(:also_known_as, {:array, ObjectValidators.ObjectID}, default: [])
field(:inbox, :string) field(:inbox, :string)
field(:shared_inbox, :string) field(:shared_inbox, :string)
field(:accepts_chat_messages, :boolean, default: nil) field(:accepts_chat_messages, :boolean, default: nil)
@ -515,6 +515,7 @@ def update_changeset(struct, params \\ %{}) do
:hide_follows_count, :hide_follows_count,
:hide_favorites, :hide_favorites,
:allow_following_move, :allow_following_move,
:also_known_as,
:background, :background,
:show_role, :show_role,
:skip_thread_containment, :skip_thread_containment,
@ -523,7 +524,6 @@ def update_changeset(struct, params \\ %{}) do
:pleroma_settings_store, :pleroma_settings_store,
:is_discoverable, :is_discoverable,
:actor_type, :actor_type,
:also_known_as,
:accepts_chat_messages :accepts_chat_messages
] ]
) )

View file

@ -112,7 +112,8 @@ def render("user.json", %{user: user}) do
"tag" => emoji_tags, "tag" => emoji_tags,
# Note: key name is indeed "discoverable" (not an error) # Note: key name is indeed "discoverable" (not an error)
"discoverable" => user.is_discoverable, "discoverable" => user.is_discoverable,
"capabilities" => capabilities "capabilities" => capabilities,
"alsoKnownAs" => user.also_known_as
} }
|> Map.merge(maybe_make_image(&User.avatar_url/2, "icon", user)) |> Map.merge(maybe_make_image(&User.avatar_url/2, "icon", user))
|> Map.merge(maybe_make_image(&User.banner_url/2, "image", user)) |> Map.merge(maybe_make_image(&User.banner_url/2, "image", user))

View file

@ -614,6 +614,12 @@ defp update_credentials_request do
nullable: true, nullable: true,
description: "Allows automatically follow moved following accounts" 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{ pleroma_background_image: %Schema{
type: :string, type: :string,
nullable: true, nullable: true,
@ -644,6 +650,7 @@ defp update_credentials_request do
pleroma_settings_store: %{"pleroma-fe" => %{"key" => "val"}}, pleroma_settings_store: %{"pleroma-fe" => %{"key" => "val"}},
skip_thread_containment: false, skip_thread_containment: false,
allow_following_move: false, allow_following_move: false,
also_known_as: ["https://foo.bar/users/foo"],
discoverable: false, discoverable: false,
actor_type: "Person" actor_type: "Person"
} }

View file

@ -40,6 +40,8 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Account do
pleroma: %Schema{ pleroma: %Schema{
type: :object, type: :object,
properties: %{ properties: %{
ap_id: %Schema{type: :string},
also_known_as: %Schema{type: :array, items: %Schema{type: :string}},
allow_following_move: %Schema{ allow_following_move: %Schema{
type: :boolean, type: :boolean,
description: "whether the user allows automatically follow moved following accounts" description: "whether the user allows automatically follow moved following accounts"

View file

@ -184,6 +184,7 @@ def update_credentials(%{assigns: %{user: user}, body_params: params} = conn, _p
:show_role, :show_role,
:skip_thread_containment, :skip_thread_containment,
:allow_following_move, :allow_following_move,
:also_known_as,
:accepts_chat_messages :accepts_chat_messages
] ]
|> Enum.reduce(%{}, fn key, acc -> |> Enum.reduce(%{}, fn key, acc ->
@ -207,6 +208,7 @@ def update_credentials(%{assigns: %{user: user}, body_params: params} = conn, _p
if bot, do: {:ok, "Service"}, else: {:ok, "Person"} if bot, do: {:ok, "Service"}, else: {:ok, "Person"}
end) end)
|> Maps.put_if_present(:actor_type, params[:actor_type]) |> Maps.put_if_present(:actor_type, params[:actor_type])
|> Maps.put_if_present(:also_known_as, params[:also_known_as])
# Note: param name is indeed :locked (not an error) # Note: param name is indeed :locked (not an error)
|> Maps.put_if_present(:is_locked, params[:locked]) |> Maps.put_if_present(:is_locked, params[:locked])
# Note: param name is indeed :discoverable (not an error) # Note: param name is indeed :discoverable (not an error)

View file

@ -265,6 +265,7 @@ defp do_render("show.json", %{user: user} = opts) do
# Pleroma extension # Pleroma extension
pleroma: %{ pleroma: %{
ap_id: user.ap_id, ap_id: user.ap_id,
also_known_as: user.also_known_as,
confirmation_pending: user.confirmation_pending, confirmation_pending: user.confirmation_pending,
tags: user.tags, tags: user.tags,
hide_followers_count: user.hide_followers_count, hide_followers_count: user.hide_followers_count,

View file

@ -58,12 +58,16 @@ defp gather_links(%User{} = user) do
] ++ Publisher.gather_webfinger_links(user) ] ++ Publisher.gather_webfinger_links(user)
end end
defp gather_aliases(%User{} = user) do
[user.ap_id | user.also_known_as]
end
def represent_user(user, "JSON") do def represent_user(user, "JSON") do
{:ok, user} = User.ensure_keys_present(user) {:ok, user} = User.ensure_keys_present(user)
%{ %{
"subject" => "acct:#{user.nickname}@#{Pleroma.Web.Endpoint.host()}", "subject" => "acct:#{user.nickname}@#{Pleroma.Web.Endpoint.host()}",
"aliases" => [user.ap_id], "aliases" => gather_aliases(user),
"links" => gather_links(user) "links" => gather_links(user)
} }
end end
@ -71,6 +75,11 @@ def represent_user(user, "JSON") do
def represent_user(user, "XML") do def represent_user(user, "XML") do
{:ok, user} = User.ensure_keys_present(user) {:ok, user} = User.ensure_keys_present(user)
aliases =
user
|> gather_aliases()
|> Enum.map(&{:Alias, &1})
links = links =
gather_links(user) gather_links(user)
|> Enum.map(fn link -> {:Link, link} end) |> Enum.map(fn link -> {:Link, link} end)
@ -79,9 +88,8 @@ def represent_user(user, "XML") do
:XRD, :XRD,
%{xmlns: "http://docs.oasis-open.org/ns/xri/xrd-1.0"}, %{xmlns: "http://docs.oasis-open.org/ns/xri/xrd-1.0"},
[ [
{:Subject, "acct:#{user.nickname}@#{Pleroma.Web.Endpoint.host()}"}, {:Subject, "acct:#{user.nickname}@#{Pleroma.Web.Endpoint.host()}"}
{:Alias, user.ap_id} ] ++ aliases ++ links
] ++ links
} }
|> XmlBuilder.to_doc() |> XmlBuilder.to_doc()
end end

View file

@ -80,6 +80,12 @@ test "renders an invisible user with the invisible property set to true" do
assert %{"invisible" => true} = UserView.render("service.json", %{user: user}) assert %{"invisible" => true} = UserView.render("service.json", %{user: user})
end end
test "renders AKAs" do
akas = ["https://i.tusooa.xyz/users/test-pleroma"]
user = insert(:user, also_known_as: akas)
assert %{"alsoKnownAs" => ^akas} = UserView.render("user.json", %{user: user})
end
describe "endpoints" do describe "endpoints" do
test "local users have a usable endpoints structure" do test "local users have a usable endpoints structure" do
user = insert(:user) user = insert(:user)

View file

@ -218,6 +218,25 @@ test "updates the user's name", %{conn: conn} do
assert update_activity.data["object"]["name"] == "markorepairs" assert update_activity.data["object"]["name"] == "markorepairs"
end 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 "doesn't update non-url akas", %{conn: conn} do
conn =
patch(conn, "/api/v1/accounts/update_credentials", %{
"also_known_as" => ["aReallyCoolGuy"]
})
assert json_response_and_validate_schema(conn, 403)
end
test "updates the user's avatar", %{user: user, conn: conn} do test "updates the user's avatar", %{user: user, conn: conn} do
new_avatar = %Plug.Upload{ new_avatar = %Plug.Upload{
content_type: "image/jpeg", content_type: "image/jpeg",

View file

@ -35,7 +35,8 @@ test "Represent a user account" do
"<script src=\"invalid-html\"></script><span>valid html</span>. a<br>b<br/>c<br >d<br />f '&<>\"", "<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], inserted_at: ~N[2017-08-15 15:47:06.597036],
emoji: %{"karjalanpiirakka" => "/file.png"}, emoji: %{"karjalanpiirakka" => "/file.png"},
raw_bio: "valid html. a\nb\nc\nd\nf '&<>\"" raw_bio: "valid html. a\nb\nc\nd\nf '&<>\"",
also_known_as: ["https://shitposter.zone/users/shp"]
}) })
expected = %{ expected = %{
@ -75,6 +76,7 @@ test "Represent a user account" do
}, },
pleroma: %{ pleroma: %{
ap_id: user.ap_id, ap_id: user.ap_id,
also_known_as: ["https://shitposter.zone/users/shp"],
background_image: "https://example.com/images/asuka_hospital.png", background_image: "https://example.com/images/asuka_hospital.png",
favicon: nil, favicon: nil,
confirmation_pending: false, confirmation_pending: false,
@ -173,6 +175,7 @@ test "Represent a Service(bot) account" do
}, },
pleroma: %{ pleroma: %{
ap_id: user.ap_id, ap_id: user.ap_id,
also_known_as: [],
background_image: nil, background_image: nil,
favicon: nil, favicon: nil,
confirmation_pending: false, confirmation_pending: false,

View file

@ -30,14 +30,24 @@ test "GET host-meta" do
end end
test "Webfinger JRD" do test "Webfinger JRD" do
user = insert(:user) user =
insert(:user,
ap_id: "https://hyrule.world/users/zelda",
also_known_as: ["https://mushroom.kingdom/users/toad"]
)
response = response =
build_conn() build_conn()
|> put_req_header("accept", "application/jrd+json") |> put_req_header("accept", "application/jrd+json")
|> get("/.well-known/webfinger?resource=acct:#{user.nickname}@localhost") |> get("/.well-known/webfinger?resource=acct:#{user.nickname}@localhost")
|> json_response(200)
assert json_response(response, 200)["subject"] == "acct:#{user.nickname}@localhost" assert response["subject"] == "acct:#{user.nickname}@localhost"
assert response["aliases"] == [
"https://hyrule.world/users/zelda",
"https://mushroom.kingdom/users/toad"
]
end end
test "it returns 404 when user isn't found (JSON)" do test "it returns 404 when user isn't found (JSON)" do
@ -51,14 +61,20 @@ test "it returns 404 when user isn't found (JSON)" do
end end
test "Webfinger XML" do 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 = response =
build_conn() build_conn()
|> put_req_header("accept", "application/xrd+xml") |> put_req_header("accept", "application/xrd+xml")
|> get("/.well-known/webfinger?resource=acct:#{user.nickname}@localhost") |> 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 end
test "it returns 404 when user isn't found (XML)" do test "it returns 404 when user isn't found (XML)" do