From 0af77b20c19240479ea287446cc1c96a67318b2e Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sat, 11 Sep 2021 22:11:18 -0400 Subject: Implement moving account Ref: emit-move --- .../api_spec/operations/twitter_util_operation.ex | 35 ++++++++++++++++++++++ lib/pleroma/web/router.ex | 1 + .../web/twitter_api/controllers/util_controller.ex | 33 +++++++++++++++++++- 3 files changed, 68 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex b/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex index 2a701066d..4993058b5 100644 --- a/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex +++ b/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex @@ -214,6 +214,41 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do } end + def move_account_operation do + %Operation{ + tags: ["Account credentials"], + summary: "Move account", + security: [%{"oAuth" => ["write:accounts"]}], + operationId: "UtilController.move_account", + requestBody: request_body("Parameters", move_account_request(), required: true), + responses: %{ + 200 => + Operation.response("Success", "application/json", %Schema{ + type: :object, + properties: %{status: %Schema{type: :string, example: "success"}} + }), + 400 => Operation.response("Error", "application/json", ApiError), + 403 => Operation.response("Error", "application/json", ApiError) + } + } + end + + defp move_account_request do + %Schema{ + title: "MoveAccountRequest", + description: "POST body for moving the account", + type: :object, + required: [:password, :target_account], + properties: %{ + password: %Schema{type: :string, description: "Current password"}, + target_account: %Schema{ + type: :string, + description: "The nickname of the target account to move to" + } + } + } + end + def healthcheck_operation do %Operation{ tags: ["Accounts"], diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 6defc8080..d4395dd7b 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -343,6 +343,7 @@ defmodule Pleroma.Web.Router do post("/delete_account", UtilController, :delete_account) put("/notification_settings", UtilController, :update_notificaton_settings) post("/disable_account", UtilController, :disable_account) + post("/move_account", UtilController, :move_account) end scope "/api/pleroma", Pleroma.Web.PleromaAPI do diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index ccbef6d9f..3ca4c208c 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -11,6 +11,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do alias Pleroma.Emoji alias Pleroma.Healthcheck alias Pleroma.User + alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.CommonAPI alias Pleroma.Web.Plugs.OAuthScopesPlug alias Pleroma.Web.WebFinger @@ -26,7 +27,8 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do :change_password, :delete_account, :update_notificaton_settings, - :disable_account + :disable_account, + :move_account ] ) @@ -158,6 +160,35 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do end end + def move_account(%{assigns: %{user: user}, body_params: body_params} = conn, %{}) do + case CommonAPI.Utils.confirm_current_password(user, body_params.password) do + {:ok, user} -> + with {:ok, target_user} <- find_user_by_nickname(body_params.target_account), + {:ok, _user} <- ActivityPub.move(user, target_user) do + json(conn, %{status: "success"}) + else + {:not_found} -> + json(conn, %{error: "Target account not found."}) + + {:error, error} -> + json(conn, %{error: error}) + end + + {:error, msg} -> + json(conn, %{error: msg}) + end + end + + defp find_user_by_nickname(nickname) do + user = User.get_cached_by_nickname(nickname) + + if user == nil do + {:not_found, nil} + else + {:ok, user} + end + end + def captcha(conn, _params) do json(conn, Pleroma.Captcha.new()) end -- cgit v1.2.3 From 60081a88181e7af9b6110e9b7456e56f33c16f6b Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sun, 12 Sep 2021 09:40:20 -0400 Subject: Add User.add_alias/2 and User.alias_users/1 Ref: emit-move --- lib/pleroma/user.ex | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 390de1e2d..ff56927de 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -2270,6 +2270,25 @@ defmodule Pleroma.User do |> update_and_set_cache() end + def alias_users(user) do + user.also_known_as + |> Enum.map(&User.get_cached_by_ap_id/1) + |> Enum.filter(fn user -> user != nil end) + end + + def add_alias(user, new_alias_user) do + current_aliases = user.also_known_as || [] + new_alias_ap_id = new_alias_user.ap_id + + if new_alias_ap_id in current_aliases do + {:ok, user} + else + user + |> cast(%{also_known_as: current_aliases ++ [new_alias_ap_id]}, [:also_known_as]) + |> update_and_set_cache() + end + end + # Internal function; public one is `deactivate/2` defp set_activation_status(user, status) do user -- cgit v1.2.3 From c1aa3c98ac923d0f1a032ef0e171ed4e27ae1453 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sun, 12 Sep 2021 11:46:37 -0400 Subject: Add get and add aliases endpoints Ref: emit-move --- .../api_spec/operations/twitter_util_operation.ex | 63 ++++++++++++++++++++++ lib/pleroma/web/router.ex | 3 ++ .../web/twitter_api/controllers/util_controller.ex | 29 +++++++++- 3 files changed, 94 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex b/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex index 4993058b5..0fb54743d 100644 --- a/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex +++ b/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex @@ -249,6 +249,69 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do } end + def list_aliases_operation do + %Operation{ + tags: ["Account credentials"], + summary: "List account aliases", + security: [%{"oAuth" => ["read:accounts"]}], + operationId: "UtilController.list_aliases", + responses: %{ + 200 => + Operation.response("Success", "application/json", %Schema{ + type: :object, + properties: %{ + aliases: %Schema{ + type: :array, + items: %Schema{type: :string}, + example: ["foo@example.org"] + } + } + }), + 400 => Operation.response("Error", "application/json", ApiError), + 403 => Operation.response("Error", "application/json", ApiError) + } + } + end + + def add_alias_operation do + %Operation{ + tags: ["Account credentials"], + summary: "Add an alias to this account", + security: [%{"oAuth" => ["write:accounts"]}], + operationId: "UtilController.add_alias", + requestBody: request_body("Parameters", add_alias_request(), required: true), + responses: %{ + 200 => + Operation.response("Success", "application/json", %Schema{ + type: :object, + properties: %{ + status: %Schema{ + type: :string, + example: "success" + } + } + }), + 400 => Operation.response("Error", "application/json", ApiError), + 403 => Operation.response("Error", "application/json", ApiError) + } + } + end + + defp add_alias_request do + %Schema{ + title: "AddAliasRequest", + description: "PUT body for adding aliases", + type: :object, + required: [:alias], + properties: %{ + alias: %Schema{ + type: :string, + description: "The nickname of the account to add to aliases" + } + } + } + end + def healthcheck_operation do %Operation{ tags: ["Accounts"], diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index d4395dd7b..9ce0c9961 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -344,6 +344,9 @@ defmodule Pleroma.Web.Router do put("/notification_settings", UtilController, :update_notificaton_settings) post("/disable_account", UtilController, :disable_account) post("/move_account", UtilController, :move_account) + + put("/aliases", UtilController, :add_alias) + get("/aliases", UtilController, :list_aliases) end scope "/api/pleroma", Pleroma.Web.PleromaAPI do diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index 3ca4c208c..4c7d11e8d 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -28,7 +28,16 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do :delete_account, :update_notificaton_settings, :disable_account, - :move_account + :move_account, + :add_alias + ] + ) + + plug( + OAuthScopesPlug, + %{scopes: ["read:accounts"]} + when action in [ + :list_aliases ] ) @@ -179,6 +188,24 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do end end + def add_alias(%{assigns: %{user: user}, body_params: body_params} = conn, _) do + with {:ok, alias_user} <- find_user_by_nickname(body_params.alias), + {:ok, _user} <- user |> User.add_alias(alias_user) do + json(conn, %{status: "success"}) + else + {:error, error} -> + json(conn, %{error: error}) + end + end + + def list_aliases(%{assigns: %{user: user}} = conn, %{}) do + alias_nicks = user + |> User.alias_users() + |> Enum.map(&User.full_nickname/1) + + json(conn, %{aliases: alias_nicks}) + end + defp find_user_by_nickname(nickname) do user = User.get_cached_by_nickname(nickname) -- cgit v1.2.3 From 54d7b4354ce6d8da87831614855afc8e8dcc6aae Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sun, 12 Sep 2021 12:26:32 -0400 Subject: Add deleting alias endpoint Ref: emit-move --- lib/pleroma/user.ex | 13 +++++++ .../api_spec/operations/twitter_util_operation.ex | 40 ++++++++++++++++++++++ lib/pleroma/web/router.ex | 1 + .../web/twitter_api/controllers/util_controller.ex | 21 ++++++++++-- 4 files changed, 73 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index ff56927de..3c0de4f24 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -2289,6 +2289,19 @@ defmodule Pleroma.User do end end + def delete_alias(user, alias_user) do + current_aliases = user.also_known_as || [] + alias_ap_id = alias_user.ap_id + + if alias_ap_id in current_aliases do + user + |> cast(%{also_known_as: current_aliases -- [alias_ap_id]}, [:also_known_as]) + |> update_and_set_cache() + else + {:error, :no_such_alias} + end + end + # Internal function; public one is `deactivate/2` defp set_activation_status(user, status) do user diff --git a/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex b/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex index 0fb54743d..3e915575c 100644 --- a/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex +++ b/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex @@ -312,6 +312,46 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do } end + def delete_alias_operation do + %Operation{ + tags: ["Account credentials"], + summary: "Delete an alias from this account", + security: [%{"oAuth" => ["write:accounts"]}], + operationId: "UtilController.delete_alias", + requestBody: request_body("Parameters", delete_alias_request(), required: true), + responses: %{ + 200 => + Operation.response("Success", "application/json", %Schema{ + type: :object, + properties: %{ + status: %Schema{ + type: :string, + example: "success" + } + } + }), + 400 => Operation.response("Error", "application/json", ApiError), + 403 => Operation.response("Error", "application/json", ApiError), + 404 => Operation.response("Error", "application/json", ApiError) + } + } + end + + defp delete_alias_request do + %Schema{ + title: "DeleteAliasRequest", + description: "PUT body for deleting aliases", + type: :object, + required: [:alias], + properties: %{ + alias: %Schema{ + type: :string, + description: "The nickname of the account to delete from aliases" + } + } + } + end + def healthcheck_operation do %Operation{ tags: ["Accounts"], diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 9ce0c9961..4f97bb451 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -347,6 +347,7 @@ defmodule Pleroma.Web.Router do put("/aliases", UtilController, :add_alias) get("/aliases", UtilController, :list_aliases) + delete("/aliases", UtilController, :delete_alias) end scope "/api/pleroma", Pleroma.Web.PleromaAPI do diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index 4c7d11e8d..b3e16d527 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -29,7 +29,8 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do :update_notificaton_settings, :disable_account, :move_account, - :add_alias + :add_alias, + :delete_alias ] ) @@ -198,8 +199,24 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do end end + def delete_alias(%{assigns: %{user: user}, body_params: body_params} = conn, _) do + with {:ok, alias_user} <- find_user_by_nickname(body_params.alias), + {:ok, _user} <- user |> User.delete_alias(alias_user) do + json(conn, %{status: "success"}) + else + {:error, :no_such_alias} -> + conn + |> put_status(404) + |> json(%{error: "Account has no such alias."}) + + {:error, error} -> + json(conn, %{error: error}) + end + end + def list_aliases(%{assigns: %{user: user}} = conn, %{}) do - alias_nicks = user + alias_nicks = + user |> User.alias_users() |> Enum.map(&User.full_nickname/1) -- cgit v1.2.3 From e41eee5ed1c4e7001a28dababe046e28357d2ffd Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sun, 12 Sep 2021 16:45:17 -0400 Subject: Make Move activity federate properly Ref: emit-move --- lib/pleroma/web/activity_pub/activity_pub.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 756096952..01dedd248 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -413,7 +413,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do "type" => "Move", "actor" => origin.ap_id, "object" => origin.ap_id, - "target" => target.ap_id + "target" => target.ap_id, + "to" => [origin.follower_address] } with true <- origin.ap_id in target.also_known_as, -- cgit v1.2.3 From 4f44fd32eae100d5ce74b3c9bd5457858f145198 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sun, 12 Sep 2021 21:52:44 -0400 Subject: Federate unfollow activity in move_following properly 0: Use the CommonAPI unfollow function to make sure the unfollow activity is federated. 1: Limit the follow and unfollow to local followers only, while let the romote servers decide whether to move their followers. Ref: emit-move --- lib/pleroma/following_relationship.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/following_relationship.ex b/lib/pleroma/following_relationship.ex index a0c7e6e39..61d36ce93 100644 --- a/lib/pleroma/following_relationship.ex +++ b/lib/pleroma/following_relationship.ex @@ -194,11 +194,12 @@ defmodule Pleroma.FollowingRelationship do |> join(:inner, [r], f in assoc(r, :follower)) |> where(following_id: ^origin.id) |> where([r, f], f.allow_following_move == true) + |> where([r, f], f.local == true) |> limit(50) |> preload([:follower]) |> Repo.all() |> Enum.map(fn following_relationship -> - Repo.delete(following_relationship) + Pleroma.Web.CommonAPI.unfollow(following_relationship.follower, origin) Pleroma.Web.CommonAPI.follow(following_relationship.follower, target) end) |> case do -- cgit v1.2.3 From a677c621e822673b3b2922d5b0975f704f2f59a7 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Wed, 22 Sep 2021 15:30:04 -0400 Subject: Make move_following worker follow then unfollow Ref: emit-move --- lib/pleroma/following_relationship.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/following_relationship.ex b/lib/pleroma/following_relationship.ex index 61d36ce93..b101b9ee7 100644 --- a/lib/pleroma/following_relationship.ex +++ b/lib/pleroma/following_relationship.ex @@ -199,8 +199,8 @@ defmodule Pleroma.FollowingRelationship do |> preload([:follower]) |> Repo.all() |> Enum.map(fn following_relationship -> - Pleroma.Web.CommonAPI.unfollow(following_relationship.follower, origin) Pleroma.Web.CommonAPI.follow(following_relationship.follower, target) + Pleroma.Web.CommonAPI.unfollow(following_relationship.follower, origin) end) |> case do [] -> -- cgit v1.2.3 From eb383ef8d366c1656494278dfe6d2a6afdc04bc6 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Wed, 22 Sep 2021 16:26:22 -0400 Subject: Make move_account endpoint process non-existent users properly Ref: emit-move --- .../api_spec/operations/twitter_util_operation.ex | 3 ++- .../web/twitter_api/controllers/util_controller.ex | 23 +++++++++++++++++++--- 2 files changed, 22 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex b/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex index 3e915575c..fbaeb8da3 100644 --- a/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex +++ b/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex @@ -228,7 +228,8 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do properties: %{status: %Schema{type: :string, example: "success"}} }), 400 => Operation.response("Error", "application/json", ApiError), - 403 => Operation.response("Error", "application/json", ApiError) + 403 => Operation.response("Error", "application/json", ApiError), + 404 => Operation.response("Error", "application/json", ApiError) } } end diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index b3e16d527..c076671d4 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -173,12 +173,14 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do def move_account(%{assigns: %{user: user}, body_params: body_params} = conn, %{}) do case CommonAPI.Utils.confirm_current_password(user, body_params.password) do {:ok, user} -> - with {:ok, target_user} <- find_user_by_nickname(body_params.target_account), + with {:ok, target_user} <- find_or_fetch_user_by_nickname(body_params.target_account), {:ok, _user} <- ActivityPub.move(user, target_user) do json(conn, %{status: "success"}) else - {:not_found} -> - json(conn, %{error: "Target account not found."}) + {:not_found, _} -> + conn + |> put_status(404) + |> json(%{error: "Target account not found."}) {:error, error} -> json(conn, %{error: error}) @@ -233,6 +235,21 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do end end + defp find_or_fetch_user_by_nickname(nickname) do + user = User.get_by_nickname(nickname) + + if user != nil and user.local do + {:ok, user} + else + with {:ok, user} <- User.fetch_by_nickname(nickname) do + {:ok, user} + else + _ -> + {:not_found, nil} + end + end + end + def captcha(conn, _params) do json(conn, Pleroma.Captcha.new()) end -- cgit v1.2.3 From 9a27cb4f9d314fe1066f566de71357f55926116e Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Wed, 22 Sep 2021 19:27:04 -0400 Subject: Deal with target not found error in add_alias Ref: emit-move --- lib/pleroma/web/api_spec/operations/twitter_util_operation.ex | 3 ++- lib/pleroma/web/twitter_api/controllers/util_controller.ex | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex b/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex index fbaeb8da3..4a2a246f5 100644 --- a/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex +++ b/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex @@ -293,7 +293,8 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do } }), 400 => Operation.response("Error", "application/json", ApiError), - 403 => Operation.response("Error", "application/json", ApiError) + 403 => Operation.response("Error", "application/json", ApiError), + 404 => Operation.response("Error", "application/json", ApiError) } } end diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index c076671d4..b8abc666e 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -196,6 +196,11 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do {:ok, _user} <- user |> User.add_alias(alias_user) do json(conn, %{status: "success"}) else + {:not_found, _} -> + conn + |> put_status(404) + |> json(%{error: "Target account does not exist."}) + {:error, error} -> json(conn, %{error: error}) end -- cgit v1.2.3