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 From 6754d1f27239d3d529a3f667a6a93b267041daf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Wed, 16 Mar 2022 14:39:02 +0100 Subject: POST /api/v1/accounts/:id/remove_from_followers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- .../web/api_spec/operations/account_operation.ex | 16 ++++++++++++++++ .../mastodon_api/controllers/account_controller.ex | 19 ++++++++++++++++--- lib/pleroma/web/router.ex | 1 + 3 files changed, 33 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/api_spec/operations/account_operation.ex b/lib/pleroma/web/api_spec/operations/account_operation.ex index 026e92c5d..2a60cab78 100644 --- a/lib/pleroma/web/api_spec/operations/account_operation.ex +++ b/lib/pleroma/web/api_spec/operations/account_operation.ex @@ -370,6 +370,22 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do } end + def remove_from_followers_operation do + %Operation{ + tags: ["Account actions"], + summary: "Remove from followers", + operationId: "AccountController.remove_from_followers", + security: [%{"oAuth" => ["follow", "write:follows"]}], + description: "Remove the given account from followers", + parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}], + responses: %{ + 200 => Operation.response("Relationship", "application/json", AccountRelationship), + 400 => Operation.response("Error", "application/json", ApiError), + 404 => Operation.response("Error", "application/json", ApiError) + } + } + end + def note_operation do %Operation{ tags: ["Account actions"], diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex index f15305f9c..31d75ba85 100644 --- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex @@ -76,16 +76,18 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do plug( OAuthScopesPlug, - %{scopes: ["follow", "write:follows"]} when action in [:follow_by_uri, :follow, :unfollow] + %{scopes: ["follow", "write:follows"]} + when action in [:follow_by_uri, :follow, :unfollow, :remove_from_followers] ) plug(OAuthScopesPlug, %{scopes: ["follow", "read:mutes"]} when action == :mutes) plug(OAuthScopesPlug, %{scopes: ["follow", "write:mutes"]} when action in [:mute, :unmute]) - @relationship_actions [:follow, :unfollow] + @relationship_actions [:follow, :unfollow, :remove_from_followers] @needs_account ~W( - followers following lists follow unfollow mute unmute block unblock note endorse unendorse + followers following lists follow unfollow mute unmute block unblock + note endorse unendorse remove_from_followers )a plug( @@ -472,6 +474,17 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do end end + @doc "POST /api/v1/accounts/:id/remove_from_followers" + def remove_from_followers(%{assigns: %{user: %{id: id}, account: %{id: id}}}, _params) do + {:error, "Can not unfollow yourself"} + end + + def remove_from_followers(%{assigns: %{user: follower, account: followed}} = conn, _params) do + with {:ok, follower} <- CommonAPI.unfollow(followed, follower) do + render(conn, "relationship.json", user: follower, target: followed) + end + end + @doc "POST /api/v1/follows" def follow_by_uri(%{body_params: %{uri: uri}} = conn, _) do case User.get_cached_by_nickname(uri) do diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index ceb6c3cfd..8dc75b01e 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -491,6 +491,7 @@ defmodule Pleroma.Web.Router do post("/accounts/:id/note", AccountController, :note) post("/accounts/:id/pin", AccountController, :endorse) post("/accounts/:id/unpin", AccountController, :unendorse) + post("/accounts/:id/remove_from_followers", AccountController, :remove_from_followers) get("/conversations", ConversationController, :index) post("/conversations/:id/read", ConversationController, :mark_as_read) -- cgit v1.2.3 From ffe081bf4417ae7efbf24e4eaf0ee65fa2c2d8cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Wed, 16 Mar 2022 18:38:28 +0100 Subject: Use reject_follow_request MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- lib/pleroma/web/mastodon_api/controllers/account_controller.ex | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex index 31d75ba85..50dd0e4c2 100644 --- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex @@ -479,9 +479,12 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do {:error, "Can not unfollow yourself"} end - def remove_from_followers(%{assigns: %{user: follower, account: followed}} = conn, _params) do - with {:ok, follower} <- CommonAPI.unfollow(followed, follower) do + def remove_from_followers(%{assigns: %{user: followed, account: follower}} = conn, _params) do + with {:ok, follower} <- CommonAPI.reject_follow_request(follower, followed) do render(conn, "relationship.json", user: follower, target: followed) + else + nil -> + render_error(conn, :not_found, "Record not found") end end -- cgit v1.2.3 From 4d482b765f8bebbad0d5e9e17fb923eb475313d6 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Thu, 5 May 2022 18:39:34 -0400 Subject: Allow to skip cache in Cache plug Ref: fix-local-public --- lib/pleroma/web/plugs/cache.ex | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/plugs/cache.ex b/lib/pleroma/web/plugs/cache.ex index 111854859..e0467f107 100644 --- a/lib/pleroma/web/plugs/cache.ex +++ b/lib/pleroma/web/plugs/cache.ex @@ -98,14 +98,19 @@ defmodule Pleroma.Web.Plugs.Cache do content_type = content_type(conn) conn = - unless opts[:tracking_fun] do - @cachex.put(:web_resp_cache, key, {content_type, body}, ttl: ttl) - conn - else - tracking_fun_data = Map.get(conn.assigns, :tracking_fun_data, nil) - @cachex.put(:web_resp_cache, key, {content_type, body, tracking_fun_data}, ttl: ttl) - - opts.tracking_fun.(conn, tracking_fun_data) + cond do + Map.get(conn.assigns, :skip_cache, false) -> + conn + + !opts[:tracking_fun] -> + @cachex.put(:web_resp_cache, key, {content_type, body}, ttl: ttl) + conn + + true -> + tracking_fun_data = Map.get(conn.assigns, :tracking_fun_data, nil) + @cachex.put(:web_resp_cache, key, {content_type, body, tracking_fun_data}, ttl: ttl) + + opts.tracking_fun.(conn, tracking_fun_data) end put_resp_header(conn, "x-cache", "MISS from Pleroma") -- cgit v1.2.3 From fa3157df964d4f88d0fd1ce466a44333c8c7ef60 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Thu, 5 May 2022 19:20:32 -0400 Subject: Skip cache when /objects or /activities is authenticated Ref: fix-local-public --- .../web/activity_pub/activity_pub_controller.ex | 11 +++++++++++ lib/pleroma/web/plugs/cache.ex | 21 ++++++++++++--------- 2 files changed, 23 insertions(+), 9 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex index 57ac40b42..d423b1139 100644 --- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex +++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex @@ -84,6 +84,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do user <- Map.get(assigns, :user, nil), {_, true} <- {:visible?, Visibility.visible_for_user?(object, user)} do conn + |> maybe_skip_cache(user) |> assign(:tracking_fun_data, object.id) |> set_cache_ttl_for(object) |> put_resp_content_type("application/activity+json") @@ -112,6 +113,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do user <- Map.get(assigns, :user, nil), {_, true} <- {:visible?, Visibility.visible_for_user?(activity, user)} do conn + |> maybe_skip_cache(user) |> maybe_set_tracking_data(activity) |> set_cache_ttl_for(activity) |> put_resp_content_type("application/activity+json") @@ -151,6 +153,15 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do assign(conn, :cache_ttl, ttl) end + def maybe_skip_cache(conn, user) do + if user do + conn + |> assign(:skip_cache, true) + else + conn + end + end + # GET /relay/following def relay_following(conn, _params) do with %{halted: false} = conn <- FederatingPlug.call(conn, []) do diff --git a/lib/pleroma/web/plugs/cache.ex b/lib/pleroma/web/plugs/cache.ex index e0467f107..935b2d834 100644 --- a/lib/pleroma/web/plugs/cache.ex +++ b/lib/pleroma/web/plugs/cache.ex @@ -97,20 +97,23 @@ defmodule Pleroma.Web.Plugs.Cache do key = cache_key(conn, opts) content_type = content_type(conn) - conn = - cond do - Map.get(conn.assigns, :skip_cache, false) -> - conn + should_cache = not Map.get(conn.assigns, :skip_cache, false) - !opts[:tracking_fun] -> + conn = + unless opts[:tracking_fun] do + if should_cache do @cachex.put(:web_resp_cache, key, {content_type, body}, ttl: ttl) - conn + end + + conn + else + tracking_fun_data = Map.get(conn.assigns, :tracking_fun_data, nil) - true -> - tracking_fun_data = Map.get(conn.assigns, :tracking_fun_data, nil) + if should_cache do @cachex.put(:web_resp_cache, key, {content_type, body, tracking_fun_data}, ttl: ttl) + end - opts.tracking_fun.(conn, tracking_fun_data) + opts.tracking_fun.(conn, tracking_fun_data) end put_resp_header(conn, "x-cache", "MISS from Pleroma") -- cgit v1.2.3 From c48be59f581fc6c3070a9d4cc889166b61981a6d Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Wed, 4 May 2022 22:51:40 -0400 Subject: Show local-only statuses in public timeline for authenticated users Ref: fix-local-public --- lib/pleroma/web/activity_pub/activity_pub.ex | 11 ++++++++++- .../web/mastodon_api/controllers/timeline_controller.ex | 2 ++ 2 files changed, 12 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 064f93b22..f8e840564 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -501,9 +501,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do @spec fetch_public_or_unlisted_activities(map(), Pagination.type()) :: [Activity.t()] def fetch_public_or_unlisted_activities(opts \\ %{}, pagination \\ :keyset) do + includes_local_public = Map.get(opts, :includes_local_public, false) + opts = Map.delete(opts, :user) - [Constants.as_public()] + intended_recipients = + if includes_local_public do + [Constants.as_public(), as_local_public()] + else + [Constants.as_public()] + end + + intended_recipients |> fetch_activities_query(opts) |> restrict_unlisted(opts) |> fetch_paginated_optimized(opts, pagination) diff --git a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex index ba7239476..293c61b41 100644 --- a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex @@ -112,6 +112,8 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do |> Map.put(:muting_user, user) |> Map.put(:reply_filtering_user, user) |> Map.put(:instance, params[:instance]) + # Restricts unfederated content to authenticated users + |> Map.put(:includes_local_public, not is_nil(user)) |> ActivityPub.fetch_public_activities() conn -- cgit v1.2.3 From 826deb737588c75d9431d260eea826208100385c Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Thu, 5 May 2022 10:44:34 -0400 Subject: Make local-only statuses searchable Ref: fix-local-public --- lib/pleroma/activity/search.ex | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/activity/search.ex b/lib/pleroma/activity/search.ex index 694dc5709..b56d4a5aa 100644 --- a/lib/pleroma/activity/search.ex +++ b/lib/pleroma/activity/search.ex @@ -30,7 +30,7 @@ defmodule Pleroma.Activity.Search do Activity |> Activity.with_preloaded_object() |> Activity.restrict_deactivated_users() - |> restrict_public() + |> restrict_public(user) |> query_with(index_type, search_query, search_function) |> maybe_restrict_local(user) |> maybe_restrict_author(author) @@ -57,7 +57,16 @@ defmodule Pleroma.Activity.Search do def maybe_restrict_blocked(query, _), do: query - defp restrict_public(q) do + defp restrict_public(q, user) when not is_nil(user) do + intended_recipients = [Pleroma.Constants.as_public(), Pleroma.Web.ActivityPub.Utils.as_local_public()] + + from([a, o] in q, + where: fragment("?->>'type' = 'Create'", a.data), + where: fragment("? && ?", ^intended_recipients, a.recipients) + ) + end + + defp restrict_public(q, _user) do from([a, o] in q, where: fragment("?->>'type' = 'Create'", a.data), where: ^Pleroma.Constants.as_public() in a.recipients -- cgit v1.2.3 From 466568ae36fd247e635e5a1c4db2b5662eda1d02 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Thu, 5 May 2022 11:18:18 -0400 Subject: Lint Ref: fix-local-public --- lib/pleroma/activity/search.ex | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/activity/search.ex b/lib/pleroma/activity/search.ex index b56d4a5aa..0b9b24aa4 100644 --- a/lib/pleroma/activity/search.ex +++ b/lib/pleroma/activity/search.ex @@ -58,7 +58,10 @@ defmodule Pleroma.Activity.Search do def maybe_restrict_blocked(query, _), do: query defp restrict_public(q, user) when not is_nil(user) do - intended_recipients = [Pleroma.Constants.as_public(), Pleroma.Web.ActivityPub.Utils.as_local_public()] + intended_recipients = [ + Pleroma.Constants.as_public(), + Pleroma.Web.ActivityPub.Utils.as_local_public() + ] from([a, o] in q, where: fragment("?->>'type' = 'Create'", a.data), -- cgit v1.2.3 From fe933b9bf2bd9787331db3a37e6bac472eace3d5 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Thu, 5 May 2022 18:07:30 -0400 Subject: Prevent remote access of local-only posts via /objects Ref: fix-local-public --- lib/pleroma/web/activity_pub/visibility.ex | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/visibility.ex b/lib/pleroma/web/activity_pub/visibility.ex index 465f8a9b7..7c57f88f9 100644 --- a/lib/pleroma/web/activity_pub/visibility.ex +++ b/lib/pleroma/web/activity_pub/visibility.ex @@ -84,7 +84,10 @@ defmodule Pleroma.Web.ActivityPub.Visibility do when module in [Activity, Object] do x = [user.ap_id | User.following(user)] y = [message.data["actor"]] ++ message.data["to"] ++ (message.data["cc"] || []) - is_public?(message) || Enum.any?(x, &(&1 in y)) + + user_is_local = user.local + federatable = not is_local_public?(message) + (is_public?(message) || Enum.any?(x, &(&1 in y))) and (user_is_local || federatable) end def entire_thread_visible_for_user?(%Activity{} = activity, %User{} = user) do -- cgit v1.2.3 From 221cb3fb8125fac1757e1f1caeb36684d6c71050 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sat, 7 May 2022 00:20:50 -0400 Subject: Allow users to create backups without providing email address Ref: backup-without-email --- lib/pleroma/user/backup.ex | 18 +----------------- lib/pleroma/workers/backup_worker.ex | 24 ++++++++++++++++++++---- 2 files changed, 21 insertions(+), 21 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/user/backup.ex b/lib/pleroma/user/backup.ex index 9cb329663..9df010605 100644 --- a/lib/pleroma/user/backup.ex +++ b/lib/pleroma/user/backup.ex @@ -32,9 +32,7 @@ defmodule Pleroma.User.Backup do end def create(user, admin_id \\ nil) do - with :ok <- validate_email_enabled(), - :ok <- validate_user_email(user), - :ok <- validate_limit(user, admin_id), + with :ok <- validate_limit(user, admin_id), {:ok, backup} <- user |> new() |> Repo.insert() do BackupWorker.process(backup, admin_id) end @@ -86,20 +84,6 @@ defmodule Pleroma.User.Backup do end end - defp validate_email_enabled do - if Pleroma.Config.get([Pleroma.Emails.Mailer, :enabled]) do - :ok - else - {:error, dgettext("errors", "Backups require enabled email")} - end - end - - defp validate_user_email(%User{email: nil}) do - {:error, dgettext("errors", "Email is required")} - end - - defp validate_user_email(%User{email: email}) when is_binary(email), do: :ok - def get_last(user_id) do __MODULE__ |> where(user_id: ^user_id) diff --git a/lib/pleroma/workers/backup_worker.ex b/lib/pleroma/workers/backup_worker.ex index 3caef85b7..7657fa9ce 100644 --- a/lib/pleroma/workers/backup_worker.ex +++ b/lib/pleroma/workers/backup_worker.ex @@ -37,10 +37,7 @@ defmodule Pleroma.Workers.BackupWorker do backup_id |> Backup.get() |> Backup.process(), {:ok, _job} <- schedule_deletion(backup), :ok <- Backup.remove_outdated(backup), - {:ok, _} <- - backup - |> Pleroma.Emails.UserEmail.backup_is_ready_email(admin_user_id) - |> Pleroma.Emails.Mailer.deliver() do + :ok <- maybe_deliver_email(backup, admin_user_id) do {:ok, backup} end end @@ -51,4 +48,23 @@ defmodule Pleroma.Workers.BackupWorker do nil -> :ok end end + + defp has_email?(user) do + not is_nil(user.email) and user.email != "" + end + + defp maybe_deliver_email(backup, admin_user_id) do + has_mailer = Pleroma.Config.get([Pleroma.Emails.Mailer, :enabled]) + backup = backup |> Pleroma.Repo.preload(:user) + + if has_email?(backup.user) and has_mailer do + backup + |> Pleroma.Emails.UserEmail.backup_is_ready_email(admin_user_id) + |> Pleroma.Emails.Mailer.deliver() + + :ok + else + :ok + end + end end -- cgit v1.2.3 From 38444aa92a4ae89065c138f0f0110bef4fe48ace Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Mon, 9 May 2022 15:04:51 -0400 Subject: Allow authenticated users to access local-only posts in MastoAPI Ref: fix-local-public --- lib/pleroma/web/activity_pub/activity_pub.ex | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index f8e840564..8e10edc24 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -612,9 +612,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do do: query defp restrict_thread_visibility(query, %{user: %User{ap_id: ap_id}}, _) do + local_public = as_local_public() from( a in query, - where: fragment("thread_visibility(?, (?)->>'id') = true", ^ap_id, a.data) + where: fragment("thread_visibility(?, (?)->>'id', ?) = true", ^ap_id, a.data, ^local_public) ) end @@ -701,8 +702,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do defp user_activities_recipients(%{godmode: true}), do: [] defp user_activities_recipients(%{reading_user: reading_user}) do - if reading_user do - [Constants.as_public(), reading_user.ap_id | User.following(reading_user)] + if not is_nil(reading_user) and reading_user.local do + [Constants.as_public(), as_local_public(), reading_user.ap_id | User.following(reading_user)] else [Constants.as_public()] end -- cgit v1.2.3 From f1722a9f4a0a96c6a58fe25d57928c9843f96fc8 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Mon, 9 May 2022 15:31:26 -0400 Subject: Make lint happy Ref: fix-local-public --- lib/pleroma/web/activity_pub/activity_pub.ex | 7 ++++++- 1 file changed, 6 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 8e10edc24..c28ea5e2f 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -613,6 +613,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do defp restrict_thread_visibility(query, %{user: %User{ap_id: ap_id}}, _) do local_public = as_local_public() + from( a in query, where: fragment("thread_visibility(?, (?)->>'id', ?) = true", ^ap_id, a.data, ^local_public) @@ -703,7 +704,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do defp user_activities_recipients(%{reading_user: reading_user}) do if not is_nil(reading_user) and reading_user.local do - [Constants.as_public(), as_local_public(), reading_user.ap_id | User.following(reading_user)] + [ + Constants.as_public(), + as_local_public(), + reading_user.ap_id | User.following(reading_user) + ] else [Constants.as_public()] end -- cgit v1.2.3 From 39c47073a3c6fd3da068d5a4c9def18f3847ff32 Mon Sep 17 00:00:00 2001 From: duponin Date: Wed, 18 May 2022 20:06:16 +0200 Subject: fix Ctrl-c catch on SSH BBS --- lib/pleroma/bbs/handler.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/bbs/handler.ex b/lib/pleroma/bbs/handler.ex index a3b623bdf..47f5a920e 100644 --- a/lib/pleroma/bbs/handler.ex +++ b/lib/pleroma/bbs/handler.ex @@ -123,7 +123,7 @@ defmodule Pleroma.BBS.Handler do loop(%{state | counter: state.counter + 1}) - {:error, :interrupted} -> + {:input, ^input, {:error, :interrupted}} -> IO.puts("Caught Ctrl+C...") loop(%{state | counter: state.counter + 1}) -- cgit v1.2.3 From 5086d6d5e9ff68d6a7a82fd3ad6dbc0bad0b599c Mon Sep 17 00:00:00 2001 From: duponin Date: Thu, 19 May 2022 00:56:20 +0200 Subject: add thread show in BBS frontend --- lib/pleroma/bbs/handler.ex | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/bbs/handler.ex b/lib/pleroma/bbs/handler.ex index 47f5a920e..f1ac0c687 100644 --- a/lib/pleroma/bbs/handler.ex +++ b/lib/pleroma/bbs/handler.ex @@ -53,6 +53,7 @@ defmodule Pleroma.BBS.Handler do IO.puts("home - Show the home timeline") IO.puts("p - Post the given text") IO.puts("r - Reply to the post with the given id") + IO.puts("t - Show a thread from the given id") IO.puts("quit - Quit") state @@ -73,6 +74,33 @@ defmodule Pleroma.BBS.Handler do state end + def handle_command(%{user: user} = state, "t " <> activity_id) do + with %Activity{} = activity <- Activity.get_by_id(activity_id) do + activities = + ActivityPub.fetch_activities_for_context(activity.data["context"], %{ + blocking_user: user, + user: user, + exclude_id: activity.id + }) + + case activities do + [] -> + activity_id + |> Activity.get_by_id() + |> puts_activity() + + _ -> + activities + |> Enum.reverse() + |> Enum.each(&puts_activity/1) + end + else + _e -> IO.puts("An error occured when trying to show the thread...") + end + + state + end + def handle_command(%{user: user} = state, "p " <> text) do text = String.trim(text) -- cgit v1.2.3 From b128e1d6c5bbc78874d05af2676550de80ae85c7 Mon Sep 17 00:00:00 2001 From: duponin Date: Thu, 19 May 2022 01:38:13 +0200 Subject: decode HTML to be human readable in BBS --- lib/pleroma/bbs/handler.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/bbs/handler.ex b/lib/pleroma/bbs/handler.ex index f1ac0c687..c2491a20c 100644 --- a/lib/pleroma/bbs/handler.ex +++ b/lib/pleroma/bbs/handler.ex @@ -43,7 +43,7 @@ defmodule Pleroma.BBS.Handler do def puts_activity(activity) do status = Pleroma.Web.MastodonAPI.StatusView.render("show.json", %{activity: activity}) IO.puts("-- #{status.id} by #{status.account.display_name} (#{status.account.acct})") - IO.puts(HTML.strip_tags(status.content)) + IO.puts(status.content |> HTML.strip_tags() |> HtmlEntities.decode()) IO.puts("") end -- cgit v1.2.3 From 33ced2c2ed9391ec95aae2205bb30d987ceac86d Mon Sep 17 00:00:00 2001 From: duponin Date: Sat, 21 May 2022 04:17:34 +0200 Subject: BBS: put a new line for each HTML break in an activity Otherwise it would just put each line on the first one, which is not really readable --- lib/pleroma/bbs/handler.ex | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/bbs/handler.ex b/lib/pleroma/bbs/handler.ex index c2491a20c..d641de9ac 100644 --- a/lib/pleroma/bbs/handler.ex +++ b/lib/pleroma/bbs/handler.ex @@ -42,9 +42,14 @@ defmodule Pleroma.BBS.Handler do def puts_activity(activity) do status = Pleroma.Web.MastodonAPI.StatusView.render("show.json", %{activity: activity}) + IO.puts("-- #{status.id} by #{status.account.display_name} (#{status.account.acct})") - IO.puts(status.content |> HTML.strip_tags() |> HtmlEntities.decode()) - IO.puts("") + + status.content + |> String.split("
") + |> Enum.map(&HTML.strip_tags/1) + |> Enum.map(&HtmlEntities.decode/1) + |> Enum.map(&IO.puts/1) end def handle_command(state, "help") do -- cgit v1.2.3 From c04c7f9e45eec680afc0bf6c145fa55fc3f56ea8 Mon Sep 17 00:00:00 2001 From: duponin Date: Sat, 21 May 2022 05:10:22 +0200 Subject: BBS: show notifactions --- lib/pleroma/bbs/handler.ex | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/bbs/handler.ex b/lib/pleroma/bbs/handler.ex index d641de9ac..e0174efe1 100644 --- a/lib/pleroma/bbs/handler.ex +++ b/lib/pleroma/bbs/handler.ex @@ -52,6 +52,40 @@ defmodule Pleroma.BBS.Handler do |> Enum.map(&IO.puts/1) end + def puts_notification(activity, user) do + notification = + Pleroma.Web.MastodonAPI.NotificationView.render("show.json", %{ + notification: activity, + for: user + }) + + IO.puts( + "== (#{notification.type}) #{notification.status.id} by #{notification.account.display_name} (#{notification.account.acct})" + ) + + notification.status.content + |> String.split("
") + |> Enum.map(&HTML.strip_tags/1) + |> Enum.map(&HtmlEntities.decode/1) + |> (fn x -> + case x do + [content] -> + "> " <> content + + [head | _tail] -> + # "> " <> hd <> "..." + head + |> String.to_charlist() + |> Enum.take(80) + |> List.to_string() + |> (fn x -> "> " <> x <> "..." end).() + end + end).() + |> IO.puts() + + IO.puts("") + end + def handle_command(state, "help") do IO.puts("Available commands:") IO.puts("help - This help") @@ -59,6 +93,7 @@ defmodule Pleroma.BBS.Handler do IO.puts("p - Post the given text") IO.puts("r - Reply to the post with the given id") IO.puts("t - Show a thread from the given id") + IO.puts("n - Show notifications") IO.puts("quit - Quit") state @@ -106,6 +141,14 @@ defmodule Pleroma.BBS.Handler do state end + def handle_command(%{user: user} = state, "n") do + user + |> Pleroma.Web.MastodonAPI.MastodonAPI.get_notifications(%{}) + |> Enum.each(&puts_notification(&1, user)) + + state + end + def handle_command(%{user: user} = state, "p " <> text) do text = String.trim(text) -- cgit v1.2.3 From e3e8ff06f9c588563003ba9855f2d38b9d6e08b7 Mon Sep 17 00:00:00 2001 From: duponin Date: Sat, 21 May 2022 05:10:48 +0200 Subject: BBS: mark notification as read --- lib/pleroma/bbs/handler.ex | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/bbs/handler.ex b/lib/pleroma/bbs/handler.ex index e0174efe1..7314453af 100644 --- a/lib/pleroma/bbs/handler.ex +++ b/lib/pleroma/bbs/handler.ex @@ -94,6 +94,7 @@ defmodule Pleroma.BBS.Handler do IO.puts("r - Reply to the post with the given id") IO.puts("t - Show a thread from the given id") IO.puts("n - Show notifications") + IO.puts("n read - Mark all notifactions as read") IO.puts("quit - Quit") state @@ -141,6 +142,13 @@ defmodule Pleroma.BBS.Handler do state end + def handle_command(%{user: user} = state, "n read") do + Pleroma.Notification.clear(user) + IO.puts("All notifications are marked as read") + + state + end + def handle_command(%{user: user} = state, "n") do user |> Pleroma.Web.MastodonAPI.MastodonAPI.get_notifications(%{}) -- cgit v1.2.3 From a4659d993d1493406e9df4a26ada35cba50511c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9l=C3=A8ne?= Date: Sat, 21 May 2022 23:23:55 +0000 Subject: =?UTF-8?q?Apply=20H=C3=A9l=C3=A8ne=20suggestions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pleroma/bbs/handler.ex | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/bbs/handler.ex b/lib/pleroma/bbs/handler.ex index 7314453af..a8f2fd37b 100644 --- a/lib/pleroma/bbs/handler.ex +++ b/lib/pleroma/bbs/handler.ex @@ -75,9 +75,7 @@ defmodule Pleroma.BBS.Handler do [head | _tail] -> # "> " <> hd <> "..." head - |> String.to_charlist() - |> Enum.take(80) - |> List.to_string() + |> String.slice(1, 80) |> (fn x -> "> " <> x <> "..." end).() end end).() @@ -136,7 +134,7 @@ defmodule Pleroma.BBS.Handler do |> Enum.each(&puts_activity/1) end else - _e -> IO.puts("An error occured when trying to show the thread...") + _e -> IO.puts("Could not show this thread...") end state @@ -144,7 +142,7 @@ defmodule Pleroma.BBS.Handler do def handle_command(%{user: user} = state, "n read") do Pleroma.Notification.clear(user) - IO.puts("All notifications are marked as read") + IO.puts("All notifications were marked as read") state end -- cgit v1.2.3 From fffd9059d67fb719c38dc014de1fa750dd5be8b4 Mon Sep 17 00:00:00 2001 From: duponin Date: Sun, 22 May 2022 02:39:38 +0200 Subject: BBS: add post favourite feature --- lib/pleroma/bbs/handler.ex | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/bbs/handler.ex b/lib/pleroma/bbs/handler.ex index a8f2fd37b..631307f02 100644 --- a/lib/pleroma/bbs/handler.ex +++ b/lib/pleroma/bbs/handler.ex @@ -93,6 +93,7 @@ defmodule Pleroma.BBS.Handler do IO.puts("t - Show a thread from the given id") IO.puts("n - Show notifications") IO.puts("n read - Mark all notifactions as read") + IO.puts("f - Favourites the post with the given id") IO.puts("quit - Quit") state @@ -167,6 +168,19 @@ defmodule Pleroma.BBS.Handler do state end + def handle_command(%{user: user} = state, "f " <> id) do + id = String.trim(id) + + with %Activity{} = activity <- Activity.get_by_id(id), + {:ok, _activity} <- CommonAPI.favorite(user, activity) do + IO.puts("Favourited!") + else + _e -> IO.puts("Could not Favourite...") + end + + state + end + def handle_command(state, "home") do user = state.user -- cgit v1.2.3 From 5951d637a98402ad0e1d11d220c9374fc02d5bcd Mon Sep 17 00:00:00 2001 From: duponin Date: Sun, 22 May 2022 02:40:56 +0200 Subject: BBS: show post ID when posted --- lib/pleroma/bbs/handler.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/bbs/handler.ex b/lib/pleroma/bbs/handler.ex index 631307f02..fecabb878 100644 --- a/lib/pleroma/bbs/handler.ex +++ b/lib/pleroma/bbs/handler.ex @@ -159,8 +159,8 @@ defmodule Pleroma.BBS.Handler do def handle_command(%{user: user} = state, "p " <> text) do text = String.trim(text) - with {:ok, _activity} <- CommonAPI.post(user, %{status: text}) do - IO.puts("Posted!") + with {:ok, activity} <- CommonAPI.post(user, %{status: text}) do + IO.puts("Posted! ID: #{activity.id}") else _e -> IO.puts("Could not post...") end -- cgit v1.2.3 From 5ca1ac041f011df458af7ebe057b39c1cc9548d0 Mon Sep 17 00:00:00 2001 From: duponin Date: Sun, 22 May 2022 03:19:24 +0200 Subject: BBS: add repeat functionality --- lib/pleroma/bbs/handler.ex | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/pleroma/bbs/handler.ex b/lib/pleroma/bbs/handler.ex index fecabb878..27799338f 100644 --- a/lib/pleroma/bbs/handler.ex +++ b/lib/pleroma/bbs/handler.ex @@ -94,6 +94,7 @@ defmodule Pleroma.BBS.Handler do IO.puts("n - Show notifications") IO.puts("n read - Mark all notifactions as read") IO.puts("f - Favourites the post with the given id") + IO.puts("R - Repeat the post with the given id") IO.puts("quit - Quit") state -- cgit v1.2.3 From 547def67a76854aa4c9c8438eb1ee4dfa36fd8ac Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sun, 29 May 2022 11:36:00 -0400 Subject: Allow Updates by every actor on the same origin --- lib/pleroma/web/activity_pub/object_validators/update_validator.ex | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/object_validators/update_validator.ex b/lib/pleroma/web/activity_pub/object_validators/update_validator.ex index a5def312e..1e940a400 100644 --- a/lib/pleroma/web/activity_pub/object_validators/update_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/update_validator.ex @@ -51,7 +51,9 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.UpdateValidator do with actor = get_field(cng, :actor), object = get_field(cng, :object), {:ok, object_id} <- ObjectValidators.ObjectID.cast(object), - true <- actor == object_id do + actor_uri <- URI.parse(actor), + object_uri <- URI.parse(object_id), + true <- actor_uri.host == object_uri.host do cng else _e -> -- cgit v1.2.3 From 0f6a5eb9a299629f295372f4d5ecdd9083a19717 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sun, 29 May 2022 12:54:57 -0400 Subject: Handle Note and Question Updates --- lib/pleroma/web/activity_pub/side_effects.ex | 82 ++++++++++++++++++++++++---- 1 file changed, 72 insertions(+), 10 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/side_effects.ex b/lib/pleroma/web/activity_pub/side_effects.ex index b997c15db..aeddf3ed8 100644 --- a/lib/pleroma/web/activity_pub/side_effects.ex +++ b/lib/pleroma/web/activity_pub/side_effects.ex @@ -153,23 +153,25 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do # Tasks this handles: # - Update the user + # - Update a non-user object (Note, Question, etc.) # # For a local user, we also get a changeset with the full information, so we # can update non-federating, non-activitypub settings as well. @impl true def handle(%{data: %{"type" => "Update", "object" => updated_object}} = object, meta) do - if changeset = Keyword.get(meta, :user_update_changeset) do - changeset - |> User.update_and_set_cache() + updated_object_id = updated_object["id"] + + with {_, true} <- {:has_id, is_binary(updated_object_id)}, + {_, user} <- {:user, Pleroma.User.get_by_ap_id(updated_object_id)} do + if user do + handle_update_user(object, meta) + else + handle_update_object(object, meta) + end else - {:ok, new_user_data} = ActivityPub.user_data_from_user_object(updated_object) - - User.get_by_ap_id(updated_object["id"]) - |> User.remote_user_changeset(new_user_data) - |> User.update_and_set_cache() + _ -> + {:ok, object, meta} end - - {:ok, object, meta} end # Tasks this handles: @@ -390,6 +392,66 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do {:ok, object, meta} end + defp handle_update_user( + %{data: %{"type" => "Update", "object" => updated_object}} = object, + meta + ) do + if changeset = Keyword.get(meta, :user_update_changeset) do + changeset + |> User.update_and_set_cache() + else + {:ok, new_user_data} = ActivityPub.user_data_from_user_object(updated_object) + + User.get_by_ap_id(updated_object["id"]) + |> User.remote_user_changeset(new_user_data) + |> User.update_and_set_cache() + end + + {:ok, object, meta} + end + + @updatable_object_types ["Note", "Question"] + # We do not allow poll options to be changed, but the poll description can be. + @updatable_fields [ + "source", + "tag", + "updated", + "emoji", + "content", + "summary", + "sensitive", + "attachment", + "generator" + ] + defp handle_update_object( + %{data: %{"type" => "Update", "object" => updated_object}} = object, + meta + ) do + orig_object = Object.get_by_ap_id(updated_object["id"]) + orig_object_data = orig_object.data + + if orig_object_data["type"] in @updatable_object_types do + updated_object_data = + @updatable_fields + |> Enum.reduce( + orig_object_data, + fn field, acc -> + if Map.has_key?(updated_object, field) do + Map.put(acc, field, updated_object[field]) + else + Map.drop(acc, [field]) + end + end + ) + + orig_object + |> Object.change(%{data: updated_object_data}) + |> Object.update_and_set_cache() + end + + {:ok, object, meta} + end + def handle_object_creation(%{"type" => "ChatMessage"} = object, _activity, meta) do with {:ok, object, meta} <- Pipeline.common_pipeline(object, meta) do actor = User.get_cached_by_ap_id(object.data["actor"]) -- cgit v1.2.3 From 5e8aac0e07cf54d527643e9793b92f3c0b3826e2 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sun, 29 May 2022 13:54:16 -0400 Subject: Record edit history for Note and Question Updates --- lib/pleroma/web/activity_pub/side_effects.ex | 34 ++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/side_effects.ex b/lib/pleroma/web/activity_pub/side_effects.ex index aeddf3ed8..c4d56fa20 100644 --- a/lib/pleroma/web/activity_pub/side_effects.ex +++ b/lib/pleroma/web/activity_pub/side_effects.ex @@ -410,6 +410,26 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do {:ok, object, meta} end + defp history_for_object(object) do + with history <- Map.get(object, "formerRepresentations"), + true <- is_map(history), + "OrderedCollection" <- Map.get(history, "type"), + true <- is_list(Map.get(history, "orderedItems")), + true <- is_integer(Map.get(history, "totalItems")) do + history + else + _ -> history_skeleton() + end + end + + defp history_skeleton do + %{ + "type" => "OrderedCollection", + "totalItems" => 0, + "orderedItems" => [] + } + end + @updatable_object_types ["Note", "Question"] # We do not allow poll options to be changed, but the poll description can be. @updatable_fields [ @@ -431,6 +451,19 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do orig_object_data = orig_object.data if orig_object_data["type"] in @updatable_object_types do + # Put edit history + # Note that we may have got the edit history by first fetching the object + history = history_for_object(orig_object_data) + + latest_history_item = + orig_object_data + |> Map.drop(["id", "formerRepresentations"]) + + new_history = + history + |> Map.put("orderedItems", [latest_history_item | history["orderedItems"]]) + |> Map.put("totalItems", history["totalItems"] + 1) + updated_object_data = @updatable_fields |> Enum.reduce( @@ -443,6 +476,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do end end ) + |> Map.put("formerRepresentations", new_history) orig_object |> Object.change(%{data: updated_object_data}) -- cgit v1.2.3 From 8acfe95f3e9d4183fd513cfe828500c852db4d5f Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sun, 29 May 2022 22:16:03 -0400 Subject: Allow updating polls --- lib/pleroma/web/activity_pub/side_effects.ex | 81 +++++++++++++++++++++------- 1 file changed, 62 insertions(+), 19 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/side_effects.ex b/lib/pleroma/web/activity_pub/side_effects.ex index c4d56fa20..ac327280c 100644 --- a/lib/pleroma/web/activity_pub/side_effects.ex +++ b/lib/pleroma/web/activity_pub/side_effects.ex @@ -443,14 +443,29 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do "attachment", "generator" ] - defp handle_update_object( - %{data: %{"type" => "Update", "object" => updated_object}} = object, - meta - ) do - orig_object = Object.get_by_ap_id(updated_object["id"]) - orig_object_data = orig_object.data + defp update_content_fields(orig_object_data, updated_object) do + @updatable_fields + |> Enum.reduce( + %{data: orig_object_data, updated: false}, + fn field, %{data: data, updated: updated} -> + updated = updated or Map.get(updated_object, field) != Map.get(orig_object_data, field) + + data = + if Map.has_key?(updated_object, field) do + Map.put(data, field, updated_object[field]) + else + Map.drop(data, [field]) + end - if orig_object_data["type"] in @updatable_object_types do + %{data: data, updated: updated} + end + ) + end + + defp maybe_update_history(updated_object, orig_object_data, updated) do + if not updated do + updated_object + else # Put edit history # Note that we may have got the edit history by first fetching the object history = history_for_object(orig_object_data) @@ -464,19 +479,47 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do |> Map.put("orderedItems", [latest_history_item | history["orderedItems"]]) |> Map.put("totalItems", history["totalItems"] + 1) + updated_object + |> Map.put("formerRepresentations", new_history) + end + end + + defp maybe_update_poll(to_be_updated, updated_object) do + choice_key = fn data -> + if Map.has_key?(data, "anyOf"), do: "anyOf", else: "oneOf" + end + + with true <- to_be_updated["type"] == "Question", + key <- choice_key.(updated_object), + true <- key == choice_key.(to_be_updated), + orig_choices <- to_be_updated[key] |> Enum.map(&Map.drop(&1, ["replies"])), + new_choices <- updated_object[key] |> Enum.map(&Map.drop(&1, ["replies"])), + true <- orig_choices == new_choices do + # Choices are the same, but counts are different + to_be_updated + |> Map.put(key, updated_object[key]) + else + # Choices (or vote type) have changed, do not allow this + _ -> to_be_updated + end + end + + defp handle_update_object( + %{data: %{"type" => "Update", "object" => updated_object}} = object, + meta + ) do + orig_object = Object.get_by_ap_id(updated_object["id"]) + orig_object_data = orig_object.data + + if orig_object_data["type"] in @updatable_object_types do + %{data: updated_object_data, updated: updated} = + orig_object_data + |> update_content_fields(updated_object) + updated_object_data = - @updatable_fields - |> Enum.reduce( - orig_object_data, - fn field, acc -> - if Map.has_key?(updated_object, field) do - Map.put(acc, field, updated_object[field]) - else - Map.drop(acc, [field]) - end - end - ) - |> Map.put("formerRepresentations", new_history) + updated_object_data + |> maybe_update_history(orig_object_data, updated) + |> maybe_update_poll(updated_object) orig_object |> Object.change(%{data: updated_object_data}) -- cgit v1.2.3 From c004eb0fa2c0a754a0fb839a961e35f406c57445 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sun, 29 May 2022 23:50:31 -0400 Subject: Implement mastodon api for showing edit history --- lib/pleroma/object.ex | 20 ++++++ lib/pleroma/web/activity_pub/side_effects.ex | 22 +----- .../web/api_spec/operations/status_operation.ex | 82 ++++++++++++++++++++++ .../mastodon_api/controllers/status_controller.ex | 30 +++++++- lib/pleroma/web/mastodon_api/views/status_view.ex | 65 +++++++++++++++++ lib/pleroma/web/router.ex | 3 + 6 files changed, 199 insertions(+), 23 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index fe264b5e0..a893f2c1a 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -425,4 +425,24 @@ defmodule Pleroma.Object do end def object_data_hashtags(_), do: [] + + def history_for(object) do + with history <- Map.get(object, "formerRepresentations"), + true <- is_map(history), + "OrderedCollection" <- Map.get(history, "type"), + true <- is_list(Map.get(history, "orderedItems")), + true <- is_integer(Map.get(history, "totalItems")) do + history + else + _ -> history_skeleton() + end + end + + defp history_skeleton do + %{ + "type" => "OrderedCollection", + "totalItems" => 0, + "orderedItems" => [] + } + end end diff --git a/lib/pleroma/web/activity_pub/side_effects.ex b/lib/pleroma/web/activity_pub/side_effects.ex index ac327280c..894c0ceef 100644 --- a/lib/pleroma/web/activity_pub/side_effects.ex +++ b/lib/pleroma/web/activity_pub/side_effects.ex @@ -410,26 +410,6 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do {:ok, object, meta} end - defp history_for_object(object) do - with history <- Map.get(object, "formerRepresentations"), - true <- is_map(history), - "OrderedCollection" <- Map.get(history, "type"), - true <- is_list(Map.get(history, "orderedItems")), - true <- is_integer(Map.get(history, "totalItems")) do - history - else - _ -> history_skeleton() - end - end - - defp history_skeleton do - %{ - "type" => "OrderedCollection", - "totalItems" => 0, - "orderedItems" => [] - } - end - @updatable_object_types ["Note", "Question"] # We do not allow poll options to be changed, but the poll description can be. @updatable_fields [ @@ -468,7 +448,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do else # Put edit history # Note that we may have got the edit history by first fetching the object - history = history_for_object(orig_object_data) + history = Object.history_for(orig_object_data) latest_history_item = orig_object_data diff --git a/lib/pleroma/web/api_spec/operations/status_operation.ex b/lib/pleroma/web/api_spec/operations/status_operation.ex index 639f24d49..e5322707f 100644 --- a/lib/pleroma/web/api_spec/operations/status_operation.ex +++ b/lib/pleroma/web/api_spec/operations/status_operation.ex @@ -6,9 +6,13 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do alias OpenApiSpex.Operation alias OpenApiSpex.Schema alias Pleroma.Web.ApiSpec.AccountOperation + alias Pleroma.Web.ApiSpec.Schemas.Account alias Pleroma.Web.ApiSpec.Schemas.ApiError + alias Pleroma.Web.ApiSpec.Schemas.Attachment alias Pleroma.Web.ApiSpec.Schemas.BooleanLike + alias Pleroma.Web.ApiSpec.Schemas.Emoji alias Pleroma.Web.ApiSpec.Schemas.FlakeID + alias Pleroma.Web.ApiSpec.Schemas.Poll alias Pleroma.Web.ApiSpec.Schemas.ScheduledStatus alias Pleroma.Web.ApiSpec.Schemas.Status alias Pleroma.Web.ApiSpec.Schemas.VisibilityScope @@ -434,6 +438,29 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do } end + def show_history_operation do + %Operation{ + tags: ["Retrieve status history"], + summary: "Status history", + description: "View history of a status", + operationId: "StatusController.show_history", + security: [%{"oAuth" => ["read:statuses"]}], + parameters: [ + id_param() + ], + responses: %{ + 200 => status_history_response(), + 404 => Operation.response("Not Found", "application/json", ApiError) + } + } + end + + def show_source_operation do + end + + def update_operation do + end + def array_of_statuses do %Schema{type: :array, items: Status, example: [Status.schema().example]} end @@ -579,6 +606,61 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do Operation.response("Status", "application/json", Status) end + defp status_history_response do + Operation.response( + "Status History", + "application/json", + %Schema{ + title: "Status history", + description: "Response schema for history of a status", + type: :array, + items: %Schema{ + type: :object, + properties: %{ + account: %Schema{ + allOf: [Account], + description: "The account that authored this status" + }, + content: %Schema{ + type: :string, + format: :html, + description: "HTML-encoded status content" + }, + sensitive: %Schema{ + type: :boolean, + description: "Is this status marked as sensitive content?" + }, + spoiler_text: %Schema{ + type: :string, + description: + "Subject or summary line, below which status content is collapsed until expanded" + }, + created_at: %Schema{ + type: :string, + format: "date-time", + description: "The date when this status was created" + }, + media_attachments: %Schema{ + type: :array, + items: Attachment, + description: "Media that is attached to this status" + }, + emojis: %Schema{ + type: :array, + items: Emoji, + description: "Custom emoji to be used when rendering status content" + }, + poll: %Schema{ + allOf: [Poll], + nullable: true, + description: "The poll attached to the status" + } + } + } + } + ) + end + defp context do %Schema{ title: "StatusContext", diff --git a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex index 42a95bdc5..72d85f1ec 100644 --- a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex @@ -38,7 +38,9 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do :index, :show, :card, - :context + :context, + :show_history, + :show_source ] ) @@ -49,7 +51,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do :create, :delete, :reblog, - :unreblog + :unreblog, + :update ] ) @@ -191,6 +194,29 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do create(%Plug.Conn{conn | body_params: params}, %{}) end + @doc "GET /api/v1/statuses/:id/history" + def show_history(%{assigns: %{user: user}} = conn, %{id: id} = params) do + with %Activity{} = activity <- Activity.get_by_id_with_object(id), + true <- Visibility.visible_for_user?(activity, user) do + try_render(conn, "history.json", + activity: activity, + for: user, + with_direct_conversation_id: true, + with_muted: Map.get(params, :with_muted, false) + ) + else + _ -> {:error, :not_found} + end + end + + @doc "GET /api/v1/statuses/:id/source" + def show_source(%{assigns: %{user: _user}} = _conn, %{id: _id} = _params) do + end + + @doc "PUT /api/v1/statuses/:id" + def update(%{assigns: %{user: _user}} = _conn, %{id: _id} = _params) do + end + @doc "GET /api/v1/statuses/:id" def show(%{assigns: %{user: user}} = conn, %{id: id} = params) do with %Activity{} = activity <- Activity.get_by_id_with_object(id), diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index 1ebfd6740..c50e0d3da 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -384,6 +384,71 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do nil end + def render("history.json", %{activity: %{data: %{"object" => _object}} = activity} = opts) do + object = Object.normalize(activity, fetch: false) + + hashtags = Object.hashtags(object) + + user = CommonAPI.get_user(activity.data["actor"]) + + past_history = + Object.history_for(object.data) + |> Map.get("orderedItems") + |> Enum.map(&Map.put(&1, "id", object.data["id"])) + |> Enum.map(&%Object{data: &1, id: object.id}) + + history = [object | past_history] + + individual_opts = + opts + |> Map.put(:as, :object) + |> Map.put(:user, user) + |> Map.put(:hashtags, hashtags) + + render_many(history, StatusView, "history_item.json", individual_opts) + end + + def render( + "history_item.json", + %{activity: activity, user: user, object: object, hashtags: hashtags} = opts + ) do + sensitive = object.data["sensitive"] || Enum.member?(hashtags, "nsfw") + + attachment_data = object.data["attachment"] || [] + attachments = render_many(attachment_data, StatusView, "attachment.json", as: :attachment) + + created_at = Utils.to_masto_date(object.data["updated"] || object.data["published"]) + + content = + object + |> render_content() + + content_html = + content + |> Activity.HTML.get_cached_scrubbed_html_for_activity( + User.html_filter_policy(opts[:for]), + activity, + "mastoapi:content" + ) + + summary = object.data["summary"] || "" + + %{ + account: + AccountView.render("show.json", %{ + user: user, + for: opts[:for] + }), + content: content_html, + sensitive: sensitive, + spoiler_text: summary, + created_at: created_at, + media_attachments: attachments, + emojis: build_emojis(object.data["emoji"]), + poll: render(PollView, "show.json", object: object, for: opts[:for]) + } + end + def render("card.json", %{rich_media: rich_media, page_url: page_url}) do page_url_data = URI.parse(page_url) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index ceb6c3cfd..2d2e5365e 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -552,6 +552,9 @@ defmodule Pleroma.Web.Router do get("/bookmarks", StatusController, :bookmarks) post("/statuses", StatusController, :create) + get("/statuses/:id/history", StatusController, :show_history) + get("/statuses/:id/source", StatusController, :show_source) + put("/statuses/:id", StatusController, :update) delete("/statuses/:id", StatusController, :delete) post("/statuses/:id/reblog", StatusController, :reblog) post("/statuses/:id/unreblog", StatusController, :unreblog) -- cgit v1.2.3 From 393b50884607f9aca4d6e08bf429c8fe8f426f96 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Mon, 30 May 2022 00:59:23 -0400 Subject: Implement viewing source --- .../web/api_spec/operations/status_operation.ex | 36 ++++++++++++++++++++++ .../mastodon_api/controllers/status_controller.ex | 11 ++++++- lib/pleroma/web/mastodon_api/views/status_view.ex | 10 ++++++ 3 files changed, 56 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/api_spec/operations/status_operation.ex b/lib/pleroma/web/api_spec/operations/status_operation.ex index e5322707f..617aba460 100644 --- a/lib/pleroma/web/api_spec/operations/status_operation.ex +++ b/lib/pleroma/web/api_spec/operations/status_operation.ex @@ -456,6 +456,20 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do end def show_source_operation do + %Operation{ + tags: ["Retrieve status source"], + summary: "Status source", + description: "View source of a status", + operationId: "StatusController.show_source", + security: [%{"oAuth" => ["read:statuses"]}], + parameters: [ + id_param() + ], + responses: %{ + 200 => status_source_response(), + 404 => Operation.response("Not Found", "application/json", ApiError) + } + } end def update_operation do @@ -661,6 +675,28 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do ) end + defp status_source_response do + Operation.response( + "Status Source", + "application/json", + %Schema{ + type: :object, + properties: %{ + id: FlakeID, + text: %Schema{ + type: :string, + description: "Raw source of status content" + }, + spoiler_text: %Schema{ + type: :string, + description: + "Subject or summary line, below which status content is collapsed until expanded" + } + } + } + ) + end + defp context do %Schema{ title: "StatusContext", diff --git a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex index 72d85f1ec..ea9e08aa8 100644 --- a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex @@ -210,7 +210,16 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do end @doc "GET /api/v1/statuses/:id/source" - def show_source(%{assigns: %{user: _user}} = _conn, %{id: _id} = _params) do + def show_source(%{assigns: %{user: user}} = conn, %{id: id} = _params) do + with %Activity{} = activity <- Activity.get_by_id_with_object(id), + true <- Visibility.visible_for_user?(activity, user) do + try_render(conn, "source.json", + activity: activity, + for: user + ) + else + _ -> {:error, :not_found} + end end @doc "PUT /api/v1/statuses/:id" diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index c50e0d3da..8d4685ffa 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -449,6 +449,16 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do } end + def render("source.json", %{activity: %{data: %{"object" => _object}} = activity} = _opts) do + object = Object.normalize(activity, fetch: false) + + %{ + id: activity.id, + text: Map.get(object.data, "source", ""), + spoiler_text: Map.get(object.data, "summary", "") + } + end + def render("card.json", %{rich_media: rich_media, page_url: page_url}) do page_url_data = URI.parse(page_url) -- cgit v1.2.3 From b613a9ec6b68972c81dfe2f0175572bc7bd547f9 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Tue, 31 May 2022 14:29:12 -0400 Subject: Implement mastodon api for editing status --- lib/pleroma/constants.ex | 24 ++++++++ lib/pleroma/web/activity_pub/builder.ex | 13 +++- lib/pleroma/web/activity_pub/side_effects.ex | 16 +---- .../web/api_spec/operations/status_operation.ex | 72 +++++++++++++++++++++- lib/pleroma/web/common_api.ex | 36 +++++++++++ .../mastodon_api/controllers/status_controller.ex | 21 ++++++- 6 files changed, 164 insertions(+), 18 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/constants.ex b/lib/pleroma/constants.ex index a42c71d23..bbb95104f 100644 --- a/lib/pleroma/constants.ex +++ b/lib/pleroma/constants.ex @@ -27,4 +27,28 @@ defmodule Pleroma.Constants do do: ~w(index.html robots.txt static static-fe finmoji emoji packs sounds images instance sw.js sw-pleroma.js favicon.png schemas doc embed.js embed.css) ) + + const(status_updatable_fields, + do: [ + "source", + "tag", + "updated", + "emoji", + "content", + "summary", + "sensitive", + "attachment", + "generator" + ] + ) + + const(actor_types, + do: [ + "Application", + "Group", + "Organization", + "Person", + "Service" + ] + ) end diff --git a/lib/pleroma/web/activity_pub/builder.ex b/lib/pleroma/web/activity_pub/builder.ex index 5b25138a4..532047599 100644 --- a/lib/pleroma/web/activity_pub/builder.ex +++ b/lib/pleroma/web/activity_pub/builder.ex @@ -218,10 +218,16 @@ defmodule Pleroma.Web.ActivityPub.Builder do end end - # Retricted to user updates for now, always public @spec update(User.t(), Object.t()) :: {:ok, map(), keyword()} def update(actor, object) do - to = [Pleroma.Constants.as_public(), actor.follower_address] + {to, cc} = + if object["type"] in Pleroma.Constants.actor_types() do + # User updates, always public + {[Pleroma.Constants.as_public(), actor.follower_address], []} + else + # Status updates, follow the recipients in the object + {object["to"] || [], object["cc"] || []} + end {:ok, %{ @@ -229,7 +235,8 @@ defmodule Pleroma.Web.ActivityPub.Builder do "type" => "Update", "actor" => actor.ap_id, "object" => object, - "to" => to + "to" => to, + "cc" => cc }, []} end diff --git a/lib/pleroma/web/activity_pub/side_effects.ex b/lib/pleroma/web/activity_pub/side_effects.ex index 894c0ceef..49054c320 100644 --- a/lib/pleroma/web/activity_pub/side_effects.ex +++ b/lib/pleroma/web/activity_pub/side_effects.ex @@ -25,6 +25,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do alias Pleroma.Web.Streamer alias Pleroma.Workers.PollWorker + require Pleroma.Constants require Logger @cachex Pleroma.Config.get([:cachex, :provider], Cachex) @@ -411,20 +412,8 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do end @updatable_object_types ["Note", "Question"] - # We do not allow poll options to be changed, but the poll description can be. - @updatable_fields [ - "source", - "tag", - "updated", - "emoji", - "content", - "summary", - "sensitive", - "attachment", - "generator" - ] defp update_content_fields(orig_object_data, updated_object) do - @updatable_fields + Pleroma.Constants.status_updatable_fields() |> Enum.reduce( %{data: orig_object_data, updated: false}, fn field, %{data: data, updated: updated} -> @@ -502,6 +491,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do |> maybe_update_poll(updated_object) orig_object + |> Repo.preload(:hashtags) |> Object.change(%{data: updated_object_data}) |> Object.update_and_set_cache() end diff --git a/lib/pleroma/web/api_spec/operations/status_operation.ex b/lib/pleroma/web/api_spec/operations/status_operation.ex index 617aba460..c69307a4d 100644 --- a/lib/pleroma/web/api_spec/operations/status_operation.ex +++ b/lib/pleroma/web/api_spec/operations/status_operation.ex @@ -473,6 +473,22 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do end def update_operation do + %Operation{ + tags: ["Update status"], + summary: "Update status", + description: "Change the content of a status", + operationId: "StatusController.update", + security: [%{"oAuth" => ["write:statuses"]}], + parameters: [ + id_param() + ], + requestBody: request_body("Parameters", update_request(), required: true), + responses: %{ + 200 => status_response(), + 403 => Operation.response("Forbidden", "application/json", ApiError), + 404 => Operation.response("Not Found", "application/json", ApiError) + } + } end def array_of_statuses do @@ -578,6 +594,60 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do } end + defp update_request do + %Schema{ + title: "StatusUpdateRequest", + type: :object, + properties: %{ + status: %Schema{ + type: :string, + nullable: true, + description: + "Text content of the status. If `media_ids` is provided, this becomes optional. Attaching a `poll` is optional while `status` is provided." + }, + media_ids: %Schema{ + nullable: true, + type: :array, + items: %Schema{type: :string}, + description: "Array of Attachment ids to be attached as media." + }, + poll: poll_params(), + sensitive: %Schema{ + allOf: [BooleanLike], + nullable: true, + description: "Mark status and attached media as sensitive?" + }, + spoiler_text: %Schema{ + type: :string, + nullable: true, + description: + "Text to be shown as a warning or subject before the actual content. Statuses are generally collapsed behind this field." + }, + content_type: %Schema{ + type: :string, + nullable: true, + description: + "The MIME type of the status, it is transformed into HTML by the backend. You can get the list of the supported MIME types with the nodeinfo endpoint." + }, + to: %Schema{ + type: :array, + nullable: true, + items: %Schema{type: :string}, + description: + "A list of nicknames (like `lain@soykaf.club` or `lain` on the local server) that will be used to determine who is going to be addressed by this post. Using this will disable the implicit addressing by mentioned names in the `status` body, only the people in the `to` list will be addressed. The normal rules for for post visibility are not affected by this and will still apply" + } + }, + example: %{ + "status" => "What time is it?", + "sensitive" => "false", + "poll" => %{ + "options" => ["Cofe", "Adventure"], + "expires_in" => 420 + } + } + } + end + def poll_params do %Schema{ nullable: true, @@ -690,7 +760,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do spoiler_text: %Schema{ type: :string, description: - "Subject or summary line, below which status content is collapsed until expanded" + "Subject or summary line, below which status content is collapsed until expanded" } } } diff --git a/lib/pleroma/web/common_api.ex b/lib/pleroma/web/common_api.ex index 1b95ee89c..e60c26053 100644 --- a/lib/pleroma/web/common_api.ex +++ b/lib/pleroma/web/common_api.ex @@ -402,6 +402,42 @@ defmodule Pleroma.Web.CommonAPI do end end + def update(user, orig_activity, changes) do + with orig_object <- Object.normalize(orig_activity), + {:ok, new_object} <- make_update_data(user, orig_object, changes), + {:ok, update_data, _} <- Builder.update(user, new_object), + {:ok, update, _} <- Pipeline.common_pipeline(update_data, local: true) do + {:ok, update} + else + _ -> {:error, nil} + end + end + + defp make_update_data(user, orig_object, changes) do + kept_params = %{ + visibility: Visibility.get_visibility(orig_object) + } + + params = Map.merge(changes, kept_params) + + with {:ok, draft} <- ActivityDraft.create(user, params) do + change = + Pleroma.Constants.status_updatable_fields() + |> Enum.reduce(orig_object.data, fn key, acc -> + if Map.has_key?(draft.object, key) do + acc |> Map.put(key, Map.get(draft.object, key)) + else + acc |> Map.drop([key]) + end + end) + |> Map.put("updated", Utils.make_date()) + + {:ok, change} + else + _ -> {:error, nil} + end + end + @spec pin(String.t(), User.t()) :: {:ok, Activity.t()} | {:error, term()} def pin(id, %User{} = user) do with %Activity{} = activity <- create_activity_by_id(id), diff --git a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex index ea9e08aa8..fa86e9dc0 100644 --- a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex @@ -223,7 +223,26 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do end @doc "PUT /api/v1/statuses/:id" - def update(%{assigns: %{user: _user}} = _conn, %{id: _id} = _params) do + def update(%{assigns: %{user: user}, body_params: body_params} = conn, %{id: id} = params) do + with {_, %Activity{}} = {_, activity} <- {:activity, Activity.get_by_id_with_object(id)}, + {_, true} <- {:visible, Visibility.visible_for_user?(activity, user)}, + {_, true} <- {:is_create, activity.data["type"] == "Create"}, + actor <- Activity.user_actor(activity), + {_, true} <- {:own_status, actor.id == user.id}, + changes <- body_params |> put_application(conn), + {_, {:ok, _update_activity}} <- {:pipeline, CommonAPI.update(user, activity, changes)}, + {_, %Activity{}} = {_, activity} <- {:refetched, Activity.get_by_id_with_object(id)} do + try_render(conn, "show.json", + activity: activity, + for: user, + with_direct_conversation_id: true, + with_muted: Map.get(params, :with_muted, false) + ) + else + {:own_status, _} -> {:error, :forbidden} + {:pipeline, _} -> {:error, :internal_server_error} + _ -> {:error, :not_found} + end end @doc "GET /api/v1/statuses/:id" -- cgit v1.2.3 From 410e177b2ac3177f0645d7728b2ea922ba3c24d3 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Wed, 1 Jun 2022 12:02:03 -0400 Subject: Strip internal fields in formerRepresentation --- lib/pleroma/web/activity_pub/transmogrifier.ex | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index a70330f0e..5750396a4 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -902,7 +902,24 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do end def strip_internal_fields(object) do - Map.drop(object, Pleroma.Constants.object_internal_fields()) + outer = Map.drop(object, Pleroma.Constants.object_internal_fields()) + + case outer do + %{"formerRepresentations" => %{"orderedItems" => list}} when is_list(list) -> + update_in( + outer["formerRepresentations"]["orderedItems"], + &Enum.map( + &1, + fn + item when is_map(item) -> Map.drop(item, Pleroma.Constants.object_internal_fields()) + item -> item + end + ) + ) + + _ -> + outer + end end defp strip_internal_tags(%{"tag" => tags} = object) do -- cgit v1.2.3 From fa31ae50e6ec44a3921a60d2a6c19e864f0511e7 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Wed, 1 Jun 2022 19:30:50 -0400 Subject: Inject history when object is refetched --- lib/pleroma/object.ex | 22 ++++++++++++++++++++++ lib/pleroma/object/fetcher.ex | 27 +++++++++++++++++++++++++++ lib/pleroma/web/activity_pub/side_effects.ex | 24 +----------------------- 3 files changed, 50 insertions(+), 23 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index a893f2c1a..670ab8743 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -445,4 +445,26 @@ defmodule Pleroma.Object do "orderedItems" => [] } end + + def maybe_update_history(updated_object, orig_object_data, updated) do + if not updated do + updated_object + else + # Put edit history + # Note that we may have got the edit history by first fetching the object + history = Object.history_for(orig_object_data) + + latest_history_item = + orig_object_data + |> Map.drop(["id", "formerRepresentations"]) + + new_history = + history + |> Map.put("orderedItems", [latest_history_item | history["orderedItems"]]) + |> Map.put("totalItems", history["totalItems"] + 1) + + updated_object + |> Map.put("formerRepresentations", new_history) + end + end end diff --git a/lib/pleroma/object/fetcher.ex b/lib/pleroma/object/fetcher.ex index deb3dc711..ce816c1fc 100644 --- a/lib/pleroma/object/fetcher.ex +++ b/lib/pleroma/object/fetcher.ex @@ -26,8 +26,35 @@ defmodule Pleroma.Object.Fetcher do end defp maybe_reinject_internal_fields(%{data: %{} = old_data}, new_data) do + has_history? = fn + %{"formerRepresentations" => %{"orderedItems" => list}} when is_list(list) -> true + _ -> false + end + internal_fields = Map.take(old_data, Pleroma.Constants.object_internal_fields()) + remote_history_exists? = has_history?.(new_data) + + # If the remote history exists, we treat that as the only source of truth. + new_data = + if has_history?.(old_data) and not remote_history_exists? do + Map.put(new_data, "formerRepresentations", old_data["formerRepresentations"]) + else + new_data + end + + # If the remote does not have history information, we need to manage it ourselves + new_data = + if not remote_history_exists? do + changed? = + Pleroma.Constants.status_updatable_fields() + |> Enum.any?(fn field -> Map.get(old_data, field) != Map.get(new_data, field) end) + + new_data |> Object.maybe_update_history(old_data, changed?) + else + new_data + end + Map.merge(new_data, internal_fields) end diff --git a/lib/pleroma/web/activity_pub/side_effects.ex b/lib/pleroma/web/activity_pub/side_effects.ex index 49054c320..52a343de7 100644 --- a/lib/pleroma/web/activity_pub/side_effects.ex +++ b/lib/pleroma/web/activity_pub/side_effects.ex @@ -431,28 +431,6 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do ) end - defp maybe_update_history(updated_object, orig_object_data, updated) do - if not updated do - updated_object - else - # Put edit history - # Note that we may have got the edit history by first fetching the object - history = Object.history_for(orig_object_data) - - latest_history_item = - orig_object_data - |> Map.drop(["id", "formerRepresentations"]) - - new_history = - history - |> Map.put("orderedItems", [latest_history_item | history["orderedItems"]]) - |> Map.put("totalItems", history["totalItems"] + 1) - - updated_object - |> Map.put("formerRepresentations", new_history) - end - end - defp maybe_update_poll(to_be_updated, updated_object) do choice_key = fn data -> if Map.has_key?(data, "anyOf"), do: "anyOf", else: "oneOf" @@ -487,7 +465,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do updated_object_data = updated_object_data - |> maybe_update_history(orig_object_data, updated) + |> Object.maybe_update_history(orig_object_data, updated) |> maybe_update_poll(updated_object) orig_object -- cgit v1.2.3 From 8bac8147d4079c0ba0a54753bbab904e46dadbfc Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Fri, 3 Jun 2022 21:15:17 -0400 Subject: Stream out edits --- lib/pleroma/web/activity_pub/activity_pub.ex | 13 ++++++++++-- lib/pleroma/web/activity_pub/side_effects.ex | 6 ++++++ lib/pleroma/web/streamer.ex | 14 +++++++++++++ lib/pleroma/web/views/streamer_view.ex | 31 ++++++++++++++++++++++++++++ 4 files changed, 62 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 064f93b22..179e6763b 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -190,7 +190,16 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do def notify_and_stream(activity) do Notification.create_notifications(activity) - conversation = create_or_bump_conversation(activity, activity.actor) + original_activity = + case activity do + %{data: %{"type" => "Update"}, object: %{data: %{"id" => id}}} -> + Activity.get_create_by_object_ap_id_with_object(id) + + _ -> + activity + end + + conversation = create_or_bump_conversation(original_activity, original_activity.actor) participations = get_participations(conversation) stream_out(activity) stream_out_participations(participations) @@ -256,7 +265,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do @impl true def stream_out(%Activity{data: %{"type" => data_type}} = activity) - when data_type in ["Create", "Announce", "Delete"] do + when data_type in ["Create", "Announce", "Delete", "Update"] do activity |> Topics.get_activity_topics() |> Streamer.stream(activity) diff --git a/lib/pleroma/web/activity_pub/side_effects.ex b/lib/pleroma/web/activity_pub/side_effects.ex index 52a343de7..05f9b9bd9 100644 --- a/lib/pleroma/web/activity_pub/side_effects.ex +++ b/lib/pleroma/web/activity_pub/side_effects.ex @@ -472,6 +472,12 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do |> Repo.preload(:hashtags) |> Object.change(%{data: updated_object_data}) |> Object.update_and_set_cache() + + if updated do + object + |> Activity.normalize() + |> ActivityPub.notify_and_stream() + end end {:ok, object, meta} diff --git a/lib/pleroma/web/streamer.ex b/lib/pleroma/web/streamer.ex index ff7f62a1e..8b7fb985b 100644 --- a/lib/pleroma/web/streamer.ex +++ b/lib/pleroma/web/streamer.ex @@ -296,6 +296,20 @@ defmodule Pleroma.Web.Streamer do defp push_to_socket(_topic, %Activity{data: %{"type" => "Delete"}}), do: :noop + defp push_to_socket(topic, %Activity{data: %{"type" => "Update"}} = item) do + anon_render = StreamerView.render("status_update.json", item) + + Registry.dispatch(@registry, topic, fn list -> + Enum.each(list, fn {pid, auth?} -> + if auth? do + send(pid, {:render_with_user, StreamerView, "status_update.json", item}) + else + send(pid, {:text, anon_render}) + end + end) + end) + end + defp push_to_socket(topic, item) do anon_render = StreamerView.render("update.json", item) diff --git a/lib/pleroma/web/views/streamer_view.ex b/lib/pleroma/web/views/streamer_view.ex index 16c2b7d61..797762d90 100644 --- a/lib/pleroma/web/views/streamer_view.ex +++ b/lib/pleroma/web/views/streamer_view.ex @@ -25,6 +25,22 @@ defmodule Pleroma.Web.StreamerView do |> Jason.encode!() end + def render("status_update.json", %Activity{} = activity, %User{} = user) do + activity = Activity.get_create_by_object_ap_id_with_object(activity.object.data["id"]) + + %{ + event: "status.update", + payload: + Pleroma.Web.MastodonAPI.StatusView.render( + "show.json", + activity: activity, + for: user + ) + |> Jason.encode!() + } + |> Jason.encode!() + end + def render("notification.json", %Notification{} = notify, %User{} = user) do %{ event: "notification", @@ -51,6 +67,21 @@ defmodule Pleroma.Web.StreamerView do |> Jason.encode!() end + def render("status_update.json", %Activity{} = activity) do + activity = Activity.get_create_by_object_ap_id_with_object(activity.object.data["id"]) + + %{ + event: "status.update", + payload: + Pleroma.Web.MastodonAPI.StatusView.render( + "show.json", + activity: activity + ) + |> Jason.encode!() + } + |> Jason.encode!() + end + def render("chat_update.json", %{chat_message_reference: cm_ref}) do # Explicitly giving the cmr for the object here, so we don't accidentally # send a later 'last_message' that was inserted between inserting this and -- cgit v1.2.3 From 3249ac1f12b69718cacc193c020e8bdccf167a9e Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Fri, 3 Jun 2022 21:47:40 -0400 Subject: Show edited_at in MastodonAPI/show --- lib/pleroma/web/api_spec/schemas/status.ex | 6 ++++++ lib/pleroma/web/mastodon_api/views/status_view.ex | 11 +++++++++++ 2 files changed, 17 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/api_spec/schemas/status.ex b/lib/pleroma/web/api_spec/schemas/status.ex index 6e6e30315..f803caec2 100644 --- a/lib/pleroma/web/api_spec/schemas/status.ex +++ b/lib/pleroma/web/api_spec/schemas/status.ex @@ -73,6 +73,12 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Status do format: "date-time", description: "The date when this status was created" }, + edited_at: %Schema{ + type: :string, + format: "date-time", + nullable: true, + description: "The date when this status was last edited" + }, emojis: %Schema{ type: :array, items: Emoji, diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index 8d4685ffa..4afba4b33 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -258,6 +258,16 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do created_at = Utils.to_masto_date(object.data["published"]) + edited_at = + with %{"updated" => updated} <- object.data, + date <- Utils.to_masto_date(updated), + true <- date != "" do + date + else + _ -> + nil + end + reply_to = get_reply_to(activity, opts) reply_to_user = reply_to && CommonAPI.get_user(reply_to.data["actor"]) @@ -346,6 +356,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do content: content_html, text: opts[:with_source] && object.data["source"], created_at: created_at, + edited_at: edited_at, reblogs_count: announcement_count, replies_count: object.data["repliesCount"] || 0, favourites_count: like_count, -- cgit v1.2.3 From fe2d4778eee5e8b4fe24f8e1d16d1065e9430027 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sat, 4 Jun 2022 12:56:56 -0400 Subject: Expose content type of status sources --- .../web/api_spec/operations/status_operation.ex | 4 ++++ lib/pleroma/web/common_api/activity_draft.ex | 5 +++- lib/pleroma/web/common_api/utils.ex | 2 +- lib/pleroma/web/mastodon_api/views/status_view.ex | 27 +++++++++++++++++++--- 4 files changed, 33 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/api_spec/operations/status_operation.ex b/lib/pleroma/web/api_spec/operations/status_operation.ex index c69307a4d..e921128c7 100644 --- a/lib/pleroma/web/api_spec/operations/status_operation.ex +++ b/lib/pleroma/web/api_spec/operations/status_operation.ex @@ -761,6 +761,10 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do type: :string, description: "Subject or summary line, below which status content is collapsed until expanded" + }, + content_type: %Schema{ + type: :string, + description: "The content type of the source" } } } diff --git a/lib/pleroma/web/common_api/activity_draft.ex b/lib/pleroma/web/common_api/activity_draft.ex index 7c21c8c3a..9af635da8 100644 --- a/lib/pleroma/web/common_api/activity_draft.ex +++ b/lib/pleroma/web/common_api/activity_draft.ex @@ -224,7 +224,10 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do object = note_data |> Map.put("emoji", emoji) - |> Map.put("source", draft.status) + |> Map.put("source", %{ + "content" => draft.status, + "mediaType" => Utils.get_content_type(draft.params[:content_type]) + }) |> Map.put("generator", draft.params[:generator]) %__MODULE__{draft | object: object} diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index ce850b038..4c6a26384 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -219,7 +219,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do |> maybe_add_attachments(draft.attachments, attachment_links) end - defp get_content_type(content_type) do + def get_content_type(content_type) do if Enum.member?(Config.get([:instance, :allowed_post_formats]), content_type) do content_type else diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index 4afba4b33..f798b2624 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -354,7 +354,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do reblog: nil, card: card, content: content_html, - text: opts[:with_source] && object.data["source"], + text: opts[:with_source] && get_source_text(object.data["source"]), created_at: created_at, edited_at: edited_at, reblogs_count: announcement_count, @@ -465,8 +465,9 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do %{ id: activity.id, - text: Map.get(object.data, "source", ""), - spoiler_text: Map.get(object.data, "summary", "") + text: get_source_text(Map.get(object.data, "source", "")), + spoiler_text: Map.get(object.data, "summary", ""), + content_type: get_source_content_type(object.data["source"]) } end @@ -687,4 +688,24 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do end defp build_image_url(_, _), do: nil + + defp get_source_text(%{"content" => content} = _source) do + content + end + + defp get_source_text(source) when is_binary(source) do + source + end + + defp get_source_text(_) do + "" + end + + defp get_source_content_type(%{"mediaType" => type} = _source) do + type + end + + defp get_source_content_type(_source) do + Utils.get_content_type(nil) + end end -- cgit v1.2.3 From 06a3998013aca1f74c563d261d050543056c1255 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sun, 5 Jun 2022 15:02:25 -0400 Subject: Create Update notifications --- lib/pleroma/notification.ex | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index 52fd2656b..82aeb1802 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -385,7 +385,7 @@ defmodule Pleroma.Notification do end def create_notifications(%Activity{data: %{"type" => type}} = activity, options) - when type in ["Follow", "Like", "Announce", "Move", "EmojiReact", "Flag"] do + when type in ["Follow", "Like", "Announce", "Move", "EmojiReact", "Flag", "Update"] do do_create_notifications(activity, options) end @@ -439,6 +439,9 @@ defmodule Pleroma.Notification do activity |> type_from_activity_object() + "Update" -> + "update" + t -> raise "No notification type for activity type #{t}" end @@ -513,7 +516,7 @@ defmodule Pleroma.Notification do def get_notified_from_activity(activity, local_only \\ true) def get_notified_from_activity(%Activity{data: %{"type" => type}} = activity, local_only) - when type in ["Create", "Like", "Announce", "Follow", "Move", "EmojiReact", "Flag"] do + when type in ["Create", "Like", "Announce", "Follow", "Move", "EmojiReact", "Flag", "Update"] do potential_receiver_ap_ids = get_potential_receiver_ap_ids(activity) potential_receivers = @@ -553,6 +556,21 @@ defmodule Pleroma.Notification do (User.all_superusers() |> Enum.map(fn user -> user.ap_id end)) -- [actor] end + # Update activity: notify all who repeated this + def get_potential_receiver_ap_ids(%{data: %{"type" => "Update", "actor" => actor}} = activity) do + with %Object{data: %{"id" => object_id}} <- Object.normalize(activity, fetch: false) do + repeaters = + Activity.Queries.by_type("Announce") + |> Activity.Queries.by_object_id(object_id) + |> Activity.with_joined_user_actor() + |> where([a, u], u.local) + |> select([a, u], u.ap_id) + |> Repo.all() + + repeaters -- [actor] + end + end + def get_potential_receiver_ap_ids(activity) do [] |> Utils.maybe_notify_to_recipients(activity) -- cgit v1.2.3 From 532f6ae3ede9b0795a164ca170314b95d5113fc8 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sun, 5 Jun 2022 16:34:42 -0400 Subject: Return update notification in mastodon api --- .../mastodon_api/controllers/notification_controller.ex | 1 + lib/pleroma/web/mastodon_api/views/notification_view.ex | 15 +++++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex b/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex index 932bc6423..e93930771 100644 --- a/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex @@ -51,6 +51,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationController do move pleroma:emoji_reaction poll + update } def index(%{assigns: %{user: user}} = conn, params) do params = diff --git a/lib/pleroma/web/mastodon_api/views/notification_view.ex b/lib/pleroma/web/mastodon_api/views/notification_view.ex index 0dc7f3beb..b5b5b2376 100644 --- a/lib/pleroma/web/mastodon_api/views/notification_view.ex +++ b/lib/pleroma/web/mastodon_api/views/notification_view.ex @@ -19,7 +19,11 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do alias Pleroma.Web.MastodonAPI.StatusView alias Pleroma.Web.PleromaAPI.Chat.MessageReferenceView - @parent_types ~w{Like Announce EmojiReact} + defp object_id_for(%{data: %{"object" => %{"id" => id}}}) when is_binary(id), do: id + + defp object_id_for(%{data: %{"object" => id}}) when is_binary(id), do: id + + @parent_types ~w{Like Announce EmojiReact Update} def render("index.json", %{notifications: notifications, for: reading_user} = opts) do activities = Enum.map(notifications, & &1.activity) @@ -30,7 +34,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do %{data: %{"type" => type}} -> type in @parent_types end) - |> Enum.map(& &1.data["object"]) + |> Enum.map(&object_id_for/1) |> Activity.create_by_object_ap_id() |> Activity.with_preloaded_object(:left) |> Pleroma.Repo.all() @@ -78,9 +82,9 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do parent_activity_fn = fn -> if opts[:parent_activities] do - Activity.Queries.find_by_object_ap_id(opts[:parent_activities], activity.data["object"]) + Activity.Queries.find_by_object_ap_id(opts[:parent_activities], object_id_for(activity)) else - Activity.get_create_by_object_ap_id(activity.data["object"]) + Activity.get_create_by_object_ap_id(object_id_for(activity)) end end @@ -109,6 +113,9 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do "reblog" -> put_status(response, parent_activity_fn.(), reading_user, status_render_opts) + "update" -> + put_status(response, parent_activity_fn.(), reading_user, status_render_opts) + "move" -> put_target(response, activity, reading_user, %{}) -- cgit v1.2.3 From d2d3532e5f3e5bcedc91fd0f5ac4ca69043348db Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sun, 5 Jun 2022 16:35:01 -0400 Subject: Lint --- lib/pleroma/notification.ex | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index 82aeb1802..2906c599d 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -516,7 +516,16 @@ defmodule Pleroma.Notification do def get_notified_from_activity(activity, local_only \\ true) def get_notified_from_activity(%Activity{data: %{"type" => type}} = activity, local_only) - when type in ["Create", "Like", "Announce", "Follow", "Move", "EmojiReact", "Flag", "Update"] do + when type in [ + "Create", + "Like", + "Announce", + "Follow", + "Move", + "EmojiReact", + "Flag", + "Update" + ] do potential_receiver_ap_ids = get_potential_receiver_ap_ids(activity) potential_receivers = -- cgit v1.2.3 From 237b220d71bfe7db66db12549851fb93900a060a Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Wed, 8 Jun 2022 11:05:48 -0400 Subject: Add object id to uploaded attachments --- lib/pleroma/upload.ex | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/upload.ex b/lib/pleroma/upload.ex index 242813dcd..7480c57a6 100644 --- a/lib/pleroma/upload.ex +++ b/lib/pleroma/upload.ex @@ -36,6 +36,7 @@ defmodule Pleroma.Upload do alias Ecto.UUID alias Pleroma.Config alias Pleroma.Maps + alias Pleroma.Web.ActivityPub.Utils require Logger @type source :: @@ -88,6 +89,7 @@ defmodule Pleroma.Upload do {:ok, url_spec} <- Pleroma.Uploaders.Uploader.put_file(opts.uploader, upload) do {:ok, %{ + "id" => Utils.generate_object_id(), "type" => opts.activity_type, "mediaType" => upload.content_type, "url" => [ -- cgit v1.2.3 From aafd7a687dea7595ee9431451d8e170fc3ff909e Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Wed, 8 Jun 2022 11:45:24 -0400 Subject: Return the corresponding object id in attachment view --- lib/pleroma/web/common_api/utils.ex | 8 ++++++-- lib/pleroma/web/mastodon_api/views/status_view.ex | 13 +++++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index 4c6a26384..5fc8c3220 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -37,7 +37,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do def attachments_from_ids_no_descs(ids) do Enum.map(ids, fn media_id -> - case Repo.get(Object, media_id) do + case get_attachment(media_id) do %Object{data: data} -> data _ -> nil end @@ -51,13 +51,17 @@ defmodule Pleroma.Web.CommonAPI.Utils do {_, descs} = Jason.decode(descs_str) Enum.map(ids, fn media_id -> - with %Object{data: data} <- Repo.get(Object, media_id) do + with %Object{data: data} <- get_attachment(media_id) do Map.put(data, "name", descs[media_id]) end end) |> Enum.reject(&is_nil/1) end + defp get_attachment(media_id) do + Repo.get(Object, media_id) + end + @spec get_to_and_cc(ActivityDraft.t()) :: {list(String.t()), list(String.t())} def get_to_and_cc(%{in_reply_to_conversation: %Participation{} = participation}) do diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index f798b2624..43f5fa02e 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -523,10 +523,19 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do true -> "unknown" end - <> = :crypto.hash(:md5, href) + attachment_id = + with {_, ap_id} when is_binary(ap_id) <- {:ap_id, attachment["id"]}, + {_, %Object{data: _object_data, id: object_id}} <- + {:object, Object.get_by_ap_id(ap_id)} do + to_string(object_id) + else + _ -> + <> = :crypto.hash(:md5, href) + to_string(attachment["id"] || hash_id) + end %{ - id: to_string(attachment["id"] || hash_id), + id: attachment_id, url: href, remote_url: href, preview_url: href_preview, -- cgit v1.2.3 From c3593639adfdd6f9e086aaab18bda5c83bcfcc8b Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Thu, 9 Jun 2022 11:39:51 -0400 Subject: Fix incorrectly cached content after editing --- lib/pleroma/activity/html.ex | 36 ++++++++++++++++++++ lib/pleroma/application.ex | 1 + lib/pleroma/web/activity_pub/side_effects.ex | 27 +++++++++------ lib/pleroma/web/mastodon_api/views/status_view.ex | 41 ++++++++++++++++++++--- 4 files changed, 90 insertions(+), 15 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/activity/html.ex b/lib/pleroma/activity/html.ex index 071a89c8d..706b2d36c 100644 --- a/lib/pleroma/activity/html.ex +++ b/lib/pleroma/activity/html.ex @@ -8,6 +8,40 @@ defmodule Pleroma.Activity.HTML do @cachex Pleroma.Config.get([:cachex, :provider], Cachex) + # We store a list of cache keys related to an activity in a + # separate cache, scrubber_management_cache. It has the same + # size as scrubber_cache (see application.ex). Every time we add + # a cache to scrubber_cache, we update scrubber_management_cache. + # + # The most recent write of a certain key in the management cache + # is the same as the most recent write of any record related to that + # key in the main cache. + # Assuming LRW ( https://hexdocs.pm/cachex/Cachex.Policy.LRW.html ), + # this means when the management cache is evicted by cachex, all + # related records in the main cache will also have been evicted. + + defp get_cache_keys_for(activity_id) do + with {:ok, list} when is_list(list) <- @cachex.get(:scrubber_management_cache, activity_id) do + list + else + _ -> [] + end + end + + defp add_cache_key_for(activity_id, additional_key) do + current = get_cache_keys_for(activity_id) + + unless additional_key in current do + @cachex.put(:scrubber_management_cache, activity_id, [additional_key | current]) + end + end + + def invalidate_cache_for(activity_id) do + keys = get_cache_keys_for(activity_id) + Enum.map(keys, &@cachex.del(:scrubber_cache, &1)) + @cachex.del(:scrubber_management_cache, activity_id) + end + def get_cached_scrubbed_html_for_activity( content, scrubbers, @@ -19,6 +53,8 @@ defmodule Pleroma.Activity.HTML do @cachex.fetch!(:scrubber_cache, key, fn _key -> object = Object.normalize(activity, fetch: false) + + add_cache_key_for(activity.id, key) HTML.ensure_scrubbed_html(content, scrubbers, object.data["fake"] || false, callback) end) end diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index d808bc732..e6b733f9b 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -189,6 +189,7 @@ defmodule Pleroma.Application do build_cachex("object", default_ttl: 25_000, ttl_interval: 1000, limit: 2500), build_cachex("rich_media", default_ttl: :timer.minutes(120), limit: 5000), build_cachex("scrubber", limit: 2500), + build_cachex("scrubber_management", limit: 2500), build_cachex("idempotency", expiration: idempotency_expiration(), limit: 2500), build_cachex("web_resp", limit: 2500), build_cachex("emoji_packs", expiration: emoji_packs_expiration(), limit: 10), diff --git a/lib/pleroma/web/activity_pub/side_effects.ex b/lib/pleroma/web/activity_pub/side_effects.ex index 05f9b9bd9..d387d9362 100644 --- a/lib/pleroma/web/activity_pub/side_effects.ex +++ b/lib/pleroma/web/activity_pub/side_effects.ex @@ -455,7 +455,8 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do %{data: %{"type" => "Update", "object" => updated_object}} = object, meta ) do - orig_object = Object.get_by_ap_id(updated_object["id"]) + orig_object_ap_id = updated_object["id"] + orig_object = Object.get_by_ap_id(orig_object_ap_id) orig_object_data = orig_object.data if orig_object_data["type"] in @updatable_object_types do @@ -468,15 +469,21 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do |> Object.maybe_update_history(orig_object_data, updated) |> maybe_update_poll(updated_object) - orig_object - |> Repo.preload(:hashtags) - |> Object.change(%{data: updated_object_data}) - |> Object.update_and_set_cache() - - if updated do - object - |> Activity.normalize() - |> ActivityPub.notify_and_stream() + changeset = + orig_object + |> Repo.preload(:hashtags) + |> Object.change(%{data: updated_object_data}) + + with {:ok, new_object} <- Repo.update(changeset), + {:ok, _} <- Object.invalid_object_cache(new_object), + {:ok, _} <- Object.set_cache(new_object), + # The metadata/utils.ex uses the object id for the cache. + {:ok, _} <- Pleroma.Activity.HTML.invalidate_cache_for(new_object.id) do + if updated do + object + |> Activity.normalize() + |> ActivityPub.notify_and_stream() + end end end diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index 43f5fa02e..9cb2adcf9 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -272,6 +272,16 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do reply_to_user = reply_to && CommonAPI.get_user(reply_to.data["actor"]) + history_len = + 1 + + (Object.history_for(object.data) + |> Map.get("orderedItems") + |> length()) + + # See render("history.json", ...) for more details + # Here the implicit index of the current content is 0 + chrono_order = history_len - 1 + content = object |> render_content() @@ -281,14 +291,14 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do |> Activity.HTML.get_cached_scrubbed_html_for_activity( User.html_filter_policy(opts[:for]), activity, - "mastoapi:content" + "mastoapi:content:#{chrono_order}" ) content_plaintext = content |> Activity.HTML.get_cached_stripped_html_for_activity( activity, - "mastoapi:content" + "mastoapi:content:#{chrono_order}" ) summary = object.data["summary"] || "" @@ -410,9 +420,25 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do history = [object | past_history] + history_len = length(history) + + history = + Enum.with_index( + history, + fn object, index -> + %{ + # The history is prepended every time there is a new edit. + # In chrono_order, the oldest item is always at 0, and so on. + # The chrono_order is an invariant kept between edits. + chrono_order: history_len - 1 - index, + object: object + } + end + ) + individual_opts = opts - |> Map.put(:as, :object) + |> Map.put(:as, :item) |> Map.put(:user, user) |> Map.put(:hashtags, hashtags) @@ -421,7 +447,12 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do def render( "history_item.json", - %{activity: activity, user: user, object: object, hashtags: hashtags} = opts + %{ + activity: activity, + user: user, + item: %{object: object, chrono_order: chrono_order}, + hashtags: hashtags + } = opts ) do sensitive = object.data["sensitive"] || Enum.member?(hashtags, "nsfw") @@ -439,7 +470,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do |> Activity.HTML.get_cached_scrubbed_html_for_activity( User.html_filter_policy(opts[:for]), activity, - "mastoapi:content" + "mastoapi:content:#{chrono_order}" ) summary = object.data["summary"] || "" -- cgit v1.2.3 From 27f3d802f2fd6e9d002654993d8eedb92d120055 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sat, 11 Jun 2022 10:35:36 -0400 Subject: Expose history and source apis to anon users --- lib/pleroma/web/mastodon_api/controllers/status_controller.ex | 10 ++++++---- lib/pleroma/web/router.ex | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex index fa86e9dc0..e594ea491 100644 --- a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex @@ -195,8 +195,9 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do end @doc "GET /api/v1/statuses/:id/history" - def show_history(%{assigns: %{user: user}} = conn, %{id: id} = params) do - with %Activity{} = activity <- Activity.get_by_id_with_object(id), + def show_history(%{assigns: assigns} = conn, %{id: id} = params) do + with user = assigns[:user], + %Activity{} = activity <- Activity.get_by_id_with_object(id), true <- Visibility.visible_for_user?(activity, user) do try_render(conn, "history.json", activity: activity, @@ -210,8 +211,9 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do end @doc "GET /api/v1/statuses/:id/source" - def show_source(%{assigns: %{user: user}} = conn, %{id: id} = _params) do - with %Activity{} = activity <- Activity.get_by_id_with_object(id), + def show_source(%{assigns: assigns} = conn, %{id: id} = _params) do + with user = assigns[:user], + %Activity{} = activity <- Activity.get_by_id_with_object(id), true <- Visibility.visible_for_user?(activity, user) do try_render(conn, "source.json", activity: activity, diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 2d2e5365e..4a999f0c2 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -552,8 +552,6 @@ defmodule Pleroma.Web.Router do get("/bookmarks", StatusController, :bookmarks) post("/statuses", StatusController, :create) - get("/statuses/:id/history", StatusController, :show_history) - get("/statuses/:id/source", StatusController, :show_source) put("/statuses/:id", StatusController, :update) delete("/statuses/:id", StatusController, :delete) post("/statuses/:id/reblog", StatusController, :reblog) @@ -611,6 +609,8 @@ defmodule Pleroma.Web.Router do get("/statuses/:id/card", StatusController, :card) get("/statuses/:id/favourited_by", StatusController, :favourited_by) get("/statuses/:id/reblogged_by", StatusController, :reblogged_by) + get("/statuses/:id/history", StatusController, :show_history) + get("/statuses/:id/source", StatusController, :show_source) get("/custom_emojis", CustomEmojiController, :index) -- cgit v1.2.3 From 7451f0e81f1fd378a3ff23d437e3cc6780d62fb4 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sat, 11 Jun 2022 12:02:16 -0400 Subject: Send the correct update in streamer get_create_by_ap_id_with_object() seems to fetch the old object. Why this happens needs further investigation. --- lib/pleroma/web/streamer.ex | 8 ++++++-- lib/pleroma/web/views/streamer_view.ex | 4 ---- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/streamer.ex b/lib/pleroma/web/streamer.ex index 8b7fb985b..fe909df0a 100644 --- a/lib/pleroma/web/streamer.ex +++ b/lib/pleroma/web/streamer.ex @@ -297,12 +297,16 @@ defmodule Pleroma.Web.Streamer do defp push_to_socket(_topic, %Activity{data: %{"type" => "Delete"}}), do: :noop defp push_to_socket(topic, %Activity{data: %{"type" => "Update"}} = item) do - anon_render = StreamerView.render("status_update.json", item) + create_activity = + Pleroma.Activity.get_create_by_object_ap_id(item.object.data["id"]) + |> Map.put(:object, item.object) + + anon_render = StreamerView.render("status_update.json", create_activity) Registry.dispatch(@registry, topic, fn list -> Enum.each(list, fn {pid, auth?} -> if auth? do - send(pid, {:render_with_user, StreamerView, "status_update.json", item}) + send(pid, {:render_with_user, StreamerView, "status_update.json", create_activity}) else send(pid, {:text, anon_render}) end diff --git a/lib/pleroma/web/views/streamer_view.ex b/lib/pleroma/web/views/streamer_view.ex index 797762d90..6a55242b0 100644 --- a/lib/pleroma/web/views/streamer_view.ex +++ b/lib/pleroma/web/views/streamer_view.ex @@ -26,8 +26,6 @@ defmodule Pleroma.Web.StreamerView do end def render("status_update.json", %Activity{} = activity, %User{} = user) do - activity = Activity.get_create_by_object_ap_id_with_object(activity.object.data["id"]) - %{ event: "status.update", payload: @@ -68,8 +66,6 @@ defmodule Pleroma.Web.StreamerView do end def render("status_update.json", %Activity{} = activity) do - activity = Activity.get_create_by_object_ap_id_with_object(activity.object.data["id"]) - %{ event: "status.update", payload: -- cgit v1.2.3 From 95b39223281a61f3ee7d52776df2713952de3be0 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sat, 11 Jun 2022 16:28:59 -0400 Subject: Workaround with_index does not support function in Elixir 1.9 --- lib/pleroma/web/mastodon_api/views/status_view.ex | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index 9cb2adcf9..6ede89803 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -423,18 +423,16 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do history_len = length(history) history = - Enum.with_index( - history, - fn object, index -> - %{ - # The history is prepended every time there is a new edit. - # In chrono_order, the oldest item is always at 0, and so on. - # The chrono_order is an invariant kept between edits. - chrono_order: history_len - 1 - index, - object: object - } - end - ) + Enum.zip(history_len..0, history) + |> Enum.map(fn {chrono_order, object} -> + %{ + # The history is prepended every time there is a new edit. + # In chrono_order, the oldest item is always at 0, and so on. + # The chrono_order is an invariant kept between edits. + chrono_order: chrono_order, + object: object + } + end) individual_opts = opts -- cgit v1.2.3 From 44613db853226015207977ee958ebbf4d26f7c00 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sat, 11 Jun 2022 19:52:07 -0400 Subject: Show original status at the first of history --- lib/pleroma/web/mastodon_api/views/status_view.ex | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index 6ede89803..8439431eb 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -418,13 +418,12 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do |> Enum.map(&Map.put(&1, "id", object.data["id"])) |> Enum.map(&%Object{data: &1, id: object.id}) - history = [object | past_history] - - history_len = length(history) - history = - Enum.zip(history_len..0, history) - |> Enum.map(fn {chrono_order, object} -> + [object | past_history] + # Mastodon expects the original to be at the first + |> Enum.reverse() + |> Enum.with_index() + |> Enum.map(fn {object, chrono_order} -> %{ # The history is prepended every time there is a new edit. # In chrono_order, the oldest item is always at 0, and so on. -- cgit v1.2.3 From 5b19543f0afaaad7f8fc302946547ae5c18e8bb3 Mon Sep 17 00:00:00 2001 From: Ilja Date: Sat, 21 May 2022 18:48:21 +0200 Subject: Add new setting and Plug to allow for privilege settings for staff --- lib/pleroma/web/plugs/ensure_privileged_plug.ex | 44 +++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 lib/pleroma/web/plugs/ensure_privileged_plug.ex (limited to 'lib') diff --git a/lib/pleroma/web/plugs/ensure_privileged_plug.ex b/lib/pleroma/web/plugs/ensure_privileged_plug.ex new file mode 100644 index 000000000..be09f3d81 --- /dev/null +++ b/lib/pleroma/web/plugs/ensure_privileged_plug.ex @@ -0,0 +1,44 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.Plugs.EnsurePrivilegedPlug do + @moduledoc """ + Ensures staff are privileged enough to do certain tasks. + """ + import Pleroma.Web.TranslationHelpers + import Plug.Conn + + alias Pleroma.Config + alias Pleroma.User + + def init(options) do + options + end + + def call(%{assigns: %{user: %User{is_admin: false, is_moderator: false}}} = conn, _) do + conn + |> render_error(:forbidden, "User isn't privileged.") + |> halt() + end + + def call( + %{assigns: %{user: %User{is_admin: is_admin, is_moderator: is_moderator}}} = conn, + priviledge + ) do + if (is_admin and priviledge in Config.get([:instance, :admin_privileges])) or + (is_moderator and priviledge in Config.get([:instance, :moderator_privileges])) do + conn + else + conn + |> render_error(:forbidden, "User isn't privileged.") + |> halt() + end + end + + def call(conn, _) do + conn + |> render_error(:forbidden, "User isn't privileged.") + |> halt() + end +end -- cgit v1.2.3 From 9f6c36475914bfd1b8c02035341765b4d1bd4395 Mon Sep 17 00:00:00 2001 From: Ilja Date: Thu, 26 May 2022 12:49:09 +0200 Subject: Add privilege :user_deletion --- lib/pleroma/web/router.ex | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index ceb6c3cfd..5012fbf9a 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -109,6 +109,11 @@ defmodule Pleroma.Web.Router do plug(Pleroma.Web.Plugs.UserIsAdminPlug) end + pipeline :require_privileged_role_user_deletion do + plug(:admin_api) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :user_deletion) + end + pipeline :pleroma_html do plug(:browser) plug(:authenticate) @@ -231,11 +236,16 @@ defmodule Pleroma.Web.Router do post("/backups", AdminAPIController, :create_backup) end - # AdminAPI: admins and mods (staff) can perform these actions (if enabled by config) + # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through([:admin_api, :require_privileged_staff]) + pipe_through([:admin_api, :require_privileged_role_user_deletion]) delete("/users", UserController, :delete) + end + + # AdminAPI: admins and mods (staff) can perform these actions (if enabled by config) + scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do + pipe_through([:admin_api, :require_privileged_staff]) get("/users/:nickname/password_reset", AdminAPIController, :get_password_reset) patch("/users/:nickname/credentials", AdminAPIController, :update_user_credentials) -- cgit v1.2.3 From 8a9144ca8b8e17df509dc8ac3934656b7dac8d77 Mon Sep 17 00:00:00 2001 From: Ilja Date: Thu, 26 May 2022 13:27:06 +0200 Subject: Add priviledges for :user_credentials I only moved the ones from the :require_privileged_staff block for now --- lib/pleroma/web/router.ex | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 5012fbf9a..24928ffb5 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -114,6 +114,11 @@ defmodule Pleroma.Web.Router do plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :user_deletion) end + pipeline :require_privileged_role_user_credentials do + plug(:admin_api) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :user_credentials) + end + pipeline :pleroma_html do plug(:browser) plug(:authenticate) @@ -206,7 +211,6 @@ defmodule Pleroma.Web.Router do patch("/users/force_password_reset", AdminAPIController, :force_password_reset) get("/users/:nickname/credentials", AdminAPIController, :show_user_credentials) - patch("/users/:nickname/credentials", AdminAPIController, :update_user_credentials) get("/instance_document/:name", InstanceDocumentController, :show) patch("/instance_document/:name", InstanceDocumentController, :update) @@ -243,12 +247,17 @@ defmodule Pleroma.Web.Router do delete("/users", UserController, :delete) end - # AdminAPI: admins and mods (staff) can perform these actions (if enabled by config) + # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through([:admin_api, :require_privileged_staff]) + pipe_through([:admin_api, :require_privileged_role_user_credentials]) get("/users/:nickname/password_reset", AdminAPIController, :get_password_reset) patch("/users/:nickname/credentials", AdminAPIController, :update_user_credentials) + end + + # AdminAPI: admins and mods (staff) can perform these actions (if enabled by config) + scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do + pipe_through([:admin_api, :require_privileged_staff]) get("/users/:nickname/statuses", AdminAPIController, :list_user_statuses) get("/users/:nickname/chats", AdminAPIController, :list_user_chats) -- cgit v1.2.3 From b1ff5241c21dac58ec1f9171de26772debfdb283 Mon Sep 17 00:00:00 2001 From: Ilja Date: Thu, 26 May 2022 14:21:14 +0200 Subject: Add priviledges for :statuses_read This was the last in :require_privileged_staff. I'll remove that in the next commit --- lib/pleroma/web/router.ex | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 24928ffb5..4696b4007 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -119,6 +119,11 @@ defmodule Pleroma.Web.Router do plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :user_credentials) end + pipeline :require_privileged_role_statuses_read do + plug(:admin_api) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :statuses_read) + end + pipeline :pleroma_html do plug(:browser) plug(:authenticate) @@ -242,22 +247,22 @@ defmodule Pleroma.Web.Router do # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through([:admin_api, :require_privileged_role_user_deletion]) + pipe_through(:require_privileged_role_user_deletion) delete("/users", UserController, :delete) end # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through([:admin_api, :require_privileged_role_user_credentials]) + pipe_through(:require_privileged_role_user_credentials) get("/users/:nickname/password_reset", AdminAPIController, :get_password_reset) patch("/users/:nickname/credentials", AdminAPIController, :update_user_credentials) end - # AdminAPI: admins and mods (staff) can perform these actions (if enabled by config) + # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through([:admin_api, :require_privileged_staff]) + pipe_through(:require_privileged_role_statuses_read) get("/users/:nickname/statuses", AdminAPIController, :list_user_statuses) get("/users/:nickname/chats", AdminAPIController, :list_user_chats) @@ -268,6 +273,11 @@ defmodule Pleroma.Web.Router do get("/chats/:id/messages", ChatController, :messages) end + # AdminAPI: admins and mods (staff) can perform these actions (if enabled by config) + scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do + pipe_through([:admin_api, :require_privileged_staff]) + end + # AdminAPI: admins and mods (staff) can perform these actions scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do pipe_through(:admin_api) -- cgit v1.2.3 From 5a65e2dac5e689b8067e37817bbfe4a6fe1a0426 Mon Sep 17 00:00:00 2001 From: Ilja Date: Thu, 26 May 2022 14:51:53 +0200 Subject: Remove privileged_staff Everything that was done through this setting, can now be set by giving the proper privileges to the roles. --- .../web/mastodon_api/views/instance_view.ex | 1 - lib/pleroma/web/nodeinfo/nodeinfo.ex | 3 +- .../web/plugs/ensure_staff_privileged_plug.ex | 36 ---------------------- lib/pleroma/web/router.ex | 9 ------ 4 files changed, 1 insertion(+), 48 deletions(-) delete mode 100644 lib/pleroma/web/plugs/ensure_staff_privileged_plug.ex (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/views/instance_view.ex b/lib/pleroma/web/mastodon_api/views/instance_view.ex index ee52475d5..f89c95a1c 100644 --- a/lib/pleroma/web/mastodon_api/views/instance_view.ex +++ b/lib/pleroma/web/mastodon_api/views/instance_view.ex @@ -47,7 +47,6 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do federation: federation(), fields_limits: fields_limits(), post_formats: Config.get([:instance, :allowed_post_formats]), - privileged_staff: Config.get([:instance, :privileged_staff]), birthday_required: Config.get([:instance, :birthday_required]), birthday_min_age: Config.get([:instance, :birthday_min_age]) }, diff --git a/lib/pleroma/web/nodeinfo/nodeinfo.ex b/lib/pleroma/web/nodeinfo/nodeinfo.ex index 62d445f34..c7b9ab2de 100644 --- a/lib/pleroma/web/nodeinfo/nodeinfo.ex +++ b/lib/pleroma/web/nodeinfo/nodeinfo.ex @@ -69,8 +69,7 @@ defmodule Pleroma.Web.Nodeinfo.Nodeinfo do mailerEnabled: Config.get([Pleroma.Emails.Mailer, :enabled], false), features: features, restrictedNicknames: Config.get([Pleroma.User, :restricted_nicknames]), - skipThreadContainment: Config.get([:instance, :skip_thread_containment], false), - privilegedStaff: Config.get([:instance, :privileged_staff]) + skipThreadContainment: Config.get([:instance, :skip_thread_containment], false) } } end diff --git a/lib/pleroma/web/plugs/ensure_staff_privileged_plug.ex b/lib/pleroma/web/plugs/ensure_staff_privileged_plug.ex deleted file mode 100644 index 3c2109496..000000000 --- a/lib/pleroma/web/plugs/ensure_staff_privileged_plug.ex +++ /dev/null @@ -1,36 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2022 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.Plugs.EnsureStaffPrivilegedPlug do - @moduledoc """ - Ensures staff are privileged enough to do certain tasks. - """ - import Pleroma.Web.TranslationHelpers - import Plug.Conn - - alias Pleroma.Config - alias Pleroma.User - - def init(options) do - options - end - - def call(%{assigns: %{user: %User{is_admin: true}}} = conn, _), do: conn - - def call(%{assigns: %{user: %User{is_moderator: true}}} = conn, _) do - if Config.get!([:instance, :privileged_staff]) do - conn - else - conn - |> render_error(:forbidden, "User is not an admin.") - |> halt() - end - end - - def call(conn, _) do - conn - |> render_error(:forbidden, "User is not a staff member.") - |> halt() - end -end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 4696b4007..21b77b624 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -101,10 +101,6 @@ defmodule Pleroma.Web.Router do plug(Pleroma.Web.Plugs.IdempotencyPlug) end - pipeline :require_privileged_staff do - plug(Pleroma.Web.Plugs.EnsureStaffPrivilegedPlug) - end - pipeline :require_admin do plug(Pleroma.Web.Plugs.UserIsAdminPlug) end @@ -273,11 +269,6 @@ defmodule Pleroma.Web.Router do get("/chats/:id/messages", ChatController, :messages) end - # AdminAPI: admins and mods (staff) can perform these actions (if enabled by config) - scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through([:admin_api, :require_privileged_staff]) - end - # AdminAPI: admins and mods (staff) can perform these actions scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do pipe_through(:admin_api) -- cgit v1.2.3 From cb60cc4e02af270fcccdcd552df4fa3ff858d67f Mon Sep 17 00:00:00 2001 From: Ilja Date: Thu, 26 May 2022 16:25:28 +0200 Subject: Add privileges for :user_tag --- lib/pleroma/web/router.ex | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 21b77b624..b5b9e7d07 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -120,6 +120,11 @@ defmodule Pleroma.Web.Router do plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :statuses_read) end + pipeline :require_privileged_role_user_tag do + plug(:admin_api) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :user_tag) + end + pipeline :pleroma_html do plug(:browser) plug(:authenticate) @@ -269,12 +274,17 @@ defmodule Pleroma.Web.Router do get("/chats/:id/messages", ChatController, :messages) end - # AdminAPI: admins and mods (staff) can perform these actions + # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through(:admin_api) + pipe_through(:require_privileged_role_user_tag) put("/users/tag", AdminAPIController, :tag_users) delete("/users/tag", AdminAPIController, :untag_users) + end + + # AdminAPI: admins and mods (staff) can perform these actions + scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do + pipe_through(:admin_api) patch("/users/:nickname/toggle_activation", UserController, :toggle_activation) patch("/users/activate", UserController, :activate) -- cgit v1.2.3 From e102d25d2385761077c08e0b280359392f0592cb Mon Sep 17 00:00:00 2001 From: Ilja Date: Thu, 26 May 2022 16:41:48 +0200 Subject: Add privileges for :user_activation --- lib/pleroma/web/router.ex | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index b5b9e7d07..bfe5c7b90 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -125,6 +125,11 @@ defmodule Pleroma.Web.Router do plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :user_tag) end + pipeline :require_privileged_role_user_activation do + plug(:admin_api) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :user_activation) + end + pipeline :pleroma_html do plug(:browser) plug(:authenticate) @@ -282,15 +287,20 @@ defmodule Pleroma.Web.Router do delete("/users/tag", AdminAPIController, :untag_users) end - # AdminAPI: admins and mods (staff) can perform these actions + # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through(:admin_api) + pipe_through(:require_privileged_role_user_activation) patch("/users/:nickname/toggle_activation", UserController, :toggle_activation) patch("/users/activate", UserController, :activate) patch("/users/deactivate", UserController, :deactivate) - patch("/users/approve", UserController, :approve) + end + + # AdminAPI: admins and mods (staff) can perform these actions + scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do + pipe_through(:admin_api) + patch("/users/approve", UserController, :approve) post("/users/invite_token", InviteController, :create) get("/users/invites", InviteController, :index) post("/users/revoke_invite", InviteController, :revoke) -- cgit v1.2.3 From 14e697a64fe2613649634d46a71acf4d9a7d7bd6 Mon Sep 17 00:00:00 2001 From: Ilja Date: Sat, 28 May 2022 08:51:49 +0200 Subject: Add privileges for :user_invite --- lib/pleroma/web/router.ex | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index bfe5c7b90..87e564488 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -130,6 +130,11 @@ defmodule Pleroma.Web.Router do plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :user_activation) end + pipeline :require_privileged_role_user_invite do + plug(:admin_api) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :user_invite) + end + pipeline :pleroma_html do plug(:browser) plug(:authenticate) @@ -296,15 +301,20 @@ defmodule Pleroma.Web.Router do patch("/users/deactivate", UserController, :deactivate) end - # AdminAPI: admins and mods (staff) can perform these actions + # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through(:admin_api) + pipe_through(:require_privileged_role_user_invite) patch("/users/approve", UserController, :approve) post("/users/invite_token", InviteController, :create) get("/users/invites", InviteController, :index) post("/users/revoke_invite", InviteController, :revoke) post("/users/email_invite", InviteController, :email) + end + + # AdminAPI: admins and mods (staff) can perform these actions + scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do + pipe_through(:admin_api) get("/users", UserController, :index) get("/users/:nickname", UserController, :show) -- cgit v1.2.3 From 3f26f1b30fe605635e3faf610f813f3ae3ad43ec Mon Sep 17 00:00:00 2001 From: Ilja Date: Sat, 28 May 2022 09:43:57 +0200 Subject: Add privileges for :report_handle --- lib/pleroma/web/router.ex | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 87e564488..dbcd6f399 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -135,6 +135,11 @@ defmodule Pleroma.Web.Router do plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :user_invite) end + pipeline :require_privileged_role_report_handle do + plug(:admin_api) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :report_handle) + end + pipeline :pleroma_html do plug(:browser) plug(:authenticate) @@ -312,6 +317,17 @@ defmodule Pleroma.Web.Router do post("/users/email_invite", InviteController, :email) end + # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) + scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do + pipe_through(:require_privileged_role_report_handle) + + get("/reports", ReportController, :index) + get("/reports/:id", ReportController, :show) + patch("/reports", ReportController, :update) + post("/reports/:id/notes", ReportController, :notes_create) + delete("/reports/:report_id/notes/:id", ReportController, :notes_delete) + end + # AdminAPI: admins and mods (staff) can perform these actions scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do pipe_through(:admin_api) @@ -322,12 +338,6 @@ defmodule Pleroma.Web.Router do get("/instances/:instance/statuses", InstanceController, :list_statuses) delete("/instances/:instance", InstanceController, :delete) - get("/reports", ReportController, :index) - get("/reports/:id", ReportController, :show) - patch("/reports", ReportController, :update) - post("/reports/:id/notes", ReportController, :notes_create) - delete("/reports/:report_id/notes/:id", ReportController, :notes_delete) - get("/statuses/:id", StatusController, :show) put("/statuses/:id", StatusController, :update) delete("/statuses/:id", StatusController, :delete) -- cgit v1.2.3 From cbb26262a5957d3a72bef383a394bb3b2ad0215d Mon Sep 17 00:00:00 2001 From: Ilja Date: Sat, 28 May 2022 12:15:36 +0200 Subject: Add privileges for :user_read --- lib/pleroma/web/router.ex | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index dbcd6f399..68719c570 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -140,6 +140,11 @@ defmodule Pleroma.Web.Router do plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :report_handle) end + pipeline :require_privileged_role_user_read do + plug(:admin_api) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :user_read) + end + pipeline :pleroma_html do plug(:browser) plug(:authenticate) @@ -328,12 +333,17 @@ defmodule Pleroma.Web.Router do delete("/reports/:report_id/notes/:id", ReportController, :notes_delete) end - # AdminAPI: admins and mods (staff) can perform these actions + # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through(:admin_api) + pipe_through(:require_privileged_role_user_read) get("/users", UserController, :index) get("/users/:nickname", UserController, :show) + end + + # AdminAPI: admins and mods (staff) can perform these actions + scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do + pipe_through(:admin_api) get("/instances/:instance/statuses", InstanceController, :list_statuses) delete("/instances/:instance", InstanceController, :delete) -- cgit v1.2.3 From 34a98990dba1e021a75a23b225cff22af23f5ca2 Mon Sep 17 00:00:00 2001 From: Ilja Date: Sat, 11 Jun 2022 09:38:43 +0200 Subject: last off :statuses_read From the endpoints left to do, I believe these should be under :statuses_read. These should be the last for that privilege for this MR --- lib/pleroma/web/router.ex | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 68719c570..13e8141e4 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -292,6 +292,10 @@ defmodule Pleroma.Web.Router do get("/chats/:id", ChatController, :show) get("/chats/:id/messages", ChatController, :messages) + + get("/instances/:instance/statuses", InstanceController, :list_statuses) + + get("/statuses/:id", StatusController, :show) end # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) @@ -345,10 +349,8 @@ defmodule Pleroma.Web.Router do scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do pipe_through(:admin_api) - get("/instances/:instance/statuses", InstanceController, :list_statuses) delete("/instances/:instance", InstanceController, :delete) - get("/statuses/:id", StatusController, :show) put("/statuses/:id", StatusController, :update) delete("/statuses/:id", StatusController, :delete) -- cgit v1.2.3 From 0ee8f33250f649c7807fd161b9d6588757f5dc94 Mon Sep 17 00:00:00 2001 From: Ilja Date: Sat, 11 Jun 2022 13:08:40 +0200 Subject: Add privilige :status_delete It also allows to update a message, so it's not just deleting. I need a better name... --- lib/pleroma/web/router.ex | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 13e8141e4..50a0ea7fc 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -145,6 +145,11 @@ defmodule Pleroma.Web.Router do plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :user_read) end + pipeline :require_privileged_role_status_delete do + plug(:admin_api) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :status_delete) + end + pipeline :pleroma_html do plug(:browser) plug(:authenticate) @@ -345,21 +350,26 @@ defmodule Pleroma.Web.Router do get("/users/:nickname", UserController, :show) end + # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) + scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do + pipe_through(:require_privileged_role_status_delete) + + put("/statuses/:id", StatusController, :update) + delete("/statuses/:id", StatusController, :delete) + + delete("/chats/:id/messages/:message_id", ChatController, :delete_message) + end + # AdminAPI: admins and mods (staff) can perform these actions scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do pipe_through(:admin_api) delete("/instances/:instance", InstanceController, :delete) - put("/statuses/:id", StatusController, :update) - delete("/statuses/:id", StatusController, :delete) - get("/moderation_log", AdminAPIController, :list_log) post("/reload_emoji", AdminAPIController, :reload_emoji) get("/stats", AdminAPIController, :stats) - - delete("/chats/:id/messages/:message_id", ChatController, :delete_message) end scope "/api/v1/pleroma/emoji", Pleroma.Web.PleromaAPI do -- cgit v1.2.3 From ecd42a2ce112489bb09cadcffc3661314a37a7fa Mon Sep 17 00:00:00 2001 From: Ilja Date: Sat, 11 Jun 2022 22:18:21 +0200 Subject: Add privilige :emoji_management --- lib/pleroma/web/router.ex | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 50a0ea7fc..46f128672 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -150,6 +150,11 @@ defmodule Pleroma.Web.Router do plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :status_delete) end + pipeline :require_privileged_role_emoji_management do + plug(:admin_api) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :emoji_management) + end + pipeline :pleroma_html do plug(:browser) plug(:authenticate) @@ -360,6 +365,13 @@ defmodule Pleroma.Web.Router do delete("/chats/:id/messages/:message_id", ChatController, :delete_message) end + # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) + scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do + pipe_through(:require_privileged_role_emoji_management) + + post("/reload_emoji", AdminAPIController, :reload_emoji) + end + # AdminAPI: admins and mods (staff) can perform these actions scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do pipe_through(:admin_api) @@ -368,13 +380,12 @@ defmodule Pleroma.Web.Router do get("/moderation_log", AdminAPIController, :list_log) - post("/reload_emoji", AdminAPIController, :reload_emoji) get("/stats", AdminAPIController, :stats) end scope "/api/v1/pleroma/emoji", Pleroma.Web.PleromaAPI do scope "/pack" do - pipe_through(:admin_api) + pipe_through(:require_privileged_role_emoji_management) post("/", EmojiPackController, :create) patch("/", EmojiPackController, :update) @@ -389,7 +400,7 @@ defmodule Pleroma.Web.Router do # Modifying packs scope "/packs" do - pipe_through(:admin_api) + pipe_through(:require_privileged_role_emoji_management) get("/import", EmojiPackController, :import_from_filesystem) get("/remote", EmojiPackController, :remote) -- cgit v1.2.3 From c842e6267545dfa88cf97cef69337296c3cb77d5 Mon Sep 17 00:00:00 2001 From: Ilja Date: Sun, 12 Jun 2022 10:07:33 +0200 Subject: Add last priviliges I still had three endpoints I didn't really know what to do with them. I added them under separate tags * :instance_delete * :moderation_log_read * :stats_read I also checked and these are the last changes done by MR https://git.pleroma.social/pleroma/pleroma/-/merge_requests/3480/diffs this is trying to fix --- lib/pleroma/web/router.ex | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 46f128672..f680c8353 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -155,6 +155,21 @@ defmodule Pleroma.Web.Router do plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :emoji_management) end + pipeline :require_privileged_role_instance_delete do + plug(:admin_api) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :instance_delete) + end + + pipeline :require_privileged_role_moderation_log_read do + plug(:admin_api) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :moderation_log_read) + end + + pipeline :require_privileged_role_stats_read do + plug(:admin_api) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :stats_read) + end + pipeline :pleroma_html do plug(:browser) plug(:authenticate) @@ -372,13 +387,23 @@ defmodule Pleroma.Web.Router do post("/reload_emoji", AdminAPIController, :reload_emoji) end - # AdminAPI: admins and mods (staff) can perform these actions + # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through(:admin_api) + pipe_through(:require_privileged_role_instance_delete) delete("/instances/:instance", InstanceController, :delete) + end + + # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) + scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do + pipe_through(:require_privileged_role_moderation_log_read) get("/moderation_log", AdminAPIController, :list_log) + end + + # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) + scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do + pipe_through(:require_privileged_role_stats_read) get("/stats", AdminAPIController, :stats) end -- cgit v1.2.3 From 7adfc2e0f429f84eb7eb2712529e9a3486354d01 Mon Sep 17 00:00:00 2001 From: Ilja Date: Mon, 13 Jun 2022 09:58:50 +0200 Subject: Add Pleroma.User.privileged?/2 This should eventually replace Pleroma.User.superuser?/1 --- lib/pleroma/user.ex | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 747a83e8d..b93ce9c2c 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -353,6 +353,24 @@ defmodule Pleroma.User do end end + @spec privileged?(User.t(), atom()) :: boolean() + def privileged?(%User{is_admin: false, is_moderator: false}, _), do: false + + def privileged?( + %User{local: true, is_admin: is_admin, is_moderator: is_moderator}, + privilege_tag + ), + do: + privileged_for?(privilege_tag, is_admin, :admin_privileges) or + privileged_for?(privilege_tag, is_moderator, :moderator_privileges) + + def privileged?(_, _), do: false + + defp privileged_for?(privilege_tag, true, config_role_key), + do: privilege_tag in Config.get([:instance, config_role_key]) + + defp privileged_for?(_, _, _), do: false + @spec superuser?(User.t()) :: boolean() def superuser?(%User{local: true, is_admin: true}), do: true def superuser?(%User{local: true, is_moderator: true}), do: true -- cgit v1.2.3 From 7cf473c50076f31bb01bad92501a8c2353874b96 Mon Sep 17 00:00:00 2001 From: Ilja Date: Mon, 13 Jun 2022 11:00:49 +0200 Subject: delete statusses is now privileged by :status_delete Instead of superusers, you now need a role with privilige :status_delete to delete other users statusses I also cleaned up some other stuff I saw --- lib/pleroma/web/common_api.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/common_api.ex b/lib/pleroma/web/common_api.ex index 1b95ee89c..ce1d5a7cc 100644 --- a/lib/pleroma/web/common_api.ex +++ b/lib/pleroma/web/common_api.ex @@ -144,7 +144,7 @@ defmodule Pleroma.Web.CommonAPI do {:find_activity, Activity.get_by_id(activity_id)}, {_, %Object{} = object, _} <- {:find_object, Object.normalize(activity, fetch: false), activity}, - true <- User.superuser?(user) || user.ap_id == object.data["actor"], + true <- User.privileged?(user, :status_delete) || user.ap_id == object.data["actor"], {:ok, delete_data, _} <- Builder.delete(user, object.data["id"]), {:ok, delete, _} <- Pipeline.common_pipeline(delete_data, local: true) do {:ok, delete} -- cgit v1.2.3 From bb61cfee8dc27c658215f05cce3ea58fca5b3db3 Mon Sep 17 00:00:00 2001 From: Ilja Date: Mon, 13 Jun 2022 13:58:26 +0200 Subject: Validator for deleting statusses is now done with priviledge instead of superuser --- .../web/activity_pub/object_validators/common_validations.ex | 6 +++--- lib/pleroma/web/activity_pub/object_validators/delete_validator.ex | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/object_validators/common_validations.ex b/lib/pleroma/web/activity_pub/object_validators/common_validations.ex index 704b3abc9..1c5b1a059 100644 --- a/lib/pleroma/web/activity_pub/object_validators/common_validations.ex +++ b/lib/pleroma/web/activity_pub/object_validators/common_validations.ex @@ -136,11 +136,11 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations do # This figures out if a user is able to create, delete or modify something # based on the domain and superuser status - @spec validate_modification_rights(Ecto.Changeset.t()) :: Ecto.Changeset.t() - def validate_modification_rights(cng) do + @spec validate_modification_rights(Ecto.Changeset.t(), atom()) :: Ecto.Changeset.t() + def validate_modification_rights(cng, privilege) do actor = User.get_cached_by_ap_id(get_field(cng, :actor)) - if User.superuser?(actor) || same_domain?(cng) do + if User.privileged?(actor, privilege) || same_domain?(cng) do cng else cng diff --git a/lib/pleroma/web/activity_pub/object_validators/delete_validator.ex b/lib/pleroma/web/activity_pub/object_validators/delete_validator.ex index 035fd5bc9..6e4208167 100644 --- a/lib/pleroma/web/activity_pub/object_validators/delete_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/delete_validator.ex @@ -61,7 +61,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.DeleteValidator do |> validate_required([:id, :type, :actor, :to, :cc, :object]) |> validate_inclusion(:type, ["Delete"]) |> validate_delete_actor(:actor) - |> validate_modification_rights() + |> validate_modification_rights(:status_delete) |> validate_object_or_user_presence(allowed_types: @deletable_types) |> add_deleted_activity_id() end -- cgit v1.2.3 From edf0013ff38ae2d7bc84431d1d1384e5fc45bc0e Mon Sep 17 00:00:00 2001 From: Ilja Date: Sat, 18 Jun 2022 08:32:05 +0200 Subject: User.visible_for/2 According to the tests, this was only used for unconfirmed accounts. So this just needed to be restricted to users with privilege :user_activation --- lib/pleroma/user.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index b93ce9c2c..7dfc6ce7b 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -326,7 +326,7 @@ defmodule Pleroma.User do end def visible_for(%User{} = user, for_user) do - if superuser?(for_user) do + if privileged?(for_user, :user_activation) do :visible else visible_account_status(user) -- cgit v1.2.3 From e45faddb38311c799b2276cb952ac7715e2cbfab Mon Sep 17 00:00:00 2001 From: Ilja Date: Sat, 18 Jun 2022 08:38:00 +0200 Subject: Revert "Delete report notifs when demoting from superuser" This reverts commit 89667189b840fc79d85336739e6b2512684d7be0 and cdc5bbe8369d4fc66d642bb3e845a237d11e34d7. This is a side effect when changing user role. The goal was to not have report notifications when someone isn't admin or moderator any more. But this won't be triggered when we change the privilege tags for a role, so we can't use this sollution any more. There was another solution to filter out report notifications during fetch. It wasn't merged because this seemed 'cleaner' at the time, but now it seems the better sollution. I'll add it in the next commit. --- lib/pleroma/notification.ex | 8 -------- lib/pleroma/user.ex | 16 +--------------- 2 files changed, 1 insertion(+), 23 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index 52fd2656b..41385884b 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -341,14 +341,6 @@ defmodule Pleroma.Notification do |> Repo.delete_all() end - def destroy_multiple_from_types(%{id: user_id}, types) do - from(n in Notification, - where: n.user_id == ^user_id, - where: n.type in ^types - ) - |> Repo.delete_all() - end - def dismiss(%Pleroma.Activity{} = activity) do Notification |> where([n], n.activity_id == ^activity.id) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 7dfc6ce7b..b68d5cf9a 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1147,24 +1147,10 @@ defmodule Pleroma.User do |> update_and_set_cache() end - def update_and_set_cache(%{data: %Pleroma.User{} = user} = changeset) do - was_superuser_before_update = User.superuser?(user) - + def update_and_set_cache(changeset) do with {:ok, user} <- Repo.update(changeset, stale_error_field: :id) do set_cache(user) end - |> maybe_remove_report_notifications(was_superuser_before_update) - end - - defp maybe_remove_report_notifications({:ok, %Pleroma.User{} = user} = result, true) do - if not User.superuser?(user), - do: user |> Notification.destroy_multiple_from_types(["pleroma:report"]) - - result - end - - defp maybe_remove_report_notifications(result, _) do - result end def get_user_friends_ap_ids(user) do -- cgit v1.2.3 From eab13fed3e6ba7edd7847fd00581b45dc4292af0 Mon Sep 17 00:00:00 2001 From: Ilja Date: Wed, 2 Mar 2022 18:05:50 +0100 Subject: Hide pleroma:report for non-privileged users Before we deleted the notifications, but that was a side effect and didn't always trigger any more. Now we just hide them when an unprivileged user asks them. --- lib/pleroma/web/mastodon_api/mastodon_api.ex | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/mastodon_api.ex b/lib/pleroma/web/mastodon_api/mastodon_api.ex index 5e32b9611..21ee5f0d4 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api.ex @@ -61,7 +61,18 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPI do end def get_notifications(user, params \\ %{}) do - options = cast_params(params) + options = + cast_params(params) |> Map.update(:include_types, [], fn include_types -> include_types end) + + options = + if "pleroma:report" not in options.include_types or User.privileged?(user, :report_handle) do + options + else + options + |> Map.update(:exclude_types, ["pleroma:report"], fn current_exclude_types -> + current_exclude_types ++ ["pleroma:report"] + end) + end user |> Notification.for_user_query(options) -- cgit v1.2.3 From a1c8aa4721de8f5edd7d69dcd745586df23f5a31 Mon Sep 17 00:00:00 2001 From: Ilja Date: Sat, 18 Jun 2022 10:55:45 +0200 Subject: Remove function superuser? Everything now happens with privileged?/2 --- lib/pleroma/user.ex | 5 ----- 1 file changed, 5 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index b68d5cf9a..af29f85b5 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -371,11 +371,6 @@ defmodule Pleroma.User do defp privileged_for?(_, _, _), do: false - @spec superuser?(User.t()) :: boolean() - def superuser?(%User{local: true, is_admin: true}), do: true - def superuser?(%User{local: true, is_moderator: true}), do: true - def superuser?(_), do: false - @spec invisible?(User.t()) :: boolean() def invisible?(%User{invisible: true}), do: true def invisible?(_), do: false -- cgit v1.2.3 From 34adea8d28cec91f03047989cbbaaf0b402c3a55 Mon Sep 17 00:00:00 2001 From: Ilja Date: Sun, 19 Jun 2022 11:05:09 +0200 Subject: Add Pleroma.User.all_users_with_privilege/1 This should eventually replace the Pleroma.User.all_superusers/0 function * I added a new param `is_privileged` in User.query * Now we can fetch all users with a specified privilege --- lib/pleroma/user.ex | 5 +++++ lib/pleroma/user/query.ex | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index af29f85b5..16438e524 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -2205,6 +2205,11 @@ defmodule Pleroma.User do |> Repo.all() end + @spec all_users_with_privilege(atom()) :: [User.t()] + def all_users_with_privilege(privilege) do + User.Query.build(%{is_privileged: privilege}) |> Repo.all() + end + def muting_reblogs?(%User{} = user, %User{} = target) do UserRelationship.reblog_mute_exists?(user, target) end diff --git a/lib/pleroma/user/query.ex b/lib/pleroma/user/query.ex index 20bc1ea61..3e090cac0 100644 --- a/lib/pleroma/user/query.ex +++ b/lib/pleroma/user/query.ex @@ -29,6 +29,7 @@ defmodule Pleroma.User.Query do import Ecto.Query import Pleroma.Web.Utils.Guards, only: [not_empty_string: 1] + alias Pleroma.Config alias Pleroma.FollowingRelationship alias Pleroma.User @@ -49,6 +50,7 @@ defmodule Pleroma.User.Query do is_suggested: boolean(), is_discoverable: boolean(), super_users: boolean(), + is_privileged: atom(), invisible: boolean(), internal: boolean(), followers: User.t(), @@ -136,6 +138,43 @@ defmodule Pleroma.User.Query do ) end + defp compose_query({:is_privileged, privilege}, query) do + moderator_privileged = privilege in Config.get([:instance, :moderator_privileges]) + admin_privileged = privilege in Config.get([:instance, :admin_privileges]) + + query = compose_query({:active, true}, query) + query = compose_query({:local, true}, query) + + case {admin_privileged, moderator_privileged} do + {false, false} -> + where( + query, + false + ) + + {true, true} -> + where( + query, + [u], + u.is_admin or u.is_moderator + ) + + {true, false} -> + where( + query, + [u], + u.is_admin + ) + + {false, true} -> + where( + query, + [u], + u.is_moderator + ) + end + end + defp compose_query({:local, _}, query), do: location_query(query, true) defp compose_query({:external, _}, query), do: location_query(query, false) -- cgit v1.2.3 From e21ef5aef389f7cef9ba53525d2d38bb29f5e257 Mon Sep 17 00:00:00 2001 From: Ilja Date: Sun, 19 Jun 2022 16:26:56 +0200 Subject: report notifications for privileged users Instead of `Pleroma.User.all_superusers()` we now use `Pleroma.User.all_superusers(:report_handle)` I also changed it for sending emails, but there were no tests. --- lib/pleroma/notification.ex | 3 ++- lib/pleroma/web/activity_pub/activity_pub.ex | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index 41385884b..9a3ffc0c2 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -542,7 +542,8 @@ defmodule Pleroma.Notification do end def get_potential_receiver_ap_ids(%{data: %{"type" => "Flag", "actor" => actor}}) do - (User.all_superusers() |> Enum.map(fn user -> user.ap_id end)) -- [actor] + (User.all_users_with_privilege(:report_handle) |> Enum.map(fn user -> user.ap_id end)) -- + [actor] end def get_potential_receiver_ap_ids(activity) do diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 064f93b22..68cd818b9 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -392,11 +392,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do _ <- notify_and_stream(activity), :ok <- maybe_federate(stripped_activity) do - User.all_superusers() + User.all_users_with_privilege(:report_handle) |> Enum.filter(fn user -> user.ap_id != actor end) |> Enum.filter(fn user -> not is_nil(user.email) end) - |> Enum.each(fn superuser -> - superuser + |> Enum.each(fn privileged_user -> + privileged_user |> Pleroma.Emails.AdminEmail.report(actor, account, statuses, content) |> Pleroma.Emails.Mailer.deliver_async() end) -- cgit v1.2.3 From 143ea7b80a228d9bd23a77354fe214553ca2b8cc Mon Sep 17 00:00:00 2001 From: Ilja Date: Tue, 21 Jun 2022 09:21:45 +0200 Subject: Add deactivated status for privileged users Deactivated users are only visible to users privileged with :user_activation since fc317f3b17 Here we also make sure the users who are deactivated get the status deactivated for users who are allowed to see these users --- lib/pleroma/web/mastodon_api/views/account_view.ex | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index 988eedbb1..d3f2245e2 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -398,12 +398,12 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do defp maybe_put_allow_following_move(data, _, _), do: data - defp maybe_put_activation_status(data, user, %User{is_admin: true}) do - Kernel.put_in(data, [:pleroma, :deactivated], !user.is_active) + defp maybe_put_activation_status(data, user, user_for) do + if User.privileged?(user_for, :user_activation), + do: Kernel.put_in(data, [:pleroma, :deactivated], !user.is_active), + else: data end - defp maybe_put_activation_status(data, _, _), do: data - defp maybe_put_unread_conversation_count(data, %User{id: user_id} = user, %User{id: user_id}) do data |> Kernel.put_in( -- cgit v1.2.3 From 211e561e2ad862c75a1b34f783d3210523dc211e Mon Sep 17 00:00:00 2001 From: Ilja Date: Tue, 21 Jun 2022 11:13:32 +0200 Subject: Show privileges to FE I added an extra key We already had is_admin and is_moderator, now we have an extra privileges key --- lib/pleroma/user.ex | 22 ++++++++++++++++++++++ lib/pleroma/web/mastodon_api/views/account_view.ex | 13 ++++++++----- 2 files changed, 30 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 16438e524..fb2fade42 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -371,6 +371,28 @@ defmodule Pleroma.User do defp privileged_for?(_, _, _), do: false + @spec privileges(User.t()) :: [atom()] + def privileges(%User{local: false}) do + [] + end + + def privileges(%User{is_moderator: false, is_admin: false}) do + [] + end + + def privileges(%User{local: true, is_moderator: true, is_admin: true}) do + (Config.get([:instance, :moderator_privileges]) ++ Config.get([:instance, :admin_privileges])) + |> Enum.uniq() + end + + def privileges(%User{local: true, is_moderator: true, is_admin: false}) do + Config.get([:instance, :moderator_privileges]) + end + + def privileges(%User{local: true, is_moderator: false, is_admin: true}) do + Config.get([:instance, :admin_privileges]) + end + @spec invisible?(User.t()) :: boolean() def invisible?(%User{invisible: true}), do: true def invisible?(_), do: false diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index d3f2245e2..a28ad9d85 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -369,19 +369,22 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do defp maybe_put_chat_token(data, _, _, _), do: data defp maybe_put_role(data, %User{show_role: true} = user, _) do - data - |> Kernel.put_in([:pleroma, :is_admin], user.is_admin) - |> Kernel.put_in([:pleroma, :is_moderator], user.is_moderator) + put_role(data, user) end defp maybe_put_role(data, %User{id: user_id} = user, %User{id: user_id}) do + put_role(data, user) + end + + defp maybe_put_role(data, _, _), do: data + + defp put_role(data, user) do data |> Kernel.put_in([:pleroma, :is_admin], user.is_admin) |> Kernel.put_in([:pleroma, :is_moderator], user.is_moderator) + |> Kernel.put_in([:pleroma, :privileges], User.privileges(user)) end - defp maybe_put_role(data, _, _), do: data - defp maybe_put_notification_settings(data, %User{id: user_id} = user, %User{id: user_id}) do Kernel.put_in( data, -- cgit v1.2.3 From 4e4eb81749076ada5692b92061c77a72832a9cc8 Mon Sep 17 00:00:00 2001 From: Ilja Date: Tue, 21 Jun 2022 12:03:35 +0200 Subject: Add nodes and privileges to nodeinfo I didn't add it to /api/v1/instance I was wondering if I should, but since it e.g. also didn't show staff, it felt better not to --- lib/pleroma/web/nodeinfo/nodeinfo.ex | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/nodeinfo/nodeinfo.ex b/lib/pleroma/web/nodeinfo/nodeinfo.ex index c7b9ab2de..9e27ac26c 100644 --- a/lib/pleroma/web/nodeinfo/nodeinfo.ex +++ b/lib/pleroma/web/nodeinfo/nodeinfo.ex @@ -49,6 +49,10 @@ defmodule Pleroma.Web.Nodeinfo.Nodeinfo do enabled: false }, staffAccounts: staff_accounts, + roles: %{ + admin: Config.get([:instance, :admin_privileges]), + moderator: Config.get([:instance, :moderator_privileges]) + }, federation: federation, pollLimits: Config.get([:instance, :poll_limits]), postFormats: Config.get([:instance, :allowed_post_formats]), -- cgit v1.2.3 From 06da000c5d4fc8d71bd36bfb4cec9cbf4399dfe8 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Tue, 21 Jun 2022 12:32:44 -0400 Subject: Add editing to features --- lib/pleroma/web/mastodon_api/views/instance_view.ex | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/views/instance_view.ex b/lib/pleroma/web/mastodon_api/views/instance_view.ex index ee52475d5..4f613416b 100644 --- a/lib/pleroma/web/mastodon_api/views/instance_view.ex +++ b/lib/pleroma/web/mastodon_api/views/instance_view.ex @@ -68,6 +68,7 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do "shareable_emoji_packs", "multifetch", "pleroma:api/v1/notifications:include_types_filter", + "editing", if Config.get([:activitypub, :blockers_visible]) do "blockers_visible" end, -- cgit v1.2.3 From 01321c88b5ef0d6c236b968cc47eaa8873054b1e Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Fri, 24 Jun 2022 10:10:22 -0400 Subject: Convert incoming Updated object into Pleroma format --- lib/pleroma/web/activity_pub/object_validator.ex | 16 ++++++++++++++++ .../object_validators/article_note_page_validator.ex | 5 ++++- 2 files changed, 20 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/object_validator.ex b/lib/pleroma/web/activity_pub/object_validator.ex index f3e31c931..b3105c46e 100644 --- a/lib/pleroma/web/activity_pub/object_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validator.ex @@ -141,6 +141,22 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do end end + def validate( + %{"type" => "Update", "object" => %{"type" => objtype} = object} = update_activity, + meta + ) + when objtype in ~w[Question Answer Audio Video Event Article Note Page] do + with {:ok, object_data} <- cast_and_apply(object), + meta = Keyword.put(meta, :object_data, object_data |> stringify_keys), + {:ok, update_activity} <- + update_activity + |> UpdateValidator.cast_and_validate() + |> Ecto.Changeset.apply_action(:insert) do + update_activity = stringify_keys(update_activity) + {:ok, update_activity, meta} + end + end + def validate(%{"type" => type} = object, meta) when type in ~w[Accept Reject Follow Update Like EmojiReact Announce ChatMessage Answer] do diff --git a/lib/pleroma/web/activity_pub/object_validators/article_note_page_validator.ex b/lib/pleroma/web/activity_pub/object_validators/article_note_page_validator.ex index ca335bc8a..0a0d30e45 100644 --- a/lib/pleroma/web/activity_pub/object_validators/article_note_page_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/article_note_page_validator.ex @@ -49,7 +49,10 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidator do defp fix_url(%{"url" => url} = data) when is_map(url), do: Map.put(data, "url", url["href"]) defp fix_url(data), do: data - defp fix_tag(%{"tag" => tag} = data) when is_list(tag), do: data + defp fix_tag(%{"tag" => tag} = data) when is_list(tag) do + Map.put(data, "tag", Enum.filter(tag, &is_map/1)) + end + defp fix_tag(%{"tag" => tag} = data) when is_map(tag), do: Map.put(data, "tag", [tag]) defp fix_tag(data), do: Map.drop(data, ["tag"]) -- cgit v1.2.3 From ee0738319169cf5c7d31dcaf641d9b744c7a72dc Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Fri, 24 Jun 2022 10:26:01 -0400 Subject: Use meta[:object_data] in SideEffects for Update --- lib/pleroma/web/activity_pub/side_effects.ex | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/side_effects.ex b/lib/pleroma/web/activity_pub/side_effects.ex index d387d9362..aa4183bf6 100644 --- a/lib/pleroma/web/activity_pub/side_effects.ex +++ b/lib/pleroma/web/activity_pub/side_effects.ex @@ -459,6 +459,8 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do orig_object = Object.get_by_ap_id(orig_object_ap_id) orig_object_data = orig_object.data + updated_object = meta[:object_data] + if orig_object_data["type"] in @updatable_object_types do %{data: updated_object_data, updated: updated} = orig_object_data -- cgit v1.2.3 From e0d6da4e7d52e2cdd0fc5290e4ff3a23da7398f6 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Fri, 24 Jun 2022 10:54:11 -0400 Subject: Fix CommonAPITest --- lib/pleroma/web/activity_pub/object_validators/attachment_validator.ex | 3 ++- lib/pleroma/web/activity_pub/object_validators/common_fields.ex | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/object_validators/attachment_validator.ex b/lib/pleroma/web/activity_pub/object_validators/attachment_validator.ex index d1c61ac82..ca6e39612 100644 --- a/lib/pleroma/web/activity_pub/object_validators/attachment_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/attachment_validator.ex @@ -11,6 +11,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidator do @primary_key false embedded_schema do + field(:id, :string) field(:type, :string) field(:mediaType, :string, default: "application/octet-stream") field(:name, :string) @@ -43,7 +44,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidator do |> fix_url() struct - |> cast(data, [:type, :mediaType, :name, :blurhash]) + |> cast(data, [:id, :type, :mediaType, :name, :blurhash]) |> cast_embed(:url, with: &url_changeset/2) |> validate_inclusion(:type, ~w[Link Document Audio Image Video]) |> validate_required([:type, :mediaType, :url]) diff --git a/lib/pleroma/web/activity_pub/object_validators/common_fields.ex b/lib/pleroma/web/activity_pub/object_validators/common_fields.ex index 8e768ffbf..a59a6e545 100644 --- a/lib/pleroma/web/activity_pub/object_validators/common_fields.ex +++ b/lib/pleroma/web/activity_pub/object_validators/common_fields.ex @@ -33,6 +33,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFields do field(:content, :string) field(:published, ObjectValidators.DateTime) + field(:updated, ObjectValidators.DateTime) field(:emoji, ObjectValidators.Emoji, default: %{}) embeds_many(:attachment, AttachmentValidator) end -- cgit v1.2.3 From 99a6f5031638da2eed237f91c6dded9e25717599 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sat, 25 Jun 2022 00:32:22 -0400 Subject: Unify the logic of updating objects --- lib/pleroma/object.ex | 42 ------ lib/pleroma/object/fetcher.ex | 9 +- lib/pleroma/object/updater.ex | 157 ++++++++++++++++++++++ lib/pleroma/web/activity_pub/side_effects.ex | 62 +++------ lib/pleroma/web/common_api.ex | 10 +- lib/pleroma/web/mastodon_api/views/status_view.ex | 4 +- 6 files changed, 183 insertions(+), 101 deletions(-) create mode 100644 lib/pleroma/object/updater.ex (limited to 'lib') diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index 670ab8743..fe264b5e0 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -425,46 +425,4 @@ defmodule Pleroma.Object do end def object_data_hashtags(_), do: [] - - def history_for(object) do - with history <- Map.get(object, "formerRepresentations"), - true <- is_map(history), - "OrderedCollection" <- Map.get(history, "type"), - true <- is_list(Map.get(history, "orderedItems")), - true <- is_integer(Map.get(history, "totalItems")) do - history - else - _ -> history_skeleton() - end - end - - defp history_skeleton do - %{ - "type" => "OrderedCollection", - "totalItems" => 0, - "orderedItems" => [] - } - end - - def maybe_update_history(updated_object, orig_object_data, updated) do - if not updated do - updated_object - else - # Put edit history - # Note that we may have got the edit history by first fetching the object - history = Object.history_for(orig_object_data) - - latest_history_item = - orig_object_data - |> Map.drop(["id", "formerRepresentations"]) - - new_history = - history - |> Map.put("orderedItems", [latest_history_item | history["orderedItems"]]) - |> Map.put("totalItems", history["totalItems"] + 1) - - updated_object - |> Map.put("formerRepresentations", new_history) - end - end end diff --git a/lib/pleroma/object/fetcher.ex b/lib/pleroma/object/fetcher.ex index ce816c1fc..d81fdcf24 100644 --- a/lib/pleroma/object/fetcher.ex +++ b/lib/pleroma/object/fetcher.ex @@ -50,7 +50,14 @@ defmodule Pleroma.Object.Fetcher do Pleroma.Constants.status_updatable_fields() |> Enum.any?(fn field -> Map.get(old_data, field) != Map.get(new_data, field) end) - new_data |> Object.maybe_update_history(old_data, changed?) + %{updated_object: updated_object} = + new_data + |> Object.Updater.maybe_update_history(old_data, + updated: changed?, + use_history_in_new_object?: false + ) + + updated_object else new_data end diff --git a/lib/pleroma/object/updater.ex b/lib/pleroma/object/updater.ex new file mode 100644 index 000000000..03136c38e --- /dev/null +++ b/lib/pleroma/object/updater.ex @@ -0,0 +1,157 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Object.Updater do + require Pleroma.Constants + + def update_content_fields(orig_object_data, updated_object) do + Pleroma.Constants.status_updatable_fields() + |> Enum.reduce( + %{data: orig_object_data, updated: false}, + fn field, %{data: data, updated: updated} -> + updated = updated or Map.get(updated_object, field) != Map.get(orig_object_data, field) + + data = + if Map.has_key?(updated_object, field) do + Map.put(data, field, updated_object[field]) + else + Map.drop(data, [field]) + end + + %{data: data, updated: updated} + end + ) + end + + def maybe_history(object) do + with history <- Map.get(object, "formerRepresentations"), + true <- is_map(history), + "OrderedCollection" <- Map.get(history, "type"), + true <- is_list(Map.get(history, "orderedItems")), + true <- is_integer(Map.get(history, "totalItems")) do + history + else + _ -> nil + end + end + + def history_for(object) do + with history when not is_nil(history) <- maybe_history(object) do + history + else + _ -> history_skeleton() + end + end + + defp history_skeleton do + %{ + "type" => "OrderedCollection", + "totalItems" => 0, + "orderedItems" => [] + } + end + + def maybe_update_history( + updated_object, + orig_object_data, + opts + ) do + updated = opts[:updated] + use_history_in_new_object? = opts[:use_history_in_new_object?] + + if not updated do + %{updated_object: updated_object, used_history_in_new_object?: false} + else + # Put edit history + # Note that we may have got the edit history by first fetching the object + {new_history, used_history_in_new_object?} = + with true <- use_history_in_new_object?, + updated_history when not is_nil(updated_history) <- maybe_history(updated_object) do + {updated_history, true} + else + _ -> + history = history_for(orig_object_data) + + latest_history_item = + orig_object_data + |> Map.drop(["id", "formerRepresentations"]) + + updated_history = + history + |> Map.put("orderedItems", [latest_history_item | history["orderedItems"]]) + |> Map.put("totalItems", history["totalItems"] + 1) + + {updated_history, false} + end + + updated_object = + updated_object + |> Map.put("formerRepresentations", new_history) + + %{updated_object: updated_object, used_history_in_new_object?: used_history_in_new_object?} + end + end + + defp maybe_update_poll(to_be_updated, updated_object) do + choice_key = fn data -> + if Map.has_key?(data, "anyOf"), do: "anyOf", else: "oneOf" + end + + with true <- to_be_updated["type"] == "Question", + key <- choice_key.(updated_object), + true <- key == choice_key.(to_be_updated), + orig_choices <- to_be_updated[key] |> Enum.map(&Map.drop(&1, ["replies"])), + new_choices <- updated_object[key] |> Enum.map(&Map.drop(&1, ["replies"])), + true <- orig_choices == new_choices do + # Choices are the same, but counts are different + to_be_updated + |> Map.put(key, updated_object[key]) + else + # Choices (or vote type) have changed, do not allow this + _ -> to_be_updated + end + end + + # This calculates the data to be sent as the object of an Update. + # new_data's formerRepresentations is not considered. + # formerRepresentations is added to the returned data. + def make_update_object_data(original_data, new_data, date) do + %{data: updated_data, updated: updated} = + original_data + |> update_content_fields(new_data) + + if not updated do + updated_data + else + %{updated_object: updated_data} = + updated_data + |> maybe_update_history(original_data, updated: updated, use_history_in_new_object?: false) + + updated_data + |> Map.put("updated", date) + end + end + + # This calculates the data of the new Object from an Update. + # new_data's formerRepresentations is considered. + def make_new_object_data_from_update_object(original_data, new_data) do + %{data: updated_data, updated: updated} = + original_data + |> update_content_fields(new_data) + + %{updated_object: updated_data, used_history_in_new_object?: used_history_in_new_object?} = + updated_data + |> maybe_update_history(original_data, updated: updated, use_history_in_new_object?: false) + + updated_data = + updated_data + |> maybe_update_poll(new_data) + + %{ + updated_data: updated_data, + updated: updated, + used_history_in_new_object?: used_history_in_new_object? + } + end +end diff --git a/lib/pleroma/web/activity_pub/side_effects.ex b/lib/pleroma/web/activity_pub/side_effects.ex index aa4183bf6..7345a6904 100644 --- a/lib/pleroma/web/activity_pub/side_effects.ex +++ b/lib/pleroma/web/activity_pub/side_effects.ex @@ -412,45 +412,6 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do end @updatable_object_types ["Note", "Question"] - defp update_content_fields(orig_object_data, updated_object) do - Pleroma.Constants.status_updatable_fields() - |> Enum.reduce( - %{data: orig_object_data, updated: false}, - fn field, %{data: data, updated: updated} -> - updated = updated or Map.get(updated_object, field) != Map.get(orig_object_data, field) - - data = - if Map.has_key?(updated_object, field) do - Map.put(data, field, updated_object[field]) - else - Map.drop(data, [field]) - end - - %{data: data, updated: updated} - end - ) - end - - defp maybe_update_poll(to_be_updated, updated_object) do - choice_key = fn data -> - if Map.has_key?(data, "anyOf"), do: "anyOf", else: "oneOf" - end - - with true <- to_be_updated["type"] == "Question", - key <- choice_key.(updated_object), - true <- key == choice_key.(to_be_updated), - orig_choices <- to_be_updated[key] |> Enum.map(&Map.drop(&1, ["replies"])), - new_choices <- updated_object[key] |> Enum.map(&Map.drop(&1, ["replies"])), - true <- orig_choices == new_choices do - # Choices are the same, but counts are different - to_be_updated - |> Map.put(key, updated_object[key]) - else - # Choices (or vote type) have changed, do not allow this - _ -> to_be_updated - end - end - defp handle_update_object( %{data: %{"type" => "Update", "object" => updated_object}} = object, meta @@ -462,14 +423,11 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do updated_object = meta[:object_data] if orig_object_data["type"] in @updatable_object_types do - %{data: updated_object_data, updated: updated} = - orig_object_data - |> update_content_fields(updated_object) - - updated_object_data = - updated_object_data - |> Object.maybe_update_history(orig_object_data, updated) - |> maybe_update_poll(updated_object) + %{ + updated_data: updated_object_data, + updated: updated, + used_history_in_new_object?: used_history_in_new_object? + } = Object.Updater.make_new_object_data_from_update_object(orig_object_data, updated_object) changeset = orig_object @@ -481,6 +439,16 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do {:ok, _} <- Object.set_cache(new_object), # The metadata/utils.ex uses the object id for the cache. {:ok, _} <- Pleroma.Activity.HTML.invalidate_cache_for(new_object.id) do + if used_history_in_new_object? do + with create_activity when not is_nil(create_activity) <- + Pleroma.Activity.get_create_by_object_ap_id(orig_object_ap_id), + {:ok, _} <- Pleroma.Activity.HTML.invalidate_cache_for(create_activity.id) do + nil + else + _ -> nil + end + end + if updated do object |> Activity.normalize() diff --git a/lib/pleroma/web/common_api.ex b/lib/pleroma/web/common_api.ex index e60c26053..e5a78c102 100644 --- a/lib/pleroma/web/common_api.ex +++ b/lib/pleroma/web/common_api.ex @@ -422,15 +422,7 @@ defmodule Pleroma.Web.CommonAPI do with {:ok, draft} <- ActivityDraft.create(user, params) do change = - Pleroma.Constants.status_updatable_fields() - |> Enum.reduce(orig_object.data, fn key, acc -> - if Map.has_key?(draft.object, key) do - acc |> Map.put(key, Map.get(draft.object, key)) - else - acc |> Map.drop([key]) - end - end) - |> Map.put("updated", Utils.make_date()) + Object.Updater.make_update_object_data(orig_object.data, draft.object, Utils.make_date()) {:ok, change} else diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index 8439431eb..54e025aae 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -274,7 +274,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do history_len = 1 + - (Object.history_for(object.data) + (Object.Updater.history_for(object.data) |> Map.get("orderedItems") |> length()) @@ -413,7 +413,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do user = CommonAPI.get_user(activity.data["actor"]) past_history = - Object.history_for(object.data) + Object.Updater.history_for(object.data) |> Map.get("orderedItems") |> Enum.map(&Map.put(&1, "id", object.data["id"])) |> Enum.map(&%Object{data: &1, id: object.id}) -- cgit v1.2.3 From 40953a8f5c299e55b3f186bd6fdebe1bbf6e7401 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sat, 25 Jun 2022 01:03:46 -0400 Subject: Reuse formerRepresentations from remote if possible --- lib/pleroma/object/updater.ex | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/object/updater.ex b/lib/pleroma/object/updater.ex index 03136c38e..0b21f6c99 100644 --- a/lib/pleroma/object/updater.ex +++ b/lib/pleroma/object/updater.ex @@ -67,7 +67,7 @@ defmodule Pleroma.Object.Updater do # Note that we may have got the edit history by first fetching the object {new_history, used_history_in_new_object?} = with true <- use_history_in_new_object?, - updated_history when not is_nil(updated_history) <- maybe_history(updated_object) do + updated_history when not is_nil(updated_history) <- maybe_history(opts[:new_data]) do {updated_history, true} else _ -> @@ -142,7 +142,11 @@ defmodule Pleroma.Object.Updater do %{updated_object: updated_data, used_history_in_new_object?: used_history_in_new_object?} = updated_data - |> maybe_update_history(original_data, updated: updated, use_history_in_new_object?: false) + |> maybe_update_history(original_data, + updated: updated, + use_history_in_new_object?: true, + new_data: new_data + ) updated_data = updated_data -- cgit v1.2.3 From 9c6dae942d2ec5e2314af1d345cf2aeed504aae8 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sat, 25 Jun 2022 09:23:09 -0400 Subject: Fix local updates causing emojis to be lost --- lib/pleroma/web/activity_pub/side_effects.ex | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/side_effects.ex b/lib/pleroma/web/activity_pub/side_effects.ex index 7345a6904..747f467db 100644 --- a/lib/pleroma/web/activity_pub/side_effects.ex +++ b/lib/pleroma/web/activity_pub/side_effects.ex @@ -420,7 +420,14 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do orig_object = Object.get_by_ap_id(orig_object_ap_id) orig_object_data = orig_object.data - updated_object = meta[:object_data] + updated_object = + if meta[:local] do + # If this is a local Update, we don't process it by transmogrifier, + # so we use the embedded object as-is. + updated_object + else + meta[:object_data] + end if orig_object_data["type"] in @updatable_object_types do %{ -- cgit v1.2.3 From 5321fd001233076e7f2b6ea00adeb41ecf7e180a Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sat, 25 Jun 2022 10:03:19 -0400 Subject: Do not put meta[:object_data] for local Updates --- lib/pleroma/web/activity_pub/object_validator.ex | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/object_validator.ex b/lib/pleroma/web/activity_pub/object_validator.ex index b3105c46e..d4bf9c31e 100644 --- a/lib/pleroma/web/activity_pub/object_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validator.ex @@ -146,7 +146,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do meta ) when objtype in ~w[Question Answer Audio Video Event Article Note Page] do - with {:ok, object_data} <- cast_and_apply(object), + with {_, false} <- {:local, Access.get(meta, :local, false)}, + {:ok, object_data} <- cast_and_apply(object), meta = Keyword.put(meta, :object_data, object_data |> stringify_keys), {:ok, update_activity} <- update_activity @@ -154,6 +155,15 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do |> Ecto.Changeset.apply_action(:insert) do update_activity = stringify_keys(update_activity) {:ok, update_activity, meta} + else + {:local, _} -> + with {:ok, object} <- + update_activity + |> UpdateValidator.cast_and_validate() + |> Ecto.Changeset.apply_action(:insert) do + object = stringify_keys(object) + {:ok, object, meta} + end end end -- cgit v1.2.3 From 014096aeefe88348323db74e2ab7f81e0184bfee Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sat, 25 Jun 2022 11:20:46 -0400 Subject: Make outbound transmogrifier aware of edit history --- lib/pleroma/constants.ex | 12 ++++++ lib/pleroma/web/activity_pub/side_effects.ex | 3 +- lib/pleroma/web/activity_pub/transmogrifier.ex | 52 +++++++++++++++++--------- 3 files changed, 47 insertions(+), 20 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/constants.ex b/lib/pleroma/constants.ex index bbb95104f..1b3d09d73 100644 --- a/lib/pleroma/constants.ex +++ b/lib/pleroma/constants.ex @@ -42,6 +42,18 @@ defmodule Pleroma.Constants do ] ) + const(updatable_object_types, + do: [ + "Note", + "Question", + "Audio", + "Video", + "Event", + "Article", + "Page" + ] + ) + const(actor_types, do: [ "Application", diff --git a/lib/pleroma/web/activity_pub/side_effects.ex b/lib/pleroma/web/activity_pub/side_effects.ex index 747f467db..f56e357bf 100644 --- a/lib/pleroma/web/activity_pub/side_effects.ex +++ b/lib/pleroma/web/activity_pub/side_effects.ex @@ -411,7 +411,6 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do {:ok, object, meta} end - @updatable_object_types ["Note", "Question"] defp handle_update_object( %{data: %{"type" => "Update", "object" => updated_object}} = object, meta @@ -429,7 +428,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do meta[:object_data] end - if orig_object_data["type"] in @updatable_object_types do + if orig_object_data["type"] in Pleroma.Constants.updatable_object_types() do %{ updated_data: updated_object_data, updated: updated, diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 5750396a4..cccee342f 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -687,6 +687,24 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do |> strip_internal_fields |> strip_internal_tags |> set_type + |> maybe_process_history + end + + defp maybe_process_history(%{"formerRepresentations" => %{"orderedItems" => history}} = object) do + processed_history = + Enum.map( + history, + fn + item when is_map(item) -> prepare_object(item) + item -> item + end + ) + + put_in(object, ["formerRepresentations", "orderedItems"], processed_history) + end + + defp maybe_process_history(object) do + object end # @doc @@ -711,6 +729,21 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do {:ok, data} end + def prepare_outgoing(%{"type" => "Update", "object" => %{"type" => objtype} = object} = data) + when objtype in Pleroma.Constants.updatable_object_types() do + object = + object + |> prepare_object + + data = + data + |> Map.put("object", object) + |> Map.merge(Utils.make_json_ld_header()) + |> Map.delete("bcc") + + {:ok, data} + end + def prepare_outgoing(%{"type" => "Announce", "actor" => ap_id, "object" => object_id} = data) do object = object_id @@ -902,24 +935,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do end def strip_internal_fields(object) do - outer = Map.drop(object, Pleroma.Constants.object_internal_fields()) - - case outer do - %{"formerRepresentations" => %{"orderedItems" => list}} when is_list(list) -> - update_in( - outer["formerRepresentations"]["orderedItems"], - &Enum.map( - &1, - fn - item when is_map(item) -> Map.drop(item, Pleroma.Constants.object_internal_fields()) - item -> item - end - ) - ) - - _ -> - outer - end + Map.drop(object, Pleroma.Constants.object_internal_fields()) end defp strip_internal_tags(%{"tag" => tags} = object) do -- cgit v1.2.3 From 37fdf148b0963b62ab746a8ece2aacf893ba8934 Mon Sep 17 00:00:00 2001 From: Ilja Date: Fri, 1 Jul 2022 09:54:05 +0200 Subject: Rename privilege tags I first focussed on getting things working Now that they do and we know what tags there are, I put some thought in providing better names I use the form _ :statuses_read => :messages_read :status_delete => :messages_delete :user_read => :users_read :user_deletion => :users_delete :user_activation => :users_manage_activation_state :user_invite => :users_manage_invites :user_tag => :users_manage_tags :user_credentials => :users_manage_credentials :report_handle => :reports_manage_reports :emoji_management => :emoji_manage_emoji --- lib/pleroma/notification.ex | 3 ++- lib/pleroma/user.ex | 2 +- lib/pleroma/web/activity_pub/activity_pub.ex | 2 +- .../object_validators/delete_validator.ex | 2 +- lib/pleroma/web/common_api.ex | 2 +- lib/pleroma/web/mastodon_api/mastodon_api.ex | 3 ++- lib/pleroma/web/mastodon_api/views/account_view.ex | 2 +- lib/pleroma/web/router.ex | 20 ++++++++++---------- 8 files changed, 19 insertions(+), 17 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index 9a3ffc0c2..cfc4bfca3 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -542,7 +542,8 @@ defmodule Pleroma.Notification do end def get_potential_receiver_ap_ids(%{data: %{"type" => "Flag", "actor" => actor}}) do - (User.all_users_with_privilege(:report_handle) |> Enum.map(fn user -> user.ap_id end)) -- + (User.all_users_with_privilege(:reports_manage_reports) + |> Enum.map(fn user -> user.ap_id end)) -- [actor] end diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index fb2fade42..11c4d0684 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -326,7 +326,7 @@ defmodule Pleroma.User do end def visible_for(%User{} = user, for_user) do - if privileged?(for_user, :user_activation) do + if privileged?(for_user, :users_manage_activation_state) do :visible else visible_account_status(user) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 68cd818b9..06c894efd 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -392,7 +392,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do _ <- notify_and_stream(activity), :ok <- maybe_federate(stripped_activity) do - User.all_users_with_privilege(:report_handle) + User.all_users_with_privilege(:reports_manage_reports) |> Enum.filter(fn user -> user.ap_id != actor end) |> Enum.filter(fn user -> not is_nil(user.email) end) |> Enum.each(fn privileged_user -> diff --git a/lib/pleroma/web/activity_pub/object_validators/delete_validator.ex b/lib/pleroma/web/activity_pub/object_validators/delete_validator.ex index 6e4208167..4d8502ada 100644 --- a/lib/pleroma/web/activity_pub/object_validators/delete_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/delete_validator.ex @@ -61,7 +61,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.DeleteValidator do |> validate_required([:id, :type, :actor, :to, :cc, :object]) |> validate_inclusion(:type, ["Delete"]) |> validate_delete_actor(:actor) - |> validate_modification_rights(:status_delete) + |> validate_modification_rights(:messages_delete) |> validate_object_or_user_presence(allowed_types: @deletable_types) |> add_deleted_activity_id() end diff --git a/lib/pleroma/web/common_api.ex b/lib/pleroma/web/common_api.ex index ce1d5a7cc..4ac5df63f 100644 --- a/lib/pleroma/web/common_api.ex +++ b/lib/pleroma/web/common_api.ex @@ -144,7 +144,7 @@ defmodule Pleroma.Web.CommonAPI do {:find_activity, Activity.get_by_id(activity_id)}, {_, %Object{} = object, _} <- {:find_object, Object.normalize(activity, fetch: false), activity}, - true <- User.privileged?(user, :status_delete) || user.ap_id == object.data["actor"], + true <- User.privileged?(user, :messages_delete) || user.ap_id == object.data["actor"], {:ok, delete_data, _} <- Builder.delete(user, object.data["id"]), {:ok, delete, _} <- Pipeline.common_pipeline(delete_data, local: true) do {:ok, delete} diff --git a/lib/pleroma/web/mastodon_api/mastodon_api.ex b/lib/pleroma/web/mastodon_api/mastodon_api.ex index 21ee5f0d4..932e5d4eb 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api.ex @@ -65,7 +65,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPI do cast_params(params) |> Map.update(:include_types, [], fn include_types -> include_types end) options = - if "pleroma:report" not in options.include_types or User.privileged?(user, :report_handle) do + if "pleroma:report" not in options.include_types or + User.privileged?(user, :reports_manage_reports) do options else options diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index a28ad9d85..34b34dc19 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -402,7 +402,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do defp maybe_put_allow_following_move(data, _, _), do: data defp maybe_put_activation_status(data, user, user_for) do - if User.privileged?(user_for, :user_activation), + if User.privileged?(user_for, :users_manage_activation_state), do: Kernel.put_in(data, [:pleroma, :deactivated], !user.is_active), else: data end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index f680c8353..cbb5ca55f 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -107,52 +107,52 @@ defmodule Pleroma.Web.Router do pipeline :require_privileged_role_user_deletion do plug(:admin_api) - plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :user_deletion) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :users_delete) end pipeline :require_privileged_role_user_credentials do plug(:admin_api) - plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :user_credentials) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :users_manage_credentials) end pipeline :require_privileged_role_statuses_read do plug(:admin_api) - plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :statuses_read) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :messages_read) end pipeline :require_privileged_role_user_tag do plug(:admin_api) - plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :user_tag) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :users_manage_tags) end pipeline :require_privileged_role_user_activation do plug(:admin_api) - plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :user_activation) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :users_manage_activation_state) end pipeline :require_privileged_role_user_invite do plug(:admin_api) - plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :user_invite) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :users_manage_invites) end pipeline :require_privileged_role_report_handle do plug(:admin_api) - plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :report_handle) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :reports_manage_reports) end pipeline :require_privileged_role_user_read do plug(:admin_api) - plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :user_read) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :users_read) end pipeline :require_privileged_role_status_delete do plug(:admin_api) - plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :status_delete) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :messages_delete) end pipeline :require_privileged_role_emoji_management do plug(:admin_api) - plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :emoji_management) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :emoji_manage_emoji) end pipeline :require_privileged_role_instance_delete do -- cgit v1.2.3 From c0e4b1b3e27a4a8f8f02ea6a33b76c6f2a386d95 Mon Sep 17 00:00:00 2001 From: Ilja Date: Sat, 2 Jul 2022 07:52:39 +0200 Subject: Fix typo's priviledge |-> privilege --- lib/pleroma/web/plugs/ensure_privileged_plug.ex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/plugs/ensure_privileged_plug.ex b/lib/pleroma/web/plugs/ensure_privileged_plug.ex index be09f3d81..f886c87ea 100644 --- a/lib/pleroma/web/plugs/ensure_privileged_plug.ex +++ b/lib/pleroma/web/plugs/ensure_privileged_plug.ex @@ -24,10 +24,10 @@ defmodule Pleroma.Web.Plugs.EnsurePrivilegedPlug do def call( %{assigns: %{user: %User{is_admin: is_admin, is_moderator: is_moderator}}} = conn, - priviledge + privilege ) do - if (is_admin and priviledge in Config.get([:instance, :admin_privileges])) or - (is_moderator and priviledge in Config.get([:instance, :moderator_privileges])) do + if (is_admin and privilege in Config.get([:instance, :admin_privileges])) or + (is_moderator and privilege in Config.get([:instance, :moderator_privileges])) do conn else conn -- cgit v1.2.3 From 42d4bd3a5d49a472b8fcb85e6cd413eb0d6dab3f Mon Sep 17 00:00:00 2001 From: Ilja Date: Sat, 2 Jul 2022 08:55:14 +0200 Subject: Rename pipelines and add forgotten tags I renamed some tags before, but forgot to rename the pipelines I also had some tags which I forgot to add to the config, description, etc. These have now been done/added --- lib/pleroma/web/router.ex | 56 +++++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 28 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index cbb5ca55f..e781d3673 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -105,59 +105,59 @@ defmodule Pleroma.Web.Router do plug(Pleroma.Web.Plugs.UserIsAdminPlug) end - pipeline :require_privileged_role_user_deletion do + pipeline :require_privileged_role_users_delete do plug(:admin_api) plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :users_delete) end - pipeline :require_privileged_role_user_credentials do + pipeline :require_privileged_role_users_manage_credentials do plug(:admin_api) plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :users_manage_credentials) end - pipeline :require_privileged_role_statuses_read do + pipeline :require_privileged_role_messages_read do plug(:admin_api) plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :messages_read) end - pipeline :require_privileged_role_user_tag do + pipeline :require_privileged_role_users_manage_tags do plug(:admin_api) plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :users_manage_tags) end - pipeline :require_privileged_role_user_activation do + pipeline :require_privileged_role_users_manage_activation_state do plug(:admin_api) plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :users_manage_activation_state) end - pipeline :require_privileged_role_user_invite do + pipeline :require_privileged_role_users_manage_invites do plug(:admin_api) plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :users_manage_invites) end - pipeline :require_privileged_role_report_handle do + pipeline :require_privileged_role_reports_manage_reports do plug(:admin_api) plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :reports_manage_reports) end - pipeline :require_privileged_role_user_read do + pipeline :require_privileged_role_users_read do plug(:admin_api) plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :users_read) end - pipeline :require_privileged_role_status_delete do + pipeline :require_privileged_role_messages_delete do plug(:admin_api) plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :messages_delete) end - pipeline :require_privileged_role_emoji_management do + pipeline :require_privileged_role_emoji_manage_emoji do plug(:admin_api) plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :emoji_manage_emoji) end - pipeline :require_privileged_role_instance_delete do + pipeline :require_privileged_role_instances_delete do plug(:admin_api) - plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :instance_delete) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :instances_delete) end pipeline :require_privileged_role_moderation_log_read do @@ -165,9 +165,9 @@ defmodule Pleroma.Web.Router do plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :moderation_log_read) end - pipeline :require_privileged_role_stats_read do + pipeline :require_privileged_role_statistics_read do plug(:admin_api) - plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :stats_read) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :statistics_read) end pipeline :pleroma_html do @@ -293,14 +293,14 @@ defmodule Pleroma.Web.Router do # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through(:require_privileged_role_user_deletion) + pipe_through(:require_privileged_role_users_delete) delete("/users", UserController, :delete) end # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through(:require_privileged_role_user_credentials) + pipe_through(:require_privileged_role_users_manage_credentials) get("/users/:nickname/password_reset", AdminAPIController, :get_password_reset) patch("/users/:nickname/credentials", AdminAPIController, :update_user_credentials) @@ -308,7 +308,7 @@ defmodule Pleroma.Web.Router do # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through(:require_privileged_role_statuses_read) + pipe_through(:require_privileged_role_messages_read) get("/users/:nickname/statuses", AdminAPIController, :list_user_statuses) get("/users/:nickname/chats", AdminAPIController, :list_user_chats) @@ -325,7 +325,7 @@ defmodule Pleroma.Web.Router do # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through(:require_privileged_role_user_tag) + pipe_through(:require_privileged_role_users_manage_tags) put("/users/tag", AdminAPIController, :tag_users) delete("/users/tag", AdminAPIController, :untag_users) @@ -333,7 +333,7 @@ defmodule Pleroma.Web.Router do # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through(:require_privileged_role_user_activation) + pipe_through(:require_privileged_role_users_manage_activation_state) patch("/users/:nickname/toggle_activation", UserController, :toggle_activation) patch("/users/activate", UserController, :activate) @@ -342,7 +342,7 @@ defmodule Pleroma.Web.Router do # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through(:require_privileged_role_user_invite) + pipe_through(:require_privileged_role_users_manage_invites) patch("/users/approve", UserController, :approve) post("/users/invite_token", InviteController, :create) @@ -353,7 +353,7 @@ defmodule Pleroma.Web.Router do # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through(:require_privileged_role_report_handle) + pipe_through(:require_privileged_role_reports_manage_reports) get("/reports", ReportController, :index) get("/reports/:id", ReportController, :show) @@ -364,7 +364,7 @@ defmodule Pleroma.Web.Router do # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through(:require_privileged_role_user_read) + pipe_through(:require_privileged_role_users_read) get("/users", UserController, :index) get("/users/:nickname", UserController, :show) @@ -372,7 +372,7 @@ defmodule Pleroma.Web.Router do # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through(:require_privileged_role_status_delete) + pipe_through(:require_privileged_role_messages_delete) put("/statuses/:id", StatusController, :update) delete("/statuses/:id", StatusController, :delete) @@ -382,14 +382,14 @@ defmodule Pleroma.Web.Router do # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through(:require_privileged_role_emoji_management) + pipe_through(:require_privileged_role_emoji_manage_emoji) post("/reload_emoji", AdminAPIController, :reload_emoji) end # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through(:require_privileged_role_instance_delete) + pipe_through(:require_privileged_role_instances_delete) delete("/instances/:instance", InstanceController, :delete) end @@ -403,14 +403,14 @@ defmodule Pleroma.Web.Router do # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through(:require_privileged_role_stats_read) + pipe_through(:require_privileged_role_statistics_read) get("/stats", AdminAPIController, :stats) end scope "/api/v1/pleroma/emoji", Pleroma.Web.PleromaAPI do scope "/pack" do - pipe_through(:require_privileged_role_emoji_management) + pipe_through(:require_privileged_role_emoji_manage_emoji) post("/", EmojiPackController, :create) patch("/", EmojiPackController, :update) @@ -425,7 +425,7 @@ defmodule Pleroma.Web.Router do # Modifying packs scope "/packs" do - pipe_through(:require_privileged_role_emoji_management) + pipe_through(:require_privileged_role_emoji_manage_emoji) get("/import", EmojiPackController, :import_from_filesystem) get("/remote", EmojiPackController, :remote) -- cgit v1.2.3 From 4367489a3e8eb8682d717014eea9092d7679c070 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sun, 3 Jul 2022 20:02:52 -0400 Subject: Pass history items through ObjectValidator for updatable object types --- lib/pleroma/web/activity_pub/object_validator.ex | 73 +++++++++++++++++++++--- 1 file changed, 64 insertions(+), 9 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/object_validator.ex b/lib/pleroma/web/activity_pub/object_validator.ex index d4bf9c31e..12278a46b 100644 --- a/lib/pleroma/web/activity_pub/object_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validator.ex @@ -128,15 +128,20 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do end with {:ok, object} <- - object - |> validator.cast_and_validate() - |> Ecto.Changeset.apply_action(:insert) do - object = stringify_keys(object) - - # Insert copy of hashtags as strings for the non-hashtag table indexing - tag = (object["tag"] || []) ++ Object.hashtags(%Object{data: object}) - object = Map.put(object, "tag", tag) - + do_separate_with_history(object, fn object -> + with {:ok, object} <- + object + |> validator.cast_and_validate() + |> Ecto.Changeset.apply_action(:insert) do + object = stringify_keys(object) + + # Insert copy of hashtags as strings for the non-hashtag table indexing + tag = (object["tag"] || []) ++ Object.hashtags(%Object{data: object}) + object = Map.put(object, "tag", tag) + + {:ok, object} + end + end) do {:ok, object, meta} end end @@ -262,4 +267,54 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do Object.normalize(object["object"], fetch: true) :ok end + + defp for_each_history_item( + %{"type" => "OrderedCollection", "orderedItems" => items} = history, + object, + fun + ) do + processed_items = + Enum.map(items, fn item -> + with item <- Map.put(item, "id", object["id"]), + {:ok, item} <- fun.(item) do + item + else + _ -> nil + end + end) + + if Enum.all?(processed_items, &(not is_nil(&1))) do + {:ok, Map.put(history, "orderedItems", processed_items)} + else + {:error, :invalid_history} + end + end + + defp for_each_history_item(nil, _object, _fun) do + {:ok, nil} + end + + defp for_each_history_item(_, _object, _fun) do + {:error, :invalid_history} + end + + # fun is (object -> {:ok, validated_object_with_string_keys}) + defp do_separate_with_history(object, fun) do + with history <- object["formerRepresentations"], + object <- Map.drop(object, ["formerRepresentations"]), + {_, {:ok, object}} <- {:main_body, fun.(object)}, + {_, {:ok, history}} <- {:history_items, for_each_history_item(history, object, fun)} do + object = + if history do + Map.put(object, "formerRepresentations", history) + else + object + end + + {:ok, object} + else + {:main_body, e} -> e + {:history_items, e} -> e + end + end end -- cgit v1.2.3 From 5ce118d970d3d7a2a5dd0a3719feb1d53be6b5ae Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sun, 3 Jul 2022 20:19:50 -0400 Subject: Validate object data for incoming Update activities In Create validator we do not validate the object data, but that is because the object itself will go through the pipeline again, which is not the case for Update. Thus, we added validation for objects in Update activities. --- lib/pleroma/web/activity_pub/object_validator.ex | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/object_validator.ex b/lib/pleroma/web/activity_pub/object_validator.ex index 12278a46b..3ccb4a3d6 100644 --- a/lib/pleroma/web/activity_pub/object_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validator.ex @@ -152,8 +152,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do ) when objtype in ~w[Question Answer Audio Video Event Article Note Page] do with {_, false} <- {:local, Access.get(meta, :local, false)}, - {:ok, object_data} <- cast_and_apply(object), - meta = Keyword.put(meta, :object_data, object_data |> stringify_keys), + {_, {:ok, object_data, _}} <- {:object_validation, validate(object, meta)}, + meta = Keyword.put(meta, :object_data, object_data), {:ok, update_activity} <- update_activity |> UpdateValidator.cast_and_validate() @@ -169,6 +169,9 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do object = stringify_keys(object) {:ok, object, meta} end + + {:object_validation, e} -> + e end end -- cgit v1.2.3 From f84ed44cea1e5793dd899c74c38336a1721889e6 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Wed, 6 Jul 2022 01:19:53 -0400 Subject: Fix cannot get full history on object fetch --- lib/pleroma/web/activity_pub/object_validator.ex | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/object_validator.ex b/lib/pleroma/web/activity_pub/object_validator.ex index 3ccb4a3d6..9f446100d 100644 --- a/lib/pleroma/web/activity_pub/object_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validator.ex @@ -103,8 +103,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do meta ) when objtype in ~w[Question Answer Audio Video Event Article Note Page] do - with {:ok, object_data} <- cast_and_apply(object), - meta = Keyword.put(meta, :object_data, object_data |> stringify_keys), + with {:ok, object_data} <- cast_and_apply_and_stringify_with_history(object), + meta = Keyword.put(meta, :object_data, object_data), {:ok, create_activity} <- create_activity |> CreateGenericValidator.cast_and_validate(meta) @@ -212,6 +212,15 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do def validate(o, m), do: {:error, {:validator_not_set, {o, m}}} + def cast_and_apply_and_stringify_with_history(object) do + do_separate_with_history(object, fn object -> + with {:ok, object_data} <- cast_and_apply(object), + object_data <- object_data |> stringify_keys() do + {:ok, object_data} + end + end) + end + def cast_and_apply(%{"type" => "ChatMessage"} = object) do ChatMessageValidator.cast_and_apply(object) end -- cgit v1.2.3 From 069554e9253a47f99225e12cc0ee99700fb89c6e Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Thu, 7 Jul 2022 15:11:29 -0400 Subject: Guard against outdated Updates It is possible for an earlier Update to be received by us later. For this, we now (1) only allows Updates to poll counts if there is no updated field, or the updated field is the same as the last updated date or creation date; (2) does not allow updating anything if the updated field is older than the last updated date or creation date; (3) allows updating updatable fields otherwise (normal updates); (4) if only the updated field is changed, it does not create a new history item on its own. --- lib/pleroma/object/updater.ex | 65 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 52 insertions(+), 13 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/object/updater.ex b/lib/pleroma/object/updater.ex index 0b21f6c99..3d34c3f27 100644 --- a/lib/pleroma/object/updater.ex +++ b/lib/pleroma/object/updater.ex @@ -10,7 +10,10 @@ defmodule Pleroma.Object.Updater do |> Enum.reduce( %{data: orig_object_data, updated: false}, fn field, %{data: data, updated: updated} -> - updated = updated or Map.get(updated_object, field) != Map.get(orig_object_data, field) + updated = + updated or + (field != "updated" and + Map.get(updated_object, field) != Map.get(orig_object_data, field)) data = if Map.has_key?(updated_object, field) do @@ -136,21 +139,57 @@ defmodule Pleroma.Object.Updater do # This calculates the data of the new Object from an Update. # new_data's formerRepresentations is considered. def make_new_object_data_from_update_object(original_data, new_data) do - %{data: updated_data, updated: updated} = - original_data - |> update_content_fields(new_data) + update_is_reasonable = + with {_, updated} when not is_nil(updated) <- {:cur_updated, new_data["updated"]}, + {_, {:ok, updated_time, _}} <- {:cur_updated, DateTime.from_iso8601(updated)}, + {_, last_updated} when not is_nil(last_updated) <- + {:last_updated, original_data["updated"] || original_data["published"]}, + {_, {:ok, last_updated_time, _}} <- + {:last_updated, DateTime.from_iso8601(last_updated)}, + :gt <- DateTime.compare(updated_time, last_updated_time) do + :update_everything + else + # only allow poll updates + {:cur_updated, _} -> :no_content_update + :eq -> :no_content_update + # allow all updates + {:last_updated, _} -> :update_everything + # allow no updates + _ -> false + end - %{updated_object: updated_data, used_history_in_new_object?: used_history_in_new_object?} = - updated_data - |> maybe_update_history(original_data, - updated: updated, - use_history_in_new_object?: true, - new_data: new_data - ) + %{ + updated_object: updated_data, + used_history_in_new_object?: used_history_in_new_object?, + updated: updated + } = + if update_is_reasonable == :update_everything do + %{data: updated_data, updated: updated} = + original_data + |> update_content_fields(new_data) + + updated_data + |> maybe_update_history(original_data, + updated: updated, + use_history_in_new_object?: true, + new_data: new_data + ) + |> Map.put(:updated, updated) + else + %{ + updated_object: original_data, + used_history_in_new_object?: false, + updated: false + } + end updated_data = - updated_data - |> maybe_update_poll(new_data) + if update_is_reasonable != false do + updated_data + |> maybe_update_poll(new_data) + else + updated_data + end %{ updated_data: updated_data, -- cgit v1.2.3 From 04ded94a50fbabb194ab9e9c5cf8f08937f85d64 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sat, 9 Jul 2022 18:00:42 -0400 Subject: Fix remote emoji in subject disappearing after edits --- lib/pleroma/web/common_api.ex | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/common_api.ex b/lib/pleroma/web/common_api.ex index e5a78c102..89f5dd606 100644 --- a/lib/pleroma/web/common_api.ex +++ b/lib/pleroma/web/common_api.ex @@ -415,7 +415,14 @@ defmodule Pleroma.Web.CommonAPI do defp make_update_data(user, orig_object, changes) do kept_params = %{ - visibility: Visibility.get_visibility(orig_object) + visibility: Visibility.get_visibility(orig_object), + in_reply_to_id: + with replied_id when is_binary(replied_id) <- orig_object.data["inReplyTo"], + %Activity{id: activity_id} <- Activity.get_create_by_object_ap_id(replied_id) do + activity_id + else + _ -> nil + end } params = Map.merge(changes, kept_params) -- cgit v1.2.3 From c1874bc8f943599383fe0a03f129d3113c1cf301 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Tue, 12 Jul 2022 19:03:18 -0400 Subject: Make mutes and blocks behave the same as other lists --- lib/pleroma/web/mastodon_api/controllers/account_controller.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex index 50c12a1b1..83d0f718d 100644 --- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex @@ -491,7 +491,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do users = user |> User.muted_users_relation(_restrict_deactivated = true) - |> Pleroma.Pagination.fetch_paginated(Map.put(params, :skip_order, true)) + |> Pleroma.Pagination.fetch_paginated(params) conn |> add_link_headers(users) @@ -508,7 +508,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do users = user |> User.blocked_users_relation(_restrict_deactivated = true) - |> Pleroma.Pagination.fetch_paginated(Map.put(params, :skip_order, true)) + |> Pleroma.Pagination.fetch_paginated(params) conn |> add_link_headers(users) -- cgit v1.2.3 From c045a49909c2a1078864484d0327e03dac73687b Mon Sep 17 00:00:00 2001 From: Ilja Date: Thu, 14 Jul 2022 08:40:26 +0200 Subject: Add privilege for announcements --- lib/pleroma/web/router.ex | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index e715aaa96..f77513046 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -170,6 +170,11 @@ defmodule Pleroma.Web.Router do plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :statistics_read) end + pipeline :require_privileged_role_announcements_manage_announcements do + plug(:admin_api) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :announcements_manage_announcements) + end + pipeline :pleroma_html do plug(:browser) plug(:authenticate) @@ -289,6 +294,11 @@ defmodule Pleroma.Web.Router do post("/frontends/install", FrontendController, :install) post("/backups", AdminAPIController, :create_backup) + end + + # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) + scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do + pipe_through(:require_privileged_role_announcements_manage_announcements) get("/announcements", AnnouncementController, :index) post("/announcements", AnnouncementController, :create) -- cgit v1.2.3 From 28626eafc174e6707ab4020f72a5550446730da9 Mon Sep 17 00:00:00 2001 From: floatingghost Date: Thu, 14 Jul 2022 13:35:33 +0200 Subject: Allow higher amount of restarts for Pleroma.Repo during testing This was done by floatingghost as part of a bigger commit in Akkoma. See . As explained in > there are so many caches that clearing them all can nuke the supervisor, which by default will become an hero if it gets more than 3 restarts in <5 seconds And further down the thread > essentially we've got like 11 caches (https://akkoma.dev/AkkomaGang/akkoma/src/commit/37ae047e1652c4089934434ec79f393c4c839122/lib/pleroma/application.ex#L165) > then in test we fetch them all (https://akkoma.dev/AkkomaGang/akkoma/src/branch/develop/test/support/data_case.ex#L50) and call clear on them > so if this clear fails on any 3 of them, the pleroma supervisor itself will die How it fails? > idk maybe cachex dies, maybe :ets does a weird thing > it doesn't log anything, it just consistently dies during cache clearing so i figured it had to be that > honestly my best bet is locksmith and queuing > https://github.com/whitfin/cachex/blob/master/lib/cachex/actions/clear.ex#L26 > clear is thrown into a locksmith transaction > locksmith says > >If the process is already in a transactional context, the provided function will be executed immediately. Otherwise the required keys will be locked until the provided function has finished executing. > so if we get 2 clears too close together, maybe it locks, then doesn't like the next clear? --- lib/pleroma/application.ex | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index d808bc732..ae3ef9738 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -112,7 +112,17 @@ defmodule Pleroma.Application do # See http://elixir-lang.org/docs/stable/elixir/Supervisor.html # for other strategies and supported options - opts = [strategy: :one_for_one, name: Pleroma.Supervisor] + # If we have a lot of caches, default max_restarts can cause test + # resets to fail. + # Go for the default 3 unless we're in test + max_restarts = + if @mix_env == :test do + 100 + else + 3 + end + + opts = [strategy: :one_for_one, name: Pleroma.Supervisor, max_restarts: max_restarts] result = Supervisor.start_link(children, opts) set_postgres_server_version() -- cgit v1.2.3 From 8371fd8ca20d7aaa16e082fd7ed39d603b9731d1 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sat, 16 Jul 2022 01:20:25 -0400 Subject: Implement settings api --- .../operations/pleroma_settings_operation.ex | 72 ++++++++++++++++++++ .../pleroma_api/controllers/settings_controller.ex | 79 ++++++++++++++++++++++ lib/pleroma/web/router.ex | 7 ++ 3 files changed, 158 insertions(+) create mode 100644 lib/pleroma/web/api_spec/operations/pleroma_settings_operation.ex create mode 100644 lib/pleroma/web/pleroma_api/controllers/settings_controller.ex (limited to 'lib') diff --git a/lib/pleroma/web/api_spec/operations/pleroma_settings_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_settings_operation.ex new file mode 100644 index 000000000..e2cef4f67 --- /dev/null +++ b/lib/pleroma/web/api_spec/operations/pleroma_settings_operation.ex @@ -0,0 +1,72 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ApiSpec.PleromaSettingsOperation do + alias OpenApiSpex.Operation + alias OpenApiSpex.Schema + + import Pleroma.Web.ApiSpec.Helpers + + def open_api_operation(action) do + operation = String.to_existing_atom("#{action}_operation") + apply(__MODULE__, operation, []) + end + + def show_operation do + %Operation{ + tags: ["Settings"], + summary: "Get settings for an application", + description: "Get synchronized settings for an application", + operationId: "SettingsController.show", + parameters: [app_name_param()], + security: [%{"oAuth" => ["read:accounts"]}], + responses: %{ + 200 => Operation.response("object", "application/json", object()) + } + } + end + + def update_operation do + %Operation{ + tags: ["Settings"], + summary: "Update settings for an application", + description: "Update synchronized settings for an application", + operationId: "SettingsController.update", + parameters: [app_name_param()], + security: [%{"oAuth" => ["write:accounts"]}], + requestBody: request_body("Parameters", update_request(), required: true), + responses: %{ + 200 => Operation.response("object", "application/json", object()) + } + } + end + + def app_name_param do + Operation.parameter(:app, :path, %Schema{type: :string}, "Application name", + example: "pleroma-fe", + required: true + ) + end + + def object do + %Schema{ + title: "Settings object", + description: "The object that contains settings for the application.", + type: :object + } + end + + def update_request do + %Schema{ + title: "SettingsUpdateRequest", + type: :object, + description: + "The settings object to be merged with the current settings. To remove a field, set it to null.", + example: %{ + "config1" => true, + "config2_to_unset" => nil + } + } + end +end diff --git a/lib/pleroma/web/pleroma_api/controllers/settings_controller.ex b/lib/pleroma/web/pleroma_api/controllers/settings_controller.ex new file mode 100644 index 000000000..1136575b6 --- /dev/null +++ b/lib/pleroma/web/pleroma_api/controllers/settings_controller.ex @@ -0,0 +1,79 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.PleromaAPI.SettingsController do + use Pleroma.Web, :controller + + alias Pleroma.Web.Plugs.OAuthScopesPlug + + plug(Pleroma.Web.ApiSpec.CastAndValidate) + + plug( + OAuthScopesPlug, + %{scopes: ["write:accounts"]} when action in [:update] + ) + + plug( + OAuthScopesPlug, + %{scopes: ["read:accounts"]} when action in [:show] + ) + + defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaSettingsOperation + + @doc "GET /api/v1/pleroma/settings/:app" + def show(%{assigns: %{user: user}} = conn, %{app: app} = _params) do + conn + |> json(get_settings(user, app)) + end + + @doc "PATCH /api/v1/pleroma/settings/:app" + def update(%{assigns: %{user: user}, body_params: body_params} = conn, %{app: app} = _params) do + settings = + get_settings(user, app) + |> merge_recursively(body_params) + + with changeset <- + Pleroma.User.update_changeset( + user, + %{pleroma_settings_store: %{app => settings}} + ), + {:ok, _} <- Pleroma.Repo.update(changeset) do + conn + |> json(settings) + end + end + + defp merge_recursively(old, %{} = new) do + old = ensure_object(old) + + Enum.reduce( + new, + old, + fn + {k, nil}, acc -> + Map.drop(acc, [k]) + + {k, %{} = new_child}, acc -> + Map.put(acc, k, merge_recursively(acc[k], new_child)) + + {k, v}, acc -> + Map.put(acc, k, v) + end + ) + end + + defp get_settings(user, app) do + user.pleroma_settings_store + |> Map.get(app, %{}) + |> ensure_object() + end + + defp ensure_object(%{} = object) do + object + end + + defp ensure_object(_) do + %{} + end +end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 7bbc20275..9023b9800 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -458,6 +458,13 @@ defmodule Pleroma.Web.Router do get("/birthdays", AccountController, :birthdays) end + scope [] do + pipe_through(:authenticated_api) + + get("/settings/:app", SettingsController, :show) + patch("/settings/:app", SettingsController, :update) + end + post("/accounts/confirmation_resend", AccountController, :confirmation_resend) end -- cgit v1.2.3 From eba9b0760f294482823b9bd55a430979fc2d21af Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sat, 23 Jul 2022 15:56:36 -0400 Subject: Make MRF Keyword history-aware --- lib/pleroma/object/updater.ex | 40 +++++++++++++++ lib/pleroma/web/activity_pub/mrf/keyword_policy.ex | 57 +++++++++++++++++----- 2 files changed, 84 insertions(+), 13 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/object/updater.ex b/lib/pleroma/object/updater.ex index 3d34c3f27..6381320bd 100644 --- a/lib/pleroma/object/updater.ex +++ b/lib/pleroma/object/updater.ex @@ -197,4 +197,44 @@ defmodule Pleroma.Object.Updater do used_history_in_new_object?: used_history_in_new_object? } end + + defp for_each_history_item(%{"orderedItems" => items} = history, _object, fun) do + new_items = + Enum.map(items, fun) + |> Enum.reduce_while( + {:ok, []}, + fn + {:ok, item}, {:ok, acc} -> {:cont, {:ok, acc ++ [item]}} + e, _acc -> {:halt, e} + end + ) + + case new_items do + {:ok, items} -> {:ok, Map.put(history, "orderedItems", items)} + e -> e + end + end + + defp for_each_history_item(history, _, _) do + {:ok, history} + end + + def do_with_history(object, fun) do + with history <- object["formerRepresentations"], + object <- Map.drop(object, ["formerRepresentations"]), + {_, {:ok, object}} <- {:main_body, fun.(object)}, + {_, {:ok, history}} <- {:history_items, for_each_history_item(history, object, fun)} do + object = + if history do + Map.put(object, "formerRepresentations", history) + else + object + end + + {:ok, object} + else + {:main_body, e} -> e + {:history_items, e} -> e + end + end end diff --git a/lib/pleroma/web/activity_pub/mrf/keyword_policy.ex b/lib/pleroma/web/activity_pub/mrf/keyword_policy.ex index 00b64744f..687ec6c2f 100644 --- a/lib/pleroma/web/activity_pub/mrf/keyword_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/keyword_policy.ex @@ -27,24 +27,46 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicy do end defp check_reject(%{"object" => %{} = object} = message) do - payload = object_payload(object) - - if Enum.any?(Pleroma.Config.get([:mrf_keyword, :reject]), fn pattern -> - string_matches?(payload, pattern) - end) do - {:reject, "[KeywordPolicy] Matches with rejected keyword"} - else + with {:ok, _new_object} <- + Pleroma.Object.Updater.do_with_history(object, fn object -> + payload = object_payload(object) + + if Enum.any?(Pleroma.Config.get([:mrf_keyword, :reject]), fn pattern -> + string_matches?(payload, pattern) + end) do + {:reject, "[KeywordPolicy] Matches with rejected keyword"} + else + {:ok, message} + end + end) do {:ok, message} + else + e -> e end end - defp check_ftl_removal(%{"to" => to, "object" => %{} = object} = message) do - payload = object_payload(object) + defp check_ftl_removal(%{"type" => "Create", "to" => to, "object" => %{} = object} = message) do + check_keyword = fn object -> + payload = object_payload(object) - if Pleroma.Constants.as_public() in to and - Enum.any?(Pleroma.Config.get([:mrf_keyword, :federated_timeline_removal]), fn pattern -> + if Enum.any?(Pleroma.Config.get([:mrf_keyword, :federated_timeline_removal]), fn pattern -> string_matches?(payload, pattern) end) do + {:should_delist, nil} + else + {:ok, %{}} + end + end + + should_delist? = fn object -> + with {:ok, _} <- Pleroma.Object.Updater.do_with_history(object, check_keyword) do + false + else + _ -> true + end + end + + if Pleroma.Constants.as_public() in to and should_delist?.(object) do to = List.delete(to, Pleroma.Constants.as_public()) cc = [Pleroma.Constants.as_public() | message["cc"] || []] @@ -59,8 +81,12 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicy do end end + defp check_ftl_removal(message) do + {:ok, message} + end + defp check_replace(%{"object" => %{} = object} = message) do - object = + replace_kw = fn object -> ["content", "name", "summary"] |> Enum.filter(fn field -> Map.has_key?(object, field) && object[field] end) |> Enum.reduce(object, fn field, object -> @@ -73,6 +99,10 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicy do Map.put(object, field, data) end) + |> (fn object -> {:ok, object} end).() + end + + {:ok, object} = Pleroma.Object.Updater.do_with_history(object, replace_kw) message = Map.put(message, "object", object) @@ -80,7 +110,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicy do end @impl true - def filter(%{"type" => "Create", "object" => %{"content" => _content}} = message) do + def filter(%{"type" => type, "object" => %{"content" => _content}} = message) + when type in ["Create", "Update"] do with {:ok, message} <- check_reject(message), {:ok, message} <- check_ftl_removal(message), {:ok, message} <- check_replace(message) do -- cgit v1.2.3 From cd19537f391b792ee67c728320801d5a247ceb2c Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sat, 23 Jul 2022 17:48:39 -0400 Subject: Make EnsureRePrepended history-aware --- lib/pleroma/object/updater.ex | 4 +- lib/pleroma/web/activity_pub/mrf.ex | 45 +++++++++++++++++++++- .../web/activity_pub/mrf/ensure_re_prepended.ex | 6 ++- lib/pleroma/web/activity_pub/mrf/policy.ex | 3 +- 4 files changed, 52 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/object/updater.ex b/lib/pleroma/object/updater.ex index 6381320bd..ab38d3ed2 100644 --- a/lib/pleroma/object/updater.ex +++ b/lib/pleroma/object/updater.ex @@ -198,7 +198,7 @@ defmodule Pleroma.Object.Updater do } end - defp for_each_history_item(%{"orderedItems" => items} = history, _object, fun) do + def for_each_history_item(%{"orderedItems" => items} = history, _object, fun) do new_items = Enum.map(items, fun) |> Enum.reduce_while( @@ -215,7 +215,7 @@ defmodule Pleroma.Object.Updater do end end - defp for_each_history_item(history, _, _) do + def for_each_history_item(history, _, _) do {:ok, history} end diff --git a/lib/pleroma/web/activity_pub/mrf.ex b/lib/pleroma/web/activity_pub/mrf.ex index 323ecdbf1..ff9f84497 100644 --- a/lib/pleroma/web/activity_pub/mrf.ex +++ b/lib/pleroma/web/activity_pub/mrf.ex @@ -53,10 +53,53 @@ defmodule Pleroma.Web.ActivityPub.MRF do @required_description_keys [:key, :related_policy] + def filter_one(policy, message) do + should_plug_history? = + if function_exported?(policy, :history_awareness, 0) do + policy.history_awareness() + else + :manual + end + |> Kernel.==(:auto) + + if not should_plug_history? do + policy.filter(message) + else + main_result = policy.filter(message) + + with {_, {:ok, main_message}} <- {:main, main_result}, + {_, + %{ + "formerRepresentations" => %{ + "orderedItems" => [_ | _] + } + }} = {_, object} <- {:object, message["object"]}, + {_, {:ok, new_history}} <- + {:history, + Pleroma.Object.Updater.for_each_history_item( + object["formerRepresentations"], + object, + fn item -> + with {:ok, filtered} <- policy.filter(Map.put(message, "object", item)) do + {:ok, filtered["object"]} + else + e -> e + end + end + )} do + {:ok, put_in(main_message, ["object", "formerRepresentations"], new_history)} + else + {:main, _} -> main_result + {:object, _} -> main_result + {:history, e} -> e + end + end + end + def filter(policies, %{} = message) do policies |> Enum.reduce({:ok, message}, fn - policy, {:ok, message} -> policy.filter(message) + policy, {:ok, message} -> filter_one(policy, message) _, error -> error end) end diff --git a/lib/pleroma/web/activity_pub/mrf/ensure_re_prepended.ex b/lib/pleroma/web/activity_pub/mrf/ensure_re_prepended.ex index 51596c09f..a148cc1e7 100644 --- a/lib/pleroma/web/activity_pub/mrf/ensure_re_prepended.ex +++ b/lib/pleroma/web/activity_pub/mrf/ensure_re_prepended.ex @@ -10,6 +10,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.EnsureRePrepended do @reply_prefix Regex.compile!("^re:[[:space:]]*", [:caseless]) + def history_awareness, do: :auto + def filter_by_summary( %{data: %{"summary" => parent_summary}} = _in_reply_to, %{"summary" => child_summary} = child @@ -27,8 +29,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.EnsureRePrepended do def filter_by_summary(_in_reply_to, child), do: child - def filter(%{"type" => "Create", "object" => child_object} = object) - when is_map(child_object) do + def filter(%{"type" => type, "object" => child_object} = object) + when type in ["Create", "Update"] and is_map(child_object) do child = child_object["inReplyTo"] |> Object.normalize(fetch: false) diff --git a/lib/pleroma/web/activity_pub/mrf/policy.ex b/lib/pleroma/web/activity_pub/mrf/policy.ex index 0ac250c3d..0234de4d5 100644 --- a/lib/pleroma/web/activity_pub/mrf/policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/policy.ex @@ -12,5 +12,6 @@ defmodule Pleroma.Web.ActivityPub.MRF.Policy do label: String.t(), description: String.t() } - @optional_callbacks config_description: 0 + @callback history_awareness() :: :auto | :manual + @optional_callbacks config_description: 0, history_awareness: 0 end -- cgit v1.2.3 From 0a337063e14a63b3ed80776b493e3c9c56dd95d1 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sat, 23 Jul 2022 22:23:57 -0400 Subject: Make ForceMentionsInContent history-aware --- lib/pleroma/web/activity_pub/mrf/force_mentions_in_content.ex | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/mrf/force_mentions_in_content.ex b/lib/pleroma/web/activity_pub/mrf/force_mentions_in_content.ex index 255910b2f..70224561c 100644 --- a/lib/pleroma/web/activity_pub/mrf/force_mentions_in_content.ex +++ b/lib/pleroma/web/activity_pub/mrf/force_mentions_in_content.ex @@ -11,6 +11,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.ForceMentionsInContent do @behaviour Pleroma.Web.ActivityPub.MRF.Policy + @impl true + def history_awareness, do: :auto + defp do_extract({:a, attrs, _}, acc) do if Enum.find(attrs, fn {name, value} -> name == "class" && value in ["mention", "u-url mention", "mention u-url"] @@ -74,11 +77,11 @@ defmodule Pleroma.Web.ActivityPub.MRF.ForceMentionsInContent do @impl true def filter( %{ - "type" => "Create", + "type" => type, "object" => %{"type" => "Note", "to" => to, "inReplyTo" => in_reply_to} } = object ) - when is_list(to) and is_binary(in_reply_to) do + when type in ["Create", "Update"] and is_list(to) and is_binary(in_reply_to) do # image-only posts from pleroma apparently reach this MRF without the content field content = object["object"]["content"] || "" -- cgit v1.2.3 From dce7e429286dfe8cb44a27c50713a03f0e696357 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sat, 23 Jul 2022 22:34:03 -0400 Subject: Make MediaProxyWarmingPolicy history-aware --- lib/pleroma/web/activity_pub/mrf/media_proxy_warming_policy.ex | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/mrf/media_proxy_warming_policy.ex b/lib/pleroma/web/activity_pub/mrf/media_proxy_warming_policy.ex index 0eac8f021..c95d35bb9 100644 --- a/lib/pleroma/web/activity_pub/mrf/media_proxy_warming_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/media_proxy_warming_policy.ex @@ -16,6 +16,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy do recv_timeout: 10_000 ] + @impl true + def history_awareness, do: :auto + defp prefetch(url) do # Fetching only proxiable resources if MediaProxy.enabled?() and MediaProxy.url_proxiable?(url) do @@ -54,10 +57,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy do end @impl true - def filter( - %{"type" => "Create", "object" => %{"attachment" => attachments} = _object} = message - ) - when is_list(attachments) and length(attachments) > 0 do + def filter(%{"type" => type, "object" => %{"attachment" => attachments} = _object} = message) + when type in ["Create", "Update"] and is_list(attachments) and length(attachments) > 0 do preload(message) {:ok, message} -- cgit v1.2.3 From fc7ce5f93c4031863cbaf62b72dce55b5b6b0390 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sat, 23 Jul 2022 22:41:04 -0400 Subject: Make NoPlaceholderTextPolicy history-aware --- lib/pleroma/web/activity_pub/mrf/no_placeholder_text_policy.ex | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/mrf/no_placeholder_text_policy.ex b/lib/pleroma/web/activity_pub/mrf/no_placeholder_text_policy.ex index aab647d8e..f81e9e52a 100644 --- a/lib/pleroma/web/activity_pub/mrf/no_placeholder_text_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/no_placeholder_text_policy.ex @@ -6,14 +6,17 @@ defmodule Pleroma.Web.ActivityPub.MRF.NoPlaceholderTextPolicy do @moduledoc "Ensure no content placeholder is present (such as the dot from mastodon)" @behaviour Pleroma.Web.ActivityPub.MRF.Policy + @impl true + def history_awareness, do: :auto + @impl true def filter( %{ - "type" => "Create", + "type" => type, "object" => %{"content" => content, "attachment" => _} = _child_object } = object ) - when content in [".", "

.

"] do + when type in ["Create", "Update"] and content in [".", "

.

"] do {:ok, put_in(object, ["object", "content"], "")} end -- cgit v1.2.3 From 46a5c06853c21e720b41a4b38a4d88a38a218ad4 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sat, 23 Jul 2022 22:50:38 -0400 Subject: Make NormalizeMarkup history-aware --- lib/pleroma/web/activity_pub/mrf/normalize_markup.ex | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/mrf/normalize_markup.ex b/lib/pleroma/web/activity_pub/mrf/normalize_markup.ex index dc2c19d49..2dfc9a901 100644 --- a/lib/pleroma/web/activity_pub/mrf/normalize_markup.ex +++ b/lib/pleroma/web/activity_pub/mrf/normalize_markup.ex @@ -9,7 +9,11 @@ defmodule Pleroma.Web.ActivityPub.MRF.NormalizeMarkup do @behaviour Pleroma.Web.ActivityPub.MRF.Policy @impl true - def filter(%{"type" => "Create", "object" => child_object} = object) do + def history_awareness, do: :auto + + @impl true + def filter(%{"type" => type, "object" => child_object} = object) + when type in ["Create", "Update"] do scrub_policy = Pleroma.Config.get([:mrf_normalize_markup, :scrub_policy]) content = -- cgit v1.2.3 From 82c8fc1ede26837d024ecc2fd1231c6d2a3c2c3e Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sat, 23 Jul 2022 23:24:25 -0400 Subject: Make NoEmptyPolicy work with Update --- lib/pleroma/web/activity_pub/mrf/no_empty_policy.ex | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/mrf/no_empty_policy.ex b/lib/pleroma/web/activity_pub/mrf/no_empty_policy.ex index 4dc96e068..855cda3b9 100644 --- a/lib/pleroma/web/activity_pub/mrf/no_empty_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/no_empty_policy.ex @@ -11,6 +11,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.NoEmptyPolicy do @impl true def filter(%{"actor" => actor} = object) do with true <- is_local?(actor), + true <- is_eligible_type?(object), true <- is_note?(object), false <- has_attachment?(object), true <- only_mentions?(object) do @@ -32,7 +33,6 @@ defmodule Pleroma.Web.ActivityPub.MRF.NoEmptyPolicy do end defp has_attachment?(%{ - "type" => "Create", "object" => %{"type" => "Note", "attachment" => attachments} }) when length(attachments) > 0, @@ -40,7 +40,13 @@ defmodule Pleroma.Web.ActivityPub.MRF.NoEmptyPolicy do defp has_attachment?(_), do: false - defp only_mentions?(%{"type" => "Create", "object" => %{"type" => "Note", "source" => source}}) do + defp only_mentions?(%{"object" => %{"type" => "Note", "source" => source}}) do + source = + case source do + %{"content" => text} -> text + _ -> source + end + non_mentions = source |> String.split() |> Enum.filter(&(not String.starts_with?(&1, "@"))) |> length @@ -53,9 +59,12 @@ defmodule Pleroma.Web.ActivityPub.MRF.NoEmptyPolicy do defp only_mentions?(_), do: false - defp is_note?(%{"type" => "Create", "object" => %{"type" => "Note"}}), do: true + defp is_note?(%{"object" => %{"type" => "Note"}}), do: true defp is_note?(_), do: false + defp is_eligible_type?(%{"type" => type}) when type in ["Create", "Update"], do: true + defp is_eligible_type?(_), do: false + @impl true def describe, do: {:ok, %{}} end -- cgit v1.2.3 From d877d2a4e7449e942b4d192f283824eebcade563 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sun, 24 Jul 2022 00:02:39 -0400 Subject: Make HashtagPolicy history-aware --- lib/pleroma/web/activity_pub/mrf/hashtag_policy.ex | 47 +++++++++++++++++----- 1 file changed, 37 insertions(+), 10 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/mrf/hashtag_policy.ex b/lib/pleroma/web/activity_pub/mrf/hashtag_policy.ex index 2142b7add..b73fd974c 100644 --- a/lib/pleroma/web/activity_pub/mrf/hashtag_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/hashtag_policy.ex @@ -16,6 +16,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.HashtagPolicy do @behaviour Pleroma.Web.ActivityPub.MRF.Policy + @impl true + def history_awareness, do: :manual + defp check_reject(message, hashtags) do if Enum.any?(Config.get([:mrf_hashtag, :reject]), fn match -> match in hashtags end) do {:reject, "[HashtagPolicy] Matches with rejected keyword"} @@ -47,22 +50,46 @@ defmodule Pleroma.Web.ActivityPub.MRF.HashtagPolicy do defp check_ftl_removal(message, _hashtags), do: {:ok, message} - defp check_sensitive(message, hashtags) do - if Enum.any?(Config.get([:mrf_hashtag, :sensitive]), fn match -> match in hashtags end) do - {:ok, Kernel.put_in(message, ["object", "sensitive"], true)} - else - {:ok, message} - end + defp check_sensitive(message) do + {:ok, new_object} = + Object.Updater.do_with_history(message["object"], fn object -> + hashtags = Object.hashtags(%Object{data: object}) + + if Enum.any?(Config.get([:mrf_hashtag, :sensitive]), fn match -> match in hashtags end) do + {:ok, Map.put(object, "sensitive", true)} + else + {:ok, object} + end + end) + + {:ok, Map.put(message, "object", new_object)} end @impl true - def filter(%{"type" => "Create", "object" => object} = message) do - hashtags = Object.hashtags(%Object{data: object}) + def filter(%{"type" => type, "object" => object} = message) when type in ["Create", "Update"] do + history_items = + with %{"formerRepresentations" => %{"orderedItems" => items}} <- object do + items + else + _ -> [] + end + + historical_hashtags = + Enum.reduce(history_items, [], fn item, acc -> + acc ++ Object.hashtags(%Object{data: item}) + end) + + hashtags = Object.hashtags(%Object{data: object}) ++ historical_hashtags if hashtags != [] do with {:ok, message} <- check_reject(message, hashtags), - {:ok, message} <- check_ftl_removal(message, hashtags), - {:ok, message} <- check_sensitive(message, hashtags) do + {:ok, message} <- + (if "type" == "Create" do + check_ftl_removal(message, hashtags) + else + {:ok, message} + end), + {:ok, message} <- check_sensitive(message) do {:ok, message} end else -- cgit v1.2.3 From 997f08b3500a983e8b27db9a6e4745582bb4763c Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sun, 24 Jul 2022 00:18:09 -0400 Subject: Make AntiLinkSpamPolicy history-aware --- lib/pleroma/web/activity_pub/mrf/anti_link_spam_policy.ex | 3 +++ 1 file changed, 3 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/mrf/anti_link_spam_policy.ex b/lib/pleroma/web/activity_pub/mrf/anti_link_spam_policy.ex index f0504ead4..3ec9c52ee 100644 --- a/lib/pleroma/web/activity_pub/mrf/anti_link_spam_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/anti_link_spam_policy.ex @@ -9,6 +9,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicy do require Logger + @impl true + def history_awareness, do: :auto + # has the user successfully posted before? defp old_user?(%User{} = u) do u.note_count > 0 || u.follower_count > 0 -- cgit v1.2.3 From 01d396585e428ea1ca7e21868d7303a0bd8ffd6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9l=C3=A8ne?= Date: Mon, 25 Jul 2022 16:20:12 +0200 Subject: Emoji: implement full-qualifier using combinations This implements fully_qualify_emoji/1, which will return the fully-qualified version of an emoji if it knows of one, or return the emoji unmodified if not. This code generates combinations per emoji: for each FE0F, all possible combinations of the character being removed or staying will be generated. This is made as an attempt to find all partially-qualified and unqualified versions of a fully-qualified emoji. I have found *no cases* for which this would be a problem, after browsing the entire emoji list in emoji-test.txt. This is safe, and, sadly, most likely the sanest too. --- lib/pleroma/emoji.ex | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/emoji.ex b/lib/pleroma/emoji.ex index 35f0da816..3726ef185 100644 --- a/lib/pleroma/emoji.ex +++ b/lib/pleroma/emoji.ex @@ -137,4 +137,49 @@ defmodule Pleroma.Emoji do end def is_unicode_emoji?(_), do: false + + # FE0F is the emoji variation sequence. It is used for fully-qualifying + # emoji, and that includes emoji combinations. + # This code generates combinations per emoji: for each FE0F, all possible + # combinations of the character being removed or staying will be generated. + # This is made as an attempt to find all partially-qualified and unqualified + # versions of a fully-qualified emoji. + # I have found *no cases* for which this would be a problem, after browsing + # the entire emoji list in emoji-test.txt. This is safe, and, sadly, most + # likely sane too. + emoji_qualification_map = + emojis + |> Enum.filter(&String.contains?(&1, "\uFE0F")) + |> Enum.map(fn emoji -> + combinate = fn x, combinate -> + case x do + [] -> + [[]] + + ["\uFE0F" | tail] -> + combinate.(tail, combinate) + |> Enum.flat_map(fn x -> [x, ["\uFE0F" | x]] end) + + [codepoint | tail] -> + combinate.(tail, combinate) + |> Enum.map(fn x -> [codepoint | x] end) + end + end + + unqualified_list = + emoji + |> String.codepoints() + |> combinate.(combinate) + |> Enum.map(&List.to_string/1) + + {emoji, unqualified_list} + end) + + for {qualified, unqualified_list} <- emoji_qualification_map do + for unqualified <- unqualified_list do + def fully_qualify_emoji(unquote(unqualified)), do: unquote(qualified) + end + end + + def fully_qualify_emoji(emoji), do: emoji end -- cgit v1.2.3 From fb3f6e1975fc44414af66377061bf30ceee9f9b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9l=C3=A8ne?= Date: Mon, 25 Jul 2022 16:49:23 +0200 Subject: EmojiReactValidator: use new qualification method --- .../web/activity_pub/object_validators/emoji_react_validator.ex | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/object_validators/emoji_react_validator.ex b/lib/pleroma/web/activity_pub/object_validators/emoji_react_validator.ex index 2eb4f6842..0858281e5 100644 --- a/lib/pleroma/web/activity_pub/object_validators/emoji_react_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/emoji_react_validator.ex @@ -63,8 +63,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do end defp fix_emoji_qualification(%{"content" => emoji} = data) do - # Emoji variation sequence - new_emoji = emoji <> "\uFE0F" + new_emoji = Pleroma.Emoji.fully_qualify_emoji(emoji) cond do Pleroma.Emoji.is_unicode_emoji?(emoji) -> -- cgit v1.2.3 From b99f5d61834ffd86f9e8aeca2b00c704f0a0467e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9l=C3=A8ne?= Date: Tue, 26 Jul 2022 01:38:59 +0200 Subject: Emoji: split qualification variation into a module --- lib/pleroma/emoji.ex | 35 ++------------------------------- lib/pleroma/emoji/combinations.ex | 41 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 33 deletions(-) create mode 100644 lib/pleroma/emoji/combinations.ex (limited to 'lib') diff --git a/lib/pleroma/emoji.ex b/lib/pleroma/emoji.ex index 3726ef185..dd65d56ae 100644 --- a/lib/pleroma/emoji.ex +++ b/lib/pleroma/emoji.ex @@ -9,6 +9,7 @@ defmodule Pleroma.Emoji do """ use GenServer + alias Pleroma.Emoji.Combinations alias Pleroma.Emoji.Loader require Logger @@ -138,42 +139,10 @@ defmodule Pleroma.Emoji do def is_unicode_emoji?(_), do: false - # FE0F is the emoji variation sequence. It is used for fully-qualifying - # emoji, and that includes emoji combinations. - # This code generates combinations per emoji: for each FE0F, all possible - # combinations of the character being removed or staying will be generated. - # This is made as an attempt to find all partially-qualified and unqualified - # versions of a fully-qualified emoji. - # I have found *no cases* for which this would be a problem, after browsing - # the entire emoji list in emoji-test.txt. This is safe, and, sadly, most - # likely sane too. emoji_qualification_map = emojis |> Enum.filter(&String.contains?(&1, "\uFE0F")) - |> Enum.map(fn emoji -> - combinate = fn x, combinate -> - case x do - [] -> - [[]] - - ["\uFE0F" | tail] -> - combinate.(tail, combinate) - |> Enum.flat_map(fn x -> [x, ["\uFE0F" | x]] end) - - [codepoint | tail] -> - combinate.(tail, combinate) - |> Enum.map(fn x -> [codepoint | x] end) - end - end - - unqualified_list = - emoji - |> String.codepoints() - |> combinate.(combinate) - |> Enum.map(&List.to_string/1) - - {emoji, unqualified_list} - end) + |> Combinations.variate_emoji_qualification() for {qualified, unqualified_list} <- emoji_qualification_map do for unqualified <- unqualified_list do diff --git a/lib/pleroma/emoji/combinations.ex b/lib/pleroma/emoji/combinations.ex new file mode 100644 index 000000000..c49466406 --- /dev/null +++ b/lib/pleroma/emoji/combinations.ex @@ -0,0 +1,41 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Emoji.Combinations do + # FE0F is the emoji variation sequence. It is used for fully-qualifying + # emoji, and that includes emoji combinations. + # This code generates combinations per emoji: for each FE0F, all possible + # combinations of the character being removed or staying will be generated. + # This is made as an attempt to find all partially-qualified and unqualified + # versions of a fully-qualified emoji. + # I have found *no cases* for which this would be a problem, after browsing + # the entire emoji list in emoji-test.txt. This is safe, and, sadly, most + # likely sane too. + + defp qualification_combinations([]), do: [[]] + + defp qualification_combinations(["\uFE0F" | tail]) do + tail + |> qualification_combinations() + |> Enum.flat_map(fn x -> [x, ["\uFE0F" | x]] end) + end + + defp qualification_combinations([codepoint | tail]) do + tail + |> qualification_combinations() + |> Enum.map(fn x -> [codepoint | x] end) + end + + def variate_emoji_qualification(emoji) when is_binary(emoji) do + emoji + |> String.codepoints() + |> qualification_combinations() + |> Enum.map(&List.to_string/1) + end + + def variate_emoji_qualification(emoji) when is_list(emoji) do + emoji + |> Enum.map(fn emoji -> {emoji, variate_emoji_qualification(emoji)} end) + end +end -- cgit v1.2.3 From 7167de592e3523459a1eb65d902085e828f962b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9l=C3=A8ne?= Date: Tue, 26 Jul 2022 23:15:09 +0200 Subject: Emoji: apply recommended tail call changes Behavior matches previous code. Co-authored-by: Tusooa Zhu --- lib/pleroma/emoji/combinations.ex | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/emoji/combinations.ex b/lib/pleroma/emoji/combinations.ex index c49466406..981c73596 100644 --- a/lib/pleroma/emoji/combinations.ex +++ b/lib/pleroma/emoji/combinations.ex @@ -13,18 +13,22 @@ defmodule Pleroma.Emoji.Combinations do # the entire emoji list in emoji-test.txt. This is safe, and, sadly, most # likely sane too. - defp qualification_combinations([]), do: [[]] + defp qualification_combinations(codepoints) do + qualification_combinations([[]], codepoints) + end - defp qualification_combinations(["\uFE0F" | tail]) do - tail - |> qualification_combinations() - |> Enum.flat_map(fn x -> [x, ["\uFE0F" | x]] end) + defp qualification_combinations(acc, []), do: acc + + defp qualification_combinations(acc, ["\uFE0F" | tail]) do + acc + |> Enum.flat_map(fn x -> [x, x ++ ["\uFE0F"]] end) + |> qualification_combinations(tail) end - defp qualification_combinations([codepoint | tail]) do - tail - |> qualification_combinations() - |> Enum.map(fn x -> [codepoint | x] end) + defp qualification_combinations(acc, [codepoint | tail]) do + acc + |> Enum.map(&Kernel.++(&1, [codepoint])) + |> qualification_combinations(tail) end def variate_emoji_qualification(emoji) when is_binary(emoji) do -- cgit v1.2.3 From 5d3d6a58f72888b8714605032b417091a8891bb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Sun, 31 Jul 2022 17:22:34 +0200 Subject: Use `duration` param for mute expiration duration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- lib/pleroma/user.ex | 8 ++++---- lib/pleroma/web/api_spec/operations/account_operation.ex | 15 +++++++++++++-- .../web/mastodon_api/controllers/account_controller.ex | 4 ++++ 3 files changed, 21 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 18699f0c8..870e8c457 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1480,12 +1480,12 @@ defmodule Pleroma.User do {:ok, list(UserRelationship.t())} | {:error, String.t()} def mute(%User{} = muter, %User{} = mutee, params \\ %{}) do notifications? = Map.get(params, :notifications, true) - expires_in = Map.get(params, :expires_in, 0) + duration = Map.get(params, :duration, 0) expires_at = - if expires_in > 0 do + if duration > 0 do DateTime.utc_now() - |> DateTime.add(expires_in) + |> DateTime.add(duration) else nil end @@ -1499,7 +1499,7 @@ defmodule Pleroma.User do expires_at )) || {:ok, nil} do - if expires_in > 0 do + if duration > 0 do Pleroma.Workers.MuteExpireWorker.enqueue( "unmute_user", %{"muter_id" => muter.id, "mutee_id" => mutee.id}, diff --git a/lib/pleroma/web/api_spec/operations/account_operation.ex b/lib/pleroma/web/api_spec/operations/account_operation.ex index 4111d1613..97616f5e7 100644 --- a/lib/pleroma/web/api_spec/operations/account_operation.ex +++ b/lib/pleroma/web/api_spec/operations/account_operation.ex @@ -278,11 +278,17 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do %Schema{allOf: [BooleanLike], default: true}, "Mute notifications in addition to statuses? Defaults to `true`." ), + Operation.parameter( + :duration, + :query, + %Schema{type: :integer}, + "Expire the mute in `duration` seconds. Default 0 for infinity" + ), Operation.parameter( :expires_in, :query, %Schema{type: :integer, default: 0}, - "Expire the mute in `expires_in` seconds. Default 0 for infinity" + "Deprecated, use `duration` instead" ) ], responses: %{ @@ -877,10 +883,15 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do description: "Mute notifications in addition to statuses? Defaults to true.", default: true }, + duration: %Schema{ + type: :integer, + nullable: true, + description: "Expire the mute in `expires_in` seconds. Default 0 for infinity" + }, expires_in: %Schema{ type: :integer, nullable: true, - description: "Expire the mute in `expires_in` seconds. Default 0 for infinity", + description: "Deprecated, use `duration` instead", default: 0 } }, diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex index 2aeb339f0..bf931dc6b 100644 --- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex @@ -411,6 +411,10 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do @doc "POST /api/v1/accounts/:id/mute" def mute(%{assigns: %{user: muter, account: muted}, body_params: params} = conn, _params) do + params = + params + |> Map.put_new(:duration, Map.get(params, :expires_in, 0)) + with {:ok, _user_relationships} <- User.mute(muter, muted, params) do render(conn, "relationship.json", user: muter, target: muted) else -- cgit v1.2.3 From a4fa286d200b4f0c0ac9f453eb3e0a0526560a20 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Tue, 2 Aug 2022 10:15:56 -0400 Subject: Use actor_types() to determine whether the Update is for user --- lib/pleroma/web/activity_pub/side_effects.ex | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/side_effects.ex b/lib/pleroma/web/activity_pub/side_effects.ex index f56e357bf..5eefd2824 100644 --- a/lib/pleroma/web/activity_pub/side_effects.ex +++ b/lib/pleroma/web/activity_pub/side_effects.ex @@ -163,8 +163,9 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do updated_object_id = updated_object["id"] with {_, true} <- {:has_id, is_binary(updated_object_id)}, - {_, user} <- {:user, Pleroma.User.get_by_ap_id(updated_object_id)} do - if user do + %{"type" => type} <- updated_object, + {_, is_user} <- {:is_user, type in Pleroma.Constants.actor_types()} do + if is_user do handle_update_user(object, meta) else handle_update_object(object, meta) -- cgit v1.2.3 From f2a9285ff089fbae043091898fb016f4aa16f689 Mon Sep 17 00:00:00 2001 From: floatingghost Date: Sat, 23 Jul 2022 18:58:45 +0000 Subject: bugfix/follow-state (#104) Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/104 --- lib/mix/tasks/pleroma/user.ex | 32 ++++++++++++++++++++++++++++++++ lib/pleroma/user.ex | 8 +++++++- 2 files changed, 39 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index 96d4eb90b..50ffb7f27 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -421,6 +421,38 @@ defmodule Mix.Tasks.Pleroma.User do |> Stream.run() end + def run(["fix_follow_state", local_user, remote_user]) do + start_pleroma() + + with {:local, %User{} = local} <- {:local, User.get_by_nickname(local_user)}, + {:remote, %User{} = remote} <- {:remote, User.get_by_nickname(remote_user)}, + {:follow_data, %{data: %{"state" => request_state}}} <- + {:follow_data, Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(local, remote)} do + calculated_state = User.following?(local, remote) + + shell_info( + "Request state is #{request_state}, vs calculated state of following=#{calculated_state}" + ) + + if calculated_state == false && request_state == "accept" do + shell_info("Discrepancy found, fixing") + Pleroma.Web.CommonAPI.reject_follow_request(local, remote) + shell_info("Relationship fixed") + else + shell_info("No discrepancy found") + end + else + {:local, _} -> + shell_error("No local user #{local_user}") + + {:remote, _} -> + shell_error("No remote user #{remote_user}") + + {:follow_data, _} -> + shell_error("No follow data for #{local_user} and #{remote_user}") + end + end + defp set_moderator(user, value) do {:ok, user} = user diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index eeea240fb..a57295891 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1574,13 +1574,19 @@ defmodule Pleroma.User do blocker end - # clear any requested follows as well + # clear any requested follows from both sides as well blocked = case CommonAPI.reject_follow_request(blocked, blocker) do {:ok, %User{} = updated_blocked} -> updated_blocked nil -> blocked end + blocker = + case CommonAPI.reject_follow_request(blocker, blocked) do + {:ok, %User{} = updated_blocker} -> updated_blocker + nil -> blocker + end + unsubscribe(blocked, blocker) unfollowing_blocked = Config.get([:activitypub, :unfollow_blocked], true) -- cgit v1.2.3 From a0166e92fac596651ecaad78659a0f6907ccb6bd Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sat, 6 Aug 2022 00:31:36 -0400 Subject: Treat MRF rejects as success in Oban worker --- lib/pleroma/workers/receiver_worker.ex | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/workers/receiver_worker.ex b/lib/pleroma/workers/receiver_worker.ex index 268b5f30f..309e197dc 100644 --- a/lib/pleroma/workers/receiver_worker.ex +++ b/lib/pleroma/workers/receiver_worker.ex @@ -9,6 +9,11 @@ defmodule Pleroma.Workers.ReceiverWorker do @impl Oban.Worker def perform(%Job{args: %{"op" => "incoming_ap_doc", "params" => params}}) do - Federator.perform(:incoming_ap_doc, params) + with {:ok, res} <- Federator.perform(:incoming_ap_doc, params) do + {:ok, res} + else + {:error, {:reject, reason}} -> {:cancel, reason} + e -> e + end end end -- cgit v1.2.3 From d487e0160cdc4cdf84c45e4c64f6589b317479cc Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Mon, 8 Aug 2022 08:41:33 -0400 Subject: Treat containment failure as cancel in ReceiverWorker --- lib/pleroma/workers/receiver_worker.ex | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/pleroma/workers/receiver_worker.ex b/lib/pleroma/workers/receiver_worker.ex index 309e197dc..c41b44e14 100644 --- a/lib/pleroma/workers/receiver_worker.ex +++ b/lib/pleroma/workers/receiver_worker.ex @@ -12,6 +12,7 @@ defmodule Pleroma.Workers.ReceiverWorker do with {:ok, res} <- Federator.perform(:incoming_ap_doc, params) do {:ok, res} else + {:error, :origin_containment_failed} -> {:cancel, :origin_containment_failed} {:error, {:reject, reason}} -> {:cancel, reason} e -> e end -- cgit v1.2.3 From a7f01ffc1d0795f65b34b6dd9337d665f27edff9 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Tue, 9 Aug 2022 00:34:04 -0400 Subject: Make backups require its own scope --- lib/pleroma/web/pleroma_api/controllers/backup_controller.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/pleroma_api/controllers/backup_controller.ex b/lib/pleroma/web/pleroma_api/controllers/backup_controller.ex index 1a0548295..b9daed22b 100644 --- a/lib/pleroma/web/pleroma_api/controllers/backup_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/backup_controller.ex @@ -9,7 +9,7 @@ defmodule Pleroma.Web.PleromaAPI.BackupController do alias Pleroma.Web.Plugs.OAuthScopesPlug action_fallback(Pleroma.Web.MastodonAPI.FallbackController) - plug(OAuthScopesPlug, %{scopes: ["read:accounts"]} when action in [:index, :create]) + plug(OAuthScopesPlug, %{scopes: ["read:backups"]} when action in [:index, :create]) plug(Pleroma.Web.ApiSpec.CastAndValidate) defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaBackupOperation -- cgit v1.2.3 From f3e061c9645571997a01b1091d0e8a3f68c6bb21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9l=C3=A8ne?= Date: Sat, 6 Aug 2022 03:24:31 +0200 Subject: Object: remove context_id field 30 to 70% of the objects in the object table are simple JSON objects containing a single field, 'id', being the context's ID. The reason for the creation of an object per context seems to be an old relic from the StatusNet era, and has only been used nowadays as an helper for threads in Pleroma-FE via the `pleroma.conversation_id` field in status views. An object per context was created, and its numerical ID (table column) was used and stored as 'context_id' in the object and activity along with the full 'context' URI/string. This commit removes this field and stops creation of objects for each context, which will also allow incoming activities to use activity IDs as contexts, something which was not possible before, or would have been very broken under most circumstances. The `pleroma.conversation_id` field has been reimplemented in a way to maintain backwards-compatibility by calculating a CRC32 of the full context URI/string in the object, instead of relying on the row ID for the created context object. --- lib/pleroma/object.ex | 4 --- .../article_note_page_validator.ex | 2 +- .../activity_pub/object_validators/common_fixes.ex | 4 +-- .../object_validators/event_validator.ex | 2 +- .../object_validators/question_validator.ex | 2 +- lib/pleroma/web/activity_pub/utils.ex | 23 ++--------------- lib/pleroma/web/common_api/utils.ex | 29 ---------------------- lib/pleroma/web/mastodon_api/views/status_view.ex | 2 +- 8 files changed, 7 insertions(+), 61 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index fe264b5e0..c214a79c5 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -208,10 +208,6 @@ defmodule Pleroma.Object do end end - def context_mapping(context) do - Object.change(%Object{}, %{data: %{"id" => context}}) - end - def make_tombstone(%Object{data: %{"id" => id, "type" => type}}, deleted \\ DateTime.utc_now()) do %ObjectTombstone{ id: id, diff --git a/lib/pleroma/web/activity_pub/object_validators/article_note_page_validator.ex b/lib/pleroma/web/activity_pub/object_validators/article_note_page_validator.ex index 57c8d1dc0..c5fb94034 100644 --- a/lib/pleroma/web/activity_pub/object_validators/article_note_page_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/article_note_page_validator.ex @@ -94,7 +94,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidator do defp validate_data(data_cng) do data_cng |> validate_inclusion(:type, ["Article", "Note", "Page"]) - |> validate_required([:id, :actor, :attributedTo, :type, :context, :context_id]) + |> validate_required([:id, :actor, :attributedTo, :type, :context]) |> CommonValidations.validate_any_presence([:cc, :to]) |> CommonValidations.validate_fields_match([:actor, :attributedTo]) |> CommonValidations.validate_actor_presence() diff --git a/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex b/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex index 4f8c083eb..c7e292bec 100644 --- a/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex +++ b/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex @@ -22,14 +22,12 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do end def fix_object_defaults(data) do - %{data: %{"id" => context}, id: context_id} = - Utils.create_context(data["context"] || data["conversation"]) + context = Utils.maybe_create_context(data["context"] || data["conversation"]) %User{follower_address: follower_collection} = User.get_cached_by_ap_id(data["attributedTo"]) data |> Map.put("context", context) - |> Map.put("context_id", context_id) |> cast_and_filter_recipients("to", follower_collection) |> cast_and_filter_recipients("cc", follower_collection) |> cast_and_filter_recipients("bto", follower_collection) diff --git a/lib/pleroma/web/activity_pub/object_validators/event_validator.ex b/lib/pleroma/web/activity_pub/object_validators/event_validator.ex index 0e99f2037..ab204f69a 100644 --- a/lib/pleroma/web/activity_pub/object_validators/event_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/event_validator.ex @@ -62,7 +62,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EventValidator do defp validate_data(data_cng) do data_cng |> validate_inclusion(:type, ["Event"]) - |> validate_required([:id, :actor, :attributedTo, :type, :context, :context_id]) + |> validate_required([:id, :actor, :attributedTo, :type, :context]) |> CommonValidations.validate_any_presence([:cc, :to]) |> CommonValidations.validate_fields_match([:actor, :attributedTo]) |> CommonValidations.validate_actor_presence() diff --git a/lib/pleroma/web/activity_pub/object_validators/question_validator.ex b/lib/pleroma/web/activity_pub/object_validators/question_validator.ex index 9412be4bc..ce3305142 100644 --- a/lib/pleroma/web/activity_pub/object_validators/question_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/question_validator.ex @@ -80,7 +80,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.QuestionValidator do defp validate_data(data_cng) do data_cng |> validate_inclusion(:type, ["Question"]) - |> validate_required([:id, :actor, :attributedTo, :type, :context, :context_id]) + |> validate_required([:id, :actor, :attributedTo, :type, :context]) |> CommonValidations.validate_any_presence([:cc, :to]) |> CommonValidations.validate_fields_match([:actor, :attributedTo]) |> CommonValidations.validate_actor_presence() diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 9cde7805c..d3b7d804f 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -154,22 +154,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do Notification.get_notified_from_activity(%Activity{data: object}, false) end - def create_context(context) do - context = context || generate_id("contexts") - - # Ecto has problems accessing the constraint inside the jsonb, - # so we explicitly check for the existed object before insert - object = Object.get_cached_by_ap_id(context) - - with true <- is_nil(object), - changeset <- Object.context_mapping(context), - {:ok, inserted_object} <- Repo.insert(changeset) do - inserted_object - else - _ -> - object - end - end + def maybe_create_context(context), do: context || generate_id("contexts") @doc """ Enqueues an activity for federation if it's local @@ -201,18 +186,16 @@ defmodule Pleroma.Web.ActivityPub.Utils do |> Map.put_new("id", "pleroma:fakeid") |> Map.put_new_lazy("published", &make_date/0) |> Map.put_new("context", "pleroma:fakecontext") - |> Map.put_new("context_id", -1) |> lazy_put_object_defaults(true) end def lazy_put_activity_defaults(map, _fake?) do - %{data: %{"id" => context}, id: context_id} = create_context(map["context"]) + context = maybe_create_context(map["context"]) map |> Map.put_new_lazy("id", &generate_activity_id/0) |> Map.put_new_lazy("published", &make_date/0) |> Map.put_new("context", context) - |> Map.put_new("context_id", context_id) |> lazy_put_object_defaults(false) end @@ -226,7 +209,6 @@ defmodule Pleroma.Web.ActivityPub.Utils do |> Map.put_new("id", "pleroma:fake_object_id") |> Map.put_new_lazy("published", &make_date/0) |> Map.put_new("context", activity["context"]) - |> Map.put_new("context_id", activity["context_id"]) |> Map.put_new("fake", true) %{activity | "object" => object} @@ -239,7 +221,6 @@ defmodule Pleroma.Web.ActivityPub.Utils do |> Map.put_new_lazy("id", &generate_object_id/0) |> Map.put_new_lazy("published", &make_date/0) |> Map.put_new("context", activity["context"]) - |> Map.put_new("context_id", activity["context_id"]) %{activity | "object" => object} end diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index ce850b038..052bd7770 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -449,35 +449,6 @@ defmodule Pleroma.Web.CommonAPI.Utils do def get_report_statuses(_, _), do: {:ok, nil} - # DEPRECATED mostly, context objects are now created at insertion time. - def context_to_conversation_id(context) do - with %Object{id: id} <- Object.get_cached_by_ap_id(context) do - id - else - _e -> - changeset = Object.context_mapping(context) - - case Repo.insert(changeset) do - {:ok, %{id: id}} -> - id - - # This should be solved by an upsert, but it seems ecto - # has problems accessing the constraint inside the jsonb. - {:error, _} -> - Object.get_cached_by_ap_id(context).id - end - end - end - - def conversation_id_to_context(id) do - with %Object{data: %{"id" => context}} <- Repo.get(Object, id) do - context - else - _e -> - {:error, dgettext("errors", "No such conversation")} - end - end - def validate_character_limit("" = _full_payload, [] = _attachments) do {:error, dgettext("errors", "Cannot post an empty status without attachments")} end diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index 1ebfd6740..31a0c420f 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -61,7 +61,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do do: context_id defp get_context_id(%{data: %{"context" => context}}) when is_binary(context), - do: Utils.context_to_conversation_id(context) + do: :erlang.crc32(context) defp get_context_id(_), do: nil -- cgit v1.2.3 From 7f71e3d0fe347920834be8c8e28d9c7f5b169e9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9l=C3=A8ne?= Date: Sat, 6 Aug 2022 03:32:58 +0200 Subject: CommonFields: remove context_id --- lib/pleroma/web/activity_pub/object_validators/common_fields.ex | 2 -- lib/pleroma/web/mastodon_api/views/status_view.ex | 3 --- 2 files changed, 5 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/object_validators/common_fields.ex b/lib/pleroma/web/activity_pub/object_validators/common_fields.ex index 8e768ffbf..095bd0da2 100644 --- a/lib/pleroma/web/activity_pub/object_validators/common_fields.ex +++ b/lib/pleroma/web/activity_pub/object_validators/common_fields.ex @@ -51,8 +51,6 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFields do field(:summary, :string) field(:context, :string) - # short identifier for PleromaFE to group statuses by context - field(:context_id, :integer) field(:sensitive, :boolean, default: false) field(:replies_count, :integer, default: 0) diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index 31a0c420f..3ffe55c5d 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -57,9 +57,6 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do end) end - defp get_context_id(%{data: %{"context_id" => context_id}}) when not is_nil(context_id), - do: context_id - defp get_context_id(%{data: %{"context" => context}}) when is_binary(context), do: :erlang.crc32(context) -- cgit v1.2.3 From a9111bcaf2ba2371a1021dc171dab50615a4c040 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9l=C3=A8ne?= Date: Sun, 7 Aug 2022 20:37:17 +0200 Subject: StatusView: clear MSB on calculated conversation_id This field seems to be a left-over from the StatusNet era. If your application uses `pleroma.conversation_id`: this field is deprecated. It is currently stubbed instead by doing a CRC32 of the context, and clearing the MSB to avoid overflow exceptions with signed integers on the different clients using this field (Java/Kotlin code, mostly; see Husky and probably other mobile clients.) This should be removed in a future version of Pleroma. Pleroma-FE currently depends on this field, as well. --- lib/pleroma/web/mastodon_api/views/status_view.ex | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index 3ffe55c5d..5cb524f56 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -57,8 +57,19 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do end) end - defp get_context_id(%{data: %{"context" => context}}) when is_binary(context), - do: :erlang.crc32(context) + # DEPRECATED This field seems to be a left-over from the StatusNet era. + # If your application uses `pleroma.conversation_id`: this field is deprecated. + # It is currently stubbed instead by doing a CRC32 of the context, and + # clearing the MSB to avoid overflow exceptions with signed integers on the + # different clients using this field (Java/Kotlin code, mostly; see Husky.) + # This should be removed in a future version of Pleroma. Pleroma-FE currently + # depends on this field, as well. + defp get_context_id(%{data: %{"context" => context}}) when is_binary(context) do + use Bitwise + + :erlang.crc32(context) + |> band(bnot(0x8000_0000)) + end defp get_context_id(_), do: nil -- cgit v1.2.3 From 738ca484fd812d3fc027d4c3037d307c61fa24ca Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Tue, 9 Aug 2022 18:15:25 -0400 Subject: Update api spec to reflect OAuth scope change --- lib/pleroma/web/api_spec/operations/pleroma_backup_operation.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/api_spec/operations/pleroma_backup_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_backup_operation.ex index 82ec1e7bb..45fa2b058 100644 --- a/lib/pleroma/web/api_spec/operations/pleroma_backup_operation.ex +++ b/lib/pleroma/web/api_spec/operations/pleroma_backup_operation.ex @@ -16,7 +16,7 @@ defmodule Pleroma.Web.ApiSpec.PleromaBackupOperation do %Operation{ tags: ["Backups"], summary: "List backups", - security: [%{"oAuth" => ["read:account"]}], + security: [%{"oAuth" => ["read:backups"]}], operationId: "PleromaAPI.BackupController.index", responses: %{ 200 => @@ -37,7 +37,7 @@ defmodule Pleroma.Web.ApiSpec.PleromaBackupOperation do %Operation{ tags: ["Backups"], summary: "Create a backup", - security: [%{"oAuth" => ["read:account"]}], + security: [%{"oAuth" => ["read:backups"]}], operationId: "PleromaAPI.BackupController.create", responses: %{ 200 => -- cgit v1.2.3 From def0f5dc2e76b7c4ac22b393abf7f5de5e197659 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9l=C3=A8ne?= Date: Sun, 7 Aug 2022 20:39:35 +0200 Subject: StatusView: implement pleroma.context field This field replaces the now deprecated conversation_id field, and now exposes the ActivityPub object `context` directly via the MastoAPI instead of relying on StatusNet-era data concepts. --- lib/pleroma/web/api_spec/schemas/status.ex | 9 ++++++++- lib/pleroma/web/mastodon_api/views/status_view.ex | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/api_spec/schemas/status.ex b/lib/pleroma/web/api_spec/schemas/status.ex index 6e6e30315..8c19a9d9f 100644 --- a/lib/pleroma/web/api_spec/schemas/status.ex +++ b/lib/pleroma/web/api_spec/schemas/status.ex @@ -142,9 +142,15 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Status do description: "A map consisting of alternate representations of the `content` property with the key being it's mimetype. Currently the only alternate representation supported is `text/plain`" }, + context: %Schema{ + type: :string, + description: "The thread identifier the status is associated with" + }, conversation_id: %Schema{ type: :integer, - description: "The ID of the AP context the status is associated with (if any)" + deprecated: true, + description: + "The ID of the AP context the status is associated with (if any); deprecated, please use `context` instead" }, direct_conversation_id: %Schema{ type: :integer, @@ -319,6 +325,7 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Status do "pinned" => false, "pleroma" => %{ "content" => %{"text/plain" => "foobar"}, + "context" => "http://localhost:4001/objects/8b4c0c80-6a37-4d2a-b1b9-05a19e3875aa", "conversation_id" => 345_972, "direct_conversation_id" => nil, "emoji_reactions" => [], diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index 5cb524f56..a4d6cd807 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -375,6 +375,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do pleroma: %{ local: activity.local, conversation_id: get_context_id(activity), + context: object.data["context"], in_reply_to_account_acct: reply_to_user && reply_to_user.nickname, content: %{"text/plain" => content_plaintext}, spoiler_text: %{"text/plain" => summary}, -- cgit v1.2.3 From 3b6784b1de8454ab8c009ac688f6c62039117742 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9l=C3=A8ne?= Date: Tue, 2 Aug 2022 17:30:36 +0200 Subject: CreateGenericValidator: fix reply context fixing Incoming Pleroma replies to a Misskey thread were rejected due to a broken context fix, which caused them to not be visible until a non-Pleroma user interacted with the replies. This fix properly sets the post-fix object context to its parent Create activity as well, if it was changed. --- .../web/activity_pub/object_validators/create_generic_validator.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/object_validators/create_generic_validator.ex b/lib/pleroma/web/activity_pub/object_validators/create_generic_validator.ex index c9a621cb1..2395abfd4 100644 --- a/lib/pleroma/web/activity_pub/object_validators/create_generic_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/create_generic_validator.ex @@ -75,7 +75,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CreateGenericValidator do data |> CommonFixes.fix_actor() - |> Map.put_new("context", object["context"]) + |> Map.put("context", object["context"]) |> fix_addressing(object) end -- cgit v1.2.3 From cbdc13b76710e854c96f504526aff9da83b90ce5 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Wed, 10 Aug 2022 17:09:58 -0400 Subject: Fix Varnish 7 support by ensuring Media Preview Proxy fetches headers with a capitalized HEAD verb --- lib/pleroma/web/media_proxy/media_proxy_controller.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/media_proxy/media_proxy_controller.ex b/lib/pleroma/web/media_proxy/media_proxy_controller.ex index 3d6716d43..d2ad62c13 100644 --- a/lib/pleroma/web/media_proxy/media_proxy_controller.ex +++ b/lib/pleroma/web/media_proxy/media_proxy_controller.ex @@ -54,7 +54,7 @@ defmodule Pleroma.Web.MediaProxy.MediaProxyController do media_proxy_url = MediaProxy.url(url) with {:ok, %{status: status} = head_response} when status in 200..299 <- - Pleroma.HTTP.request("head", media_proxy_url, [], [], pool: :media) do + Pleroma.HTTP.request("HEAD", media_proxy_url, [], [], pool: :media) do content_type = Tesla.get_header(head_response, "content-type") content_length = Tesla.get_header(head_response, "content-length") content_length = content_length && String.to_integer(content_length) -- cgit v1.2.3 From bb02ee99f58e378e33162211f41fe5979d5da8ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9l=C3=A8ne?= Date: Wed, 10 Aug 2022 04:21:28 +0200 Subject: CommonFixes: more predictable context generation `context` fields for objects and activities can now be generated based on the object/activity `inReplyTo` field or its ActivityPub ID, as a fallback method in cases where `context` fields are missing for incoming activities and objects. --- lib/pleroma/web/activity_pub/object_validators/common_fixes.ex | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex b/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex index c7e292bec..add46d561 100644 --- a/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex +++ b/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex @@ -22,7 +22,10 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do end def fix_object_defaults(data) do - context = Utils.maybe_create_context(data["context"] || data["conversation"]) + context = + Utils.maybe_create_context( + data["context"] || data["conversation"] || data["inReplyTo"] || data["id"] + ) %User{follower_address: follower_collection} = User.get_cached_by_ap_id(data["attributedTo"]) -- cgit v1.2.3 From 88c1c76d3eca3412d1e02008f1b8d96fe8fe0b96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9l=C3=A8ne?= Date: Mon, 15 Aug 2022 01:15:23 +0200 Subject: Migrations: delete contexts with BaseMigrator Due to the lengthiness of this task, the migration has been adapted into a BaseMigrator migration, running in the background instead. --- lib/pleroma/application.ex | 3 +- lib/pleroma/data_migration.ex | 1 + .../migrators/context_objects_deletion_migrator.ex | 139 +++++++++++++++++++++ 3 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 lib/pleroma/migrators/context_objects_deletion_migrator.ex (limited to 'lib') diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index d808bc732..c546713ca 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -238,7 +238,8 @@ defmodule Pleroma.Application do defp background_migrators do [ - Pleroma.Migrators.HashtagsTableMigrator + Pleroma.Migrators.HashtagsTableMigrator, + Pleroma.Migrators.ContextObjectsDeletionMigrator ] end diff --git a/lib/pleroma/data_migration.ex b/lib/pleroma/data_migration.ex index 59d891d8d..8451678fc 100644 --- a/lib/pleroma/data_migration.ex +++ b/lib/pleroma/data_migration.ex @@ -42,4 +42,5 @@ defmodule Pleroma.DataMigration do end def populate_hashtags_table, do: get_by_name("populate_hashtags_table") + def delete_context_objects, do: get_by_name("delete_context_objects") end diff --git a/lib/pleroma/migrators/context_objects_deletion_migrator.ex b/lib/pleroma/migrators/context_objects_deletion_migrator.ex new file mode 100644 index 000000000..fb224795a --- /dev/null +++ b/lib/pleroma/migrators/context_objects_deletion_migrator.ex @@ -0,0 +1,139 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Migrators.ContextObjectsDeletionMigrator do + defmodule State do + use Pleroma.Migrators.Support.BaseMigratorState + + @impl Pleroma.Migrators.Support.BaseMigratorState + defdelegate data_migration(), to: Pleroma.DataMigration, as: :delete_context_objects + end + + use Pleroma.Migrators.Support.BaseMigrator + + alias Pleroma.Migrators.Support.BaseMigrator + alias Pleroma.Object + + @doc "This migration removes objects created exclusively for contexts, containing only an `id` field." + + @impl BaseMigrator + def feature_config_path, do: [:features, :delete_context_objects] + + @impl BaseMigrator + def fault_rate_allowance, do: Config.get([:delete_context_objects, :fault_rate_allowance], 0) + + @impl BaseMigrator + def perform do + data_migration_id = data_migration_id() + max_processed_id = get_stat(:max_processed_id, 0) + + Logger.info("Deleting context objects from `objects` (from oid: #{max_processed_id})...") + + query() + |> where([object], object.id > ^max_processed_id) + |> Repo.chunk_stream(100, :batches, timeout: :infinity) + |> Stream.each(fn objects -> + object_ids = Enum.map(objects, & &1.id) + + results = Enum.map(object_ids, &delete_context_object(&1)) + + failed_ids = + results + |> Enum.filter(&(elem(&1, 0) == :error)) + |> Enum.map(&elem(&1, 1)) + + chunk_affected_count = + results + |> Enum.filter(&(elem(&1, 0) == :ok)) + |> length() + + for failed_id <- failed_ids do + _ = + Repo.query( + "INSERT INTO data_migration_failed_ids(data_migration_id, record_id) " <> + "VALUES ($1, $2) ON CONFLICT DO NOTHING;", + [data_migration_id, failed_id] + ) + end + + _ = + Repo.query( + "DELETE FROM data_migration_failed_ids " <> + "WHERE data_migration_id = $1 AND record_id = ANY($2)", + [data_migration_id, object_ids -- failed_ids] + ) + + max_object_id = Enum.at(object_ids, -1) + + put_stat(:max_processed_id, max_object_id) + increment_stat(:iteration_processed_count, length(object_ids)) + increment_stat(:processed_count, length(object_ids)) + increment_stat(:failed_count, length(failed_ids)) + increment_stat(:affected_count, chunk_affected_count) + put_stat(:records_per_second, records_per_second()) + persist_state() + + # A quick and dirty approach to controlling the load this background migration imposes + sleep_interval = Config.get([:delete_context_objects, :sleep_interval_ms], 0) + Process.sleep(sleep_interval) + end) + |> Stream.run() + end + + @impl BaseMigrator + def query do + # Context objects have no activity type, and only one field, `id`. + # Only those context objects are without types. + from( + object in Object, + where: fragment("(?)->'type' IS NULL", object.data), + select: %{ + id: object.id + } + ) + end + + @spec delete_context_object(integer()) :: {:ok | :error, integer()} + defp delete_context_object(id) do + result = + %Object{id: id} + |> Repo.delete() + |> elem(0) + + {result, id} + end + + @impl BaseMigrator + def retry_failed do + data_migration_id = data_migration_id() + + failed_objects_query() + |> Repo.chunk_stream(100, :one) + |> Stream.each(fn object -> + with {res, _} when res != :error <- delete_context_object(object.id) do + _ = + Repo.query( + "DELETE FROM data_migration_failed_ids " <> + "WHERE data_migration_id = $1 AND record_id = $2", + [data_migration_id, object.id] + ) + end + end) + |> Stream.run() + + put_stat(:failed_count, failures_count()) + persist_state() + + force_continue() + end + + defp failed_objects_query do + from(o in Object) + |> join(:inner, [o], dmf in fragment("SELECT * FROM data_migration_failed_ids"), + on: dmf.record_id == o.id + ) + |> where([_o, dmf], dmf.data_migration_id == ^data_migration_id()) + |> order_by([o], asc: o.id) + end +end -- cgit v1.2.3 From f41d970a592568956aa97959f28cb89cadf5f2bc Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Mon, 18 Jul 2022 15:21:27 +0100 Subject: fix resolution of GTS user keys --- lib/pleroma/signature.ex | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/signature.ex b/lib/pleroma/signature.ex index dbe6fd209..ff0c56856 100644 --- a/lib/pleroma/signature.ex +++ b/lib/pleroma/signature.ex @@ -10,17 +10,14 @@ defmodule Pleroma.Signature do alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub + @known_suffixes ["/publickey", "/main-key"] + def key_id_to_actor_id(key_id) do uri = - URI.parse(key_id) + key_id + |> URI.parse() |> Map.put(:fragment, nil) - - uri = - if not is_nil(uri.path) and String.ends_with?(uri.path, "/publickey") do - Map.put(uri, :path, String.replace(uri.path, "/publickey", "")) - else - uri - end + |> remove_suffix(@known_suffixes) maybe_ap_id = URI.to_string(uri) @@ -36,6 +33,16 @@ defmodule Pleroma.Signature do end end + defp remove_suffix(uri, [test | rest]) do + if not is_nil(uri.path) and String.ends_with?(uri.path, test) do + Map.put(uri, :path, String.replace(uri.path, test, "")) + else + remove_suffix(uri, rest) + end + end + + defp remove_suffix(uri, []), do: uri + def fetch_public_key(conn) do with %{"keyId" => kid} <- HTTPSignatures.signature_for_conn(conn), {:ok, actor_id} <- key_id_to_actor_id(kid), -- cgit v1.2.3 From 61254111e59f02118cad15de49d1e0704c07030e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9l=C3=A8ne?= Date: Wed, 17 Aug 2022 03:30:02 +0200 Subject: HttpSignaturePlug: accept standard (request-target) The (request-target) used by Pleroma is non-standard, but many HTTP signature implementations do it this way due to a misinterpretation of the draft 06 of HTTP signatures: "path" was interpreted as not having the query, though later examples show that it must be the absolute path with the query part of the URL as well. This behavior is kept to make sure most software (Pleroma itself, Mastodon, and probably others) do not break, but Pleroma now accepts signatures for a (request-target) containing the query, as expected by many HTTP signature libraries, and clarified in the draft 11 of HTTP signatures. Additionally, the new draft renamed (request-target) to @request-target. We now support both for incoming requests' signatures. --- lib/pleroma/web/plugs/http_signature_plug.ex | 53 +++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 8 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/plugs/http_signature_plug.ex b/lib/pleroma/web/plugs/http_signature_plug.ex index d023754a6..4bf325218 100644 --- a/lib/pleroma/web/plugs/http_signature_plug.ex +++ b/lib/pleroma/web/plugs/http_signature_plug.ex @@ -25,21 +25,58 @@ defmodule Pleroma.Web.Plugs.HTTPSignaturePlug do end end + defp validate_signature(conn, request_target) do + # Newer drafts for HTTP signatures now use @request-target instead of the + # old (request-target). We'll now support both for incoming signatures. + conn = + conn + |> put_req_header("(request-target)", request_target) + |> put_req_header("@request-target", request_target) + + HTTPSignatures.validate_conn(conn) + end + + defp validate_signature(conn) do + # This (request-target) is non-standard, but many implementations do it + # this way due to a misinterpretation of + # https://datatracker.ietf.org/doc/html/draft-cavage-http-signatures-06 + # "path" was interpreted as not having the query, though later examples + # show that it must be the absolute path + query. This behavior is kept to + # make sure most software (Pleroma itself, Mastodon, and probably others) + # do not break. + request_target = String.downcase("#{conn.method}") <> " #{conn.request_path}" + + # This is the proper way to build the @request-target, as expected by + # many HTTP signature libraries, clarified in the following draft: + # https://www.ietf.org/archive/id/draft-ietf-httpbis-message-signatures-11.html#section-2.2.6 + # It is the same as before, but containing the query part as well. + proper_target = request_target <> "?#{conn.query_string}" + + cond do + # Normal, non-standard behavior but expected by Pleroma and more. + validate_signature(conn, request_target) -> + true + + # Has query string and the previous one failed: let's try the standard. + conn.query_string != "" -> + validate_signature(conn, proper_target) + + # If there's no query string and signature fails, it's rotten. + true -> + false + end + end + defp maybe_assign_valid_signature(conn) do if has_signature_header?(conn) do - # set (request-target) header to the appropriate value - # we also replace the digest header with the one we computed - request_target = String.downcase("#{conn.method}") <> " #{conn.request_path}" - + # we replace the digest header with the one we computed in DigestPlug conn = - conn - |> put_req_header("(request-target)", request_target) - |> case do + case conn do %{assigns: %{digest: digest}} = conn -> put_req_header(conn, "digest", digest) conn -> conn end - assign(conn, :valid_signature, HTTPSignatures.validate_conn(conn)) + assign(conn, :valid_signature, validate_signature(conn)) else Logger.debug("No signature header!") conn -- cgit v1.2.3 From 4661b56720b4f70eb6996bf975c4d88db9828006 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9l=C3=A8ne?= Date: Fri, 19 Aug 2022 02:45:49 +0200 Subject: ArticleNotePageValidator: fix replies fixing Some software, like GoToSocial, expose replies as ActivityPub Collections, but do not expose any item array directly in the object, causing validation to fail via the ObjectID validator. Now, Pleroma will drop that field in this situation too. --- .../activity_pub/object_validators/article_note_page_validator.ex | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/object_validators/article_note_page_validator.ex b/lib/pleroma/web/activity_pub/object_validators/article_note_page_validator.ex index 57c8d1dc0..4243e0fbf 100644 --- a/lib/pleroma/web/activity_pub/object_validators/article_note_page_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/article_note_page_validator.ex @@ -60,7 +60,10 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidator do defp fix_replies(%{"replies" => %{"items" => replies}} = data) when is_list(replies), do: Map.put(data, "replies", replies) - defp fix_replies(%{"replies" => replies} = data) when is_bitstring(replies), + # TODO: Pleroma does not have any support for Collections at the moment. + # If the `replies` field is not something the ObjectID validator can handle, + # the activity/object would be rejected, which is bad behavior. + defp fix_replies(%{"replies" => replies} = data) when not is_list(replies), do: Map.drop(data, ["replies"]) defp fix_replies(data), do: data -- cgit v1.2.3 From 0cee3c6e937ce7b15392a7abc5bbc30bfc80e7f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9l=C3=A8ne?= Date: Sat, 20 Aug 2022 00:21:07 +0200 Subject: emoji-test: update to latest 15.0 draft --- lib/pleroma/emoji-test.txt | 125 ++++++++++++++++++++++++++++----------------- 1 file changed, 79 insertions(+), 46 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/emoji-test.txt b/lib/pleroma/emoji-test.txt index dd5493366..87d093d64 100644 --- a/lib/pleroma/emoji-test.txt +++ b/lib/pleroma/emoji-test.txt @@ -1,13 +1,13 @@ # emoji-test.txt -# Date: 2021-08-26, 17:22:23 GMT -# © 2021 Unicode®, Inc. +# Date: 2022-08-12, 20:24:39 GMT +# © 2022 Unicode®, Inc. # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. -# For terms of use, see http://www.unicode.org/terms_of_use.html +# For terms of use, see https://www.unicode.org/terms_of_use.html # # Emoji Keyboard/Display Test Data for UTS #51 -# Version: 14.0 +# Version: 15.0 # -# For documentation and usage, see http://www.unicode.org/reports/tr51 +# For documentation and usage, see https://www.unicode.org/reports/tr51 # # This file provides data for testing which emoji forms should be in keyboards and which should also be displayed/processed. # Format: code points; status # emoji name @@ -92,6 +92,7 @@ 1F62C ; fully-qualified # 😬 E1.0 grimacing face 1F62E 200D 1F4A8 ; fully-qualified # 😮‍💨 E13.1 face exhaling 1F925 ; fully-qualified # 🤥 E3.0 lying face +1FAE8 ; fully-qualified # 🫨 E15.0 shaking face # subgroup: face-sleepy 1F60C ; fully-qualified # 😌 E0.6 relieved face @@ -155,7 +156,7 @@ # subgroup: face-negative 1F624 ; fully-qualified # 😤 E0.6 face with steam from nose -1F621 ; fully-qualified # 😡 E0.6 pouting face +1F621 ; fully-qualified # 😡 E0.6 enraged face 1F620 ; fully-qualified # 😠 E0.6 angry face 1F92C ; fully-qualified # 🤬 E5.0 face with symbols on mouth 1F608 ; fully-qualified # 😈 E1.0 smiling face with horns @@ -190,8 +191,7 @@ 1F649 ; fully-qualified # 🙉 E0.6 hear-no-evil monkey 1F64A ; fully-qualified # 🙊 E0.6 speak-no-evil monkey -# subgroup: emotion -1F48B ; fully-qualified # 💋 E0.6 kiss mark +# subgroup: heart 1F48C ; fully-qualified # 💌 E0.6 love letter 1F498 ; fully-qualified # 💘 E0.6 heart with arrow 1F49D ; fully-qualified # 💝 E0.6 heart with ribbon @@ -210,14 +210,20 @@ 2764 200D 1FA79 ; unqualified # ❤‍🩹 E13.1 mending heart 2764 FE0F ; fully-qualified # ❤️ E0.6 red heart 2764 ; unqualified # ❤ E0.6 red heart +1FA77 ; fully-qualified # 🩷 E15.0 pink heart 1F9E1 ; fully-qualified # 🧡 E5.0 orange heart 1F49B ; fully-qualified # 💛 E0.6 yellow heart 1F49A ; fully-qualified # 💚 E0.6 green heart 1F499 ; fully-qualified # 💙 E0.6 blue heart +1FA75 ; fully-qualified # 🩵 E15.0 light blue heart 1F49C ; fully-qualified # 💜 E0.6 purple heart 1F90E ; fully-qualified # 🤎 E12.0 brown heart 1F5A4 ; fully-qualified # 🖤 E3.0 black heart +1FA76 ; fully-qualified # 🩶 E15.0 grey heart 1F90D ; fully-qualified # 🤍 E12.0 white heart + +# subgroup: emotion +1F48B ; fully-qualified # 💋 E0.6 kiss mark 1F4AF ; fully-qualified # 💯 E0.6 hundred points 1F4A2 ; fully-qualified # 💢 E0.6 anger symbol 1F4A5 ; fully-qualified # 💥 E0.6 collision @@ -226,21 +232,20 @@ 1F4A8 ; fully-qualified # 💨 E0.6 dashing away 1F573 FE0F ; fully-qualified # 🕳️ E0.7 hole 1F573 ; unqualified # 🕳 E0.7 hole -1F4A3 ; fully-qualified # 💣 E0.6 bomb 1F4AC ; fully-qualified # 💬 E0.6 speech balloon 1F441 FE0F 200D 1F5E8 FE0F ; fully-qualified # 👁️‍🗨️ E2.0 eye in speech bubble 1F441 200D 1F5E8 FE0F ; unqualified # 👁‍🗨️ E2.0 eye in speech bubble -1F441 FE0F 200D 1F5E8 ; unqualified # 👁️‍🗨 E2.0 eye in speech bubble +1F441 FE0F 200D 1F5E8 ; minimally-qualified # 👁️‍🗨 E2.0 eye in speech bubble 1F441 200D 1F5E8 ; unqualified # 👁‍🗨 E2.0 eye in speech bubble 1F5E8 FE0F ; fully-qualified # 🗨️ E2.0 left speech bubble 1F5E8 ; unqualified # 🗨 E2.0 left speech bubble 1F5EF FE0F ; fully-qualified # 🗯️ E0.7 right anger bubble 1F5EF ; unqualified # 🗯 E0.7 right anger bubble 1F4AD ; fully-qualified # 💭 E1.0 thought balloon -1F4A4 ; fully-qualified # 💤 E0.6 zzz +1F4A4 ; fully-qualified # 💤 E0.6 ZZZ -# Smileys & Emotion subtotal: 177 -# Smileys & Emotion subtotal: 177 w/o modifiers +# Smileys & Emotion subtotal: 180 +# Smileys & Emotion subtotal: 180 w/o modifiers # group: People & Body @@ -300,6 +305,18 @@ 1FAF4 1F3FD ; fully-qualified # 🫴🏽 E14.0 palm up hand: medium skin tone 1FAF4 1F3FE ; fully-qualified # 🫴🏾 E14.0 palm up hand: medium-dark skin tone 1FAF4 1F3FF ; fully-qualified # 🫴🏿 E14.0 palm up hand: dark skin tone +1FAF7 ; fully-qualified # 🫷 E15.0 leftwards pushing hand +1FAF7 1F3FB ; fully-qualified # 🫷🏻 E15.0 leftwards pushing hand: light skin tone +1FAF7 1F3FC ; fully-qualified # 🫷🏼 E15.0 leftwards pushing hand: medium-light skin tone +1FAF7 1F3FD ; fully-qualified # 🫷🏽 E15.0 leftwards pushing hand: medium skin tone +1FAF7 1F3FE ; fully-qualified # 🫷🏾 E15.0 leftwards pushing hand: medium-dark skin tone +1FAF7 1F3FF ; fully-qualified # 🫷🏿 E15.0 leftwards pushing hand: dark skin tone +1FAF8 ; fully-qualified # 🫸 E15.0 rightwards pushing hand +1FAF8 1F3FB ; fully-qualified # 🫸🏻 E15.0 rightwards pushing hand: light skin tone +1FAF8 1F3FC ; fully-qualified # 🫸🏼 E15.0 rightwards pushing hand: medium-light skin tone +1FAF8 1F3FD ; fully-qualified # 🫸🏽 E15.0 rightwards pushing hand: medium skin tone +1FAF8 1F3FE ; fully-qualified # 🫸🏾 E15.0 rightwards pushing hand: medium-dark skin tone +1FAF8 1F3FF ; fully-qualified # 🫸🏿 E15.0 rightwards pushing hand: dark skin tone # subgroup: hand-fingers-partial 1F44C ; fully-qualified # 👌 E0.6 OK hand @@ -473,11 +490,11 @@ 1F932 1F3FE ; fully-qualified # 🤲🏾 E5.0 palms up together: medium-dark skin tone 1F932 1F3FF ; fully-qualified # 🤲🏿 E5.0 palms up together: dark skin tone 1F91D ; fully-qualified # 🤝 E3.0 handshake -1F91D 1F3FB ; fully-qualified # 🤝🏻 E3.0 handshake: light skin tone -1F91D 1F3FC ; fully-qualified # 🤝🏼 E3.0 handshake: medium-light skin tone -1F91D 1F3FD ; fully-qualified # 🤝🏽 E3.0 handshake: medium skin tone -1F91D 1F3FE ; fully-qualified # 🤝🏾 E3.0 handshake: medium-dark skin tone -1F91D 1F3FF ; fully-qualified # 🤝🏿 E3.0 handshake: dark skin tone +1F91D 1F3FB ; fully-qualified # 🤝🏻 E14.0 handshake: light skin tone +1F91D 1F3FC ; fully-qualified # 🤝🏼 E14.0 handshake: medium-light skin tone +1F91D 1F3FD ; fully-qualified # 🤝🏽 E14.0 handshake: medium skin tone +1F91D 1F3FE ; fully-qualified # 🤝🏾 E14.0 handshake: medium-dark skin tone +1F91D 1F3FF ; fully-qualified # 🤝🏿 E14.0 handshake: dark skin tone 1FAF1 1F3FB 200D 1FAF2 1F3FC ; fully-qualified # 🫱🏻‍🫲🏼 E14.0 handshake: light skin tone, medium-light skin tone 1FAF1 1F3FB 200D 1FAF2 1F3FD ; fully-qualified # 🫱🏻‍🫲🏽 E14.0 handshake: light skin tone, medium skin tone 1FAF1 1F3FB 200D 1FAF2 1F3FE ; fully-qualified # 🫱🏻‍🫲🏾 E14.0 handshake: light skin tone, medium-dark skin tone @@ -1455,7 +1472,7 @@ 1F575 1F3FF ; fully-qualified # 🕵🏿 E2.0 detective: dark skin tone 1F575 FE0F 200D 2642 FE0F ; fully-qualified # 🕵️‍♂️ E4.0 man detective 1F575 200D 2642 FE0F ; unqualified # 🕵‍♂️ E4.0 man detective -1F575 FE0F 200D 2642 ; unqualified # 🕵️‍♂ E4.0 man detective +1F575 FE0F 200D 2642 ; minimally-qualified # 🕵️‍♂ E4.0 man detective 1F575 200D 2642 ; unqualified # 🕵‍♂ E4.0 man detective 1F575 1F3FB 200D 2642 FE0F ; fully-qualified # 🕵🏻‍♂️ E4.0 man detective: light skin tone 1F575 1F3FB 200D 2642 ; minimally-qualified # 🕵🏻‍♂ E4.0 man detective: light skin tone @@ -1469,7 +1486,7 @@ 1F575 1F3FF 200D 2642 ; minimally-qualified # 🕵🏿‍♂ E4.0 man detective: dark skin tone 1F575 FE0F 200D 2640 FE0F ; fully-qualified # 🕵️‍♀️ E4.0 woman detective 1F575 200D 2640 FE0F ; unqualified # 🕵‍♀️ E4.0 woman detective -1F575 FE0F 200D 2640 ; unqualified # 🕵️‍♀ E4.0 woman detective +1F575 FE0F 200D 2640 ; minimally-qualified # 🕵️‍♀ E4.0 woman detective 1F575 200D 2640 ; unqualified # 🕵‍♀ E4.0 woman detective 1F575 1F3FB 200D 2640 FE0F ; fully-qualified # 🕵🏻‍♀️ E4.0 woman detective: light skin tone 1F575 1F3FB 200D 2640 ; minimally-qualified # 🕵🏻‍♀ E4.0 woman detective: light skin tone @@ -2302,7 +2319,7 @@ 1F3CC 1F3FF ; fully-qualified # 🏌🏿 E4.0 person golfing: dark skin tone 1F3CC FE0F 200D 2642 FE0F ; fully-qualified # 🏌️‍♂️ E4.0 man golfing 1F3CC 200D 2642 FE0F ; unqualified # 🏌‍♂️ E4.0 man golfing -1F3CC FE0F 200D 2642 ; unqualified # 🏌️‍♂ E4.0 man golfing +1F3CC FE0F 200D 2642 ; minimally-qualified # 🏌️‍♂ E4.0 man golfing 1F3CC 200D 2642 ; unqualified # 🏌‍♂ E4.0 man golfing 1F3CC 1F3FB 200D 2642 FE0F ; fully-qualified # 🏌🏻‍♂️ E4.0 man golfing: light skin tone 1F3CC 1F3FB 200D 2642 ; minimally-qualified # 🏌🏻‍♂ E4.0 man golfing: light skin tone @@ -2316,7 +2333,7 @@ 1F3CC 1F3FF 200D 2642 ; minimally-qualified # 🏌🏿‍♂ E4.0 man golfing: dark skin tone 1F3CC FE0F 200D 2640 FE0F ; fully-qualified # 🏌️‍♀️ E4.0 woman golfing 1F3CC 200D 2640 FE0F ; unqualified # 🏌‍♀️ E4.0 woman golfing -1F3CC FE0F 200D 2640 ; unqualified # 🏌️‍♀ E4.0 woman golfing +1F3CC FE0F 200D 2640 ; minimally-qualified # 🏌️‍♀ E4.0 woman golfing 1F3CC 200D 2640 ; unqualified # 🏌‍♀ E4.0 woman golfing 1F3CC 1F3FB 200D 2640 FE0F ; fully-qualified # 🏌🏻‍♀️ E4.0 woman golfing: light skin tone 1F3CC 1F3FB 200D 2640 ; minimally-qualified # 🏌🏻‍♀ E4.0 woman golfing: light skin tone @@ -2427,7 +2444,7 @@ 26F9 1F3FF ; fully-qualified # ⛹🏿 E2.0 person bouncing ball: dark skin tone 26F9 FE0F 200D 2642 FE0F ; fully-qualified # ⛹️‍♂️ E4.0 man bouncing ball 26F9 200D 2642 FE0F ; unqualified # ⛹‍♂️ E4.0 man bouncing ball -26F9 FE0F 200D 2642 ; unqualified # ⛹️‍♂ E4.0 man bouncing ball +26F9 FE0F 200D 2642 ; minimally-qualified # ⛹️‍♂ E4.0 man bouncing ball 26F9 200D 2642 ; unqualified # ⛹‍♂ E4.0 man bouncing ball 26F9 1F3FB 200D 2642 FE0F ; fully-qualified # ⛹🏻‍♂️ E4.0 man bouncing ball: light skin tone 26F9 1F3FB 200D 2642 ; minimally-qualified # ⛹🏻‍♂ E4.0 man bouncing ball: light skin tone @@ -2441,7 +2458,7 @@ 26F9 1F3FF 200D 2642 ; minimally-qualified # ⛹🏿‍♂ E4.0 man bouncing ball: dark skin tone 26F9 FE0F 200D 2640 FE0F ; fully-qualified # ⛹️‍♀️ E4.0 woman bouncing ball 26F9 200D 2640 FE0F ; unqualified # ⛹‍♀️ E4.0 woman bouncing ball -26F9 FE0F 200D 2640 ; unqualified # ⛹️‍♀ E4.0 woman bouncing ball +26F9 FE0F 200D 2640 ; minimally-qualified # ⛹️‍♀ E4.0 woman bouncing ball 26F9 200D 2640 ; unqualified # ⛹‍♀ E4.0 woman bouncing ball 26F9 1F3FB 200D 2640 FE0F ; fully-qualified # ⛹🏻‍♀️ E4.0 woman bouncing ball: light skin tone 26F9 1F3FB 200D 2640 ; minimally-qualified # ⛹🏻‍♀ E4.0 woman bouncing ball: light skin tone @@ -2462,7 +2479,7 @@ 1F3CB 1F3FF ; fully-qualified # 🏋🏿 E2.0 person lifting weights: dark skin tone 1F3CB FE0F 200D 2642 FE0F ; fully-qualified # 🏋️‍♂️ E4.0 man lifting weights 1F3CB 200D 2642 FE0F ; unqualified # 🏋‍♂️ E4.0 man lifting weights -1F3CB FE0F 200D 2642 ; unqualified # 🏋️‍♂ E4.0 man lifting weights +1F3CB FE0F 200D 2642 ; minimally-qualified # 🏋️‍♂ E4.0 man lifting weights 1F3CB 200D 2642 ; unqualified # 🏋‍♂ E4.0 man lifting weights 1F3CB 1F3FB 200D 2642 FE0F ; fully-qualified # 🏋🏻‍♂️ E4.0 man lifting weights: light skin tone 1F3CB 1F3FB 200D 2642 ; minimally-qualified # 🏋🏻‍♂ E4.0 man lifting weights: light skin tone @@ -2476,7 +2493,7 @@ 1F3CB 1F3FF 200D 2642 ; minimally-qualified # 🏋🏿‍♂ E4.0 man lifting weights: dark skin tone 1F3CB FE0F 200D 2640 FE0F ; fully-qualified # 🏋️‍♀️ E4.0 woman lifting weights 1F3CB 200D 2640 FE0F ; unqualified # 🏋‍♀️ E4.0 woman lifting weights -1F3CB FE0F 200D 2640 ; unqualified # 🏋️‍♀ E4.0 woman lifting weights +1F3CB FE0F 200D 2640 ; minimally-qualified # 🏋️‍♀ E4.0 woman lifting weights 1F3CB 200D 2640 ; unqualified # 🏋‍♀ E4.0 woman lifting weights 1F3CB 1F3FB 200D 2640 FE0F ; fully-qualified # 🏋🏻‍♀️ E4.0 woman lifting weights: light skin tone 1F3CB 1F3FB 200D 2640 ; minimally-qualified # 🏋🏻‍♀ E4.0 woman lifting weights: light skin tone @@ -3262,8 +3279,8 @@ 1FAC2 ; fully-qualified # 🫂 E13.0 people hugging 1F463 ; fully-qualified # 👣 E0.6 footprints -# People & Body subtotal: 2986 -# People & Body subtotal: 506 w/o modifiers +# People & Body subtotal: 2998 +# People & Body subtotal: 508 w/o modifiers # group: Component @@ -3306,6 +3323,8 @@ 1F405 ; fully-qualified # 🐅 E1.0 tiger 1F406 ; fully-qualified # 🐆 E1.0 leopard 1F434 ; fully-qualified # 🐴 E0.6 horse face +1FACE ; fully-qualified # 🫎 E15.0 moose +1FACF ; fully-qualified # 🫏 E15.0 donkey 1F40E ; fully-qualified # 🐎 E0.6 horse 1F984 ; fully-qualified # 🦄 E1.0 unicorn 1F993 ; fully-qualified # 🦓 E5.0 zebra @@ -3373,6 +3392,9 @@ 1F9A9 ; fully-qualified # 🦩 E12.0 flamingo 1F99A ; fully-qualified # 🦚 E11.0 peacock 1F99C ; fully-qualified # 🦜 E11.0 parrot +1FABD ; fully-qualified # 🪽 E15.0 wing +1F426 200D 2B1B ; fully-qualified # 🐦‍⬛ E15.0 black bird +1FABF ; fully-qualified # 🪿 E15.0 goose # subgroup: animal-amphibian 1F438 ; fully-qualified # 🐸 E0.6 frog @@ -3399,6 +3421,7 @@ 1F419 ; fully-qualified # 🐙 E0.6 octopus 1F41A ; fully-qualified # 🐚 E0.6 spiral shell 1FAB8 ; fully-qualified # 🪸 E14.0 coral +1FABC ; fully-qualified # 🪼 E15.0 jellyfish # subgroup: animal-bug 1F40C ; fully-qualified # 🐌 E0.6 snail @@ -3433,6 +3456,7 @@ 1F33B ; fully-qualified # 🌻 E0.6 sunflower 1F33C ; fully-qualified # 🌼 E0.6 blossom 1F337 ; fully-qualified # 🌷 E0.6 tulip +1FABB ; fully-qualified # 🪻 E15.0 hyacinth # subgroup: plant-other 1F331 ; fully-qualified # 🌱 E0.6 seedling @@ -3451,9 +3475,10 @@ 1F343 ; fully-qualified # 🍃 E0.6 leaf fluttering in wind 1FAB9 ; fully-qualified # 🪹 E14.0 empty nest 1FABA ; fully-qualified # 🪺 E14.0 nest with eggs +1F344 ; fully-qualified # 🍄 E0.6 mushroom -# Animals & Nature subtotal: 151 -# Animals & Nature subtotal: 151 w/o modifiers +# Animals & Nature subtotal: 159 +# Animals & Nature subtotal: 159 w/o modifiers # group: Food & Drink @@ -3492,10 +3517,11 @@ 1F966 ; fully-qualified # 🥦 E5.0 broccoli 1F9C4 ; fully-qualified # 🧄 E12.0 garlic 1F9C5 ; fully-qualified # 🧅 E12.0 onion -1F344 ; fully-qualified # 🍄 E0.6 mushroom 1F95C ; fully-qualified # 🥜 E3.0 peanuts 1FAD8 ; fully-qualified # 🫘 E14.0 beans 1F330 ; fully-qualified # 🌰 E0.6 chestnut +1FADA ; fully-qualified # 🫚 E15.0 ginger root +1FADB ; fully-qualified # 🫛 E15.0 pea pod # subgroup: food-prepared 1F35E ; fully-qualified # 🍞 E0.6 bread @@ -3607,8 +3633,8 @@ 1FAD9 ; fully-qualified # 🫙 E14.0 jar 1F3FA ; fully-qualified # 🏺 E1.0 amphora -# Food & Drink subtotal: 134 -# Food & Drink subtotal: 134 w/o modifiers +# Food & Drink subtotal: 135 +# Food & Drink subtotal: 135 w/o modifiers # group: Travel & Places @@ -3974,11 +4000,10 @@ 1F3AF ; fully-qualified # 🎯 E0.6 bullseye 1FA80 ; fully-qualified # 🪀 E12.0 yo-yo 1FA81 ; fully-qualified # 🪁 E12.0 kite +1F52B ; fully-qualified # 🔫 E0.6 water pistol 1F3B1 ; fully-qualified # 🎱 E0.6 pool 8 ball 1F52E ; fully-qualified # 🔮 E0.6 crystal ball 1FA84 ; fully-qualified # 🪄 E13.0 magic wand -1F9FF ; fully-qualified # 🧿 E11.0 nazar amulet -1FAAC ; fully-qualified # 🪬 E14.0 hamsa 1F3AE ; fully-qualified # 🎮 E0.6 video game 1F579 FE0F ; fully-qualified # 🕹️ E0.7 joystick 1F579 ; unqualified # 🕹 E0.7 joystick @@ -4013,8 +4038,8 @@ 1F9F6 ; fully-qualified # 🧶 E11.0 yarn 1FAA2 ; fully-qualified # 🪢 E13.0 knot -# Activities subtotal: 97 -# Activities subtotal: 97 w/o modifiers +# Activities subtotal: 96 +# Activities subtotal: 96 w/o modifiers # group: Objects @@ -4040,6 +4065,7 @@ 1FA73 ; fully-qualified # 🩳 E12.0 shorts 1F459 ; fully-qualified # 👙 E0.6 bikini 1F45A ; fully-qualified # 👚 E0.6 woman’s clothes +1FAAD ; fully-qualified # 🪭 E15.0 folding hand fan 1F45B ; fully-qualified # 👛 E0.6 purse 1F45C ; fully-qualified # 👜 E0.6 handbag 1F45D ; fully-qualified # 👝 E0.6 clutch bag @@ -4055,6 +4081,7 @@ 1F461 ; fully-qualified # 👡 E0.6 woman’s sandal 1FA70 ; fully-qualified # 🩰 E12.0 ballet shoes 1F462 ; fully-qualified # 👢 E0.6 woman’s boot +1FAAE ; fully-qualified # 🪮 E15.0 hair pick 1F451 ; fully-qualified # 👑 E0.6 crown 1F452 ; fully-qualified # 👒 E0.6 woman’s hat 1F3A9 ; fully-qualified # 🎩 E0.6 top hat @@ -4103,6 +4130,8 @@ 1FA95 ; fully-qualified # 🪕 E12.0 banjo 1F941 ; fully-qualified # 🥁 E3.0 drum 1FA98 ; fully-qualified # 🪘 E13.0 long drum +1FA87 ; fully-qualified # 🪇 E15.0 maracas +1FA88 ; fully-qualified # 🪈 E15.0 flute # subgroup: phone 1F4F1 ; fully-qualified # 📱 E0.6 mobile phone @@ -4275,7 +4304,7 @@ 1F5E1 ; unqualified # 🗡 E0.7 dagger 2694 FE0F ; fully-qualified # ⚔️ E1.0 crossed swords 2694 ; unqualified # ⚔ E1.0 crossed swords -1F52B ; fully-qualified # 🔫 E0.6 water pistol +1F4A3 ; fully-qualified # 💣 E0.6 bomb 1FA83 ; fully-qualified # 🪃 E13.0 boomerang 1F3F9 ; fully-qualified # 🏹 E1.0 bow and arrow 1F6E1 FE0F ; fully-qualified # 🛡️ E0.7 shield @@ -4354,12 +4383,14 @@ 1FAA6 ; fully-qualified # 🪦 E13.0 headstone 26B1 FE0F ; fully-qualified # ⚱️ E1.0 funeral urn 26B1 ; unqualified # ⚱ E1.0 funeral urn +1F9FF ; fully-qualified # 🧿 E11.0 nazar amulet +1FAAC ; fully-qualified # 🪬 E14.0 hamsa 1F5FF ; fully-qualified # 🗿 E0.6 moai 1FAA7 ; fully-qualified # 🪧 E13.0 placard 1FAAA ; fully-qualified # 🪪 E14.0 identification card -# Objects subtotal: 304 -# Objects subtotal: 304 w/o modifiers +# Objects subtotal: 310 +# Objects subtotal: 310 w/o modifiers # group: Symbols @@ -4455,6 +4486,7 @@ 262E ; unqualified # ☮ E1.0 peace symbol 1F54E ; fully-qualified # 🕎 E1.0 menorah 1F52F ; fully-qualified # 🔯 E0.6 dotted six-pointed star +1FAAF ; fully-qualified # 🪯 E15.0 khanda # subgroup: zodiac 2648 ; fully-qualified # ♈ E0.6 Aries @@ -4503,6 +4535,7 @@ 1F505 ; fully-qualified # 🔅 E1.0 dim button 1F506 ; fully-qualified # 🔆 E1.0 bright button 1F4F6 ; fully-qualified # 📶 E0.6 antenna bars +1F6DC ; fully-qualified # 🛜 E15.0 wireless 1F4F3 ; fully-qualified # 📳 E0.6 vibration mode 1F4F4 ; fully-qualified # 📴 E0.6 mobile phone off @@ -4693,8 +4726,8 @@ 1F533 ; fully-qualified # 🔳 E0.6 white square button 1F532 ; fully-qualified # 🔲 E0.6 black square button -# Symbols subtotal: 302 -# Symbols subtotal: 302 w/o modifiers +# Symbols subtotal: 304 +# Symbols subtotal: 304 w/o modifiers # group: Flags @@ -4709,7 +4742,7 @@ 1F3F3 200D 1F308 ; unqualified # 🏳‍🌈 E4.0 rainbow flag 1F3F3 FE0F 200D 26A7 FE0F ; fully-qualified # 🏳️‍⚧️ E13.0 transgender flag 1F3F3 200D 26A7 FE0F ; unqualified # 🏳‍⚧️ E13.0 transgender flag -1F3F3 FE0F 200D 26A7 ; unqualified # 🏳️‍⚧ E13.0 transgender flag +1F3F3 FE0F 200D 26A7 ; minimally-qualified # 🏳️‍⚧ E13.0 transgender flag 1F3F3 200D 26A7 ; unqualified # 🏳‍⚧ E13.0 transgender flag 1F3F4 200D 2620 FE0F ; fully-qualified # 🏴‍☠️ E11.0 pirate flag 1F3F4 200D 2620 ; minimally-qualified # 🏴‍☠ E11.0 pirate flag @@ -4983,9 +5016,9 @@ # Flags subtotal: 275 w/o modifiers # Status Counts -# fully-qualified : 3624 -# minimally-qualified : 817 -# unqualified : 252 +# fully-qualified : 3655 +# minimally-qualified : 827 +# unqualified : 242 # component : 9 #EOF -- cgit v1.2.3 From c62a4f1c173490ad64fdfbab0c005ca3523b6013 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Fri, 19 Aug 2022 13:19:38 -0400 Subject: Disconnect streaming sessions when token is revoked --- lib/pleroma/web/mastodon_api/websocket_handler.ex | 8 ++++++-- lib/pleroma/web/o_auth/token/strategy/revoke.ex | 1 + lib/pleroma/web/streamer.ex | 24 +++++++++++++++++++---- 3 files changed, 27 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/websocket_handler.ex b/lib/pleroma/web/mastodon_api/websocket_handler.ex index 0d1faffbd..ffbc2c4de 100644 --- a/lib/pleroma/web/mastodon_api/websocket_handler.ex +++ b/lib/pleroma/web/mastodon_api/websocket_handler.ex @@ -32,7 +32,7 @@ defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do req end - {:cowboy_websocket, req, %{user: user, topic: topic, count: 0, timer: nil}, + {:cowboy_websocket, req, %{user: user, topic: topic, oauth_token: oauth_token, count: 0, timer: nil}, %{idle_timeout: @timeout}} else {:error, :bad_topic} -> @@ -54,7 +54,7 @@ defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do }, topic #{state.topic}" ) - Streamer.add_socket(state.topic, state.user) + Streamer.add_socket(state.topic, state.oauth_token) {:ok, %{state | timer: timer()}} end @@ -100,6 +100,10 @@ defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do {:reply, :ping, %{state | timer: nil, count: 0}, :hibernate} end + def websocket_info(:close, state) do + {:stop, state} + end + # State can be `[]` only in case we terminate before switching to websocket, # we already log errors for these cases in `init/1`, so just do nothing here def terminate(_reason, _req, []), do: :ok diff --git a/lib/pleroma/web/o_auth/token/strategy/revoke.ex b/lib/pleroma/web/o_auth/token/strategy/revoke.ex index 8d6572704..03a0b91ae 100644 --- a/lib/pleroma/web/o_auth/token/strategy/revoke.ex +++ b/lib/pleroma/web/o_auth/token/strategy/revoke.ex @@ -22,5 +22,6 @@ defmodule Pleroma.Web.OAuth.Token.Strategy.Revoke do @spec revoke(Token.t()) :: {:ok, Token.t()} | {:error, Ecto.Changeset.t()} def revoke(%Token{} = token) do Repo.delete(token) + Pleroma.Web.Streamer.close_streams_by_oauth_token(token) end end diff --git a/lib/pleroma/web/streamer.ex b/lib/pleroma/web/streamer.ex index fc3bbb130..8bf70d99b 100644 --- a/lib/pleroma/web/streamer.ex +++ b/lib/pleroma/web/streamer.ex @@ -37,7 +37,7 @@ defmodule Pleroma.Web.Streamer do {:ok, topic :: String.t()} | {:error, :bad_topic} | {:error, :unauthorized} def get_topic_and_add_socket(stream, user, oauth_token, params \\ %{}) do with {:ok, topic} <- get_topic(stream, user, oauth_token, params) do - add_socket(topic, user) + add_socket(topic, oauth_token) end end @@ -120,10 +120,10 @@ defmodule Pleroma.Web.Streamer do end @doc "Registers the process for streaming. Use `get_topic/3` to get the full authorized topic." - def add_socket(topic, user) do + def add_socket(topic, oauth_token) do if should_env_send?() do - auth? = if user, do: true - Registry.register(@registry, topic, auth?) + oauth_token_id = if oauth_token, do: oauth_token.id, else: false + Registry.register(@registry, topic, oauth_token_id) end {:ok, topic} @@ -320,6 +320,22 @@ defmodule Pleroma.Web.Streamer do end end + def close_streams_by_oauth_token(oauth_token) do + if should_env_send?() do + Registry.select( + @registry, + [ + { + {:"$1", :"$2", :"$3"}, + [{:==, :"$3", oauth_token.id}], + [:"$2"] + } + ] + ) + |> Enum.each(fn pid -> send(pid, :close) end) + end + end + # In test environement, only return true if the registry is started. # In benchmark environment, returns false. # In any other environment, always returns true. -- cgit v1.2.3 From f459c1260b43396fb7173e97e29ccef441a615ec Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Fri, 19 Aug 2022 14:10:07 -0400 Subject: Lint --- lib/pleroma/web/mastodon_api/websocket_handler.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/websocket_handler.ex b/lib/pleroma/web/mastodon_api/websocket_handler.ex index ffbc2c4de..930e9eb29 100644 --- a/lib/pleroma/web/mastodon_api/websocket_handler.ex +++ b/lib/pleroma/web/mastodon_api/websocket_handler.ex @@ -32,7 +32,8 @@ defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do req end - {:cowboy_websocket, req, %{user: user, topic: topic, oauth_token: oauth_token, count: 0, timer: nil}, + {:cowboy_websocket, req, + %{user: user, topic: topic, oauth_token: oauth_token, count: 0, timer: nil}, %{idle_timeout: @timeout}} else {:error, :bad_topic} -> -- cgit v1.2.3 From a31d6bb52c8856c71f20d49aec8948573dacba68 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Fri, 19 Aug 2022 14:58:57 -0400 Subject: Execute session disconnect in background --- lib/pleroma/application.ex | 3 ++- lib/pleroma/web/o_auth/token/strategy/revoke.ex | 15 +++++++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index 9824e0a4a..92d143665 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -89,7 +89,8 @@ defmodule Pleroma.Application do Pleroma.Repo, Config.TransferTask, Pleroma.Emoji, - Pleroma.Web.Plugs.RateLimiter.Supervisor + Pleroma.Web.Plugs.RateLimiter.Supervisor, + {Task.Supervisor, name: Pleroma.TaskSupervisor} ] ++ cachex_children() ++ http_children(adapter, @mix_env) ++ diff --git a/lib/pleroma/web/o_auth/token/strategy/revoke.ex b/lib/pleroma/web/o_auth/token/strategy/revoke.ex index 03a0b91ae..de99bc137 100644 --- a/lib/pleroma/web/o_auth/token/strategy/revoke.ex +++ b/lib/pleroma/web/o_auth/token/strategy/revoke.ex @@ -21,7 +21,18 @@ defmodule Pleroma.Web.OAuth.Token.Strategy.Revoke do @doc "Revokes access token" @spec revoke(Token.t()) :: {:ok, Token.t()} | {:error, Ecto.Changeset.t()} def revoke(%Token{} = token) do - Repo.delete(token) - Pleroma.Web.Streamer.close_streams_by_oauth_token(token) + with {:ok, token} <- Repo.delete(token) do + Task.Supervisor.start_child( + Pleroma.TaskSupervisor, + Pleroma.Web.Streamer, + :close_streams_by_oauth_token, + [token], + restart: :transient + ) + + {:ok, token} + else + result -> result + end end end -- cgit v1.2.3 From 3885ee182a572a10b326ae553703ee0d38f3b66d Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Mon, 11 Jul 2022 15:49:58 -0400 Subject: Switch to associated_object_id index --- lib/mix/tasks/pleroma/database.ex | 3 +-- lib/pleroma/activity.ex | 5 ++--- lib/pleroma/activity/queries.ex | 6 ++---- lib/pleroma/migrators/hashtags_table_migrator.ex | 2 +- lib/pleroma/notification.ex | 9 +++------ lib/pleroma/object.ex | 3 +-- lib/pleroma/web/activity_pub/activity_pub.ex | 3 +-- 7 files changed, 11 insertions(+), 20 deletions(-) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/database.ex b/lib/mix/tasks/pleroma/database.ex index 6b8f0ef68..ed560c177 100644 --- a/lib/mix/tasks/pleroma/database.ex +++ b/lib/mix/tasks/pleroma/database.ex @@ -154,9 +154,8 @@ defmodule Mix.Tasks.Pleroma.Database do |> join(:inner, [a], o in Object, on: fragment( - "(?->>'id') = COALESCE((?)->'object'->> 'id', (?)->>'object')", + "(?->>'id') = associated_object_id((?))", o.data, - a.data, a.data ) ) diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index 12c1a3b2e..ebfd4ed45 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -53,7 +53,7 @@ defmodule Pleroma.Activity do # # ``` # |> join(:inner, [activity], o in Object, - # on: fragment("(?->>'id') = COALESCE((?)->'object'->> 'id', (?)->>'object')", + # on: fragment("(?->>'id') = associated_object_id((?))", # o.data, activity.data, activity.data)) # |> preload([activity, object], [object: object]) # ``` @@ -69,9 +69,8 @@ defmodule Pleroma.Activity do join(query, join_type, [activity], o in Object, on: fragment( - "(?->>'id') = COALESCE(?->'object'->>'id', ?->>'object')", + "(?->>'id') = associated_object_id(?)", o.data, - activity.data, activity.data ), as: :object diff --git a/lib/pleroma/activity/queries.ex b/lib/pleroma/activity/queries.ex index a898b2ea7..81c44ac05 100644 --- a/lib/pleroma/activity/queries.ex +++ b/lib/pleroma/activity/queries.ex @@ -52,8 +52,7 @@ defmodule Pleroma.Activity.Queries do activity in query, where: fragment( - "coalesce((?)->'object'->>'id', (?)->>'object') = ANY(?)", - activity.data, + "associated_object_id((?)) = ANY(?)", activity.data, ^object_ids ) @@ -64,8 +63,7 @@ defmodule Pleroma.Activity.Queries do from(activity in query, where: fragment( - "coalesce((?)->'object'->>'id', (?)->>'object') = ?", - activity.data, + "associated_object_id((?)) = ?", activity.data, ^object_id ) diff --git a/lib/pleroma/migrators/hashtags_table_migrator.ex b/lib/pleroma/migrators/hashtags_table_migrator.ex index fa1190b7d..dca4bfa6f 100644 --- a/lib/pleroma/migrators/hashtags_table_migrator.ex +++ b/lib/pleroma/migrators/hashtags_table_migrator.ex @@ -183,7 +183,7 @@ defmodule Pleroma.Migrators.HashtagsTableMigrator do DELETE FROM hashtags_objects WHERE object_id IN (SELECT DISTINCT objects.id FROM objects JOIN hashtags_objects ON hashtags_objects.object_id = objects.id LEFT JOIN activities - ON COALESCE(activities.data->'object'->>'id', activities.data->>'object') = + ON associated_object_id(activities) = (objects.data->>'id') AND activities.data->>'type' = 'Create' WHERE activities.id IS NULL); diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index 52fd2656b..76d2d5ece 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -117,9 +117,8 @@ defmodule Pleroma.Notification do |> join(:left, [n, a], object in Object, on: fragment( - "(?->>'id') = COALESCE(?->'object'->>'id', ?->>'object')", + "(?->>'id') = associated_object_id(?)", object.data, - a.data, a.data ) ) @@ -193,13 +192,11 @@ defmodule Pleroma.Notification do |> join(:left, [n, a], mutated_activity in Pleroma.Activity, on: fragment( - "COALESCE((?->'object')->>'id', ?->>'object')", - a.data, + "associated_object_id(?)", a.data ) == fragment( - "COALESCE((?->'object')->>'id', ?->>'object')", - mutated_activity.data, + "associated_object_id(?)", mutated_activity.data ) and fragment("(?->>'type' = 'Like' or ?->>'type' = 'Announce')", a.data, a.data) and diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index fe264b5e0..e7d0d52b0 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -40,8 +40,7 @@ defmodule Pleroma.Object do join(query, join_type, [{object, object_position}], a in Activity, on: fragment( - "COALESCE(?->'object'->>'id', ?->>'object') = (? ->> 'id') AND (?->>'type' = ?) ", - a.data, + "associated_object_id(?) = (? ->> 'id') AND (?->>'type' = ?) ", a.data, object.data, a.data, diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index bded254c6..07b0a92a4 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -1150,8 +1150,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do [activity, object: o] in query, where: fragment( - "(?)->>'type' = 'Create' and coalesce((?)->'object'->>'id', (?)->>'object') = any (?)", - activity.data, + "(?)->>'type' = 'Create' and associated_object_id((?)) = any (?)", activity.data, activity.data, ^ids -- cgit v1.2.3 From 27016287862a93b1fb4a4bebda3199e32c46d962 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Tue, 28 Dec 2021 15:01:37 -0500 Subject: Add remote interaction ui for posts --- .../twitter_api/util/status_interact.html.eex | 13 ++++++ .../web/twitter_api/controllers/util_controller.ex | 47 ++++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 lib/pleroma/web/templates/twitter_api/util/status_interact.html.eex (limited to 'lib') diff --git a/lib/pleroma/web/templates/twitter_api/util/status_interact.html.eex b/lib/pleroma/web/templates/twitter_api/util/status_interact.html.eex new file mode 100644 index 000000000..bb3d0a0af --- /dev/null +++ b/lib/pleroma/web/templates/twitter_api/util/status_interact.html.eex @@ -0,0 +1,13 @@ +<%= if @error do %> +

Error: <%= @error %>

+<% else %> +

Interacting with <%= @nickname %>

+
+ <%= @status_id %> +
+ <%= form_for @conn, Routes.util_path(@conn, :remote_subscribe), [as: "status"], fn f -> %> + <%= hidden_input f, :status, value: @status_id %> + <%= text_input f, :profile, placeholder: "Your account ID, e.g. lain@quitter.se" %> + <%= submit "Interact" %> + <% end %> +<% end %> diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index 5731c78a8..ee99aab3e 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -7,6 +7,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do require Logger + alias Pleroma.Activity alias Pleroma.Config alias Pleroma.Emoji alias Pleroma.Healthcheck @@ -59,6 +60,27 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do end end + def remote_subscribe(conn, %{"status_id" => id, "profile" => _}) do + with %Activity{} = activity <- Activity.get_by_id(id), + %User{} = user <- User.get_cached_by_ap_id(activity.actor), + avatar = User.avatar_url(user) do + conn + |> render("status_interact.html", %{ + status_id: id, + nickname: user.nickname, + avatar: avatar, + error: false + }) + else + _e -> + render(conn, "status_interact.html", %{ + status_id: id, + avatar: nil, + error: "Could not find status" + }) + end + end + def remote_subscribe(conn, %{"user" => %{"nickname" => nick, "profile" => profile}}) do with {:ok, %{"subscribe_address" => template}} <- WebFinger.finger(profile), %User{ap_id: ap_id} <- User.get_cached_by_nickname(nick) do @@ -74,6 +96,31 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do end end + def remote_subscribe(conn, %{"status" => %{"status_id" => id, "profile" => profile}}) do + get_ap_id = fn activity -> + object = Pleroma.Object.normalize(activity, fetch: false) + + case object do + %{data: %{"id" => ap_id}} -> {:ok, ap_id} + _ -> {:no_ap_id, nil} + end + end + + with {:ok, %{"subscribe_address" => template}} <- WebFinger.finger(profile), + %Activity{} = activity <- Activity.get_by_id(id), + {:ok, ap_id} <- get_ap_id.(activity) do + conn + |> Phoenix.Controller.redirect(external: String.replace(template, "{uri}", ap_id)) + else + _e -> + render(conn, "status_interact.html", %{ + status_id: id, + avatar: nil, + error: "Something went wrong." + }) + end + end + def remote_interaction(%{body_params: %{ap_id: ap_id, profile: profile}} = conn, _params) do with {:ok, %{"subscribe_address" => template}} <- WebFinger.finger(profile) do conn -- cgit v1.2.3 From a243a217a7006352542a22aca605e60fc80f9ff0 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Tue, 28 Dec 2021 16:12:00 -0500 Subject: Fix form item name in status_interact.html --- lib/pleroma/web/templates/twitter_api/util/status_interact.html.eex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/templates/twitter_api/util/status_interact.html.eex b/lib/pleroma/web/templates/twitter_api/util/status_interact.html.eex index bb3d0a0af..6354b409f 100644 --- a/lib/pleroma/web/templates/twitter_api/util/status_interact.html.eex +++ b/lib/pleroma/web/templates/twitter_api/util/status_interact.html.eex @@ -6,7 +6,7 @@ <%= @status_id %> <%= form_for @conn, Routes.util_path(@conn, :remote_subscribe), [as: "status"], fn f -> %> - <%= hidden_input f, :status, value: @status_id %> + <%= hidden_input f, :status_id, value: @status_id %> <%= text_input f, :profile, placeholder: "Your account ID, e.g. lain@quitter.se" %> <%= submit "Interact" %> <% end %> -- cgit v1.2.3 From 779457d9a4e6b3e5e8b7823119907c1eb24a3b87 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Tue, 28 Dec 2021 16:41:46 -0500 Subject: Add GET endpoints for remote subscription forms There are two reasons for adding a GET endpoint: 0: Barely displaying the form does not change anything on the server. 1: It makes frontend development easier as they can now use a link, instead of a form, to allow remote users to interact with local ones. --- .../web/api_spec/operations/twitter_util_operation.ex | 10 ++++++++++ lib/pleroma/web/router.ex | 1 + .../web/twitter_api/controllers/util_controller.ex | 16 ++++++++++++---- 3 files changed, 23 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 1cc90990f..29df03e34 100644 --- a/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex +++ b/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex @@ -405,6 +405,16 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do } end + def show_subscribe_form_operation do + %Operation{ + tags: ["Accounts"], + summary: "Show remote subscribe form", + operationId: "UtilController.show_subscribe_form", + parameters: [], + responses: %{200 => Operation.response("Web Page", "test/html", %Schema{type: :string})} + } + end + defp delete_account_request do %Schema{ title: "AccountDeleteRequest", diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 842596e97..846ba8363 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -337,6 +337,7 @@ defmodule Pleroma.Web.Router do pipe_through(:pleroma_html) post("/main/ostatus", UtilController, :remote_subscribe) + get("/main/ostatus", UtilController, :show_subscribe_form) get("/ostatus_subscribe", RemoteFollowController, :follow) post("/ostatus_subscribe", RemoteFollowController, :do_follow) end diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index ee99aab3e..049329c38 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -17,8 +17,8 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do alias Pleroma.Web.Plugs.OAuthScopesPlug alias Pleroma.Web.WebFinger - plug(Pleroma.Web.ApiSpec.CastAndValidate when action != :remote_subscribe) - plug(Pleroma.Web.Plugs.FederatingPlug when action == :remote_subscribe) + plug(Pleroma.Web.ApiSpec.CastAndValidate when action != :remote_subscribe and action != :show_subscribe_form) + plug(Pleroma.Web.Plugs.FederatingPlug when action == :remote_subscribe when action == :show_subscribe_form) plug( OAuthScopesPlug, @@ -45,7 +45,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.TwitterUtilOperation - def remote_subscribe(conn, %{"nickname" => nick, "profile" => _}) do + def show_subscribe_form(conn, %{"nickname" => nick}) do with %User{} = user <- User.get_cached_by_nickname(nick), avatar = User.avatar_url(user) do conn @@ -60,7 +60,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do end end - def remote_subscribe(conn, %{"status_id" => id, "profile" => _}) do + def show_subscribe_form(conn, %{"status_id" => id}) do with %Activity{} = activity <- Activity.get_by_id(id), %User{} = user <- User.get_cached_by_ap_id(activity.actor), avatar = User.avatar_url(user) do @@ -81,6 +81,14 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do end end + def remote_subscribe(conn, %{"nickname" => nick, "profile" => _}) do + show_subscribe_form(conn, %{"nickname" => nick}) + end + + def remote_subscribe(conn, %{"status_id" => id, "profile" => _}) do + show_subscribe_form(conn, %{"status_id" => id}) + end + def remote_subscribe(conn, %{"user" => %{"nickname" => nick, "profile" => profile}}) do with {:ok, %{"subscribe_address" => template}} <- WebFinger.finger(profile), %User{ap_id: ap_id} <- User.get_cached_by_nickname(nick) do -- cgit v1.2.3 From b7c75db0f7f2c048d45fc387dfcf00073cbf8d62 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Tue, 28 Dec 2021 16:58:08 -0500 Subject: Lint --- lib/pleroma/web/twitter_api/controllers/util_controller.ex | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index 049329c38..24b419c31 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -17,8 +17,16 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do alias Pleroma.Web.Plugs.OAuthScopesPlug alias Pleroma.Web.WebFinger - plug(Pleroma.Web.ApiSpec.CastAndValidate when action != :remote_subscribe and action != :show_subscribe_form) - plug(Pleroma.Web.Plugs.FederatingPlug when action == :remote_subscribe when action == :show_subscribe_form) + plug( + Pleroma.Web.ApiSpec.CastAndValidate + when action != :remote_subscribe and action != :show_subscribe_form + ) + + plug( + Pleroma.Web.Plugs.FederatingPlug + when action == :remote_subscribe + when action == :show_subscribe_form + ) plug( OAuthScopesPlug, -- cgit v1.2.3 From 1218adacc52f1235aedb1bb102d2e9385507efa4 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Tue, 28 Dec 2021 19:37:56 -0500 Subject: Display status link in remote interaction form --- .../twitter_api/util/status_interact.html.eex | 5 +---- .../web/twitter_api/controllers/util_controller.ex | 22 ++++++++++++---------- lib/pleroma/web/twitter_api/views/util_view.ex | 1 + 3 files changed, 14 insertions(+), 14 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/templates/twitter_api/util/status_interact.html.eex b/lib/pleroma/web/templates/twitter_api/util/status_interact.html.eex index 6354b409f..695c5d64b 100644 --- a/lib/pleroma/web/templates/twitter_api/util/status_interact.html.eex +++ b/lib/pleroma/web/templates/twitter_api/util/status_interact.html.eex @@ -1,10 +1,7 @@ <%= if @error do %>

Error: <%= @error %>

<% else %> -

Interacting with <%= @nickname %>

-
- <%= @status_id %> -
+

Interacting with <%= @nickname %>'s <%= link("status", to: @status_link) %>

<%= form_for @conn, Routes.util_path(@conn, :remote_subscribe), [as: "status"], fn f -> %> <%= hidden_input f, :status_id, value: @status_id %> <%= text_input f, :profile, placeholder: "Your account ID, e.g. lain@quitter.se" %> diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index 24b419c31..2c3103185 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -70,10 +70,12 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do def show_subscribe_form(conn, %{"status_id" => id}) do with %Activity{} = activity <- Activity.get_by_id(id), + {:ok, ap_id} <- get_ap_id(activity), %User{} = user <- User.get_cached_by_ap_id(activity.actor), avatar = User.avatar_url(user) do conn |> render("status_interact.html", %{ + status_link: ap_id, status_id: id, nickname: user.nickname, avatar: avatar, @@ -113,18 +115,9 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do end def remote_subscribe(conn, %{"status" => %{"status_id" => id, "profile" => profile}}) do - get_ap_id = fn activity -> - object = Pleroma.Object.normalize(activity, fetch: false) - - case object do - %{data: %{"id" => ap_id}} -> {:ok, ap_id} - _ -> {:no_ap_id, nil} - end - end - with {:ok, %{"subscribe_address" => template}} <- WebFinger.finger(profile), %Activity{} = activity <- Activity.get_by_id(id), - {:ok, ap_id} <- get_ap_id.(activity) do + {:ok, ap_id} <- get_ap_id(activity) do conn |> Phoenix.Controller.redirect(external: String.replace(template, "{uri}", ap_id)) else @@ -146,6 +139,15 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do end end + defp get_ap_id(activity) do + object = Pleroma.Object.normalize(activity, fetch: false) + + case object do + %{data: %{"id" => ap_id}} -> {:ok, ap_id} + _ -> {:no_ap_id, nil} + end + end + def frontend_configurations(conn, _params) do render(conn, "frontend_configurations.json") end diff --git a/lib/pleroma/web/twitter_api/views/util_view.ex b/lib/pleroma/web/twitter_api/views/util_view.ex index 69f243097..2365a396b 100644 --- a/lib/pleroma/web/twitter_api/views/util_view.ex +++ b/lib/pleroma/web/twitter_api/views/util_view.ex @@ -5,6 +5,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilView do use Pleroma.Web, :view import Phoenix.HTML.Form + import Phoenix.HTML.Link alias Pleroma.Config alias Pleroma.Web.Endpoint alias Pleroma.Web.Gettext -- cgit v1.2.3 From 4ec9eeb3f8f3502841cd136ea7afe9298b477120 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Fri, 25 Mar 2022 22:05:28 -0400 Subject: Make remote interaction page translatable --- .../twitter_api/util/status_interact.html.eex | 8 +++---- .../web/twitter_api/controllers/util_controller.ex | 28 ++++++++++++++++++---- lib/pleroma/web/twitter_api/views/util_view.ex | 1 + 3 files changed, 29 insertions(+), 8 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/templates/twitter_api/util/status_interact.html.eex b/lib/pleroma/web/templates/twitter_api/util/status_interact.html.eex index 695c5d64b..d77174967 100644 --- a/lib/pleroma/web/templates/twitter_api/util/status_interact.html.eex +++ b/lib/pleroma/web/templates/twitter_api/util/status_interact.html.eex @@ -1,10 +1,10 @@ <%= if @error do %> -

Error: <%= @error %>

+

<%= Gettext.dpgettext("static_pages", "status interact error", "Error: %{error}", error: @error) %>

<% else %> -

Interacting with <%= @nickname %>'s <%= link("status", to: @status_link) %>

+

<%= raw Gettext.dpgettext("static_pages", "status interact header", "Interacting with %{nickname}'s %{status_link}", nickname: safe_to_string(html_escape(@nickname)), status_link: safe_to_string(link(Gettext.dpgettext("static_pages", "status interact header - status link text", "status"), to: @status_link))) %>

<%= form_for @conn, Routes.util_path(@conn, :remote_subscribe), [as: "status"], fn f -> %> <%= hidden_input f, :status_id, value: @status_id %> - <%= text_input f, :profile, placeholder: "Your account ID, e.g. lain@quitter.se" %> - <%= submit "Interact" %> + <%= text_input f, :profile, placeholder: Gettext.dpgettext("static_pages", "placeholder text for account id", "Your account ID, e.g. lain@quitter.se") %> + <%= submit Gettext.dpgettext("static_pages", "status interact authorization button", "Interact") %> <% end %> <% end %> diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index 2c3103185..d5a24ae6c 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -63,7 +63,12 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do render(conn, "subscribe.html", %{ nickname: nick, avatar: nil, - error: "Could not find user" + error: + Pleroma.Web.Gettext.dpgettext( + "static_pages", + "remote follow error message - user not found", + "Could not find user" + ) }) end end @@ -86,7 +91,12 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do render(conn, "status_interact.html", %{ status_id: id, avatar: nil, - error: "Could not find status" + error: + Pleroma.Web.Gettext.dpgettext( + "static_pages", + "status interact error message - status not found", + "Could not find status" + ) }) end end @@ -109,7 +119,12 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do render(conn, "subscribe.html", %{ nickname: nick, avatar: nil, - error: "Something went wrong." + error: + Pleroma.Web.Gettext.dpgettext( + "static_pages", + "remote follow error message - unknown error", + "Something went wrong." + ) }) end end @@ -125,7 +140,12 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do render(conn, "status_interact.html", %{ status_id: id, avatar: nil, - error: "Something went wrong." + error: + Pleroma.Web.Gettext.dpgettext( + "static_pages", + "status interact error message - unknown error", + "Something went wrong." + ) }) end end diff --git a/lib/pleroma/web/twitter_api/views/util_view.ex b/lib/pleroma/web/twitter_api/views/util_view.ex index 2365a396b..31b7c0c0c 100644 --- a/lib/pleroma/web/twitter_api/views/util_view.ex +++ b/lib/pleroma/web/twitter_api/views/util_view.ex @@ -4,6 +4,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilView do use Pleroma.Web, :view + import Phoenix.HTML import Phoenix.HTML.Form import Phoenix.HTML.Link alias Pleroma.Config -- cgit v1.2.3 From c59ee1f172628d37e1396e080876f0f3aebaf730 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sat, 20 Aug 2022 21:19:31 -0400 Subject: Expose availability of GET /main/ostatus via instance --- lib/pleroma/web/mastodon_api/views/instance_view.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/views/instance_view.ex b/lib/pleroma/web/mastodon_api/views/instance_view.ex index 62931bd41..dc44295e5 100644 --- a/lib/pleroma/web/mastodon_api/views/instance_view.ex +++ b/lib/pleroma/web/mastodon_api/views/instance_view.ex @@ -98,7 +98,8 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do end, if Config.get([:instance, :profile_directory]) do "profile_directory" - end + end, + "pleroma:get:main/ostatus" ] |> Enum.filter(& &1) end -- cgit v1.2.3 From 439c1baf25b19723bcbaac78b10d00181074e3b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9l=C3=A8ne?= Date: Tue, 23 Aug 2022 17:15:06 +0200 Subject: OAuthPlug: use user cache instead of joining As this plug is called on every request, this should reduce load on the database by not requiring to select on the users table every single time, and to instead use the by-ID user cache whenever possible. --- lib/pleroma/web/plugs/o_auth_plug.ex | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/plugs/o_auth_plug.ex b/lib/pleroma/web/plugs/o_auth_plug.ex index 0f74d626b..ba04ddb72 100644 --- a/lib/pleroma/web/plugs/o_auth_plug.ex +++ b/lib/pleroma/web/plugs/o_auth_plug.ex @@ -47,15 +47,17 @@ defmodule Pleroma.Web.Plugs.OAuthPlug do # @spec fetch_user_and_token(String.t()) :: {:ok, User.t(), Token.t()} | nil defp fetch_user_and_token(token) do - query = + token_query = from(t in Token, - where: t.token == ^token, - join: user in assoc(t, :user), - preload: [user: user] + where: t.token == ^token ) - with %Token{user: user} = token_record <- Repo.one(query) do + with %Token{user_id: user_id} = token_record <- Repo.one(token_query), + false <- is_nil(user_id), + %User{} = user <- User.get_cached_by_id(user_id) do {:ok, user, token_record} + else + _ -> nil end end -- cgit v1.2.3 From 47e3a72b6ecff3fcc9eedf0dc23bffef5f8c9060 Mon Sep 17 00:00:00 2001 From: Ilja <672-ilja@users.noreply.git.pleroma.social> Date: Wed, 24 Aug 2022 15:24:07 +0000 Subject: fix flaky test_user_relationship_test.exs:81 --- lib/pleroma/user_relationship.ex | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/user_relationship.ex b/lib/pleroma/user_relationship.ex index 5b3e593d3..fbecf3129 100644 --- a/lib/pleroma/user_relationship.ex +++ b/lib/pleroma/user_relationship.ex @@ -91,8 +91,9 @@ defmodule Pleroma.UserRelationship do expires_at: expires_at }) |> Repo.insert( - on_conflict: {:replace_all_except, [:id]}, - conflict_target: [:source_id, :relationship_type, :target_id] + on_conflict: {:replace_all_except, [:id, :inserted_at]}, + conflict_target: [:source_id, :relationship_type, :target_id], + returning: true ) end -- cgit v1.2.3 From 3afa1903ee202cc0acb4170bc06c491c15875145 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sat, 27 Aug 2022 17:51:41 -0400 Subject: Do not stream out Create of ChatMessage --- lib/pleroma/activity/ir/topics.ex | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/activity/ir/topics.ex b/lib/pleroma/activity/ir/topics.ex index 56c52e9d1..f058cc0c9 100644 --- a/lib/pleroma/activity/ir/topics.ex +++ b/lib/pleroma/activity/ir/topics.ex @@ -13,6 +13,14 @@ defmodule Pleroma.Activity.Ir.Topics do |> List.flatten() end + defp generate_topics(%{data: %{"type" => "ChatMessage"}}, %{data: %{"type" => "Delete"}}) do + ["user", "user:pleroma_chat"] + end + + defp generate_topics(%{data: %{"type" => "ChatMessage"}}, %{data: %{"type" => "Create"}}) do + [] + end + defp generate_topics(%{data: %{"type" => "Answer"}}, _) do [] end -- cgit v1.2.3 From f9b86c3c22c10d54a721cfe632f9c7455a8b2f9c Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Sat, 27 Aug 2022 19:34:56 -0400 Subject: Make local-only posts stream in local timeline --- lib/pleroma/activity/ir/topics.ex | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/activity/ir/topics.ex b/lib/pleroma/activity/ir/topics.ex index f058cc0c9..fa4350797 100644 --- a/lib/pleroma/activity/ir/topics.ex +++ b/lib/pleroma/activity/ir/topics.ex @@ -39,6 +39,10 @@ defmodule Pleroma.Activity.Ir.Topics do end |> item_creation_tags(object, activity) + "local" -> + ["public:local"] + |> item_creation_tags(object, activity) + "direct" -> ["direct"] @@ -71,7 +75,18 @@ defmodule Pleroma.Activity.Ir.Topics do defp attachment_topics(%{data: %{"attachment" => []}}, _act), do: [] - defp attachment_topics(_object, %{local: true}), do: ["public:media", "public:local:media"] + defp attachment_topics(_object, %{local: true} = activity) do + case Visibility.get_visibility(activity) do + "public" -> + ["public:media", "public:local:media"] + + "local" -> + ["public:local:media"] + + _ -> + [] + end + end defp attachment_topics(_object, %{actor: actor}) when is_binary(actor), do: ["public:media", "public:remote:media:" <> URI.parse(actor).host] -- cgit v1.2.3 From ffd379456bb9e4f125ce5e2480be4d2819b88147 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Wed, 31 Aug 2022 15:57:06 -0400 Subject: Do not stream out Announces to public timelines --- lib/pleroma/activity/ir/topics.ex | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/activity/ir/topics.ex b/lib/pleroma/activity/ir/topics.ex index fa4350797..b9fcd6693 100644 --- a/lib/pleroma/activity/ir/topics.ex +++ b/lib/pleroma/activity/ir/topics.ex @@ -29,7 +29,7 @@ defmodule Pleroma.Activity.Ir.Topics do ["user", "list"] ++ visibility_tags(object, activity) end - defp visibility_tags(object, activity) do + defp visibility_tags(object, %{data: %{"type" => "Create"}} = activity) do case Visibility.get_visibility(activity) do "public" -> if activity.local do @@ -51,6 +51,10 @@ defmodule Pleroma.Activity.Ir.Topics do end end + defp visibility_tags(_object, _activity) do + [] + end + defp item_creation_tags(tags, object, %{data: %{"type" => "Create"}} = activity) do tags ++ remote_topics(activity) ++ hashtags_to_topics(object) ++ attachment_topics(object, activity) -- cgit v1.2.3 From 20a0dd6516e453cdedb5a7a2b7356c529eeacf84 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Wed, 31 Aug 2022 22:14:54 -0400 Subject: Exclude Announce instead of restricting to Create in visibility_tags --- lib/pleroma/activity/ir/topics.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/activity/ir/topics.ex b/lib/pleroma/activity/ir/topics.ex index b9fcd6693..8249cbe27 100644 --- a/lib/pleroma/activity/ir/topics.ex +++ b/lib/pleroma/activity/ir/topics.ex @@ -29,7 +29,7 @@ defmodule Pleroma.Activity.Ir.Topics do ["user", "list"] ++ visibility_tags(object, activity) end - defp visibility_tags(object, %{data: %{"type" => "Create"}} = activity) do + defp visibility_tags(object, %{data: %{"type" => type}} = activity) when type != "Announce" do case Visibility.get_visibility(activity) do "public" -> if activity.local do -- cgit v1.2.3 From 21ab7369cad6504be2f815aec888b38023d7a17a Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Fri, 2 Sep 2022 22:35:08 +0200 Subject: Bump minimum Elixir version to 1.10 With the release of Elixir 1.14, Elixir 1.9 is now end-of-life. Elixir 1.10 Release Notes: https://github.com/elixir-lang/elixir/releases/tag/v1.10.0 --- lib/mix/tasks/pleroma/config.ex | 9 ++------- lib/pleroma/config/loader.ex | 15 ++------------- lib/pleroma/web/activity_pub/object_validator.ex | 3 +-- 3 files changed, 5 insertions(+), 22 deletions(-) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/config.ex b/lib/mix/tasks/pleroma/config.ex index 33d147d36..3a2ea44f8 100644 --- a/lib/mix/tasks/pleroma/config.ex +++ b/lib/mix/tasks/pleroma/config.ex @@ -304,13 +304,8 @@ defmodule Mix.Tasks.Pleroma.Config do System.cmd("mix", ["format", path]) end - if Code.ensure_loaded?(Config.Reader) do - defp config_header, do: "import Config\r\n\r\n" - defp read_file(config_file), do: Config.Reader.read_imports!(config_file) - else - defp config_header, do: "use Mix.Config\r\n\r\n" - defp read_file(config_file), do: Mix.Config.eval!(config_file) - end + defp config_header, do: "import Config\r\n\r\n" + defp read_file(config_file), do: Config.Reader.read_imports!(config_file) defp write_and_delete(config, file, delete?) do config diff --git a/lib/pleroma/config/loader.ex b/lib/pleroma/config/loader.ex index 015be3d8e..bd85eccab 100644 --- a/lib/pleroma/config/loader.ex +++ b/lib/pleroma/config/loader.ex @@ -19,21 +19,10 @@ defmodule Pleroma.Config.Loader do :tesla ] - if Code.ensure_loaded?(Config.Reader) do - @reader Config.Reader - - def read(path), do: @reader.read!(path) - else - # support for Elixir less than 1.9 - @reader Mix.Config - def read(path) do - path - |> @reader.eval!() - |> elem(0) - end - end + @reader Config.Reader @spec read(Path.t()) :: keyword() + def read(path), do: @reader.read!(path) @spec merge(keyword(), keyword()) :: keyword() def merge(c1, c2), do: @reader.merge(c1, c2) diff --git a/lib/pleroma/web/activity_pub/object_validator.ex b/lib/pleroma/web/activity_pub/object_validator.ex index f3e31c931..21442687c 100644 --- a/lib/pleroma/web/activity_pub/object_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validator.ex @@ -204,8 +204,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do def cast_and_apply(o), do: {:error, {:validator_not_set, o}} - # is_struct/1 appears in Elixir 1.11 - def stringify_keys(%{__struct__: _} = object) do + def stringify_keys(object) when is_struct(object) do object |> Map.from_struct() |> stringify_keys -- cgit v1.2.3 From e124776d1448f9043d335dea9425578f37ad1a57 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Fri, 2 Sep 2022 21:12:16 +0200 Subject: Elixir 1.14 formatting --- lib/mix/tasks/pleroma/user.ex | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index 50ffb7f27..929fa1717 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -112,9 +112,10 @@ defmodule Mix.Tasks.Pleroma.User do {:ok, token} <- Pleroma.PasswordResetToken.create_token(user) do shell_info("Generated password reset token for #{user.nickname}") - IO.puts("URL: #{Pleroma.Web.Router.Helpers.reset_password_url(Pleroma.Web.Endpoint, - :reset, - token.token)}") + url = + Pleroma.Web.Router.Helpers.reset_password_url(Pleroma.Web.Endpoint, :reset, token.token) + + IO.puts("URL: #{url}") else _ -> shell_error("No local user #{nickname}") -- cgit v1.2.3 From ec80a1e405c7b1d893c08ea99e824f2c13719c3a Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Fri, 2 Sep 2022 22:35:08 +0200 Subject: Bump minimum Elixir version to 1.10 1.9 being end-of-life --- lib/pleroma/config/loader.ex | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/config/loader.ex b/lib/pleroma/config/loader.ex index 015be3d8e..bd85eccab 100644 --- a/lib/pleroma/config/loader.ex +++ b/lib/pleroma/config/loader.ex @@ -19,21 +19,10 @@ defmodule Pleroma.Config.Loader do :tesla ] - if Code.ensure_loaded?(Config.Reader) do - @reader Config.Reader - - def read(path), do: @reader.read!(path) - else - # support for Elixir less than 1.9 - @reader Mix.Config - def read(path) do - path - |> @reader.eval!() - |> elem(0) - end - end + @reader Config.Reader @spec read(Path.t()) :: keyword() + def read(path), do: @reader.read!(path) @spec merge(keyword(), keyword()) :: keyword() def merge(c1, c2), do: @reader.merge(c1, c2) -- cgit v1.2.3 From 4477c6baff6ea3c17ceca5d9113960b5b78d5ac3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9l=C3=A8ne?= Date: Tue, 23 Aug 2022 14:49:05 +0200 Subject: Metadata/Utils: use summary as description if set When generating OpenGraph and TwitterCard metadata for a post, the summary field will be used first if it is set to generate the post description. --- lib/pleroma/web/metadata/utils.ex | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/metadata/utils.ex b/lib/pleroma/web/metadata/utils.ex index 8052eaa44..15414a988 100644 --- a/lib/pleroma/web/metadata/utils.ex +++ b/lib/pleroma/web/metadata/utils.ex @@ -8,8 +8,8 @@ defmodule Pleroma.Web.Metadata.Utils do alias Pleroma.Formatter alias Pleroma.HTML - def scrub_html_and_truncate(%{data: %{"content" => content}} = object) do - content + defp scrub_html_and_truncate_object_field(field, object) do + field # html content comes from DB already encoded, decode first and scrub after |> HtmlEntities.decode() |> String.replace(~r//, " ") @@ -19,6 +19,17 @@ defmodule Pleroma.Web.Metadata.Utils do |> Formatter.truncate() end + def scrub_html_and_truncate(%{data: %{"summary" => summary}} = object) + when is_binary(summary) and summary != "" do + summary + |> scrub_html_and_truncate_object_field(object) + end + + def scrub_html_and_truncate(%{data: %{"content" => content}} = object) do + content + |> scrub_html_and_truncate_object_field(object) + end + def scrub_html_and_truncate(content, max_length \\ 200) when is_binary(content) do content |> scrub_html -- cgit v1.2.3 From cd237d22f165edb84202154e4c6f6725f63df635 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9l=C3=A8ne?= Date: Fri, 26 Aug 2022 18:30:43 +0200 Subject: User: generate private keys on user creation This fixes a race condition bug where keys could be regenerated post-federation, causing activities and HTTP signatures from an user to be dropped due to key differences. --- lib/pleroma/signature.ex | 5 +-- lib/pleroma/user.ex | 19 ++++---- .../web/activity_pub/activity_pub_controller.ex | 52 ++++++---------------- lib/pleroma/web/activity_pub/views/user_view.ex | 2 - lib/pleroma/web/federator.ex | 6 +-- lib/pleroma/web/web_finger.ex | 4 -- 6 files changed, 25 insertions(+), 63 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/signature.ex b/lib/pleroma/signature.ex index dbe6fd209..a7b8f48aa 100644 --- a/lib/pleroma/signature.ex +++ b/lib/pleroma/signature.ex @@ -59,9 +59,8 @@ defmodule Pleroma.Signature do end end - def sign(%User{} = user, headers) do - with {:ok, %{keys: keys}} <- User.ensure_keys_present(user), - {:ok, private_key, _} <- Keys.keys_from_pem(keys) do + def sign(%User{keys: keys} = user, headers) do + with {:ok, private_key, _} <- Keys.keys_from_pem(keys) do HTTPSignatures.sign(private_key, user.ap_id <> "#main-key", headers) end end diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index a57295891..85d3382cb 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -711,6 +711,7 @@ defmodule Pleroma.User do |> put_ap_id() |> unique_constraint(:ap_id) |> put_following_and_follower_and_featured_address() + |> put_private_key() end def register_changeset(struct, params \\ %{}, opts \\ []) do @@ -768,6 +769,7 @@ defmodule Pleroma.User do |> put_ap_id() |> unique_constraint(:ap_id) |> put_following_and_follower_and_featured_address() + |> put_private_key() end def validate_not_restricted_nickname(changeset, field) do @@ -846,6 +848,11 @@ defmodule Pleroma.User do |> put_change(:featured_address, featured) end + defp put_private_key(changeset) do + {:ok, pem} = Keys.generate_rsa_pem() + put_change(changeset, :keys, pem) + end + defp autofollow_users(user) do candidates = Config.get([:instance, :autofollowed_nicknames]) @@ -2086,6 +2093,7 @@ defmodule Pleroma.User do follower_address: uri <> "/followers" } |> change + |> put_private_key() |> unique_constraint(:nickname) |> Repo.insert() |> set_cache() @@ -2351,17 +2359,6 @@ defmodule Pleroma.User do } end - def ensure_keys_present(%{keys: keys} = user) when not is_nil(keys), do: {:ok, user} - - def ensure_keys_present(%User{} = user) do - with {:ok, pem} <- Keys.generate_rsa_pem() do - user - |> cast(%{keys: pem}, [:keys]) - |> validate_required([:keys]) - |> update_and_set_cache() - end - end - def get_ap_ids_by_nicknames(nicknames) do from(u in User, where: u.nickname in ^nicknames, diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex index b8f63d69d..1357c379c 100644 --- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex +++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex @@ -66,8 +66,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do end def user(conn, %{"nickname" => nickname}) do - with %User{local: true} = user <- User.get_cached_by_nickname(nickname), - {:ok, user} <- User.ensure_keys_present(user) do + with %User{local: true} = user <- User.get_cached_by_nickname(nickname) do conn |> put_resp_content_type("application/activity+json") |> put_view(UserView) @@ -174,7 +173,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do def following(%{assigns: %{user: for_user}} = conn, %{"nickname" => nickname, "page" => page}) do with %User{} = user <- User.get_cached_by_nickname(nickname), - {user, for_user} <- ensure_user_keys_present_and_maybe_refresh_for_user(user, for_user), {:show_follows, true} <- {:show_follows, (for_user && for_user == user) || !user.hide_follows} do {page, _} = Integer.parse(page) @@ -192,8 +190,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do end def following(%{assigns: %{user: for_user}} = conn, %{"nickname" => nickname}) do - with %User{} = user <- User.get_cached_by_nickname(nickname), - {user, for_user} <- ensure_user_keys_present_and_maybe_refresh_for_user(user, for_user) do + with %User{} = user <- User.get_cached_by_nickname(nickname) do conn |> put_resp_content_type("application/activity+json") |> put_view(UserView) @@ -213,7 +210,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do def followers(%{assigns: %{user: for_user}} = conn, %{"nickname" => nickname, "page" => page}) do with %User{} = user <- User.get_cached_by_nickname(nickname), - {user, for_user} <- ensure_user_keys_present_and_maybe_refresh_for_user(user, for_user), {:show_followers, true} <- {:show_followers, (for_user && for_user == user) || !user.hide_followers} do {page, _} = Integer.parse(page) @@ -231,8 +227,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do end def followers(%{assigns: %{user: for_user}} = conn, %{"nickname" => nickname}) do - with %User{} = user <- User.get_cached_by_nickname(nickname), - {user, for_user} <- ensure_user_keys_present_and_maybe_refresh_for_user(user, for_user) do + with %User{} = user <- User.get_cached_by_nickname(nickname) do conn |> put_resp_content_type("application/activity+json") |> put_view(UserView) @@ -245,8 +240,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do %{"nickname" => nickname, "page" => page?} = params ) when page? in [true, "true"] do - with %User{} = user <- User.get_cached_by_nickname(nickname), - {:ok, user} <- User.ensure_keys_present(user) do + with %User{} = user <- User.get_cached_by_nickname(nickname) do # "include_poll_votes" is a hack because postgres generates inefficient # queries when filtering by 'Answer', poll votes will be hidden by the # visibility filter in this case anyway @@ -270,8 +264,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do end def outbox(conn, %{"nickname" => nickname}) do - with %User{} = user <- User.get_cached_by_nickname(nickname), - {:ok, user} <- User.ensure_keys_present(user) do + with %User{} = user <- User.get_cached_by_nickname(nickname) do conn |> put_resp_content_type("application/activity+json") |> put_view(UserView) @@ -328,14 +321,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do end defp represent_service_actor(%User{} = user, conn) do - with {:ok, user} <- User.ensure_keys_present(user) do - conn - |> put_resp_content_type("application/activity+json") - |> put_view(UserView) - |> render("user.json", %{user: user}) - else - nil -> {:error, :not_found} - end + conn + |> put_resp_content_type("application/activity+json") + |> put_view(UserView) + |> render("user.json", %{user: user}) end defp represent_service_actor(nil, _), do: {:error, :not_found} @@ -388,12 +377,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do def read_inbox(%{assigns: %{user: %User{nickname: nickname} = user}} = conn, %{ "nickname" => nickname }) do - with {:ok, user} <- User.ensure_keys_present(user) do - conn - |> put_resp_content_type("application/activity+json") - |> put_view(UserView) - |> render("activity_collection.json", %{iri: "#{user.ap_id}/inbox"}) - end + conn + |> put_resp_content_type("application/activity+json") + |> put_view(UserView) + |> render("activity_collection.json", %{iri: "#{user.ap_id}/inbox"}) end def read_inbox(%{assigns: %{user: %User{nickname: as_nickname}}} = conn, %{ @@ -530,19 +517,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do conn end - defp ensure_user_keys_present_and_maybe_refresh_for_user(user, for_user) do - {:ok, new_user} = User.ensure_keys_present(user) - - for_user = - if new_user != user and match?(%User{}, for_user) do - User.get_cached_by_nickname(for_user.nickname) - else - for_user - end - - {new_user, for_user} - end - def upload_media(%{assigns: %{user: %User{} = user}} = conn, %{"file" => file} = data) do with {:ok, object} <- ActivityPub.upload( diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex index 52f6bb56d..f69fca075 100644 --- a/lib/pleroma/web/activity_pub/views/user_view.ex +++ b/lib/pleroma/web/activity_pub/views/user_view.ex @@ -34,7 +34,6 @@ defmodule Pleroma.Web.ActivityPub.UserView do def render("endpoints.json", _), do: %{} def render("service.json", %{user: user}) do - {:ok, user} = User.ensure_keys_present(user) {:ok, _, public_key} = Keys.keys_from_pem(user.keys) public_key = :public_key.pem_entry_encode(:SubjectPublicKeyInfo, public_key) public_key = :public_key.pem_encode([public_key]) @@ -71,7 +70,6 @@ defmodule Pleroma.Web.ActivityPub.UserView do do: render("service.json", %{user: user}) |> Map.put("preferredUsername", user.nickname) def render("user.json", %{user: user}) do - {:ok, user} = User.ensure_keys_present(user) {:ok, _, public_key} = Keys.keys_from_pem(user.keys) public_key = :public_key.pem_entry_encode(:SubjectPublicKeyInfo, public_key) public_key = :public_key.pem_encode([public_key]) diff --git a/lib/pleroma/web/federator.ex b/lib/pleroma/web/federator.ex index e7feefc07..3be71c1b6 100644 --- a/lib/pleroma/web/federator.ex +++ b/lib/pleroma/web/federator.ex @@ -61,10 +61,8 @@ defmodule Pleroma.Web.Federator do def perform(:publish, activity) do Logger.debug(fn -> "Running publish for #{activity.data["id"]}" end) - with %User{} = actor <- User.get_cached_by_ap_id(activity.data["actor"]), - {:ok, actor} <- User.ensure_keys_present(actor) do - Publisher.publish(actor, activity) - end + %User{} = actor = User.get_cached_by_ap_id(activity.data["actor"]) + Publisher.publish(actor, activity) end def perform(:incoming_ap_doc, params) do diff --git a/lib/pleroma/web/web_finger.ex b/lib/pleroma/web/web_finger.ex index 6cd9962ce..77ff40f46 100644 --- a/lib/pleroma/web/web_finger.ex +++ b/lib/pleroma/web/web_finger.ex @@ -63,8 +63,6 @@ defmodule Pleroma.Web.WebFinger do end def represent_user(user, "JSON") do - {:ok, user} = User.ensure_keys_present(user) - %{ "subject" => "acct:#{user.nickname}@#{Pleroma.Web.Endpoint.host()}", "aliases" => gather_aliases(user), @@ -73,8 +71,6 @@ defmodule Pleroma.Web.WebFinger do end def represent_user(user, "XML") do - {:ok, user} = User.ensure_keys_present(user) - aliases = user |> gather_aliases() -- cgit v1.2.3 From 50923f543826bb97efe8e01737ca854003ab934f Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Thu, 8 Sep 2022 11:58:17 -0400 Subject: Fix User.get_or_fetch/1 with usernames starting with http --- lib/pleroma/user.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 85d3382cb..b422e5c1d 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -2126,7 +2126,8 @@ defmodule Pleroma.User do @doc "Gets or fetch a user by uri or nickname." @spec get_or_fetch(String.t()) :: {:ok, User.t()} | {:error, String.t()} - def get_or_fetch("http" <> _host = uri), do: get_or_fetch_by_ap_id(uri) + def get_or_fetch("http://" <> _host = uri), do: get_or_fetch_by_ap_id(uri) + def get_or_fetch("https://" <> _host = uri), do: get_or_fetch_by_ap_id(uri) def get_or_fetch(nickname), do: get_or_fetch_by_nickname(nickname) # wait a period of time and return newest version of the User structs -- cgit v1.2.3 From 0b19625bfba0ef4a9a4c97bada981dfb5c1edbf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9l=C3=A8ne?= Date: Sun, 11 Sep 2022 04:54:04 +0200 Subject: ObjectView: do not fetch an object for its ID Non-Create/Listen activities had their associated object field normalized and fetched, but only to use their `id` field, which is both slow and redundant. This also failed on Undo activities, which delete the associated object/activity in database. Undo activities will now render properly and database loads should improve ever so slightly. --- lib/pleroma/object.ex | 15 ++++++++++----- lib/pleroma/web/activity_pub/views/object_view.ex | 4 ++-- 2 files changed, 12 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index fee3f1842..38accae5d 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -144,7 +144,7 @@ defmodule Pleroma.Object do Logger.debug("Backtrace: #{inspect(Process.info(:erlang.self(), :current_stacktrace))}") end - def normalize(_, options \\ [fetch: false]) + def normalize(_, options \\ [fetch: false, id_only: false]) # If we pass an Activity to Object.normalize(), we can try to use the preloaded object. # Use this whenever possible, especially when walking graphs in an O(N) loop! @@ -172,10 +172,15 @@ defmodule Pleroma.Object do def normalize(%{"id" => ap_id}, options), do: normalize(ap_id, options) def normalize(ap_id, options) when is_binary(ap_id) do - if Keyword.get(options, :fetch) do - Fetcher.fetch_object_from_id!(ap_id, options) - else - get_cached_by_ap_id(ap_id) + cond do + Keyword.get(options, :id_only) -> + ap_id + + Keyword.get(options, :fetch) -> + Fetcher.fetch_object_from_id!(ap_id, options) + + true -> + get_cached_by_ap_id(ap_id) end end diff --git a/lib/pleroma/web/activity_pub/views/object_view.ex b/lib/pleroma/web/activity_pub/views/object_view.ex index f848aba3a..63caa915c 100644 --- a/lib/pleroma/web/activity_pub/views/object_view.ex +++ b/lib/pleroma/web/activity_pub/views/object_view.ex @@ -29,11 +29,11 @@ defmodule Pleroma.Web.ActivityPub.ObjectView do def render("object.json", %{object: %Activity{} = activity}) do base = Pleroma.Web.ActivityPub.Utils.make_json_ld_header() - object = Object.normalize(activity, fetch: false) + object_id = Object.normalize(activity, id_only: true) additional = Transmogrifier.prepare_object(activity.data) - |> Map.put("object", object.data["id"]) + |> Map.put("object", object_id) Map.merge(base, additional) end -- cgit v1.2.3 From ea60c4e7097c69df2023f23f60451f69668394f8 Mon Sep 17 00:00:00 2001 From: Tusooa Zhu Date: Wed, 14 Sep 2022 20:24:04 -0400 Subject: Fix wrong relationship direction --- lib/pleroma/web/mastodon_api/controllers/account_controller.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex index 50dd0e4c2..2b736e5a3 100644 --- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex @@ -481,7 +481,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do def remove_from_followers(%{assigns: %{user: followed, account: follower}} = conn, _params) do with {:ok, follower} <- CommonAPI.reject_follow_request(follower, followed) do - render(conn, "relationship.json", user: follower, target: followed) + render(conn, "relationship.json", user: followed, target: follower) else nil -> render_error(conn, :not_found, "Record not found") -- cgit v1.2.3 From 7f63b4c315653b4ed35afa326fc194feec21aea3 Mon Sep 17 00:00:00 2001 From: a1batross Date: Thu, 15 Sep 2022 22:38:35 +0200 Subject: User: search: exclude deactivated users from user search This way we don't pollute search results with deactivated and deleted users --- lib/pleroma/user/search.ex | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/user/search.ex b/lib/pleroma/user/search.ex index cd6f69f56..a7fb8fb83 100644 --- a/lib/pleroma/user/search.ex +++ b/lib/pleroma/user/search.ex @@ -94,6 +94,7 @@ defmodule Pleroma.User.Search do |> subquery() |> order_by(desc: :search_rank) |> maybe_restrict_local(for_user) + |> filter_deactivated_users() end defp select_top_users(query, top_user_ids) do @@ -166,6 +167,10 @@ defmodule Pleroma.User.Search do from(q in query, where: q.actor_type != "Application") end + defp filter_deactivated_users(query) do + from(q in query, where: q.is_active == true) + end + defp filter_blocked_user(query, %User{} = blocker) do query |> join(:left, [u], b in Pleroma.UserRelationship, -- cgit v1.2.3 From 2d7ea263a1f7dba8e0a7667a95ea8af110e9be27 Mon Sep 17 00:00:00 2001 From: Ilja Date: Sat, 24 Sep 2022 13:52:28 +0200 Subject: Add extra routes to :users_manage_credentials privilege --- lib/pleroma/web/router.ex | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index f77513046..a50232422 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -233,8 +233,6 @@ defmodule Pleroma.Web.Router do scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do pipe_through([:admin_api, :require_admin]) - put("/users/disable_mfa", AdminAPIController, :disable_mfa) - get("/users/:nickname/permission_group", AdminAPIController, :right_get) get("/users/:nickname/permission_group/:permission_group", AdminAPIController, :right_get) @@ -265,16 +263,10 @@ defmodule Pleroma.Web.Router do post("/relay", RelayController, :follow) delete("/relay", RelayController, :unfollow) - patch("/users/force_password_reset", AdminAPIController, :force_password_reset) - get("/users/:nickname/credentials", AdminAPIController, :show_user_credentials) - get("/instance_document/:name", InstanceDocumentController, :show) patch("/instance_document/:name", InstanceDocumentController, :update) delete("/instance_document/:name", InstanceDocumentController, :delete) - patch("/users/confirm_email", AdminAPIController, :confirm_email) - patch("/users/resend_confirmation_email", AdminAPIController, :resend_confirmation_email) - get("/config", ConfigController, :show) post("/config", ConfigController, :update) get("/config/descriptions", ConfigController, :descriptions) @@ -319,7 +311,12 @@ defmodule Pleroma.Web.Router do pipe_through(:require_privileged_role_users_manage_credentials) get("/users/:nickname/password_reset", AdminAPIController, :get_password_reset) + get("/users/:nickname/credentials", AdminAPIController, :show_user_credentials) patch("/users/:nickname/credentials", AdminAPIController, :update_user_credentials) + put("/users/disable_mfa", AdminAPIController, :disable_mfa) + patch("/users/force_password_reset", AdminAPIController, :force_password_reset) + patch("/users/confirm_email", AdminAPIController, :confirm_email) + patch("/users/resend_confirmation_email", AdminAPIController, :resend_confirmation_email) end # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) -- cgit v1.2.3 From 1958f23fe709fbd59f8eb09ed8749fffa2c91f23 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Fri, 30 Sep 2022 12:22:06 -0400 Subject: Fix deprecation warning for Gun timeout --- lib/pleroma/config/deprecation_warnings.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/config/deprecation_warnings.ex b/lib/pleroma/config/deprecation_warnings.ex index 599f1d3cf..b53b15d95 100644 --- a/lib/pleroma/config/deprecation_warnings.ex +++ b/lib/pleroma/config/deprecation_warnings.ex @@ -311,7 +311,7 @@ defmodule Pleroma.Config.DeprecationWarnings do warning_preface = """ !!!DEPRECATION WARNING!!! - Your config is using old setting name `timeout` instead of `recv_timeout` in pool settings. Setting should work for now, but you are advised to change format to scheme with port to prevent possible issues later. + Your config is using old setting name `timeout` instead of `recv_timeout` in pool settings. The setting will not take effect until updated. """ updated_config = -- cgit v1.2.3 From 1b238a4fadd50811b1cce64812858c101e790c60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Sat, 1 Oct 2022 23:28:02 +0200 Subject: Push.Impl: support edits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- lib/pleroma/web/push/impl.ex | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/push/impl.ex b/lib/pleroma/web/push/impl.ex index daf3eeb9e..3c5f00764 100644 --- a/lib/pleroma/web/push/impl.ex +++ b/lib/pleroma/web/push/impl.ex @@ -16,7 +16,7 @@ defmodule Pleroma.Web.Push.Impl do require Logger import Ecto.Query - @types ["Create", "Follow", "Announce", "Like", "Move", "EmojiReact"] + @types ["Create", "Follow", "Announce", "Like", "Move", "EmojiReact", "Update"] @doc "Performs sending notifications for user subscriptions" @spec perform(Notification.t()) :: list(any) | :error | {:error, :unknown_type} @@ -174,6 +174,15 @@ defmodule Pleroma.Web.Push.Impl do end end + def format_body( + %{activity: %{data: %{"type" => "Update"}}}, + actor, + _object, + _mastodon_type + ) do + "@#{actor.nickname} edited a status" + end + def format_title(activity, mastodon_type \\ nil) def format_title(%{activity: %{data: %{"directMessage" => true}}}, _mastodon_type) do @@ -187,6 +196,7 @@ defmodule Pleroma.Web.Push.Impl do "follow_request" -> "New Follow Request" "reblog" -> "New Repeat" "favourite" -> "New Favorite" + "update" -> "New Update" "pleroma:chat_mention" -> "New Chat Message" "pleroma:emoji_reaction" -> "New Reaction" type -> "New #{String.capitalize(type || "event")}" -- cgit v1.2.3 From 16b06160acbaec054736b18edf08d77e88a27aee Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Fri, 14 Oct 2022 18:32:13 +0200 Subject: CommonAPI: generate ModerationLog for all admin/moderator deletes As a side-effect it also changes the ChatMessage delete ID to an Activity.id rather than MessageReference.id Closes: https://git.pleroma.social/pleroma/pleroma/-/issues/2958 --- lib/pleroma/web/admin_api/controllers/chat_controller.ex | 7 ------- .../web/admin_api/controllers/status_controller.ex | 6 ------ lib/pleroma/web/common_api.ex | 16 ++++++++++++++++ 3 files changed, 16 insertions(+), 13 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/admin_api/controllers/chat_controller.ex b/lib/pleroma/web/admin_api/controllers/chat_controller.ex index c3e9e12ce..298543fcf 100644 --- a/lib/pleroma/web/admin_api/controllers/chat_controller.ex +++ b/lib/pleroma/web/admin_api/controllers/chat_controller.ex @@ -8,7 +8,6 @@ defmodule Pleroma.Web.AdminAPI.ChatController do alias Pleroma.Activity alias Pleroma.Chat alias Pleroma.Chat.MessageReference - alias Pleroma.ModerationLog alias Pleroma.Pagination alias Pleroma.Web.AdminAPI alias Pleroma.Web.CommonAPI @@ -42,12 +41,6 @@ defmodule Pleroma.Web.AdminAPI.ChatController do ^chat_id <- to_string(cm_ref.chat_id), %Activity{id: activity_id} <- Activity.get_create_by_object_ap_id(object_ap_id), {:ok, _} <- CommonAPI.delete(activity_id, user) do - ModerationLog.insert_log(%{ - action: "chat_message_delete", - actor: user, - subject_id: message_id - }) - conn |> put_view(MessageReferenceView) |> render("show.json", chat_message_reference: cm_ref) diff --git a/lib/pleroma/web/admin_api/controllers/status_controller.ex b/lib/pleroma/web/admin_api/controllers/status_controller.ex index c9a4bfde9..9a3d49b57 100644 --- a/lib/pleroma/web/admin_api/controllers/status_controller.ex +++ b/lib/pleroma/web/admin_api/controllers/status_controller.ex @@ -65,12 +65,6 @@ defmodule Pleroma.Web.AdminAPI.StatusController do def delete(%{assigns: %{user: user}} = conn, %{id: id}) do with {:ok, %Activity{}} <- CommonAPI.delete(id, user) do - ModerationLog.insert_log(%{ - action: "status_delete", - actor: user, - subject_id: id - }) - json(conn, %{}) end end diff --git a/lib/pleroma/web/common_api.ex b/lib/pleroma/web/common_api.ex index 89f5dd606..62ab6b69c 100644 --- a/lib/pleroma/web/common_api.ex +++ b/lib/pleroma/web/common_api.ex @@ -6,6 +6,7 @@ defmodule Pleroma.Web.CommonAPI do alias Pleroma.Activity alias Pleroma.Conversation.Participation alias Pleroma.Formatter + alias Pleroma.ModerationLog alias Pleroma.Object alias Pleroma.ThreadMute alias Pleroma.User @@ -147,6 +148,21 @@ defmodule Pleroma.Web.CommonAPI do true <- User.superuser?(user) || user.ap_id == object.data["actor"], {:ok, delete_data, _} <- Builder.delete(user, object.data["id"]), {:ok, delete, _} <- Pipeline.common_pipeline(delete_data, local: true) do + if User.superuser?(user) and user.ap_id != object.data["actor"] do + action = + if object.data["type"] == "ChatMessage" do + "chat_message_delete" + else + "status_delete" + end + + ModerationLog.insert_log(%{ + action: action, + actor: user, + subject_id: activity_id + }) + end + {:ok, delete} else {:find_activity, _} -> -- cgit v1.2.3 From 4121bca8957838f094ef134de4b54e492517e527 Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Thu, 4 Mar 2021 13:06:12 +0300 Subject: expanding WebFinger --- lib/pleroma/http.ex | 9 ++++- lib/pleroma/web/activity_pub/activity_pub.ex | 57 +++++++++++++++------------- lib/pleroma/web/web_finger.ex | 45 ++++++++++++---------- 3 files changed, 64 insertions(+), 47 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/http.ex b/lib/pleroma/http.ex index 2e82ceff2..d41061538 100644 --- a/lib/pleroma/http.ex +++ b/lib/pleroma/http.ex @@ -106,5 +106,12 @@ defmodule Pleroma.HTTP do [Tesla.Middleware.FollowRedirects, Pleroma.Tesla.Middleware.ConnectionPool] end - defp adapter_middlewares(_), do: [] + defp adapter_middlewares(_) do + if Pleroma.Config.get(:env) == :test do + # Emulate redirects in test env, which are handled by adapters in other environments + [Tesla.Middleware.FollowRedirects] + else + [] + end + end end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index a5d7036d9..5099caef7 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -1482,7 +1482,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do defp normalize_image(urls) when is_list(urls), do: urls |> List.first() |> normalize_image() defp normalize_image(_), do: nil - defp object_to_user_data(data) do + defp object_to_user_data(data, additional) do fields = data |> Map.get("attachment", []) @@ -1514,15 +1514,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do public_key = if is_map(data["publicKey"]) && is_binary(data["publicKey"]["publicKeyPem"]) do data["publicKey"]["publicKeyPem"] - else - nil end shared_inbox = if is_map(data["endpoints"]) && is_binary(data["endpoints"]["sharedInbox"]) do data["endpoints"]["sharedInbox"] - else - nil end birthday = @@ -1531,13 +1527,15 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do {:ok, date} -> date {:error, _} -> nil end - else - nil end show_birthday = !!birthday - user_data = %{ + # if WebFinger request was already done, we probably have acct, otherwise + # we request WebFinger here + nickname = additional[:nickname_from_acct] || generate_nickname(data) + + %{ ap_id: data["id"], uri: get_actor_url(data["url"]), ap_enabled: true, @@ -1559,23 +1557,29 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do inbox: data["inbox"], shared_inbox: shared_inbox, accepts_chat_messages: accepts_chat_messages, - pinned_objects: pinned_objects, birthday: birthday, - show_birthday: show_birthday + show_birthday: show_birthday, + pinned_objects: pinned_objects, + nickname: nickname } + end - # nickname can be nil because of virtual actors - if data["preferredUsername"] do - Map.put( - user_data, - :nickname, - "#{data["preferredUsername"]}@#{URI.parse(data["id"]).host}" - ) + defp generate_nickname(%{"preferredUsername" => username} = data) when is_binary(username) do + generated = "#{username}@#{URI.parse(data["id"]).host}" + + if Config.get([WebFinger, :update_nickname_on_user_fetch]) do + case WebFinger.finger(generated) do + {:ok, %{"subject" => "acct:" <> acct}} -> acct + _ -> generated + end else - Map.put(user_data, :nickname, nil) + generated end end + # nickname can be nil because of virtual actors + defp generate_nickname(_), do: nil + def fetch_follow_information_for_user(user) do with {:ok, following_data} <- Fetcher.fetch_and_contain_remote_object_from_id(user.following_address), @@ -1647,17 +1651,17 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do defp collection_private(_data), do: {:ok, true} - def user_data_from_user_object(data) do + def user_data_from_user_object(data, additional \\ []) do with {:ok, data} <- MRF.filter(data) do - {:ok, object_to_user_data(data)} + {:ok, object_to_user_data(data, additional)} else e -> {:error, e} end end - def fetch_and_prepare_user_from_ap_id(ap_id) do + def fetch_and_prepare_user_from_ap_id(ap_id, additional \\ []) do with {:ok, data} <- Fetcher.fetch_and_contain_remote_object_from_id(ap_id), - {:ok, data} <- user_data_from_user_object(data) do + {:ok, data} <- user_data_from_user_object(data, additional) do {:ok, maybe_update_follow_information(data)} else # If this has been deleted, only log a debug and not an error @@ -1735,13 +1739,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do end end - def make_user_from_ap_id(ap_id) do + def make_user_from_ap_id(ap_id, additional \\ []) do user = User.get_cached_by_ap_id(ap_id) if user && !User.ap_enabled?(user) do Transmogrifier.upgrade_user_from_ap_id(ap_id) else - with {:ok, data} <- fetch_and_prepare_user_from_ap_id(ap_id) do + with {:ok, data} <- fetch_and_prepare_user_from_ap_id(ap_id, additional) do {:ok, _pid} = Task.start(fn -> pinned_fetch_task(data) end) if user do @@ -1761,8 +1765,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do end def make_user_from_nickname(nickname) do - with {:ok, %{"ap_id" => ap_id}} when not is_nil(ap_id) <- WebFinger.finger(nickname) do - make_user_from_ap_id(ap_id) + with {:ok, %{"ap_id" => ap_id, "subject" => "acct:" <> acct}} when not is_nil(ap_id) <- + WebFinger.finger(nickname) do + make_user_from_ap_id(ap_id, nickname_from_acct: acct) else _e -> {:error, "No AP id in WebFinger"} end diff --git a/lib/pleroma/web/web_finger.ex b/lib/pleroma/web/web_finger.ex index 77ff40f46..3aed7e508 100644 --- a/lib/pleroma/web/web_finger.ex +++ b/lib/pleroma/web/web_finger.ex @@ -32,7 +32,13 @@ defmodule Pleroma.Web.WebFinger do def webfinger(resource, fmt) when fmt in ["XML", "JSON"] do host = Pleroma.Web.Endpoint.host() - regex = ~r/(acct:)?(?[a-z0-9A-Z_\.-]+)@#{host}/ + + regex = + if webfinger_domain = Pleroma.Config.get([__MODULE__, :domain]) do + ~r/(acct:)?(?[a-z0-9A-Z_\.-]+)@(#{host}|#{webfinger_domain})/ + else + ~r/(acct:)?(?[a-z0-9A-Z_\.-]+)@#{host}/ + end with %{"username" => username} <- Regex.named_captures(regex, resource), %User{} = user <- User.get_cached_by_nickname(username) do @@ -63,8 +69,12 @@ defmodule Pleroma.Web.WebFinger do end def represent_user(user, "JSON") do + {:ok, user} = User.ensure_keys_present(user) + + domain = Pleroma.Config.get([__MODULE__, :domain]) || Pleroma.Web.Endpoint.host() + %{ - "subject" => "acct:#{user.nickname}@#{Pleroma.Web.Endpoint.host()}", + "subject" => "acct:#{user.nickname}@#{domain}", "aliases" => gather_aliases(user), "links" => gather_links(user) } @@ -146,17 +156,15 @@ defmodule Pleroma.Web.WebFinger do end def find_lrdd_template(domain) do - with {:ok, %{status: status, body: body}} when status in 200..299 <- - HTTP.get("http://#{domain}/.well-known/host-meta") do + # WebFinger is restricted to HTTPS - https://tools.ietf.org/html/rfc7033#section-9.1 + meta_url = "https://#{domain}/.well-known/host-meta" + + with {:ok, %{status: status, body: body}} when status in 200..299 <- HTTP.get(meta_url) do get_template_from_xml(body) else - _ -> - with {:ok, %{body: body, status: status}} when status in 200..299 <- - HTTP.get("https://#{domain}/.well-known/host-meta") do - get_template_from_xml(body) - else - e -> {:error, "Can't find LRDD template: #{inspect(e)}"} - end + error -> + Logger.warn("Can't find LRDD template in #{inspect(meta_url)}: #{inspect(error)}") + {:error, :lrdd_not_found} end end @@ -170,7 +178,7 @@ defmodule Pleroma.Web.WebFinger do end end - defp get_address_from_domain(_, _), do: nil + defp get_address_from_domain(_, _), do: {:error, :webfinger_no_domain} @spec finger(String.t()) :: {:ok, map()} | {:error, any()} def finger(account) do @@ -187,13 +195,11 @@ defmodule Pleroma.Web.WebFinger do encoded_account = URI.encode("acct:#{account}") with address when is_binary(address) <- get_address_from_domain(domain, encoded_account), - response <- + {:ok, %{status: status, body: body, headers: headers}} when status in 200..299 <- HTTP.get( address, [{"accept", "application/xrd+xml,application/jrd+json"}] - ), - {:ok, %{status: status, body: body, headers: headers}} when status in 200..299 <- - response do + ) do case List.keyfind(headers, "content-type", 0) do {_, content_type} -> case Plug.Conn.Utils.media_type(content_type) do @@ -211,10 +217,9 @@ defmodule Pleroma.Web.WebFinger do {:error, {:content_type, nil}} end else - e -> - Logger.debug(fn -> "Couldn't finger #{account}" end) - Logger.debug(fn -> inspect(e) end) - {:error, e} + error -> + Logger.debug("Couldn't finger #{account}: #{inspect(error)}") + error end end end -- cgit v1.2.3 From 5a9ea98baf1d64a1ba61b0f88b2b0e0334bd5ca3 Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Thu, 4 Mar 2021 19:14:00 +0300 Subject: XML WebFinger user representation correct domain --- lib/pleroma/web/web_finger.ex | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/web_finger.ex b/lib/pleroma/web/web_finger.ex index 3aed7e508..967935e5e 100644 --- a/lib/pleroma/web/web_finger.ex +++ b/lib/pleroma/web/web_finger.ex @@ -71,10 +71,8 @@ defmodule Pleroma.Web.WebFinger do def represent_user(user, "JSON") do {:ok, user} = User.ensure_keys_present(user) - domain = Pleroma.Config.get([__MODULE__, :domain]) || Pleroma.Web.Endpoint.host() - %{ - "subject" => "acct:#{user.nickname}@#{domain}", + "subject" => "acct:#{user.nickname}@#{domain()}", "aliases" => gather_aliases(user), "links" => gather_links(user) } @@ -94,12 +92,16 @@ 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()}"} + {:Subject, "acct:#{user.nickname}@#{domain()}"} ] ++ aliases ++ links } |> XmlBuilder.to_doc() end + defp domain do + Pleroma.Config.get([__MODULE__, :domain]) || Pleroma.Web.Endpoint.host() + end + defp webfinger_from_xml(body) do with {:ok, doc} <- XML.parse_document(body) do subject = XML.string_from_xpath("//Subject", doc) -- cgit v1.2.3 From 8407e26b0c1ec315fe8864948c78657f29f370c7 Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Sun, 21 Mar 2021 13:41:20 +0300 Subject: rebase fix --- lib/pleroma/web/web_finger.ex | 2 -- 1 file changed, 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/web_finger.ex b/lib/pleroma/web/web_finger.ex index 967935e5e..f95dc2458 100644 --- a/lib/pleroma/web/web_finger.ex +++ b/lib/pleroma/web/web_finger.ex @@ -69,8 +69,6 @@ defmodule Pleroma.Web.WebFinger do end def represent_user(user, "JSON") do - {:ok, user} = User.ensure_keys_present(user) - %{ "subject" => "acct:#{user.nickname}@#{domain()}", "aliases" => gather_aliases(user), -- cgit v1.2.3 From 7c64f705f6ee0364f1e016004bb0baf79d88dae2 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Wed, 2 Nov 2022 21:56:43 -0400 Subject: Update to Phoenix 1.6 and chase dependencies Also bump minimum Elixir to 1.11 --- lib/pleroma/web/templates/feed/feed/_tag_activity.atom.eex | 2 +- lib/pleroma/web/templates/feed/feed/tag.atom.eex | 2 +- lib/pleroma/web/templates/feed/feed/tag.rss.eex | 2 +- lib/pleroma/web/templates/feed/feed/user.atom.eex | 4 ++-- lib/pleroma/web/templates/feed/feed/user.rss.eex | 4 ++-- lib/pleroma/web/templates/layout/email.html.eex | 2 +- lib/pleroma/web/templates/layout/embed.html.eex | 2 +- lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex | 2 +- lib/pleroma/web/templates/o_auth/o_auth/show.html.eex | 4 ++-- 9 files changed, 12 insertions(+), 12 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/templates/feed/feed/_tag_activity.atom.eex b/lib/pleroma/web/templates/feed/feed/_tag_activity.atom.eex index aa3035bca..7e2e587e1 100644 --- a/lib/pleroma/web/templates/feed/feed/_tag_activity.atom.eex +++ b/lib/pleroma/web/templates/feed/feed/_tag_activity.atom.eex @@ -2,7 +2,7 @@ http://activitystrea.ms/schema/1.0/note http://activitystrea.ms/schema/1.0/post - <%= render @view_module, "_tag_author.atom", assigns %> + <%= render Phoenix.Controller.view_module(@conn), "_tag_author.atom", assigns %> <%= @data["id"] %> <%= activity_title(@data, Keyword.get(@feed_config, :post_title, %{})) %> diff --git a/lib/pleroma/web/templates/feed/feed/tag.atom.eex b/lib/pleroma/web/templates/feed/feed/tag.atom.eex index 6d497e84c..8c551feaf 100644 --- a/lib/pleroma/web/templates/feed/feed/tag.atom.eex +++ b/lib/pleroma/web/templates/feed/feed/tag.atom.eex @@ -17,6 +17,6 @@ <%= most_recent_update(@activities) %> <%= for activity <- @activities do %> - <%= render @view_module, "_tag_activity.atom", Map.merge(assigns, prepare_activity(activity, actor: true)) %> + <%= render Phoenix.Controller.view_module(@conn), "_tag_activity.atom", Map.merge(assigns, prepare_activity(activity, actor: true)) %> <% end %> diff --git a/lib/pleroma/web/templates/feed/feed/tag.rss.eex b/lib/pleroma/web/templates/feed/feed/tag.rss.eex index edcc3e436..86466d367 100644 --- a/lib/pleroma/web/templates/feed/feed/tag.rss.eex +++ b/lib/pleroma/web/templates/feed/feed/tag.rss.eex @@ -9,7 +9,7 @@ <%= feed_logo() %> 2b90d9 <%= for activity <- @activities do %> - <%= render @view_module, "_tag_activity.xml", Map.merge(assigns, prepare_activity(activity)) %> + <%= render Phoenix.Controller.view_module(@conn), "_tag_activity.xml", Map.merge(assigns, prepare_activity(activity)) %> <% end %> diff --git a/lib/pleroma/web/templates/feed/feed/user.atom.eex b/lib/pleroma/web/templates/feed/feed/user.atom.eex index 5c1f0ecbc..97a7535ab 100644 --- a/lib/pleroma/web/templates/feed/feed/user.atom.eex +++ b/lib/pleroma/web/templates/feed/feed/user.atom.eex @@ -12,13 +12,13 @@ <%= logo(@user) %> - <%= render @view_module, "_author.atom", assigns %> + <%= render Phoenix.Controller.view_module(@conn), "_author.atom", assigns %> <%= if last_activity(@activities) do %> <% end %> <%= for activity <- @activities do %> - <%= render @view_module, "_activity.atom", Map.merge(assigns, prepare_activity(activity)) %> + <%= render Phoenix.Controller.view_module(@conn), "_activity.atom", Map.merge(assigns, prepare_activity(activity)) %> <% end %> diff --git a/lib/pleroma/web/templates/feed/feed/user.rss.eex b/lib/pleroma/web/templates/feed/feed/user.rss.eex index 6b842a085..a9fee244c 100644 --- a/lib/pleroma/web/templates/feed/feed/user.rss.eex +++ b/lib/pleroma/web/templates/feed/feed/user.rss.eex @@ -7,14 +7,14 @@ <%= logo(@user) %> <%= '#{Routes.user_feed_url(@conn, :feed, @user.nickname)}.rss' %> - <%= render @view_module, "_author.rss", assigns %> + <%= render Phoenix.Controller.view_module(@conn), "_author.rss", assigns %> <%= if last_activity(@activities) do %> <%= '#{Routes.user_feed_url(@conn, :feed, @user.nickname)}.rss?max_id=#{last_activity(@activities).id}' %> <% end %> <%= for activity <- @activities do %> - <%= render @view_module, "_activity.rss", Map.merge(assigns, prepare_activity(activity)) %> + <%= render Phoenix.Controller.view_module(@conn), "_activity.rss", Map.merge(assigns, prepare_activity(activity)) %> <% end %> diff --git a/lib/pleroma/web/templates/layout/email.html.eex b/lib/pleroma/web/templates/layout/email.html.eex index 087aa4fc0..5858e48b4 100644 --- a/lib/pleroma/web/templates/layout/email.html.eex +++ b/lib/pleroma/web/templates/layout/email.html.eex @@ -5,6 +5,6 @@ <%= @email.subject %> - <%= render @view_module, @view_template, assigns %> + <%= render Phoenix.Controller.view_module(@conn), Phoenix.Controller.view_template(@conn), assigns %> diff --git a/lib/pleroma/web/templates/layout/embed.html.eex b/lib/pleroma/web/templates/layout/embed.html.eex index 8b905f070..1197288e5 100644 --- a/lib/pleroma/web/templates/layout/embed.html.eex +++ b/lib/pleroma/web/templates/layout/embed.html.eex @@ -10,6 +10,6 @@ - <%= render @view_module, @view_template, assigns %> + <%= render Phoenix.Controller.view_module(@conn), Phoenix.Controller.view_template(@conn), assigns %> diff --git a/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex index 8b894cd58..98904ad64 100644 --- a/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex +++ b/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex @@ -2,7 +2,7 @@ <%= form_for @conn, Routes.o_auth_path(@conn, :prepare_request), [as: "authorization", method: "get"], fn f -> %>
- <%= render @view_module, "_scopes.html", Map.merge(assigns, %{form: f}) %> + <%= render Phoenix.Controller.view_module(@conn), "_scopes.html", Map.merge(assigns, %{form: f}) %>
<%= hidden_input f, :client_id, value: @client_id %> diff --git a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex index a2f41618e..b3654f3eb 100644 --- a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex +++ b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex @@ -21,7 +21,7 @@
<%= if @app do %>

<%= raw Gettext.dpgettext("static_pages", "oauth authorize message", "Application %{client_name} is requesting access to your account.", client_name: safe_to_string(html_escape(@app.client_name))) %>

- <%= render @view_module, "_scopes.html", Map.merge(assigns, %{form: f}) %> + <%= render Phoenix.Controller.view_module(@conn), "_scopes.html", Map.merge(assigns, %{form: f}) %> <% end %> <%= if @user do %> @@ -63,5 +63,5 @@ <% end %> <%= if Pleroma.Config.oauth_consumer_enabled?() do %> - <%= render @view_module, Pleroma.Web.Auth.WrapperAuthenticator.oauth_consumer_template(), assigns %> + <%= render Phoenix.Controller.view_module(@conn), Pleroma.Web.Auth.WrapperAuthenticator.oauth_consumer_template(), assigns %> <% end %> -- cgit v1.2.3 From bdedc41cbc60cc699e44ff323b945c276af32122 Mon Sep 17 00:00:00 2001 From: Thomas Citharel Date: Fri, 4 Nov 2022 09:43:13 +0100 Subject: Fix typo in CSP Report-To header name The header name was Report-To, not Reply-To. In any case, that's now being changed to the Reporting-Endpoints HTTP Response Header. https://w3c.github.io/reporting/#header https://github.com/w3c/reporting/issues/177 CanIUse says the Report-To header is still supported by current Chrome and friends. https://caniuse.com/mdn-http_headers_report-to It doesn't have any data for the Reporting-Endpoints HTTP header, but this article says Chrome 96 supports it. https://web.dev/reporting-api/ (Even though that's come out one year ago, that's not compatible with Network Error Logging which's still using the Report-To version of the API) Signed-off-by: Thomas Citharel --- lib/pleroma/web/plugs/http_security_plug.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/plugs/http_security_plug.ex b/lib/pleroma/web/plugs/http_security_plug.ex index b89948cec..cd1bae235 100644 --- a/lib/pleroma/web/plugs/http_security_plug.ex +++ b/lib/pleroma/web/plugs/http_security_plug.ex @@ -68,7 +68,7 @@ defmodule Pleroma.Web.Plugs.HTTPSecurityPlug do ] } - [{"reply-to", Jason.encode!(report_group)} | headers] + [{"report-to", Jason.encode!(report_group)} | headers] else headers end -- cgit v1.2.3 From 648e012022f1b0a65ed21f9576b479a12daeba6c Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Mon, 7 Nov 2022 14:56:59 +0100 Subject: ObjectAgePolicy: Make strip_followers behavior for followers-only explicit --- lib/pleroma/web/activity_pub/mrf/object_age_policy.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/mrf/object_age_policy.ex b/lib/pleroma/web/activity_pub/mrf/object_age_policy.ex index 0e9d25a0a..df1a6dcbb 100644 --- a/lib/pleroma/web/activity_pub/mrf/object_age_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/object_age_policy.ex @@ -131,7 +131,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy do type: {:list, :atom}, description: "A list of actions to apply to the post. `:delist` removes the post from public timelines; " <> - "`:strip_followers` removes followers from the ActivityPub recipient list ensuring they won't be delivered to home timelines; " <> + "`:strip_followers` removes followers from the ActivityPub recipient list ensuring they won't be delivered to home timelines, additionally for followers-only it degrades to a direct message; " <> "`:reject` rejects the message entirely", suggestions: [:delist, :strip_followers, :reject] } -- cgit v1.2.3 From 6f047cc308352cb3437f95e31e73487bba194abe Mon Sep 17 00:00:00 2001 From: tusooa Date: Wed, 9 Nov 2022 22:36:42 -0500 Subject: Do not strip reported statuses when configured not to --- lib/pleroma/web/activity_pub/utils.ex | 23 +++++++++++------------ lib/pleroma/web/admin_api/report.ex | 33 +++++++++++++++++++++++++++++++-- 2 files changed, 42 insertions(+), 14 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index d3b7d804f..57a2f53c4 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -748,22 +748,21 @@ defmodule Pleroma.Web.ActivityPub.Utils do ActivityPub.fetch_activities([], params, :offset) end - def update_report_state(%Activity{} = activity, state) - when state in @strip_status_report_states do - {:ok, stripped_activity} = strip_report_status_data(activity) + defp maybe_strip_report_status(data, state) do + with true <- Config.get([:instance, :report_strip_status]), + true <- state in @strip_status_report_states, + {:ok, stripped_activity} = strip_report_status_data(%Activity{data: data}) do + data |> Map.put("object", stripped_activity.data["object"]) + else + _ -> data + end + end + def update_report_state(%Activity{} = activity, state) when state in @supported_report_states do new_data = activity.data |> Map.put("state", state) - |> Map.put("object", stripped_activity.data["object"]) - - activity - |> Changeset.change(data: new_data) - |> Repo.update() - end - - def update_report_state(%Activity{} = activity, state) when state in @supported_report_states do - new_data = Map.put(activity.data, "state", state) + |> maybe_strip_report_status(state) activity |> Changeset.change(data: new_data) diff --git a/lib/pleroma/web/admin_api/report.ex b/lib/pleroma/web/admin_api/report.ex index 8d1abfa56..f377e1804 100644 --- a/lib/pleroma/web/admin_api/report.ex +++ b/lib/pleroma/web/admin_api/report.ex @@ -4,6 +4,7 @@ defmodule Pleroma.Web.AdminAPI.Report do alias Pleroma.Activity + alias Pleroma.Object alias Pleroma.User def extract_report_info( @@ -16,10 +17,38 @@ defmodule Pleroma.Web.AdminAPI.Report do status_ap_ids |> Enum.reject(&is_nil(&1)) |> Enum.map(fn - act when is_map(act) -> Activity.get_by_ap_id_with_object(act["id"]) - act when is_binary(act) -> Activity.get_by_ap_id_with_object(act) + act when is_map(act) -> + Activity.get_by_ap_id_with_object(act["id"]) || make_fake_activity(act, user) + + act when is_binary(act) -> + Activity.get_by_ap_id_with_object(act) end) %{report: report, user: user, account: account, statuses: statuses} end + + defp make_fake_activity(act, user) do + %Activity{ + id: "pleroma:fake", + data: %{ + "actor" => user.ap_id, + "type" => "Create", + "to" => [], + "cc" => [], + "object" => act["id"], + "published" => act["published"] + }, + recipients: [user.ap_id], + object: %Object{ + data: %{ + "actor" => user.ap_id, + "type" => "Note", + "content" => act["content"], + "published" => act["published"], + "to" => [], + "cc" => [] + } + } + } + end end -- cgit v1.2.3 From 717c5901f893527b059201d1ce7899060a18a1a5 Mon Sep 17 00:00:00 2001 From: tusooa Date: Wed, 9 Nov 2022 23:02:27 -0500 Subject: Render a generated reported activity properly --- lib/pleroma/web/admin_api/report.ex | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/admin_api/report.ex b/lib/pleroma/web/admin_api/report.ex index f377e1804..6856bfcb3 100644 --- a/lib/pleroma/web/admin_api/report.ex +++ b/lib/pleroma/web/admin_api/report.ex @@ -36,7 +36,9 @@ defmodule Pleroma.Web.AdminAPI.Report do "to" => [], "cc" => [], "object" => act["id"], - "published" => act["published"] + "published" => act["published"], + "id" => act["id"], + "context" => "pleroma:fake" }, recipients: [user.ap_id], object: %Object{ @@ -46,7 +48,9 @@ defmodule Pleroma.Web.AdminAPI.Report do "content" => act["content"], "published" => act["published"], "to" => [], - "cc" => [] + "cc" => [], + "id" => act["id"], + "context" => "pleroma:fake" } } } -- cgit v1.2.3 From 6b87b3f2eae62a7d6e20681468c367489a47f0a3 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Fri, 11 Nov 2022 11:39:43 -0500 Subject: Remove Quack logging backend --- lib/pleroma/config/transfer_task.ex | 7 +------ lib/pleroma/config_db.ex | 3 +-- 2 files changed, 2 insertions(+), 8 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/config/transfer_task.ex b/lib/pleroma/config/transfer_task.ex index 4199630af..44a984019 100644 --- a/lib/pleroma/config/transfer_task.ex +++ b/lib/pleroma/config/transfer_task.ex @@ -47,7 +47,7 @@ defmodule Pleroma.Config.TransferTask do {logger, other} = (Repo.all(ConfigDB) ++ deleted_settings) |> Enum.map(&merge_with_default/1) - |> Enum.split_with(fn {group, _, _, _} -> group in [:logger, :quack] end) + |> Enum.split_with(fn {group, _, _, _} -> group in [:logger] end) logger |> Enum.sort() @@ -104,11 +104,6 @@ defmodule Pleroma.Config.TransferTask do end # change logger configuration in runtime, without restart - defp configure({:quack, key, _, merged}) do - Logger.configure_backend(Quack.Logger, [{key, merged}]) - :ok = update_env(:quack, key, merged) - end - defp configure({_, :backends, _, merged}) do # removing current backends Enum.each(Application.get_env(:logger, :backends), &Logger.remove_backend/1) diff --git a/lib/pleroma/config_db.ex b/lib/pleroma/config_db.ex index 6befbbe19..846cede04 100644 --- a/lib/pleroma/config_db.ex +++ b/lib/pleroma/config_db.ex @@ -163,7 +163,6 @@ defmodule Pleroma.ConfigDB do defp only_full_update?(%ConfigDB{group: group, key: key}) do full_key_update = [ {:pleroma, :ecto_repos}, - {:quack, :meta}, {:mime, :types}, {:cors_plug, [:max_age, :methods, :expose, :headers]}, {:swarm, :node_blacklist}, @@ -386,7 +385,7 @@ defmodule Pleroma.ConfigDB do @spec module_name?(String.t()) :: boolean() def module_name?(string) do - Regex.match?(~r/^(Pleroma|Phoenix|Tesla|Quack|Ueberauth|Swoosh)\./, string) or + Regex.match?(~r/^(Pleroma|Phoenix|Tesla|Ueberauth|Swoosh)\./, string) or string in ["Oban", "Ueberauth", "ExSyslogger", "ConcurrentLimiter"] end end -- cgit v1.2.3 From 8be7f87e1f1513998584258aee80231e3347b31f Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Fri, 11 Nov 2022 13:42:29 -0500 Subject: Define sane Oban Worker timeouts --- lib/pleroma/workers/attachments_cleanup_worker.ex | 3 +++ lib/pleroma/workers/background_worker.ex | 3 +++ lib/pleroma/workers/backup_worker.ex | 4 ++++ lib/pleroma/workers/mailer_worker.ex | 3 +++ lib/pleroma/workers/mute_expire_worker.ex | 3 +++ lib/pleroma/workers/poll_worker.ex | 3 +++ lib/pleroma/workers/publisher_worker.ex | 3 +++ lib/pleroma/workers/purge_expired_activity.ex | 3 +++ lib/pleroma/workers/purge_expired_filter.ex | 3 +++ lib/pleroma/workers/purge_expired_token.ex | 3 +++ lib/pleroma/workers/receiver_worker.ex | 3 +++ lib/pleroma/workers/remote_fetcher_worker.ex | 3 +++ lib/pleroma/workers/scheduled_activity_worker.ex | 3 +++ lib/pleroma/workers/transmogrifier_worker.ex | 3 +++ lib/pleroma/workers/web_pusher_worker.ex | 3 +++ 15 files changed, 46 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/workers/attachments_cleanup_worker.ex b/lib/pleroma/workers/attachments_cleanup_worker.ex index 0a397eae0..4c1764053 100644 --- a/lib/pleroma/workers/attachments_cleanup_worker.ex +++ b/lib/pleroma/workers/attachments_cleanup_worker.ex @@ -31,6 +31,9 @@ defmodule Pleroma.Workers.AttachmentsCleanupWorker do def perform(%Job{args: %{"op" => "cleanup_attachments", "object" => _object}}), do: {:ok, :skip} + @impl Oban.Worker + def timeout(_job), do: :timer.seconds(900) + defp do_clean({object_ids, attachment_urls}) do uploader = Pleroma.Config.get([Pleroma.Upload, :uploader]) diff --git a/lib/pleroma/workers/background_worker.ex b/lib/pleroma/workers/background_worker.ex index 91440cbe6..3805293bc 100644 --- a/lib/pleroma/workers/background_worker.ex +++ b/lib/pleroma/workers/background_worker.ex @@ -43,4 +43,7 @@ defmodule Pleroma.Workers.BackgroundWorker do def perform(%Job{args: %{"op" => "delete_instance", "host" => host}}) do Instance.perform(:delete_instance, host) end + + @impl Oban.Worker + def timeout(_job), do: :timer.seconds(5) end diff --git a/lib/pleroma/workers/backup_worker.ex b/lib/pleroma/workers/backup_worker.ex index 7657fa9ce..12ee70f00 100644 --- a/lib/pleroma/workers/backup_worker.ex +++ b/lib/pleroma/workers/backup_worker.ex @@ -30,6 +30,7 @@ defmodule Pleroma.Workers.BackupWorker do |> Oban.insert() end + @impl Oban.Worker def perform(%Job{ args: %{"op" => "process", "backup_id" => backup_id, "admin_user_id" => admin_user_id} }) do @@ -49,6 +50,9 @@ defmodule Pleroma.Workers.BackupWorker do end end + @impl Oban.Worker + def timeout(_job), do: :timer.seconds(900) + defp has_email?(user) do not is_nil(user.email) and user.email != "" end diff --git a/lib/pleroma/workers/mailer_worker.ex b/lib/pleroma/workers/mailer_worker.ex index 81764ba72..940716558 100644 --- a/lib/pleroma/workers/mailer_worker.ex +++ b/lib/pleroma/workers/mailer_worker.ex @@ -12,4 +12,7 @@ defmodule Pleroma.Workers.MailerWorker do |> :erlang.binary_to_term() |> Pleroma.Emails.Mailer.deliver(config) end + + @impl Oban.Worker + def timeout(_job), do: :timer.seconds(5) end diff --git a/lib/pleroma/workers/mute_expire_worker.ex b/lib/pleroma/workers/mute_expire_worker.ex index a7841d917..8ce458d48 100644 --- a/lib/pleroma/workers/mute_expire_worker.ex +++ b/lib/pleroma/workers/mute_expire_worker.ex @@ -17,4 +17,7 @@ defmodule Pleroma.Workers.MuteExpireWorker do Pleroma.Web.CommonAPI.remove_mute(user_id, activity_id) :ok end + + @impl Oban.Worker + def timeout(_job), do: :timer.seconds(5) end diff --git a/lib/pleroma/workers/poll_worker.ex b/lib/pleroma/workers/poll_worker.ex index 4c7eab5c1..022d026f8 100644 --- a/lib/pleroma/workers/poll_worker.ex +++ b/lib/pleroma/workers/poll_worker.ex @@ -19,6 +19,9 @@ defmodule Pleroma.Workers.PollWorker do end end + @impl Oban.Worker + def timeout(_job), do: :timer.seconds(5) + defp find_poll_activity(activity_id) do with nil <- Activity.get_by_id(activity_id) do {:error, :poll_activity_not_found} diff --git a/lib/pleroma/workers/publisher_worker.ex b/lib/pleroma/workers/publisher_worker.ex index 528a06bb3..598ae3779 100644 --- a/lib/pleroma/workers/publisher_worker.ex +++ b/lib/pleroma/workers/publisher_worker.ex @@ -22,4 +22,7 @@ defmodule Pleroma.Workers.PublisherWorker do params = Map.new(params, fn {k, v} -> {String.to_atom(k), v} end) Federator.perform(:publish_one, String.to_atom(module_name), params) end + + @impl Oban.Worker + def timeout(_job), do: :timer.seconds(10) end diff --git a/lib/pleroma/workers/purge_expired_activity.ex b/lib/pleroma/workers/purge_expired_activity.ex index 0545d3ece..e554684fe 100644 --- a/lib/pleroma/workers/purge_expired_activity.ex +++ b/lib/pleroma/workers/purge_expired_activity.ex @@ -35,6 +35,9 @@ defmodule Pleroma.Workers.PurgeExpiredActivity do end end + @impl Oban.Worker + def timeout(_job), do: :timer.seconds(5) + defp enabled? do with false <- Pleroma.Config.get([__MODULE__, :enabled], false) do {:error, :expired_activities_disabled} diff --git a/lib/pleroma/workers/purge_expired_filter.ex b/lib/pleroma/workers/purge_expired_filter.ex index 933ecb3f6..9114aeb7f 100644 --- a/lib/pleroma/workers/purge_expired_filter.ex +++ b/lib/pleroma/workers/purge_expired_filter.ex @@ -31,6 +31,9 @@ defmodule Pleroma.Workers.PurgeExpiredFilter do |> Repo.delete() end + @impl Oban.Worker + def timeout(_job), do: :timer.seconds(5) + @spec get_expiration(pos_integer()) :: Job.t() | nil def get_expiration(id) do from(j in Job, diff --git a/lib/pleroma/workers/purge_expired_token.ex b/lib/pleroma/workers/purge_expired_token.ex index 1d322b6b6..2ccd9e80b 100644 --- a/lib/pleroma/workers/purge_expired_token.ex +++ b/lib/pleroma/workers/purge_expired_token.ex @@ -26,4 +26,7 @@ defmodule Pleroma.Workers.PurgeExpiredToken do |> Pleroma.Repo.get(id) |> Pleroma.Repo.delete() end + + @impl Oban.Worker + def timeout(_job), do: :timer.seconds(5) end diff --git a/lib/pleroma/workers/receiver_worker.ex b/lib/pleroma/workers/receiver_worker.ex index c41b44e14..4f513b907 100644 --- a/lib/pleroma/workers/receiver_worker.ex +++ b/lib/pleroma/workers/receiver_worker.ex @@ -17,4 +17,7 @@ defmodule Pleroma.Workers.ReceiverWorker do e -> e end end + + @impl Oban.Worker + def timeout(_job), do: :timer.seconds(5) end diff --git a/lib/pleroma/workers/remote_fetcher_worker.ex b/lib/pleroma/workers/remote_fetcher_worker.ex index c3158bbbe..d2a77aa17 100644 --- a/lib/pleroma/workers/remote_fetcher_worker.ex +++ b/lib/pleroma/workers/remote_fetcher_worker.ex @@ -11,4 +11,7 @@ defmodule Pleroma.Workers.RemoteFetcherWorker do def perform(%Job{args: %{"op" => "fetch_remote", "id" => id} = args}) do {:ok, _object} = Fetcher.fetch_object_from_id(id, depth: args["depth"]) end + + @impl Oban.Worker + def timeout(_job), do: :timer.seconds(10) end diff --git a/lib/pleroma/workers/scheduled_activity_worker.ex b/lib/pleroma/workers/scheduled_activity_worker.ex index 9a17330b6..4df84d00f 100644 --- a/lib/pleroma/workers/scheduled_activity_worker.ex +++ b/lib/pleroma/workers/scheduled_activity_worker.ex @@ -37,6 +37,9 @@ defmodule Pleroma.Workers.ScheduledActivityWorker do end end + @impl Oban.Worker + def timeout(_job), do: :timer.seconds(5) + defp find_scheduled_activity(id) do with nil <- Repo.get(ScheduledActivity, id) do {:error, :scheduled_activity_not_found} diff --git a/lib/pleroma/workers/transmogrifier_worker.ex b/lib/pleroma/workers/transmogrifier_worker.ex index ed319c585..1f3f5385e 100644 --- a/lib/pleroma/workers/transmogrifier_worker.ex +++ b/lib/pleroma/workers/transmogrifier_worker.ex @@ -12,4 +12,7 @@ defmodule Pleroma.Workers.TransmogrifierWorker do user = User.get_cached_by_id(user_id) Pleroma.Web.ActivityPub.Transmogrifier.perform(:user_upgrade, user) end + + @impl Oban.Worker + def timeout(_job), do: :timer.seconds(5) end diff --git a/lib/pleroma/workers/web_pusher_worker.ex b/lib/pleroma/workers/web_pusher_worker.ex index 6447a5edc..67e84b0c9 100644 --- a/lib/pleroma/workers/web_pusher_worker.ex +++ b/lib/pleroma/workers/web_pusher_worker.ex @@ -17,4 +17,7 @@ defmodule Pleroma.Workers.WebPusherWorker do Pleroma.Web.Push.Impl.perform(notification) end + + @impl Oban.Worker + def timeout(_job), do: :timer.seconds(5) end -- cgit v1.2.3 From 4d321be05c0aa34921f96f38c17dd611691f3c44 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Mon, 10 Oct 2022 15:55:58 +0100 Subject: Extract deactivated users query to a join --- lib/pleroma/activity.ex | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index ebfd4ed45..3556aaf9e 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -361,9 +361,11 @@ defmodule Pleroma.Activity do end def restrict_deactivated_users(query) do - deactivated_users_query = from(u in User.Query.build(%{deactivated: true}), select: u.ap_id) - - from(activity in query, where: activity.actor not in subquery(deactivated_users_query)) + query + |> join(:inner, [activity], user in User, + as: :user, + on: activity.actor == user.ap_id and user.is_active == true + ) end defdelegate search(user, query, options \\ []), to: Pleroma.Activity.Search -- cgit v1.2.3 From 749445dd50ba9376779c902584da3b55be7270bb Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Sat, 12 Nov 2022 17:52:37 -0500 Subject: Fix reports which do not have a user The check for deactivated users was being applied to report activities. --- lib/pleroma/web/activity_pub/activity_pub.ex | 8 +++++++- 1 file changed, 7 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 5099caef7..ad9eb2505 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -1239,6 +1239,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do end end + defp exclude_invisible_actors(query, %{type: "Flag"}), do: query defp exclude_invisible_actors(query, %{invisible_actors: true}), do: query defp exclude_invisible_actors(query, _opts) do @@ -1377,7 +1378,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do |> restrict_instance(opts) |> restrict_announce_object_actor(opts) |> restrict_filtered(opts) - |> Activity.restrict_deactivated_users() + |> maybe_restrict_deactivated_users(opts) |> exclude_poll_votes(opts) |> exclude_chat_messages(opts) |> exclude_invisible_actors(opts) @@ -1789,4 +1790,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do |> restrict_visibility(%{visibility: "direct"}) |> order_by([activity], asc: activity.id) end + + defp maybe_restrict_deactivated_users(activity, %{type: "Flag"}), do: activity + + defp maybe_restrict_deactivated_users(activity, _opts), + do: Activity.restrict_deactivated_users(activity) end -- cgit v1.2.3 From edaf0a05f8d3b9476d868e153fbca029e74b4bd3 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Sat, 12 Nov 2022 18:05:58 -0500 Subject: Add same optimized join for excluding invisible users --- lib/pleroma/web/activity_pub/activity_pub.ex | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index ad9eb2505..fa251394b 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -1243,12 +1243,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do defp exclude_invisible_actors(query, %{invisible_actors: true}), do: query defp exclude_invisible_actors(query, _opts) do - invisible_ap_ids = - User.Query.build(%{invisible: true, select: [:ap_id]}) - |> Repo.all() - |> Enum.map(fn %{ap_id: ap_id} -> ap_id end) - - from([activity] in query, where: activity.actor not in ^invisible_ap_ids) + query + |> join(:inner, [activity], u in User, + as: :u, + on: activity.actor == u.ap_id and u.invisible == false + ) end defp exclude_id(query, %{exclude_id: id}) when is_binary(id) do -- cgit v1.2.3 From b2713357b9410fc43478de4fb271b2920d618956 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Fri, 11 Nov 2022 12:02:26 +0100 Subject: Object.Fetcher: Set reachable on successful fetch --- lib/pleroma/object/fetcher.ex | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/object/fetcher.ex b/lib/pleroma/object/fetcher.ex index d81fdcf24..a9a9eeeed 100644 --- a/lib/pleroma/object/fetcher.ex +++ b/lib/pleroma/object/fetcher.ex @@ -4,6 +4,7 @@ defmodule Pleroma.Object.Fetcher do alias Pleroma.HTTP + alias Pleroma.Instances alias Pleroma.Maps alias Pleroma.Object alias Pleroma.Object.Containment @@ -234,6 +235,10 @@ defmodule Pleroma.Object.Fetcher do {:ok, body} <- get_object(id), {:ok, data} <- safe_json_decode(body), :ok <- Containment.contain_origin_from_id(id, data) do + if not Instances.reachable?(id) do + Instances.set_reachable(id) + end + {:ok, data} else {:scheme, _} -> -- cgit v1.2.3 From 47b9847edd74c394e2bdfcb95a42f858329c9ef1 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Sun, 13 Nov 2022 12:25:52 -0500 Subject: Deletes do not generate notifications of any kind, so skip trying --- lib/pleroma/web/activity_pub/side_effects.ex | 1 - 1 file changed, 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/side_effects.ex b/lib/pleroma/web/activity_pub/side_effects.ex index 5eefd2824..b2e15e1a0 100644 --- a/lib/pleroma/web/activity_pub/side_effects.ex +++ b/lib/pleroma/web/activity_pub/side_effects.ex @@ -324,7 +324,6 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do end if result == :ok do - Notification.create_notifications(object) {:ok, object, meta} else {:error, result} -- cgit v1.2.3 From 2e0089dd5c27c86488d2c68170d80d02c24135f3 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Sun, 13 Nov 2022 13:33:27 -0500 Subject: Alter priority of Delete activities to be lowest This will prevent a user with a large number of posts from negatively affecting performance of the outgoing federation queue if they delete their account. --- lib/pleroma/web/activity_pub/side_effects.ex | 1 - lib/pleroma/web/federator.ex | 9 +++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/side_effects.ex b/lib/pleroma/web/activity_pub/side_effects.ex index b2e15e1a0..a2152b945 100644 --- a/lib/pleroma/web/activity_pub/side_effects.ex +++ b/lib/pleroma/web/activity_pub/side_effects.ex @@ -282,7 +282,6 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do # Tasks this handles: # - Delete and unpins the create activity # - Replace object with Tombstone - # - Set up notification # - Reduce the user note count # - Reduce the reply count # - Stream out the activity diff --git a/lib/pleroma/web/federator.ex b/lib/pleroma/web/federator.ex index 3be71c1b6..318b6cb11 100644 --- a/lib/pleroma/web/federator.ex +++ b/lib/pleroma/web/federator.ex @@ -47,10 +47,15 @@ defmodule Pleroma.Web.Federator do end @impl true - def publish(activity) do - PublisherWorker.enqueue("publish", %{"activity_id" => activity.id}) + def publish(%Pleroma.Activity{data: %{"type" => type}} = activity) do + PublisherWorker.enqueue("publish", %{"activity_id" => activity.id}, + priority: publish_priority(type) + ) end + defp publish_priority("Delete"), do: 3 + defp publish_priority(_), do: 0 + # Job Worker Callbacks @spec perform(atom(), module(), any()) :: {:ok, any()} | {:error, any()} -- cgit v1.2.3 From db76ea578a550a4cbc0298d428b9c57ba605b276 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 12 Apr 2021 00:38:25 +0300 Subject: try to fix ruffle on chrome --- lib/pleroma/web/plugs/http_security_plug.ex | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/plugs/http_security_plug.ex b/lib/pleroma/web/plugs/http_security_plug.ex index cd1bae235..3ee48062e 100644 --- a/lib/pleroma/web/plugs/http_security_plug.ex +++ b/lib/pleroma/web/plugs/http_security_plug.ex @@ -117,7 +117,9 @@ defmodule Pleroma.Web.Plugs.HTTPSecurityPlug do if Config.get(:env) == :dev do "script-src 'self' 'unsafe-eval'" else - "script-src 'self'" + # TODO right now unsafe-eval is needed for WASM to load in chrome + # see: https://github.com/WebAssembly/content-security-policy/issues/7 + "script-src 'self' 'unsafe-eval'" end report = if report_uri, do: ["report-uri ", report_uri, ";report-to csp-endpoint"] -- cgit v1.2.3 From 79bd363a68cce0600c93eaa4ac08782333c3e8bb Mon Sep 17 00:00:00 2001 From: HJ <30-hj@users.noreply.git.pleroma.social> Date: Wed, 16 Nov 2022 21:27:04 +0000 Subject: Update lib/pleroma/web/plugs/http_security_plug.ex --- lib/pleroma/web/plugs/http_security_plug.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/plugs/http_security_plug.ex b/lib/pleroma/web/plugs/http_security_plug.ex index 3ee48062e..7a987a30b 100644 --- a/lib/pleroma/web/plugs/http_security_plug.ex +++ b/lib/pleroma/web/plugs/http_security_plug.ex @@ -119,7 +119,7 @@ defmodule Pleroma.Web.Plugs.HTTPSecurityPlug do else # TODO right now unsafe-eval is needed for WASM to load in chrome # see: https://github.com/WebAssembly/content-security-policy/issues/7 - "script-src 'self' 'unsafe-eval'" + "script-src 'self' 'wasm-unsafe-eval'" end report = if report_uri, do: ["report-uri ", report_uri, ";report-to csp-endpoint"] -- cgit v1.2.3 From a31d3589ed8c91cceece7dbdf362c9bfe69e0115 Mon Sep 17 00:00:00 2001 From: HJ <30-hj@users.noreply.git.pleroma.social> Date: Wed, 16 Nov 2022 21:28:35 +0000 Subject: Update http_security_plug.ex --- lib/pleroma/web/plugs/http_security_plug.ex | 2 -- 1 file changed, 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/plugs/http_security_plug.ex b/lib/pleroma/web/plugs/http_security_plug.ex index 7a987a30b..34895c8d5 100644 --- a/lib/pleroma/web/plugs/http_security_plug.ex +++ b/lib/pleroma/web/plugs/http_security_plug.ex @@ -117,8 +117,6 @@ defmodule Pleroma.Web.Plugs.HTTPSecurityPlug do if Config.get(:env) == :dev do "script-src 'self' 'unsafe-eval'" else - # TODO right now unsafe-eval is needed for WASM to load in chrome - # see: https://github.com/WebAssembly/content-security-policy/issues/7 "script-src 'self' 'wasm-unsafe-eval'" end -- cgit v1.2.3 From a69e9ae2ef943f57faf803441c25aee09a86f9ca Mon Sep 17 00:00:00 2001 From: tusooa Date: Sat, 19 Nov 2022 23:51:43 -0500 Subject: Flag an Object, not an Activity --- lib/pleroma/web/activity_pub/utils.ex | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 57a2f53c4..dacacb83b 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -695,8 +695,9 @@ defmodule Pleroma.Web.ActivityPub.Utils do Enum.map(statuses || [], &build_flag_object/1) end - defp build_flag_object(%Activity{data: %{"id" => id}, object: %{data: data}}) do - activity_actor = User.get_by_ap_id(data["actor"]) + defp build_flag_object(%Object{data: data}) do + actor = User.get_by_ap_id(data["actor"]) + id = data["id"] %{ "type" => "Note", @@ -706,7 +707,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do "actor" => AccountView.render( "show.json", - %{user: activity_actor, skip_visibility_check: true} + %{user: actor, skip_visibility_check: true} ) } end @@ -720,12 +721,12 @@ defmodule Pleroma.Web.ActivityPub.Utils do end case Activity.get_by_ap_id_with_object(id) do - %Activity{} = activity -> - build_flag_object(activity) + %Activity{object: object} = _ -> + build_flag_object(object) nil -> - if activity = Activity.get_by_object_ap_id_with_object(id) do - build_flag_object(activity) + if %Object{} = object = Object.get_by_ap_id(id) do + build_flag_object(object) else %{"id" => id, "deleted" => true} end -- cgit v1.2.3 From 0e0c316c76527fb5ac3a28f03628e62799e8694b Mon Sep 17 00:00:00 2001 From: tusooa Date: Sun, 20 Nov 2022 00:35:52 -0500 Subject: Fix report api --- lib/pleroma/web/activity_pub/utils.ex | 5 +++++ lib/pleroma/web/admin_api/report.ex | 6 ++++-- 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index dacacb83b..22057e703 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -695,6 +695,11 @@ defmodule Pleroma.Web.ActivityPub.Utils do Enum.map(statuses || [], &build_flag_object/1) end + defp build_flag_object(%Activity{} = activity) do + object = Object.normalize(activity, fetch: false) + build_flag_object(object) + end + defp build_flag_object(%Object{data: data}) do actor = User.get_by_ap_id(data["actor"]) id = data["id"] diff --git a/lib/pleroma/web/admin_api/report.ex b/lib/pleroma/web/admin_api/report.ex index 6856bfcb3..c79bee27e 100644 --- a/lib/pleroma/web/admin_api/report.ex +++ b/lib/pleroma/web/admin_api/report.ex @@ -18,10 +18,12 @@ defmodule Pleroma.Web.AdminAPI.Report do |> Enum.reject(&is_nil(&1)) |> Enum.map(fn act when is_map(act) -> - Activity.get_by_ap_id_with_object(act["id"]) || make_fake_activity(act, user) + Activity.get_create_by_object_ap_id_with_object(act["id"]) || + Activity.get_by_ap_id_with_object(act["id"]) || make_fake_activity(act, user) act when is_binary(act) -> - Activity.get_by_ap_id_with_object(act) + Activity.get_create_by_object_ap_id_with_object(act) || + Activity.get_by_ap_id_with_object(act) end) %{report: report, user: user, account: account, statuses: statuses} -- cgit v1.2.3 From 9d99e76a3ae7c1af8b6b03bf88534f3959b62544 Mon Sep 17 00:00:00 2001 From: tusooa Date: Sun, 20 Nov 2022 00:57:04 -0500 Subject: Fix unit tests --- lib/pleroma/web/activity_pub/utils.ex | 44 ++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 16 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 22057e703..b898d6fe8 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -697,24 +697,22 @@ defmodule Pleroma.Web.ActivityPub.Utils do defp build_flag_object(%Activity{} = activity) do object = Object.normalize(activity, fetch: false) - build_flag_object(object) - end - defp build_flag_object(%Object{data: data}) do - actor = User.get_by_ap_id(data["actor"]) - id = data["id"] + # Do not allow people to report Creates. Instead, report the Object that is Created. + if activity.data["type"] != "Create" do + build_flag_object_with_actor_and_id( + object, + User.get_by_ap_id(activity.data["actor"]), + activity.data["id"] + ) + else + build_flag_object(object) + end + end - %{ - "type" => "Note", - "id" => id, - "content" => data["content"], - "published" => data["published"], - "actor" => - AccountView.render( - "show.json", - %{user: actor, skip_visibility_check: true} - ) - } + defp build_flag_object(%Object{} = object) do + actor = User.get_by_ap_id(object.data["actor"]) + build_flag_object_with_actor_and_id(object, actor, object.data["id"]) end defp build_flag_object(act) when is_map(act) or is_binary(act) do @@ -740,6 +738,20 @@ defmodule Pleroma.Web.ActivityPub.Utils do defp build_flag_object(_), do: [] + defp build_flag_object_with_actor_and_id(%Object{data: data}, actor, id) do + %{ + "type" => "Note", + "id" => id, + "content" => data["content"], + "published" => data["published"], + "actor" => + AccountView.render( + "show.json", + %{user: actor, skip_visibility_check: true} + ) + } + end + #### Report-related helpers def get_reports(params, page, page_size) do params = -- cgit v1.2.3 From 0f88c2bca437b7d2fa6d6320aae8b8bbe4e5d6c4 Mon Sep 17 00:00:00 2001 From: ave Date: Mon, 28 Nov 2022 00:13:34 +0000 Subject: Change follow_operation schema to use type BooleanLike --- lib/pleroma/web/api_spec/operations/account_operation.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/api_spec/operations/account_operation.ex b/lib/pleroma/web/api_spec/operations/account_operation.ex index aed59293c..012cbdc79 100644 --- a/lib/pleroma/web/api_spec/operations/account_operation.ex +++ b/lib/pleroma/web/api_spec/operations/account_operation.ex @@ -223,12 +223,12 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do type: :object, properties: %{ reblogs: %Schema{ - type: :boolean, + allOf: [BooleanLike], description: "Receive this account's reblogs in home timeline? Defaults to true.", default: true }, notify: %Schema{ - type: :boolean, + allOf: [BooleanLike], description: "Receive notifications for all statuses posted by the account? Defaults to false.", default: false -- cgit v1.2.3 From 452595baeda8327b862d03e450ac004679efe86e Mon Sep 17 00:00:00 2001 From: duponin Date: Sun, 11 Dec 2022 22:54:47 +0100 Subject: Uploading an avatar media exceeding max size returns a 413 Until now it was returning a 500 because the upload plug were going through the changeset and ending in the JSON encoder, which raised because struct has to @derive the encoder. --- lib/pleroma/user.ex | 8 +++++++- lib/pleroma/web/api_spec/operations/account_operation.ex | 3 ++- lib/pleroma/web/mastodon_api/controllers/account_controller.ex | 6 +++++- 3 files changed, 14 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index b422e5c1d..17f6b9a0d 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -611,7 +611,13 @@ defmodule Pleroma.User do {:ok, new_value} <- value_function.(value) do put_change(changeset, map_field, new_value) else - _ -> changeset + {:error, :file_too_large} -> + Ecto.Changeset.validate_change(changeset, map_field, fn map_field, _value -> + [{map_field, "file is too large"}] + end) + + _ -> + changeset 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 012cbdc79..aabe988f7 100644 --- a/lib/pleroma/web/api_spec/operations/account_operation.ex +++ b/lib/pleroma/web/api_spec/operations/account_operation.ex @@ -64,7 +64,8 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do requestBody: request_body("Parameters", update_credentials_request(), required: true), responses: %{ 200 => Operation.response("Account", "application/json", Account), - 403 => Operation.response("Error", "application/json", ApiError) + 403 => Operation.response("Error", "application/json", ApiError), + 413 => Operation.response("Error", "application/json", ApiError) } } end diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex index 7c24c35d2..656a861cd 100644 --- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex @@ -254,7 +254,11 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do with_pleroma_settings: true ) else - _e -> render_error(conn, :forbidden, "Invalid request") + {:error, %Ecto.Changeset{errors: [avatar: {"file is too large", _}]}} -> + render_error(conn, :request_entity_too_large, "File is too large") + + _e -> + render_error(conn, :forbidden, "Invalid request") end end -- cgit v1.2.3 From 987674235814205344d320c0e4c21df17b1cdd15 Mon Sep 17 00:00:00 2001 From: duponin Date: Sun, 11 Dec 2022 23:15:08 +0100 Subject: Return 413 when an actor's banner or background exceeds the size limit --- lib/pleroma/web/mastodon_api/controllers/account_controller.ex | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex index 656a861cd..ea6e593d9 100644 --- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex @@ -257,6 +257,12 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do {:error, %Ecto.Changeset{errors: [avatar: {"file is too large", _}]}} -> render_error(conn, :request_entity_too_large, "File is too large") + {:error, %Ecto.Changeset{errors: [banner: {"file is too large", _}]}} -> + render_error(conn, :request_entity_too_large, "File is too large") + + {:error, %Ecto.Changeset{errors: [background: {"file is too large", _}]}} -> + render_error(conn, :request_entity_too_large, "File is too large") + _e -> render_error(conn, :forbidden, "Invalid request") end -- cgit v1.2.3 From 62c27e016441d8f0649fea0ea9cfe0646e2b6f11 Mon Sep 17 00:00:00 2001 From: tusooa Date: Wed, 14 Dec 2022 01:04:42 -0500 Subject: Fix failure when registering a user with no email when approval required --- lib/pleroma/user.ex | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index b422e5c1d..d2ae08888 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -905,7 +905,7 @@ defmodule Pleroma.User do end end - defp send_user_approval_email(user) do + defp send_user_approval_email(%User{email: email} = user) when is_binary(email) do user |> Pleroma.Emails.UserEmail.approval_pending_email() |> Pleroma.Emails.Mailer.deliver_async() @@ -913,6 +913,10 @@ defmodule Pleroma.User do {:ok, :enqueued} end + defp send_user_approval_email(_user) do + {:ok, :skipped} + end + defp send_admin_approval_emails(user) do all_superusers() |> Enum.filter(fn user -> not is_nil(user.email) end) -- cgit v1.2.3 From dc7efcd08b822e84e893775084d3b35288462264 Mon Sep 17 00:00:00 2001 From: tusooa Date: Thu, 15 Dec 2022 11:08:24 -0500 Subject: Make TagPolicy Update-aware This is inspired by https://akkoma.dev/AkkomaGang/akkoma/commit/d5828f1c5e54ca236e50ef7837bfba3d1e665854 --- lib/pleroma/web/activity_pub/mrf/tag_policy.ex | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/mrf/tag_policy.ex b/lib/pleroma/web/activity_pub/mrf/tag_policy.ex index 10072b693..73760ca8f 100644 --- a/lib/pleroma/web/activity_pub/mrf/tag_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/tag_policy.ex @@ -27,22 +27,22 @@ defmodule Pleroma.Web.ActivityPub.MRF.TagPolicy do defp process_tag( "mrf_tag:media-force-nsfw", %{ - "type" => "Create", + "type" => type, "object" => %{"attachment" => child_attachment} } = message ) - when length(child_attachment) > 0 do + when length(child_attachment) > 0 and type in ["Create", "Update"] do {:ok, Kernel.put_in(message, ["object", "sensitive"], true)} end defp process_tag( "mrf_tag:media-strip", %{ - "type" => "Create", + "type" => type, "object" => %{"attachment" => child_attachment} = object } = message ) - when length(child_attachment) > 0 do + when length(child_attachment) > 0 and type in ["Create", "Update"] do object = Map.delete(object, "attachment") message = Map.put(message, "object", object) @@ -152,7 +152,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.TagPolicy do do: filter_message(target_actor, message) @impl true - def filter(%{"actor" => actor, "type" => "Create"} = message), + def filter(%{"actor" => actor, "type" => type} = message) when type in ["Create", "Update"], do: filter_message(actor, message) @impl true -- cgit v1.2.3 From 2554028097b3dbc1644269f7d5612152748d3c7f Mon Sep 17 00:00:00 2001 From: tusooa Date: Thu, 15 Dec 2022 11:20:00 -0500 Subject: Make SimplePolicy Update-aware This is inspired by https://akkoma.dev/AkkomaGang/akkoma/commit/d5828f1c5e54ca236e50ef7837bfba3d1e665854 --- lib/pleroma/web/activity_pub/mrf/simple_policy.ex | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex index c0c7f3806..829ddeaea 100644 --- a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex @@ -40,9 +40,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do defp check_media_removal( %{host: actor_host} = _actor_info, - %{"type" => "Create", "object" => %{"attachment" => child_attachment}} = object + %{"type" => type, "object" => %{"attachment" => child_attachment}} = object ) - when length(child_attachment) > 0 do + when length(child_attachment) > 0 and type in ["Create", "Update"] do media_removal = instance_list(:media_removal) |> MRF.subdomains_regex() @@ -63,10 +63,11 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do defp check_media_nsfw( %{host: actor_host} = _actor_info, %{ - "type" => "Create", + "type" => type, "object" => %{} = _child_object } = object - ) do + ) + when type in ["Create", "Update"] do media_nsfw = instance_list(:media_nsfw) |> MRF.subdomains_regex() -- cgit v1.2.3 From 9838790a7d14e72449af3ae53daf3df30fd1aba0 Mon Sep 17 00:00:00 2001 From: Lain Soykaf Date: Thu, 15 Dec 2022 17:46:20 -0500 Subject: AttachmentValidator: Actually require url --- .../web/activity_pub/object_validators/attachment_validator.ex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/object_validators/attachment_validator.ex b/lib/pleroma/web/activity_pub/object_validators/attachment_validator.ex index 14f51e2c5..398020bff 100644 --- a/lib/pleroma/web/activity_pub/object_validators/attachment_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/attachment_validator.ex @@ -45,9 +45,9 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidator do struct |> cast(data, [:id, :type, :mediaType, :name, :blurhash]) - |> cast_embed(:url, with: &url_changeset/2) + |> cast_embed(:url, with: &url_changeset/2, required: true) |> validate_inclusion(:type, ~w[Link Document Audio Image Video]) - |> validate_required([:type, :mediaType, :url]) + |> validate_required([:type, :mediaType]) end def url_changeset(struct, data) do @@ -91,6 +91,6 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidator do defp validate_data(cng) do cng |> validate_inclusion(:type, ~w[Document Audio Image Video]) - |> validate_required([:mediaType, :url, :type]) + |> validate_required([:mediaType, :type]) end end -- cgit v1.2.3 From 4a32b584e148a5625a983e0932f2a3e16fdbbf30 Mon Sep 17 00:00:00 2001 From: Lain Soykaf Date: Thu, 15 Dec 2022 18:02:33 -0500 Subject: StatusView: Fix warning --- lib/pleroma/web/mastodon_api/views/status_view.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index b949d8f9a..0a8c98b44 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -65,7 +65,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do # This should be removed in a future version of Pleroma. Pleroma-FE currently # depends on this field, as well. defp get_context_id(%{data: %{"context" => context}}) when is_binary(context) do - use Bitwise + import Bitwise :erlang.crc32(context) |> band(bnot(0x8000_0000)) -- cgit v1.2.3 From bb27e4134b67e406810e40bbefd99fe392c25fed Mon Sep 17 00:00:00 2001 From: Lain Soykaf Date: Thu, 15 Dec 2022 18:06:28 -0500 Subject: AudioVideoValidator: Fix embedded attachment requirements --- .../web/activity_pub/object_validators/audio_video_validator.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/object_validators/audio_video_validator.ex b/lib/pleroma/web/activity_pub/object_validators/audio_video_validator.ex index 432bd9039..671a7ef0c 100644 --- a/lib/pleroma/web/activity_pub/object_validators/audio_video_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/audio_video_validator.ex @@ -104,14 +104,14 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AudioVideoValidator do struct |> cast(data, __schema__(:fields) -- [:attachment, :tag]) - |> cast_embed(:attachment) + |> cast_embed(:attachment, required: true) |> cast_embed(:tag) end defp validate_data(data_cng) do data_cng |> validate_inclusion(:type, ["Audio", "Video"]) - |> validate_required([:id, :actor, :attributedTo, :type, :context, :attachment]) + |> validate_required([:id, :actor, :attributedTo, :type, :context]) |> CommonValidations.validate_any_presence([:cc, :to]) |> CommonValidations.validate_fields_match([:actor, :attributedTo]) |> CommonValidations.validate_actor_presence() -- cgit v1.2.3 From 3f0783c0a50c99ba4697829f9571b57d8b08f5de Mon Sep 17 00:00:00 2001 From: faried nawaz Date: Mon, 14 Nov 2022 01:50:52 +0500 Subject: fix atom and rss feeds for users and tags Changes: - make the XML closer to spec (RSS does not pass w3c's validator, but works) - fix dates (RFC3339 for Atom, doc says RFC822 for RSS but RFC1123 is closer) - fix attachment/enclosure links (but see below) - set feed item title to post's "summary" if present - pruned several elements that validators did not like - examples: ap_enabled, user banner urls. Specs: - https://www.rssboard.org/rss-specification - https://validator.w3.org/feed/docs/atom.html - https://www.intertwingly.net/wiki/pie/Rss20AndAtom10Compared Validators: - https://validator.w3.org/feed/ - https://rssatom.com/feedvalidator.php Attachment/enclosure links should have a "length" field (mandatory according to the spec). This is not present in the object's data map. --- lib/pleroma/web/feed/feed_view.ex | 71 +++++++++++++++++++--- .../web/templates/feed/feed/_activity.atom.eex | 8 +-- .../web/templates/feed/feed/_activity.rss.eex | 11 +--- .../web/templates/feed/feed/_author.atom.eex | 19 +++--- .../web/templates/feed/feed/_author.rss.eex | 27 +++----- .../web/templates/feed/feed/_tag_activity.atom.eex | 64 ++++++++++--------- .../web/templates/feed/feed/_tag_author.atom.eex | 28 ++++----- lib/pleroma/web/templates/feed/feed/tag.atom.eex | 32 +++++----- lib/pleroma/web/templates/feed/feed/user.atom.eex | 4 +- lib/pleroma/web/templates/feed/feed/user.rss.eex | 17 ++++-- 10 files changed, 162 insertions(+), 119 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/feed/feed_view.ex b/lib/pleroma/web/feed/feed_view.ex index 35a5f9482..323ede90a 100644 --- a/lib/pleroma/web/feed/feed_view.ex +++ b/lib/pleroma/web/feed/feed_view.ex @@ -21,7 +21,7 @@ defmodule Pleroma.Web.Feed.FeedView do |> pub_date end - def pub_date(%DateTime{} = date), do: Timex.format!(date, "{RFC822}") + def pub_date(%DateTime{} = date), do: to_rfc1123(date) def prepare_activity(activity, opts \\ []) do object = Object.normalize(activity, fetch: false) @@ -41,13 +41,18 @@ defmodule Pleroma.Web.Feed.FeedView do def most_recent_update(activities) do with %{updated_at: updated_at} <- List.first(activities) do - NaiveDateTime.to_iso8601(updated_at) + to_rfc3339(updated_at) end end - def most_recent_update(activities, user) do + def most_recent_update(activities, user, :atom) do (List.first(activities) || user).updated_at - |> NaiveDateTime.to_iso8601() + |> to_rfc3339() + end + + def most_recent_update(activities, user, :rss) do + (List.first(activities) || user).updated_at + |> to_rfc1123() end def feed_logo do @@ -61,6 +66,10 @@ defmodule Pleroma.Web.Feed.FeedView do |> MediaProxy.url() end + def email(user) do + user.nickname <> "@" <> Pleroma.Web.Endpoint.host() + end + def logo(user) do user |> User.avatar_url() @@ -69,18 +78,35 @@ defmodule Pleroma.Web.Feed.FeedView do def last_activity(activities), do: List.last(activities) - def activity_title(%{"content" => content}, opts \\ %{}) do - content + def activity_title(%{"content" => content, "summary" => summary} = data, opts \\ %{}) do + title = + cond do + summary != "" -> summary + content != "" -> activity_content(data) + true -> "a post" + end + + title |> Pleroma.Web.Metadata.Utils.scrub_html() |> Pleroma.Emoji.Formatter.demojify() |> Formatter.truncate(opts[:max_length], opts[:omission]) |> escape() end + def activity_description(data) do + content = activity_content(data) + summary = data["summary"] + + cond do + content != "" -> escape(content) + summary != "" -> escape(summary) + true -> escape(data["type"]) + end + end + def activity_content(%{"content" => content}) do content |> String.replace(~r/[\n\r]/, "") - |> escape() end def activity_content(_), do: "" @@ -112,4 +138,35 @@ defmodule Pleroma.Web.Feed.FeedView do |> html_escape() |> safe_to_string() end + + @spec to_rfc3339(String.t() | NativeDateTime.t()) :: String.t() + def to_rfc3339(date) when is_binary(date) do + date + |> Timex.parse!("{ISO:Extended}") + |> to_rfc3339() + end + + def to_rfc3339(nd) do + nd + |> Timex.to_datetime() + |> Timex.format!("{RFC3339}") + end + + @spec to_rfc1123(String.t() | DateTime.t() | NativeDateTime.t()) :: String.t() + def to_rfc1123(datestr) when is_binary(datestr) do + datestr + |> Timex.parse!("{ISO:Extended}") + |> to_rfc1123() + end + + def to_rfc1123(%DateTime{} = date) do + date + |> Timex.format!("{RFC1123}") + end + + def to_rfc1123(nd) do + nd + |> Timex.to_datetime() + |> Timex.format!("{RFC1123}") + end end diff --git a/lib/pleroma/web/templates/feed/feed/_activity.atom.eex b/lib/pleroma/web/templates/feed/feed/_activity.atom.eex index 57bd92468..260338772 100644 --- a/lib/pleroma/web/templates/feed/feed/_activity.atom.eex +++ b/lib/pleroma/web/templates/feed/feed/_activity.atom.eex @@ -3,15 +3,15 @@ http://activitystrea.ms/schema/1.0/post <%= @data["id"] %> <%= activity_title(@data, Keyword.get(@feed_config, :post_title, %{})) %> - <%= activity_content(@data) %> - <%= @activity.data["published"] %> - <%= @activity.data["published"] %> + <%= activity_description(@data) %> + <%= to_rfc3339(@activity.data["published"]) %> + <%= to_rfc3339(@activity.data["published"]) %> <%= activity_context(@activity) %> - <%= if @data["summary"] do %> + <%= if @data["summary"] != "" do %> <%= escape(@data["summary"]) %> <% end %> diff --git a/lib/pleroma/web/templates/feed/feed/_activity.rss.eex b/lib/pleroma/web/templates/feed/feed/_activity.rss.eex index 279f2171d..7a7e494c0 100644 --- a/lib/pleroma/web/templates/feed/feed/_activity.rss.eex +++ b/lib/pleroma/web/templates/feed/feed/_activity.rss.eex @@ -3,17 +3,12 @@ http://activitystrea.ms/schema/1.0/post <%= @data["id"] %> <%= activity_title(@data, Keyword.get(@feed_config, :post_title, %{})) %> - <%= activity_content(@data) %> - <%= @activity.data["published"] %> - <%= @activity.data["published"] %> + <%= activity_description(@data) %> + <%= to_rfc1123(@activity.data["published"]) %> <%= activity_context(@activity) %> - <%= if @data["summary"] do %> - <%= escape(@data["summary"]) %> - <% end %> - <%= if @activity.local do %> <%= @data["id"] %> <% else %> @@ -27,7 +22,7 @@ <% end %> <%= for attachment <- @data["attachment"] || [] do %> - <%= attachment_href(attachment) %> + <% end %> <%= if @data["inReplyTo"] do %> diff --git a/lib/pleroma/web/templates/feed/feed/_author.atom.eex b/lib/pleroma/web/templates/feed/feed/_author.atom.eex index 25cbffada..90be8a559 100644 --- a/lib/pleroma/web/templates/feed/feed/_author.atom.eex +++ b/lib/pleroma/web/templates/feed/feed/_author.atom.eex @@ -1,17 +1,14 @@ - <%= @user.ap_id %> - http://activitystrea.ms/schema/1.0/person <%= @user.ap_id %> + <%= @user.nickname %> + http://activitystrea.ms/schema/1.0/person + <%= @user.name %> + <%= User.avatar_url(@user) %> + <%= @user.ap_id %> + <%= to_rfc3339(@user.inserted_at) %> + <%= to_rfc3339(@user.updated_at) %> + <%= @user.ap_id %> <%= @user.nickname %> <%= @user.name %> <%= escape(@user.bio) %> - <%= escape(@user.bio) %> - <%= @user.nickname %> - - <%= if User.banner_url(@user) do %> - - <% end %> - <%= if @user.local do %> - true - <% end %> diff --git a/lib/pleroma/web/templates/feed/feed/_author.rss.eex b/lib/pleroma/web/templates/feed/feed/_author.rss.eex index 526aeddcf..22477e6b1 100644 --- a/lib/pleroma/web/templates/feed/feed/_author.rss.eex +++ b/lib/pleroma/web/templates/feed/feed/_author.rss.eex @@ -1,17 +1,10 @@ - - <%= @user.ap_id %> - http://activitystrea.ms/schema/1.0/person - <%= @user.ap_id %> - <%= @user.nickname %> - <%= @user.name %> - <%= escape(@user.bio) %> - <%= escape(@user.bio) %> - <%= @user.nickname %> - <%= User.avatar_url(@user) %> - <%= if User.banner_url(@user) do %> - <%= User.banner_url(@user) %> - <% end %> - <%= if @user.local do %> - true - <% end %> - +<%= "#{email(@user)} (#{escape(@user.name)})" %> +http://activitystrea.ms/schema/1.0/person +<%= @user.name %> +<%= User.avatar_url(@user) %> +<%= @user.ap_id %> +<%= to_rfc3339(@user.inserted_at) %> +<%= to_rfc3339(@user.updated_at) %> +<%= @user.nickname %> +<%= @user.name %> +<%= escape(@user.bio) %> diff --git a/lib/pleroma/web/templates/feed/feed/_tag_activity.atom.eex b/lib/pleroma/web/templates/feed/feed/_tag_activity.atom.eex index 7e2e587e1..25980c1e4 100644 --- a/lib/pleroma/web/templates/feed/feed/_tag_activity.atom.eex +++ b/lib/pleroma/web/templates/feed/feed/_tag_activity.atom.eex @@ -1,12 +1,22 @@ - http://activitystrea.ms/schema/1.0/note - http://activitystrea.ms/schema/1.0/post + http://activitystrea.ms/schema/1.0/note + http://activitystrea.ms/schema/1.0/post <%= render Phoenix.Controller.view_module(@conn), "_tag_author.atom", assigns %> - <%= @data["id"] %> - <%= activity_title(@data, Keyword.get(@feed_config, :post_title, %{})) %> - <%= activity_content(@data) %> + <%= @data["id"] %> + <%= activity_title(@data, Keyword.get(@feed_config, :post_title, %{})) %> + <%= activity_description(@data) %> + <%= to_rfc3339(@activity.data["published"]) %> + <%= to_rfc3339(@activity.data["published"]) %> + + <%= activity_context(@activity) %> + + + + <%= if @data["summary"] != "" do %> + <%= @data["summary"] %> + <% end %> <%= if @activity.local do %> @@ -15,37 +25,25 @@ <% end %> - <%= @activity.data["published"] %> - <%= @activity.data["published"] %> - - - <%= activity_context(@activity) %> - - - - <%= if @data["summary"] do %> - <%= @data["summary"] %> - <% end %> - - <%= for id <- @activity.recipients do %> - <%= if id == Pleroma.Constants.as_public() do %> + <%= for id <- @activity.recipients do %> + <%= if id == Pleroma.Constants.as_public() do %> + + <% else %> + <%= unless Regex.match?(~r/^#{Pleroma.Web.Endpoint.url()}.+followers$/, id) do %> - <% else %> - <%= unless Regex.match?(~r/^#{Pleroma.Web.Endpoint.url()}.+followers$/, id) do %> - - <% end %> + ostatus:object-type="http://activitystrea.ms/schema/1.0/person" + href="<%= id %>" /> <% end %> <% end %> + <% end %> - <%= for tag <- Pleroma.Object.hashtags(@object) do %> - - <% end %> + <%= for tag <- Pleroma.Object.hashtags(@object) do %> + + <% end %> - <%= for {emoji, file} <- @data["emoji"] || %{} do %> - - <% end %> + <%= for {emoji, file} <- @data["emoji"] || %{} do %> + + <% end %> diff --git a/lib/pleroma/web/templates/feed/feed/_tag_author.atom.eex b/lib/pleroma/web/templates/feed/feed/_tag_author.atom.eex index 997c4936e..71c696832 100644 --- a/lib/pleroma/web/templates/feed/feed/_tag_author.atom.eex +++ b/lib/pleroma/web/templates/feed/feed/_tag_author.atom.eex @@ -1,18 +1,14 @@ - http://activitystrea.ms/schema/1.0/person - <%= @actor.ap_id %> - <%= @actor.ap_id %> - <%= @actor.nickname %> - <%= escape(@actor.bio) %> - - <%= if User.banner_url(@actor) do %> - - <% end %> - <%= if @actor.local do %> - true - <% end %> - - <%= @actor.nickname %> - <%= @actor.name %> - <%= escape(@actor.bio) %> + <%= @actor.ap_id %> + <%= @actor.nickname %> + http://activitystrea.ms/schema/1.0/person + <%= @actor.name %> + <%= User.avatar_url(@actor) %> + <%= @actor.ap_id %> + <%= to_rfc3339(@actor.inserted_at) %> + <%= to_rfc3339(@actor.updated_at) %> + <%= @actor.ap_id %> + <%= @actor.nickname %> + <%= @actor.name %> + <%= escape(@actor.bio) %> diff --git a/lib/pleroma/web/templates/feed/feed/tag.atom.eex b/lib/pleroma/web/templates/feed/feed/tag.atom.eex index 8c551feaf..4955996c9 100644 --- a/lib/pleroma/web/templates/feed/feed/tag.atom.eex +++ b/lib/pleroma/web/templates/feed/feed/tag.atom.eex @@ -1,22 +1,20 @@ - + - <%= '#{Routes.tag_feed_url(@conn, :feed, @tag)}.rss' %> - #<%= @tag %> + <%= Routes.tag_feed_url(@conn, :feed, @tag) <> ".atom" %> + #<%= @tag %> + <%= Gettext.dpgettext("static_pages", "tag feed description", "These are public toots tagged with #%{tag}. You can interact with them if you have an account anywhere in the fediverse.", tag: @tag) %> + <%= feed_logo() %> + <%= most_recent_update(@activities) %> + - <%= Gettext.dpgettext("static_pages", "tag feed description", "These are public toots tagged with #%{tag}. You can interact with them if you have an account anywhere in the fediverse.", tag: @tag) %> - <%= feed_logo() %> - <%= most_recent_update(@activities) %> - - <%= for activity <- @activities do %> - <%= render Phoenix.Controller.view_module(@conn), "_tag_activity.atom", Map.merge(assigns, prepare_activity(activity, actor: true)) %> - <% end %> + <%= for activity <- @activities do %> + <%= render Phoenix.Controller.view_module(@conn), "_tag_activity.atom", Map.merge(assigns, prepare_activity(activity, actor: true)) %> + <% end %> diff --git a/lib/pleroma/web/templates/feed/feed/user.atom.eex b/lib/pleroma/web/templates/feed/feed/user.atom.eex index 97a7535ab..a0148d768 100644 --- a/lib/pleroma/web/templates/feed/feed/user.atom.eex +++ b/lib/pleroma/web/templates/feed/feed/user.atom.eex @@ -1,14 +1,14 @@ <%= Routes.user_feed_url(@conn, :feed, @user.nickname) <> ".atom" %> <%= @user.nickname <> "'s timeline" %> - <%= most_recent_update(@activities, @user) %> + <%= escape(@user.bio) %> + <%= most_recent_update(@activities, @user, :atom) %> <%= logo(@user) %> diff --git a/lib/pleroma/web/templates/feed/feed/user.rss.eex b/lib/pleroma/web/templates/feed/feed/user.rss.eex index a9fee244c..80ad8b161 100644 --- a/lib/pleroma/web/templates/feed/feed/user.rss.eex +++ b/lib/pleroma/web/templates/feed/feed/user.rss.eex @@ -1,11 +1,20 @@ - + - <%= Routes.user_feed_url(@conn, :feed, @user.nickname) <> ".rss" %> <%= @user.nickname <> "'s timeline" %> - <%= most_recent_update(@activities, @user) %> - <%= logo(@user) %> <%= '#{Routes.user_feed_url(@conn, :feed, @user.nickname)}.rss' %> + " + rel="self" type="application/rss+xml" /> + <%= escape(@user.bio) %> + + <%= logo(@user) %> + <%= @user.nickname <> "'s timeline" %> + <%= '#{Routes.user_feed_url(@conn, :feed, @user.nickname)}.rss' %> + <%= render Phoenix.Controller.view_module(@conn), "_author.rss", assigns %> -- cgit v1.2.3 From f3253c0c6a0f6350437fc701023b375ecb1b7bc6 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Tue, 15 Nov 2022 11:45:32 -0500 Subject: Implement RFC2822 timestamp formatting --- lib/pleroma/web/feed/feed_view.ex | 46 +++++++++++++++++----- .../web/templates/feed/feed/_activity.rss.eex | 2 +- 2 files changed, 38 insertions(+), 10 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/feed/feed_view.ex b/lib/pleroma/web/feed/feed_view.ex index 323ede90a..35136897f 100644 --- a/lib/pleroma/web/feed/feed_view.ex +++ b/lib/pleroma/web/feed/feed_view.ex @@ -14,6 +14,9 @@ defmodule Pleroma.Web.Feed.FeedView do require Pleroma.Constants + @days ~w(Mon Tue Wed Thu Fri Sat Sun) + @months ~w(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec) + @spec pub_date(String.t() | DateTime.t()) :: String.t() def pub_date(date) when is_binary(date) do date @@ -21,7 +24,7 @@ defmodule Pleroma.Web.Feed.FeedView do |> pub_date end - def pub_date(%DateTime{} = date), do: to_rfc1123(date) + def pub_date(%DateTime{} = date), do: to_rfc2822(date) def prepare_activity(activity, opts \\ []) do object = Object.normalize(activity, fetch: false) @@ -52,7 +55,7 @@ defmodule Pleroma.Web.Feed.FeedView do def most_recent_update(activities, user, :rss) do (List.first(activities) || user).updated_at - |> to_rfc1123() + |> to_rfc2822() end def feed_logo do @@ -152,21 +155,46 @@ defmodule Pleroma.Web.Feed.FeedView do |> Timex.format!("{RFC3339}") end - @spec to_rfc1123(String.t() | DateTime.t() | NativeDateTime.t()) :: String.t() - def to_rfc1123(datestr) when is_binary(datestr) do + @spec to_rfc2822(String.t() | DateTime.t() | NativeDateTime.t()) :: String.t() + def to_rfc2822(datestr) when is_binary(datestr) do datestr |> Timex.parse!("{ISO:Extended}") - |> to_rfc1123() + |> to_rfc2822() end - def to_rfc1123(%DateTime{} = date) do + def to_rfc2822(%DateTime{} = date) do date - |> Timex.format!("{RFC1123}") + |> DateTime.to_naive() + |> NaiveDateTime.to_erl() + |> rfc2822_from_erl() end - def to_rfc1123(nd) do + def to_rfc2822(nd) do nd |> Timex.to_datetime() - |> Timex.format!("{RFC1123}") + |> DateTime.to_naive() + |> NaiveDateTime.to_erl() + |> rfc2822_from_erl() + end + + @doc """ + Builds a RFC2822 timestamp from an Erlang timestamp + [RFC2822 3.3 - Date and Time Specification](https://tools.ietf.org/html/rfc2822#section-3.3) + This function always assumes the Erlang timestamp is in Universal time, not Local time + """ + def rfc2822_from_erl({{year, month, day} = date, {hour, minute, second}}) do + day_name = Enum.at(@days, :calendar.day_of_the_week(date) - 1) + month_name = Enum.at(@months, month - 1) + + date_part = "#{day_name}, #{day} #{month_name} #{year}" + time_part = "#{pad(hour)}:#{pad(minute)}:#{pad(second)}" + + date_part <> " " <> time_part <> " +0000" + end + + defp pad(num) do + num + |> Integer.to_string() + |> String.pad_leading(2, "0") end end diff --git a/lib/pleroma/web/templates/feed/feed/_activity.rss.eex b/lib/pleroma/web/templates/feed/feed/_activity.rss.eex index 7a7e494c0..5c8f35fe4 100644 --- a/lib/pleroma/web/templates/feed/feed/_activity.rss.eex +++ b/lib/pleroma/web/templates/feed/feed/_activity.rss.eex @@ -4,7 +4,7 @@ <%= @data["id"] %> <%= activity_title(@data, Keyword.get(@feed_config, :post_title, %{})) %> <%= activity_description(@data) %> - <%= to_rfc1123(@activity.data["published"]) %> + <%= to_rfc2822(@activity.data["published"]) %> <%= activity_context(@activity) %> -- cgit v1.2.3 From 8d500977a6ce9b0fd461c16ee2b343bab510e27f Mon Sep 17 00:00:00 2001 From: faried nawaz Date: Tue, 15 Nov 2022 23:29:40 +0500 Subject: fix: feed item title was escaped twice --- lib/pleroma/web/feed/feed_view.ex | 1 - 1 file changed, 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/feed/feed_view.ex b/lib/pleroma/web/feed/feed_view.ex index 35136897f..3e24397aa 100644 --- a/lib/pleroma/web/feed/feed_view.ex +++ b/lib/pleroma/web/feed/feed_view.ex @@ -93,7 +93,6 @@ defmodule Pleroma.Web.Feed.FeedView do |> Pleroma.Web.Metadata.Utils.scrub_html() |> Pleroma.Emoji.Formatter.demojify() |> Formatter.truncate(opts[:max_length], opts[:omission]) - |> escape() end def activity_description(data) do -- cgit v1.2.3 From 3f63caee2ade363719591edf7f6cb4c56587efda Mon Sep 17 00:00:00 2001 From: faried nawaz Date: Tue, 15 Nov 2022 23:30:56 +0500 Subject: fix: add xmlns:thr for in-reply-to refs --- lib/pleroma/web/templates/feed/feed/tag.atom.eex | 2 +- lib/pleroma/web/templates/feed/feed/tag.rss.eex | 5 +++-- lib/pleroma/web/templates/feed/feed/user.atom.eex | 1 + lib/pleroma/web/templates/feed/feed/user.rss.eex | 1 + 4 files changed, 6 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/templates/feed/feed/tag.atom.eex b/lib/pleroma/web/templates/feed/feed/tag.atom.eex index 4955996c9..14b0ee594 100644 --- a/lib/pleroma/web/templates/feed/feed/tag.atom.eex +++ b/lib/pleroma/web/templates/feed/feed/tag.atom.eex @@ -1,7 +1,7 @@ - - + - #<%= @tag %> <%= Gettext.dpgettext("static_pages", "tag feed description", "These are public toots tagged with #%{tag}. You can interact with them if you have an account anywhere in the fediverse.", tag: @tag) %> <%= '#{Routes.tag_feed_url(@conn, :feed, @tag)}.rss' %> diff --git a/lib/pleroma/web/templates/feed/feed/user.atom.eex b/lib/pleroma/web/templates/feed/feed/user.atom.eex index a0148d768..e36bfc66c 100644 --- a/lib/pleroma/web/templates/feed/feed/user.atom.eex +++ b/lib/pleroma/web/templates/feed/feed/user.atom.eex @@ -1,6 +1,7 @@ diff --git a/lib/pleroma/web/templates/feed/feed/user.rss.eex b/lib/pleroma/web/templates/feed/feed/user.rss.eex index 80ad8b161..fae3fcf3d 100644 --- a/lib/pleroma/web/templates/feed/feed/user.rss.eex +++ b/lib/pleroma/web/templates/feed/feed/user.rss.eex @@ -1,6 +1,7 @@ -- cgit v1.2.3 From 0f67eab38483c574db82a00b53fb29e13c7df089 Mon Sep 17 00:00:00 2001 From: faried nawaz Date: Tue, 15 Nov 2022 23:42:54 +0500 Subject: remove pub_date() -- use to_rfc2822 instead _tag_activity.xml.eex used activity_content() instead of activity_description(), and did not escape html properly. --- lib/pleroma/web/feed/feed_view.ex | 9 --------- lib/pleroma/web/templates/feed/feed/_tag_activity.xml.eex | 4 ++-- 2 files changed, 2 insertions(+), 11 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/feed/feed_view.ex b/lib/pleroma/web/feed/feed_view.ex index 3e24397aa..449659f4b 100644 --- a/lib/pleroma/web/feed/feed_view.ex +++ b/lib/pleroma/web/feed/feed_view.ex @@ -17,15 +17,6 @@ defmodule Pleroma.Web.Feed.FeedView do @days ~w(Mon Tue Wed Thu Fri Sat Sun) @months ~w(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec) - @spec pub_date(String.t() | DateTime.t()) :: String.t() - def pub_date(date) when is_binary(date) do - date - |> Timex.parse!("{ISO:Extended}") - |> pub_date - end - - def pub_date(%DateTime{} = date), do: to_rfc2822(date) - def prepare_activity(activity, opts \\ []) do object = Object.normalize(activity, fetch: false) diff --git a/lib/pleroma/web/templates/feed/feed/_tag_activity.xml.eex b/lib/pleroma/web/templates/feed/feed/_tag_activity.xml.eex index 2334e24a2..d582c83e8 100644 --- a/lib/pleroma/web/templates/feed/feed/_tag_activity.xml.eex +++ b/lib/pleroma/web/templates/feed/feed/_tag_activity.xml.eex @@ -4,9 +4,9 @@ <%= activity_context(@activity) %> <%= activity_context(@activity) %> - <%= pub_date(@activity.data["published"]) %> + <%= to_rfc2822(@activity.data["published"]) %> - <%= activity_content(@data) %> + <%= activity_description(@data) %> <%= for attachment <- @data["attachment"] || [] do %> <% end %> -- cgit v1.2.3 From c58eb873dd47ebd1b207c9f79ccffe2c3819949d Mon Sep 17 00:00:00 2001 From: Sean King Date: Sun, 18 Dec 2022 22:05:07 -0700 Subject: Fix CommonAPI delete function to use User.privileged? instead of User.superuser? --- lib/pleroma/web/common_api.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/common_api.ex b/lib/pleroma/web/common_api.ex index 97f2aec3b..89cc0d6fe 100644 --- a/lib/pleroma/web/common_api.ex +++ b/lib/pleroma/web/common_api.ex @@ -148,7 +148,7 @@ defmodule Pleroma.Web.CommonAPI do true <- User.privileged?(user, :messages_delete) || user.ap_id == object.data["actor"], {:ok, delete_data, _} <- Builder.delete(user, object.data["id"]), {:ok, delete, _} <- Pipeline.common_pipeline(delete_data, local: true) do - if User.superuser?(user) and user.ap_id != object.data["actor"] do + if User.privileged?(user, :messages_delete) and user.ap_id != object.data["actor"] do action = if object.data["type"] == "ChatMessage" do "chat_message_delete" -- cgit v1.2.3 From 72d4d1b392c7889e13b238a190a437090c360f2e Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Mon, 19 Dec 2022 14:40:08 -0500 Subject: Fix TwitterCard meta tags MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TwitterCard meta tags are supposed to use the attributes "name" and "content". OpenGraph tags use the attributes "property" and "content". Twitter itself is smart enough to detect broken meta tags and discover the TwitterCard using "property" and "content", but other platforms that only implement parsing of TwitterCards and not OpenGraph may fail to correctly detect the tags as they're under the wrong attributes. > "Open Graph protocol also specifies the use of property and content attributes for markup while > Twitter cards use name and content. Twitter’s parser will fall back to using property and content, > so there is no need to modify existing Open Graph protocol markup if it already exists." [0] [0] https://developer.twitter.com/en/docs/twitter-for-websites/cards/guides/getting-started --- lib/pleroma/web/metadata/providers/twitter_card.ex | 43 +++++++++++----------- 1 file changed, 21 insertions(+), 22 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/metadata/providers/twitter_card.ex b/lib/pleroma/web/metadata/providers/twitter_card.ex index bf0a12212..2dac22ee2 100644 --- a/lib/pleroma/web/metadata/providers/twitter_card.ex +++ b/lib/pleroma/web/metadata/providers/twitter_card.ex @@ -20,12 +20,12 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCard do [ title_tag(user), - {:meta, [property: "twitter:description", content: scrubbed_content], []} + {:meta, [name: "twitter:description", content: scrubbed_content], []} ] ++ if attachments == [] or Metadata.activity_nsfw?(object) do [ image_tag(user), - {:meta, [property: "twitter:card", content: "summary"], []} + {:meta, [name: "twitter:card", content: "summary"], []} ] else attachments @@ -37,20 +37,19 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCard do with truncated_bio = Utils.scrub_html_and_truncate(user.bio) do [ title_tag(user), - {:meta, [property: "twitter:description", content: truncated_bio], []}, + {:meta, [name: "twitter:description", content: truncated_bio], []}, image_tag(user), - {:meta, [property: "twitter:card", content: "summary"], []} + {:meta, [name: "twitter:card", content: "summary"], []} ] end end defp title_tag(user) do - {:meta, [property: "twitter:title", content: Utils.user_name_string(user)], []} + {:meta, [name: "twitter:title", content: Utils.user_name_string(user)], []} end def image_tag(user) do - {:meta, [property: "twitter:image", content: MediaProxy.preview_url(User.avatar_url(user))], - []} + {:meta, [name: "twitter:image", content: MediaProxy.preview_url(User.avatar_url(user))], []} end defp build_attachments(id, %{data: %{"attachment" => attachments}}) do @@ -60,10 +59,10 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCard do case Utils.fetch_media_type(@media_types, url["mediaType"]) do "audio" -> [ - {:meta, [property: "twitter:card", content: "player"], []}, - {:meta, [property: "twitter:player:width", content: "480"], []}, - {:meta, [property: "twitter:player:height", content: "80"], []}, - {:meta, [property: "twitter:player", content: player_url(id)], []} + {:meta, [name: "twitter:card", content: "player"], []}, + {:meta, [name: "twitter:player:width", content: "480"], []}, + {:meta, [name: "twitter:player:height", content: "80"], []}, + {:meta, [name: "twitter:player", content: player_url(id)], []} | acc ] @@ -74,10 +73,10 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCard do # workaround. "image" -> [ - {:meta, [property: "twitter:card", content: "summary_large_image"], []}, + {:meta, [name: "twitter:card", content: "summary_large_image"], []}, {:meta, [ - property: "twitter:player", + name: "twitter:player", content: MediaProxy.url(url["href"]) ], []} | acc @@ -90,14 +89,14 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCard do width = url["width"] || 480 [ - {:meta, [property: "twitter:card", content: "player"], []}, - {:meta, [property: "twitter:player", content: player_url(id)], []}, - {:meta, [property: "twitter:player:width", content: "#{width}"], []}, - {:meta, [property: "twitter:player:height", content: "#{height}"], []}, - {:meta, [property: "twitter:player:stream", content: MediaProxy.url(url["href"])], + {:meta, [name: "twitter:card", content: "player"], []}, + {:meta, [name: "twitter:player", content: player_url(id)], []}, + {:meta, [name: "twitter:player:width", content: "#{width}"], []}, + {:meta, [name: "twitter:player:height", content: "#{height}"], []}, + {:meta, [name: "twitter:player:stream", content: MediaProxy.url(url["href"])], []}, - {:meta, - [property: "twitter:player:stream:content_type", content: url["mediaType"]], []} + {:meta, [name: "twitter:player:stream:content_type", content: url["mediaType"]], + []} | acc ] @@ -123,8 +122,8 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCard do !is_nil(url["height"]) && !is_nil(url["width"]) -> metadata ++ [ - {:meta, [property: "twitter:player:width", content: "#{url["width"]}"], []}, - {:meta, [property: "twitter:player:height", content: "#{url["height"]}"], []} + {:meta, [name: "twitter:player:width", content: "#{url["width"]}"], []}, + {:meta, [name: "twitter:player:height", content: "#{url["height"]}"], []} ] true -> -- cgit v1.2.3 From 351b5a9df406a8a093d10dec3cdfa3bb2d709efb Mon Sep 17 00:00:00 2001 From: Sean King Date: Wed, 21 Dec 2022 23:35:39 -0700 Subject: Use crazy hack to finally get pleroma:report notifications not visible after revoking privileges --- lib/pleroma/web/mastodon_api/mastodon_api.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/mastodon_api.ex b/lib/pleroma/web/mastodon_api/mastodon_api.ex index c51230b92..98bf90af7 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api.ex @@ -65,7 +65,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPI do cast_params(params) |> Map.update(:include_types, [], fn include_types -> include_types end) options = - if "pleroma:report" not in options.include_types or + if ("pleroma:report" not in options.include_types and + User.privileged?(user, :reports_manage_reports)) or User.privileged?(user, :reports_manage_reports) do options else -- cgit v1.2.3 From 90681c720d4c0530b67b0105db1204fff82835d8 Mon Sep 17 00:00:00 2001 From: Sean King Date: Wed, 21 Dec 2022 23:40:39 -0700 Subject: Make lint happy --- lib/pleroma/web/mastodon_api/mastodon_api.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/mastodon_api.ex b/lib/pleroma/web/mastodon_api/mastodon_api.ex index 98bf90af7..467dc2fac 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api.ex @@ -66,7 +66,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPI do options = if ("pleroma:report" not in options.include_types and - User.privileged?(user, :reports_manage_reports)) or + User.privileged?(user, :reports_manage_reports)) or User.privileged?(user, :reports_manage_reports) do options else -- cgit v1.2.3