From eb84de01439c4ee25f59390e5be4ffa7f36e01b8 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Mon, 4 Mar 2019 19:55:11 +0700 Subject: [PATCH 01/18] allow users to disable their own account --- config/config.exs | 3 +- lib/mix/tasks/pleroma/user.ex | 20 +++++- lib/pleroma/activity.ex | 16 ++++- lib/pleroma/gopher/server.ex | 3 +- lib/pleroma/notification.ex | 32 +++++----- lib/pleroma/user.ex | 64 +++++++++++++++---- lib/pleroma/user/info.ex | 9 +++ lib/pleroma/web/activity_pub/activity_pub.ex | 1 + .../web/admin_api/admin_api_controller.ex | 10 +++ lib/pleroma/web/common_api/utils.ex | 4 +- .../mastodon_api/mastodon_api_controller.ex | 12 ++-- lib/pleroma/web/router.ex | 2 + .../controllers/util_controller.ex | 11 ++++ lib/pleroma/web/twitter_api/twitter_api.ex | 20 ++++-- .../web/twitter_api/twitter_api_controller.ex | 4 +- ...0190228121252_users_add_disabled_index.exs | 7 ++ 16 files changed, 167 insertions(+), 51 deletions(-) create mode 100644 priv/repo/migrations/20190228121252_users_add_disabled_index.exs diff --git a/config/config.exs b/config/config.exs index a620e7451..d9ed43dda 100644 --- a/config/config.exs +++ b/config/config.exs @@ -343,7 +343,8 @@ config :pleroma, Pleroma.Jobs, federator_incoming: [max_jobs: 50], federator_outgoing: [max_jobs: 50], - mailer: [max_jobs: 10] + mailer: [max_jobs: 10], + user: [max_jobs: 10] config :auto_linker, opts: [ diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index 037e44716..297332bc4 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -23,7 +23,7 @@ defmodule Mix.Tasks.Pleroma.User do - `--password PASSWORD` - the user's password - `--moderator`/`--no-moderator` - whether the user is a moderator - `--admin`/`--no-admin` - whether the user is an admin - - `-y`, `--assume-yes`/`--no-assume-yes` - whether to assume yes to all questions + - `-y`, `--assume-yes`/`--no-assume-yes` - whether to assume yes to all questions ## Generate an invite link. @@ -37,6 +37,10 @@ defmodule Mix.Tasks.Pleroma.User do mix pleroma.user toggle_activated NICKNAME + ## Disable or enable the user's account. + + mix pleroma.user toggle_disabled NICKNAME + ## Unsubscribe local users from user's account and deactivate it mix pleroma.user unsubscribe NICKNAME @@ -170,6 +174,20 @@ def run(["toggle_activated", nickname]) do end end + def run(["toggle_disabled", nickname]) do + Common.start_pleroma() + + case User.get_by_nickname(nickname) do + %User{} = user -> + {:ok, user} = User.disable(user, !user.info.disabled) + status = if(user.info.disabled, do: "ON", else: "OFF") + Mix.shell().info("Disabled status of #{nickname}: #{status}") + + _ -> + Mix.shell().error("No user #{nickname}") + end + end + def run(["reset_password", nickname]) do Common.start_pleroma() diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index 66854dc2d..c466bff7f 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -42,7 +42,10 @@ def get_by_ap_id(ap_id) do end def get_by_id(id) do - Repo.get(Activity, id) + Activity + |> where([a], a.id == ^id) + |> restrict_disabled_users() + |> Repo.one() end def by_object_ap_id(ap_id) do @@ -92,6 +95,7 @@ def get_all_create_by_object_ap_id(ap_id) do def get_create_by_object_ap_id(ap_id) when is_binary(ap_id) do create_by_object_ap_id(ap_id) + |> restrict_disabled_users() |> Repo.one() end @@ -123,4 +127,14 @@ def all_by_actor_and_id(actor, status_ids) do |> where([s], s.actor == ^actor) |> Repo.all() end + + def restrict_disabled_users(query) do + from(activity in query, + where: + fragment( + "? not in (SELECT ap_id FROM users WHERE info->'disabled' @> 'true')", + activity.actor + ) + ) + end end diff --git a/lib/pleroma/gopher/server.ex b/lib/pleroma/gopher/server.ex index ba9614029..24190574e 100644 --- a/lib/pleroma/gopher/server.ex +++ b/lib/pleroma/gopher/server.ex @@ -41,7 +41,6 @@ defmodule Pleroma.Gopher.Server.ProtocolHandler do alias Pleroma.Activity alias Pleroma.HTML alias Pleroma.User - alias Pleroma.Repo def start_link(ref, socket, transport, opts) do pid = spawn_link(__MODULE__, :init, [ref, socket, transport, opts]) @@ -110,7 +109,7 @@ def response("/main/all") do end def response("/notices/" <> id) do - with %Activity{} = activity <- Repo.get(Activity, id), + with %Activity{} = activity <- Activity.get_by_id(id), true <- Visibility.is_public?(activity) do activities = ActivityPub.fetch_activities_for_context(activity.data["context"]) diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index c88512567..0f9f74b1e 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -36,22 +36,22 @@ defp restrict_since(query, %{"since_id" => since_id}) do defp restrict_since(query, _), do: query def for_user(user, opts \\ %{}) do - query = - from( - n in Notification, - where: n.user_id == ^user.id, - order_by: [desc: n.id], - join: activity in assoc(n, :activity), - preload: [activity: activity], - limit: 20 - ) - - query = - query - |> restrict_since(opts) - |> restrict_max(opts) - - Repo.all(query) + from( + n in Notification, + where: n.user_id == ^user.id, + order_by: [desc: n.id], + join: activity in assoc(n, :activity), + preload: [activity: activity], + limit: 20, + where: + fragment( + "? not in (SELECT ap_id FROM users WHERE info->'disabled' @> 'true')", + activity.actor + ) + ) + |> restrict_since(opts) + |> restrict_max(opts) + |> Repo.all() end def set_read_up_to(%{id: user_id} = _user, id) do diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 50e7e7ccd..f02051174 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -108,10 +108,8 @@ def ap_followers(%User{} = user) do end def user_info(%User{} = user) do - oneself = if user.local, do: 1, else: 0 - %{ - following_count: length(user.following) - oneself, + following_count: following_count(user), note_count: user.info.note_count, follower_count: user.info.follower_count, locked: user.info.locked, @@ -120,6 +118,23 @@ def user_info(%User{} = user) do } end + defp restrict_disabled(query) do + from(u in query, + where: not fragment("? \\? 'disabled' AND ?->'disabled' @> 'true'", u.info, u.info) + ) + end + + def following_count(%User{following: []}), do: 0 + + def following_count(%User{following: following, id: id}) do + from(u in User, + where: u.follower_address in ^following, + where: u.id != ^id + ) + |> restrict_disabled() + |> Repo.aggregate(:count, :id) + end + def remote_user_creation(params) do params = params @@ -545,6 +560,7 @@ def get_followers_query(%User{id: id, follower_address: follower_address}, nil) where: fragment("? <@ ?", ^[follower_address], u.following), where: u.id != ^id ) + |> restrict_disabled() end def get_followers_query(user, page) do @@ -572,6 +588,7 @@ def get_friends_query(%User{id: id, following: following}, nil) do where: u.follower_address in ^following, where: u.id != ^id ) + |> restrict_disabled() end def get_friends_query(user, page) do @@ -681,11 +698,10 @@ def update_note_count(%User{} = user) do info_cng = User.Info.set_note_count(user.info, note_count) - cng = - change(user) - |> put_embed(:info, info_cng) - - update_and_set_cache(cng) + user + |> change() + |> put_embed(:info, info_cng) + |> update_and_set_cache() end def update_follower_count(%User{} = user) do @@ -694,6 +710,7 @@ def update_follower_count(%User{} = user) do |> where([u], ^user.follower_address in u.following) |> where([u], u.id != ^user.id) |> select([u], %{count: count(u.id)}) + |> restrict_disabled() User |> where(id: ^user.id) @@ -860,6 +877,7 @@ defp fts_search_subquery(term, query \\ User) do ^processed_query ) ) + |> restrict_disabled() end defp trigram_search_subquery(term) do @@ -876,6 +894,7 @@ defp trigram_search_subquery(term) do }, where: fragment("trim(? || ' ' || coalesce(?, '')) % ?", u.nickname, u.name, ^term) ) + |> restrict_disabled() end defp boost_search_results(results, nil), do: results @@ -1062,11 +1081,10 @@ def moderator_user_query do def deactivate(%User{} = user, status \\ true) do info_cng = User.Info.set_activation_status(user.info, status) - cng = - change(user) - |> put_embed(:info, info_cng) - - update_and_set_cache(cng) + user + |> change() + |> put_embed(:info, info_cng) + |> update_and_set_cache() end def delete(%User{} = user) do @@ -1100,6 +1118,26 @@ def delete(%User{} = user) do {:ok, user} end + def disable_async(user, status \\ true) do + Pleroma.Jobs.enqueue(:user, __MODULE__, [:disable_async, user, status]) + end + + def disable(%User{} = user, status \\ true) do + with {:ok, user} <- User.deactivate(user, status), + info_cng <- User.Info.set_disabled_status(user.info, status), + {:ok, user} <- + user + |> change() + |> put_embed(:info, info_cng) + |> update_and_set_cache(), + {:ok, friends} <- User.get_friends(user) do + Enum.each(friends, &update_follower_count(&1)) + {:ok, user} + end + end + + def perform(:disable_async, user, status), do: disable(user, status) + def html_filter_policy(%User{info: %{no_rich_text: true}}) do Pleroma.HTML.Scrubber.TwitterText end diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index 818b64645..1ec356ba9 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -36,6 +36,7 @@ defmodule Pleroma.User.Info do field(:hide_follows, :boolean, default: false) field(:pinned_activities, {:array, :string}, default: []) field(:flavour, :string, default: nil) + field(:disabled, :boolean, default: false) # Found in the wild # ap_id -> Where is this used? @@ -54,6 +55,14 @@ def set_activation_status(info, deactivated) do |> validate_required([:deactivated]) end + def set_disabled_status(info, disabled) do + params = %{disabled: disabled} + + info + |> cast(params, [:disabled]) + |> validate_required([:disabled]) + end + def add_to_note_count(info, number) do set_note_count(info, info.note_count + number) end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 783491b67..aa20990f3 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -703,6 +703,7 @@ def fetch_activities_query(recipients, opts \\ %{}) do |> restrict_replies(opts) |> restrict_reblogs(opts) |> restrict_pinned(opts) + |> Activity.restrict_disabled_users() end def fetch_activities(recipients, opts \\ %{}) do diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index aae02cab8..1b94f0609 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -44,6 +44,16 @@ def user_create( |> json(user.nickname) end + def user_toggle_disabled(conn, %{"nickname" => nickname}) do + user = User.get_by_nickname(nickname) + + {:ok, updated_user} = User.disable(user, !user.info.disabled) + + conn + |> put_view(AccountView) + |> render("show.json", %{user: updated_user}) + end + def user_toggle_activation(conn, %{"nickname" => nickname}) do user = User.get_by_nickname(nickname) diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index e4b9102c5..60d1185d3 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -17,7 +17,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do # This is a hack for twidere. def get_by_id_or_ap_id(id) do - activity = Repo.get(Activity, id) || Activity.get_create_by_object_ap_id(id) + activity = Activity.get_by_id(id) || Activity.get_create_by_object_ap_id(id) activity && if activity.data["type"] == "Create" do @@ -30,7 +30,7 @@ def get_by_id_or_ap_id(id) do def get_replied_to_activity(""), do: nil def get_replied_to_activity(id) when not is_nil(id) do - Repo.get(Activity, id) + Activity.get_by_id(id) end def get_replied_to_activity(_), do: nil diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 056be49b0..00a0f1351 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -307,7 +307,7 @@ def dm_timeline(%{assigns: %{user: user}} = conn, params) do end def get_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do - with %Activity{} = activity <- Repo.get(Activity, id), + with %Activity{} = activity <- Activity.get_by_id(id), true <- Visibility.visible_for_user?(activity, user) do conn |> put_view(StatusView) @@ -316,7 +316,7 @@ def get_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do end def get_context(%{assigns: %{user: user}} = conn, %{"id" => id}) do - with %Activity{} = activity <- Repo.get(Activity, id), + with %Activity{} = activity <- Activity.get_by_id(id), activities <- ActivityPub.fetch_activities_for_context(activity.data["context"], %{ "blocking_user" => user, @@ -448,7 +448,7 @@ def unpin_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do end def bookmark_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do - with %Activity{} = activity <- Repo.get(Activity, id), + with %Activity{} = activity <- Activity.get_by_id(id), %User{} = user <- User.get_by_nickname(user.nickname), true <- Visibility.visible_for_user?(activity, user), {:ok, user} <- User.bookmark(user, activity.data["object"]["id"]) do @@ -459,7 +459,7 @@ def bookmark_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do end def unbookmark_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do - with %Activity{} = activity <- Repo.get(Activity, id), + with %Activity{} = activity <- Activity.get_by_id(id), %User{} = user <- User.get_by_nickname(user.nickname), true <- Visibility.visible_for_user?(activity, user), {:ok, user} <- User.unbookmark(user, activity.data["object"]["id"]) do @@ -583,7 +583,7 @@ def upload(%{assigns: %{user: user}} = conn, %{"file" => file} = data) do end def favourited_by(conn, %{"id" => id}) do - with %Activity{data: %{"object" => %{"likes" => likes}}} <- Repo.get(Activity, id) do + with %Activity{data: %{"object" => %{"likes" => likes}}} <- Activity.get_by_id(id) do q = from(u in User, where: u.ap_id in ^likes) users = Repo.all(q) @@ -596,7 +596,7 @@ def favourited_by(conn, %{"id" => id}) do end def reblogged_by(conn, %{"id" => id}) do - with %Activity{data: %{"object" => %{"announcements" => announces}}} <- Repo.get(Activity, id) do + with %Activity{data: %{"object" => %{"announcements" => announces}}} <- Activity.get_by_id(id) do q = from(u in User, where: u.ap_id in ^announces) users = Repo.all(q) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 6fcb46878..5033b5446 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -143,6 +143,7 @@ defmodule Pleroma.Web.Router do get("/users/search", AdminAPIController, :search_users) delete("/user", AdminAPIController, :user_delete) patch("/users/:nickname/toggle_activation", AdminAPIController, :user_toggle_activation) + patch("/users/:nickname/toggle_disabled", AdminAPIController, :user_toggle_disabled) post("/user", AdminAPIController, :user_create) put("/users/tag", AdminAPIController, :tag_users) delete("/users/tag", AdminAPIController, :untag_users) @@ -183,6 +184,7 @@ defmodule Pleroma.Web.Router do post("/change_password", UtilController, :change_password) post("/delete_account", UtilController, :delete_account) + post("/disable_account", UtilController, :disable_account) end scope [] do diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index e2fdedb25..0006d53e8 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -311,6 +311,17 @@ def delete_account(%{assigns: %{user: user}} = conn, params) do end end + def disable_account(%{assigns: %{user: user}} = conn, params) do + case CommonAPI.Utils.confirm_current_password(user, params["password"]) do + {:ok, user} -> + User.disable_async(user) + json(conn, %{status: "success"}) + + {:error, msg} -> + json(conn, %{error: msg}) + end + end + def captcha(conn, _params) do json(conn, Pleroma.Captcha.new()) end diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex index ab6470d78..615a34be9 100644 --- a/lib/pleroma/web/twitter_api/twitter_api.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -21,7 +21,7 @@ def create_status(%User{} = user, %{"status" => _} = data) do end def delete(%User{} = user, id) do - with %Activity{data: %{"type" => _type}} <- Repo.get(Activity, id), + with %Activity{data: %{"type" => _type}} <- Activity.get_by_id(id), {:ok, activity} <- CommonAPI.delete(id, user) do {:ok, activity} end @@ -232,21 +232,27 @@ def password_reset(nickname_or_email) do def get_user(user \\ nil, params) do case params do %{"user_id" => user_id} -> - case target = User.get_cached_by_nickname_or_id(user_id) do + case User.get_cached_by_nickname_or_id(user_id) do nil -> {:error, "No user with such user_id"} - _ -> - {:ok, target} + %User{info: %{disabled: true}} -> + {:error, "User has been disabled"} + + user -> + {:ok, user} end %{"screen_name" => nickname} -> - case target = Repo.get_by(User, nickname: nickname) do + case User.get_by_nickname(nickname) do nil -> {:error, "No user with such screen_name"} - _ -> - {:ok, target} + %User{info: %{disabled: true}} -> + {:error, "User has been disabled"} + + user -> + {:ok, user} end _ -> diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex index de7b9f24c..0769f8698 100644 --- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex +++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex @@ -269,7 +269,7 @@ def unfollow(%{assigns: %{user: user}} = conn, params) do end def fetch_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do - with %Activity{} = activity <- Repo.get(Activity, id), + with %Activity{} = activity <- Activity.get_by_id(id), true <- Visibility.visible_for_user?(activity, user) do conn |> put_view(ActivityView) @@ -341,7 +341,7 @@ def upload_json(%{assigns: %{user: user}} = conn, %{"media" => media}) do end def get_by_id_or_ap_id(id) do - activity = Repo.get(Activity, id) || Activity.get_create_by_object_ap_id(id) + activity = Activity.get_by_id(id) || Activity.get_create_by_object_ap_id(id) if activity.data["type"] == "Create" do activity diff --git a/priv/repo/migrations/20190228121252_users_add_disabled_index.exs b/priv/repo/migrations/20190228121252_users_add_disabled_index.exs new file mode 100644 index 000000000..7b921d3e7 --- /dev/null +++ b/priv/repo/migrations/20190228121252_users_add_disabled_index.exs @@ -0,0 +1,7 @@ +defmodule Pleroma.Repo.Migrations.UsersAddDisabledIndex do + use Ecto.Migration + + def change do + create(index(:users, ["(info->'disabled')"], name: :users_disabled_index, using: :gin)) + end +end From db4badc6aa71df4cb9372ef4aff699399516ffb2 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Thu, 11 Apr 2019 17:22:42 +0700 Subject: [PATCH 02/18] move user disable into deactivation --- lib/mix/tasks/pleroma/user.ex | 18 ------- lib/pleroma/activity.ex | 8 +-- lib/pleroma/notification.ex | 2 +- lib/pleroma/user.ex | 51 ++++++++----------- lib/pleroma/user/info.ex | 9 ---- lib/pleroma/web/activity_pub/activity_pub.ex | 2 +- .../web/admin_api/admin_api_controller.ex | 10 ---- lib/pleroma/web/router.ex | 1 - .../controllers/util_controller.ex | 2 +- lib/pleroma/web/twitter_api/twitter_api.ex | 2 +- ...0190228121252_users_add_disabled_index.exs | 7 --- ...120_add_index_on_user_info_deactivated.exs | 7 +++ 12 files changed, 36 insertions(+), 83 deletions(-) delete mode 100644 priv/repo/migrations/20190228121252_users_add_disabled_index.exs create mode 100644 priv/repo/migrations/20190411094120_add_index_on_user_info_deactivated.exs diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index 78493231c..441168df2 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -53,10 +53,6 @@ defmodule Mix.Tasks.Pleroma.User do mix pleroma.user toggle_activated NICKNAME - ## Disable or enable the user's account. - - mix pleroma.user toggle_disabled NICKNAME - ## Unsubscribe local users from user's account and deactivate it mix pleroma.user unsubscribe NICKNAME @@ -190,20 +186,6 @@ def run(["toggle_activated", nickname]) do end end - def run(["toggle_disabled", nickname]) do - Common.start_pleroma() - - case User.get_by_nickname(nickname) do - %User{} = user -> - {:ok, user} = User.disable(user, !user.info.disabled) - status = if(user.info.disabled, do: "ON", else: "OFF") - Mix.shell().info("Disabled status of #{nickname}: #{status}") - - _ -> - Mix.shell().error("No user #{nickname}") - end - end - def run(["reset_password", nickname]) do Common.start_pleroma() diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index c8c7f0d04..d06fd917d 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -100,7 +100,7 @@ def get_by_ap_id_with_object(ap_id) do def get_by_id(id) do Activity |> where([a], a.id == ^id) - |> restrict_disabled_users() + |> restrict_deactivated_users() |> Repo.one() end @@ -169,7 +169,7 @@ def get_all_create_by_object_ap_id(ap_id) do def get_create_by_object_ap_id(ap_id) when is_binary(ap_id) do create_by_object_ap_id(ap_id) - |> restrict_disabled_users() + |> restrict_deactivated_users() |> Repo.one() end @@ -296,11 +296,11 @@ def decrease_replies_count(id) do end end - def restrict_disabled_users(query) do + def restrict_deactivated_users(query) do from(activity in query, where: fragment( - "? not in (SELECT ap_id FROM users WHERE info->'disabled' @> 'true')", + "? not in (SELECT ap_id FROM users WHERE info->'deactivated' @> 'true')", activity.actor ) ) diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index 7de2d4c18..941218eea 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -36,7 +36,7 @@ def for_user_query(user) do |> where( [n, a], fragment( - "? not in (SELECT ap_id FROM users WHERE info->'disabled' @> 'true')", + "? not in (SELECT ap_id FROM users WHERE info->'deactivated' @> 'true')", a.actor ) ) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 1f2aca235..c08d3a171 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -117,9 +117,9 @@ def user_info(%User{} = user) do } end - defp restrict_disabled(query) do + defp restrict_deactivated(query) do from(u in query, - where: not fragment("? \\? 'disabled' AND ?->'disabled' @> 'true'", u.info, u.info) + where: not fragment("? \\? 'deactivated' AND ?->'deactivated' @> 'true'", u.info, u.info) ) end @@ -130,7 +130,7 @@ def following_count(%User{following: following, id: id}) do where: u.follower_address in ^following, where: u.id != ^id ) - |> restrict_disabled() + |> restrict_deactivated() |> Repo.aggregate(:count, :id) end @@ -584,7 +584,7 @@ def get_followers_query(%User{id: id, follower_address: follower_address}, nil) where: fragment("? <@ ?", ^[follower_address], u.following), where: u.id != ^id ) - |> restrict_disabled() + |> restrict_deactivated() end def get_followers_query(user, page) do @@ -612,7 +612,7 @@ def get_friends_query(%User{id: id, following: following}, nil) do where: u.follower_address in ^following, where: u.id != ^id ) - |> restrict_disabled() + |> restrict_deactivated() end def get_friends_query(user, page) do @@ -736,7 +736,7 @@ def update_follower_count(%User{} = user) do |> where([u], ^user.follower_address in u.following) |> where([u], u.id != ^user.id) |> select([u], %{count: count(u.id)}) - |> restrict_disabled() + |> restrict_deactivated() User |> where(id: ^user.id) @@ -887,7 +887,7 @@ defp fts_search_subquery(term, query \\ User) do ^processed_query ) ) - |> restrict_disabled() + |> restrict_deactivated() end defp trigram_search_subquery(term) do @@ -906,7 +906,7 @@ defp trigram_search_subquery(term) do }, where: fragment("trim(? || ' ' || coalesce(?, '')) % ?", u.nickname, u.name, ^term) ) - |> restrict_disabled() + |> restrict_deactivated() end def blocks_import(%User{} = blocker, blocked_identifiers) when is_list(blocked_identifiers) do @@ -1150,13 +1150,24 @@ def moderator_user_query do ) end + + def deactivate_async(user, status \\ true) do + PleromaJobQueue.enqueue(:user, __MODULE__, [:deactivate_async, user, status]) + end + + def perform(:deactivate_async, user, status), do: deactivate(user, status) + def deactivate(%User{} = user, status \\ true) do info_cng = User.Info.set_activation_status(user.info, status) - user + with {:ok, user} <- user |> change() |> put_embed(:info, info_cng) - |> update_and_set_cache() + |> update_and_set_cache(), + {:ok, friends} <- User.get_friends(user) do + Enum.each(friends, &update_follower_count(&1)) + {:ok, user} + end end def update_notification_settings(%User{} = user, settings \\ %{}) do @@ -1199,26 +1210,6 @@ def delete_user_activities(%User{ap_id: ap_id} = user) do {:ok, user} end - def disable_async(user, status \\ true) do - PleromaJobQueue.enqueue(:user, __MODULE__, [:disable_async, user, status]) - end - - def disable(%User{} = user, status \\ true) do - with {:ok, user} <- User.deactivate(user, status), - info_cng <- User.Info.set_disabled_status(user.info, status), - {:ok, user} <- - user - |> change() - |> put_embed(:info, info_cng) - |> update_and_set_cache(), - {:ok, friends} <- User.get_friends(user) do - Enum.each(friends, &update_follower_count(&1)) - {:ok, user} - end - end - - def perform(:disable_async, user, status), do: disable(user, status) - def html_filter_policy(%User{info: %{no_rich_text: true}}) do Pleroma.HTML.Scrubber.TwitterText end diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index 07825a1c4..5afa7988c 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -40,7 +40,6 @@ defmodule Pleroma.User.Info do field(:hide_follows, :boolean, default: false) field(:pinned_activities, {:array, :string}, default: []) field(:flavour, :string, default: nil) - field(:disabled, :boolean, default: false) field(:notification_settings, :map, default: %{"remote" => true, "local" => true, "followers" => true, "follows" => true} @@ -76,14 +75,6 @@ def update_notification_settings(info, settings) do |> validate_required([:notification_settings]) end - def set_disabled_status(info, disabled) do - params = %{disabled: disabled} - - info - |> cast(params, [:disabled]) - |> validate_required([:disabled]) - end - def add_to_note_count(info, number) do set_note_count(info, info.note_count + number) end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index dd51d63c8..e749a80aa 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -804,7 +804,7 @@ def fetch_activities_query(recipients, opts \\ %{}) do |> restrict_reblogs(opts) |> restrict_pinned(opts) |> restrict_muted_reblogs(opts) - |> Activity.restrict_disabled_users() + |> Activity.restrict_deactivated_users() end def fetch_activities(recipients, opts \\ %{}) do diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index fb43d0b01..70a5b5c5d 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -75,16 +75,6 @@ def user_show(conn, %{"nickname" => nickname}) do end end - def user_toggle_disabled(conn, %{"nickname" => nickname}) do - user = User.get_by_nickname(nickname) - - {:ok, updated_user} = User.disable(user, !user.info.disabled) - - conn - |> put_view(AccountView) - |> render("show.json", %{user: updated_user}) - end - def user_toggle_activation(conn, %{"nickname" => nickname}) do user = User.get_by_nickname(nickname) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index dd23d7fd5..c331098b4 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -153,7 +153,6 @@ defmodule Pleroma.Web.Router do delete("/user", AdminAPIController, :user_delete) patch("/users/:nickname/toggle_activation", AdminAPIController, :user_toggle_activation) - patch("/users/:nickname/toggle_disabled", AdminAPIController, :user_toggle_disabled) post("/user", AdminAPIController, :user_create) put("/users/tag", AdminAPIController, :tag_users) delete("/users/tag", AdminAPIController, :untag_users) diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index 317f2b0ff..44f4b183b 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -358,7 +358,7 @@ def delete_account(%{assigns: %{user: user}} = conn, params) do def disable_account(%{assigns: %{user: user}} = conn, params) do case CommonAPI.Utils.confirm_current_password(user, params["password"]) do {:ok, user} -> - User.disable_async(user) + User.deactivate_async(user) json(conn, %{status: "success"}) {:error, msg} -> diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex index 156f5d40f..bf1051afd 100644 --- a/lib/pleroma/web/twitter_api/twitter_api.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -235,7 +235,7 @@ def get_user(user \\ nil, params) do nil -> {:error, "No user with such user_id"} - %User{info: %{disabled: true}} -> + %User{info: %{deactivated: true}} -> {:error, "User has been disabled"} user -> diff --git a/priv/repo/migrations/20190228121252_users_add_disabled_index.exs b/priv/repo/migrations/20190228121252_users_add_disabled_index.exs deleted file mode 100644 index 7b921d3e7..000000000 --- a/priv/repo/migrations/20190228121252_users_add_disabled_index.exs +++ /dev/null @@ -1,7 +0,0 @@ -defmodule Pleroma.Repo.Migrations.UsersAddDisabledIndex do - use Ecto.Migration - - def change do - create(index(:users, ["(info->'disabled')"], name: :users_disabled_index, using: :gin)) - end -end diff --git a/priv/repo/migrations/20190411094120_add_index_on_user_info_deactivated.exs b/priv/repo/migrations/20190411094120_add_index_on_user_info_deactivated.exs new file mode 100644 index 000000000..d701dcecc --- /dev/null +++ b/priv/repo/migrations/20190411094120_add_index_on_user_info_deactivated.exs @@ -0,0 +1,7 @@ +defmodule Pleroma.Repo.Migrations.AddIndexOnUserInfoDeactivated do + use Ecto.Migration + + def change do + create(index(:users, ["(info->'deactivated')"], name: :users_deactivated_index, using: :gin)) + end +end From 46bd5c1d875934370621375957fa33a10e2d3507 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Thu, 11 Apr 2019 17:28:12 +0700 Subject: [PATCH 03/18] fix format --- lib/pleroma/user.ex | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index c08d3a171..a8e902bf3 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1150,7 +1150,6 @@ def moderator_user_query do ) end - def deactivate_async(user, status \\ true) do PleromaJobQueue.enqueue(:user, __MODULE__, [:deactivate_async, user, status]) end @@ -1160,11 +1159,12 @@ def perform(:deactivate_async, user, status), do: deactivate(user, status) def deactivate(%User{} = user, status \\ true) do info_cng = User.Info.set_activation_status(user.info, status) - with {:ok, user} <- user - |> change() - |> put_embed(:info, info_cng) - |> update_and_set_cache(), - {:ok, friends} <- User.get_friends(user) do + with {:ok, user} <- + user + |> change() + |> put_embed(:info, info_cng) + |> update_and_set_cache(), + {:ok, friends} <- User.get_friends(user) do Enum.each(friends, &update_follower_count(&1)) {:ok, user} end From dd097a406baf15e983454ab8f13635b4af2a8de4 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Fri, 12 Apr 2019 16:38:32 +0700 Subject: [PATCH 04/18] add tests --- lib/pleroma/user.ex | 9 ++++-- test/user_test.exs | 78 +++++++++++++++++++++++++++++++++++++++------ 2 files changed, 75 insertions(+), 12 deletions(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index a8e902bf3..95f5c6d21 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1159,13 +1159,16 @@ def perform(:deactivate_async, user, status), do: deactivate(user, status) def deactivate(%User{} = user, status \\ true) do info_cng = User.Info.set_activation_status(user.info, status) - with {:ok, user} <- + with {:ok, friends} <- User.get_friends(user), + {:ok, followers} <- User.get_followers(user), + {:ok, user} <- user |> change() |> put_embed(:info, info_cng) - |> update_and_set_cache(), - {:ok, friends} <- User.get_friends(user) do + |> update_and_set_cache() do + Enum.each(followers, &invalidate_cache(&1)) Enum.each(friends, &update_follower_count(&1)) + {:ok, user} end end diff --git a/test/user_test.exs b/test/user_test.exs index d2167a970..ac1675d0f 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -5,8 +5,10 @@ defmodule Pleroma.UserTest do alias Pleroma.Activity alias Pleroma.Builders.UserBuilder + alias Pleroma.Notification alias Pleroma.Repo alias Pleroma.User + alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.CommonAPI use Pleroma.DataCase @@ -212,8 +214,8 @@ test "test if a user is following another user" do test "fetches correct profile for nickname beginning with number" do # Use old-style integer ID to try to reproduce the problem user = insert(:user, %{id: 1080}) - userwithnumbers = insert(:user, %{nickname: "#{user.id}garbage"}) - assert userwithnumbers == User.get_cached_by_nickname_or_id(userwithnumbers.nickname) + user_with_numbers = insert(:user, %{nickname: "#{user.id}garbage"}) + assert user_with_numbers == User.get_cached_by_nickname_or_id(user_with_numbers.nickname) end describe "user registration" do @@ -815,13 +817,71 @@ test "get recipients from activity" do assert addressed in recipients end - test ".deactivate can de-activate then re-activate a user" do - user = insert(:user) - assert false == user.info.deactivated - {:ok, user} = User.deactivate(user) - assert true == user.info.deactivated - {:ok, user} = User.deactivate(user, false) - assert false == user.info.deactivated + describe ".deactivate" do + test "can de-activate then re-activate a user" do + user = insert(:user) + assert false == user.info.deactivated + {:ok, user} = User.deactivate(user) + assert true == user.info.deactivated + {:ok, user} = User.deactivate(user, false) + assert false == user.info.deactivated + end + + test "hide a user from followers " do + user = insert(:user) + user2 = insert(:user) + + {:ok, user} = User.follow(user, user2) + {:ok, _user} = User.deactivate(user) + + info = User.get_cached_user_info(user2) + + assert info.follower_count == 0 + assert {:ok, []} = User.get_followers(user2) + end + + test "hide a user from friends" do + user = insert(:user) + user2 = insert(:user) + + {:ok, user2} = User.follow(user2, user) + assert User.following_count(user2) == 1 + + {:ok, _user} = User.deactivate(user) + + info = User.get_cached_user_info(user2) + + assert info.following_count == 0 + assert User.following_count(user2) == 0 + assert {:ok, []} = User.get_friends(user2) + end + + test "hide a user's statuses from timelines and notifications" do + user = insert(:user) + user2 = insert(:user) + + {:ok, user2} = User.follow(user2, user) + + {:ok, activity} = CommonAPI.post(user, %{"status" => "hey @#{user2.nickname}"}) + + [notification] = Notification.for_user(user2) + assert notification.activity == activity + + assert [activity] == ActivityPub.fetch_public_activities(%{}) + + assert [activity] == + ActivityPub.fetch_activities([user2.ap_id | user2.following], %{"user" => user2}) + |> ActivityPub.contain_timeline(user2) + + {:ok, _user} = User.deactivate(user) + + assert [] == ActivityPub.fetch_public_activities(%{}) + assert [] == Notification.for_user(user2) + + assert [] == + ActivityPub.fetch_activities([user2.ap_id | user2.following], %{"user" => user2}) + |> ActivityPub.contain_timeline(user2) + end end test ".delete_user_activities deletes all create activities" do From d0304b4f925ac9b3b57f294ef091b96b071e97b9 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Fri, 12 Apr 2019 16:51:28 +0700 Subject: [PATCH 05/18] more tests --- test/web/twitter_api/util_controller_test.exs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/web/twitter_api/util_controller_test.exs b/test/web/twitter_api/util_controller_test.exs index a4b3d651a..66d89eee0 100644 --- a/test/web/twitter_api/util_controller_test.exs +++ b/test/web/twitter_api/util_controller_test.exs @@ -230,4 +230,22 @@ test "show follow account page if the `acct` is a account link", %{conn: conn} d assert html_response(response, 200) =~ "Log in to follow" end end + + describe "POST /api/pleroma/disable_account" do + test "it returns HTTP 200", %{conn: conn} do + user = insert(:user) + + response = + conn + |> assign(:user, user) + |> post("/api/pleroma/disable_account", %{"password" => "test"}) + |> json_response(:ok) + + assert response == %{"status" => "success"} + + user = User.get_cached_by_id(user.id) + + assert user.info.deactivated == true + end + end end From 38926a063a39c4d4387049f5d364f72a9f8bd2de Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Mon, 15 Apr 2019 16:39:42 +0700 Subject: [PATCH 06/18] add `/api/pleroma/disable_account` to `docs/api/pleroma_api.md` --- docs/api/pleroma_api.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/api/pleroma_api.md b/docs/api/pleroma_api.md index dbe250300..b9622f586 100644 --- a/docs/api/pleroma_api.md +++ b/docs/api/pleroma_api.md @@ -61,6 +61,15 @@ Request parameters can be passed via [query strings](https://en.wikipedia.org/wi * Response: JSON. Returns `{"status": "success"}` if the deletion was successful, `{"error": "[error message]"}` otherwise * Example response: `{"error": "Invalid password."}` +## `/api/pleroma/disable_account` +### Disable an account +* Method `POST` +* Authentication: required +* Params: + * `password`: user's password +* Response: JSON. Returns `{"status": "success"}` if the account was successfully disabled, `{"error": "[error message]"}` otherwise +* Example response: `{"error": "Invalid password."}` + ## `/api/account/register` ### Register a new user * Method `POST` From 32d4630c9ca1c89e655b37b3b939d728f569dc9f Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Mon, 13 May 2019 01:58:30 +0000 Subject: [PATCH 07/18] user: move initial post fetching to job queue --- lib/pleroma/user.ex | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 474de9ba5..a79da4dd8 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -552,8 +552,7 @@ def get_or_fetch_by_nickname(nickname) do with [_nick, _domain] <- String.split(nickname, "@"), {:ok, user} <- fetch_by_nickname(nickname) do if Pleroma.Config.get([:fetch_initial_posts, :enabled]) do - # TODO turn into job - {:ok, _} = Task.start(__MODULE__, :fetch_initial_posts, [user]) + fetch_initial_posts(user) end {:ok, user} @@ -564,15 +563,8 @@ def get_or_fetch_by_nickname(nickname) do end @doc "Fetch some posts when the user has just been federated with" - def fetch_initial_posts(user) do - pages = Pleroma.Config.get!([:fetch_initial_posts, :pages]) - - Enum.each( - # Insert all the posts in reverse order, so they're in the right order on the timeline - Enum.reverse(Utils.fetch_ordered_collection(user.info.source_data["outbox"], pages)), - &Pleroma.Web.Federator.incoming_ap_doc/1 - ) - end + def fetch_initial_posts(user), + do: PleromaJobQueue.enqueue(:background, __MODULE__, [:fetch_initial_posts, user]) @spec get_followers_query(User.t(), pos_integer() | nil) :: Ecto.Query.t() def get_followers_query(%User{} = user, nil) do @@ -1077,6 +1069,19 @@ def perform(:delete, %User{} = user) do delete_user_activities(user) end + @spec perform(atom(), User.t()) :: {:ok, User.t()} + def perform(:fetch_initial_posts, %User{} = user) do + pages = Pleroma.Config.get!([:fetch_initial_posts, :pages]) + + Enum.each( + # Insert all the posts in reverse order, so they're in the right order on the timeline + Enum.reverse(Utils.fetch_ordered_collection(user.info.source_data["outbox"], pages)), + &Pleroma.Web.Federator.incoming_ap_doc/1 + ) + + {:ok, user} + end + def delete_user_activities(%User{ap_id: ap_id} = user) do stream = ap_id @@ -1130,8 +1135,8 @@ def get_or_fetch_by_ap_id(ap_id) do resp = fetch_by_ap_id(ap_id) if should_fetch_initial do - with {:ok, %User{} = user} = resp do - {:ok, _} = Task.start(__MODULE__, :fetch_initial_posts, [user]) + with {:ok, %User{} = user} <- resp do + fetch_initial_posts(user) end end From 57d11ac9dbe4f3befd288cb0f59f368968474f93 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Mon, 13 May 2019 02:02:00 +0000 Subject: [PATCH 08/18] activitypub: move post rich media fetching to job queue --- lib/pleroma/web/activity_pub/activity_pub.ex | 4 +--- lib/pleroma/web/rich_media/helpers.ex | 2 ++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 11777c220..d7c0ab4d3 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -133,9 +133,7 @@ def insert(map, local \\ true, fake \\ false) when is_map(map) do activity end - Task.start(fn -> - Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity) - end) + PleromaJobQueue.enqueue(:background, Pleroma.Web.RichMedia.Helpers, [:fetch, activity]) Notification.create_notifications(activity) diff --git a/lib/pleroma/web/rich_media/helpers.ex b/lib/pleroma/web/rich_media/helpers.ex index f67aaf58b..0162a5be9 100644 --- a/lib/pleroma/web/rich_media/helpers.ex +++ b/lib/pleroma/web/rich_media/helpers.ex @@ -34,4 +34,6 @@ def fetch_data_for_activity(%Activity{data: %{"type" => "Create"}} = activity) d end def fetch_data_for_activity(_), do: %{} + + def perform(:fetch, %Activity{} = activity), do: fetch_data_for_activity(activity) end From 69a9e0563cc441a772c4884d747bb755ddf58c45 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Mon, 13 May 2019 02:09:28 +0000 Subject: [PATCH 09/18] user: migrate follow/blocks import to job queue --- lib/pleroma/user.ex | 73 ++++++++++--------- .../controllers/util_controller.ex | 14 +++- 2 files changed, 50 insertions(+), 37 deletions(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index a79da4dd8..c94660de4 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -413,24 +413,6 @@ def following?(%User{} = follower, %User{} = followed) do Enum.member?(follower.following, followed.follower_address) end - def follow_import(%User{} = follower, followed_identifiers) - when is_list(followed_identifiers) do - Enum.map( - followed_identifiers, - fn followed_identifier -> - with {:ok, %User{} = followed} <- get_or_fetch(followed_identifier), - {:ok, follower} <- maybe_direct_follow(follower, followed), - {:ok, _} <- ActivityPub.follow(follower, followed) do - followed - else - err -> - Logger.debug("follow_import failed for #{followed_identifier} with: #{inspect(err)}") - err - end - end - ) - end - def locked?(%User{} = user) do user.info.locked || false end @@ -844,23 +826,6 @@ defp trigram_search_subquery(term) do ) end - def blocks_import(%User{} = blocker, blocked_identifiers) when is_list(blocked_identifiers) do - Enum.map( - blocked_identifiers, - fn blocked_identifier -> - with {:ok, %User{} = blocked} <- get_or_fetch(blocked_identifier), - {:ok, blocker} <- block(blocker, blocked), - {:ok, _} <- ActivityPub.block(blocker, blocked) do - blocked - else - err -> - Logger.debug("blocks_import failed for #{blocked_identifier} with: #{inspect(err)}") - err - end - end - ) - end - def mute(muter, %User{ap_id: ap_id}) do info_cng = muter.info @@ -1082,6 +1047,44 @@ def perform(:fetch_initial_posts, %User{} = user) do {:ok, user} end + @spec perform(atom(), User.t(), list()) :: list() | {:error, any()} + def perform(:blocks_import, %User{} = blocker, blocked_identifiers) + when is_list(blocked_identifiers) do + Enum.map( + blocked_identifiers, + fn blocked_identifier -> + with {:ok, %User{} = blocked} <- get_or_fetch(blocked_identifier), + {:ok, blocker} <- block(blocker, blocked), + {:ok, _} <- ActivityPub.block(blocker, blocked) do + blocked + else + err -> + Logger.debug("blocks_import failed for #{blocked_identifier} with: #{inspect(err)}") + err + end + end + ) + end + + @spec perform(atom(), User.t(), list()) :: list() | {:error, any()} + def perform(:follow_import, %User{} = follower, followed_identifiers) + when is_list(followed_identifiers) do + Enum.map( + followed_identifiers, + fn followed_identifier -> + with {:ok, %User{} = followed} <- get_or_fetch(followed_identifier), + {:ok, follower} <- maybe_direct_follow(follower, followed), + {:ok, _} <- ActivityPub.follow(follower, followed) do + followed + else + err -> + Logger.debug("follow_import failed for #{followed_identifier} with: #{inspect(err)}") + err + end + end + ) + end + def delete_user_activities(%User{ap_id: ap_id} = user) do stream = ap_id diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index c03f8ab3a..143960206 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -310,7 +310,12 @@ def follow_import(%{assigns: %{user: follower}} = conn, %{"list" => list}) do String.split(line, ",") |> List.first() end) |> List.delete("Account address"), - {:ok, _} = Task.start(fn -> User.follow_import(follower, followed_identifiers) end) do + :ok <- + PleromaJobQueue.enqueue(:background, User, [ + :follow_import, + follower, + followed_identifiers + ]) do json(conn, "job started") end end @@ -321,7 +326,12 @@ def blocks_import(conn, %{"list" => %Plug.Upload{} = listfile}) do def blocks_import(%{assigns: %{user: blocker}} = conn, %{"list" => list}) do with blocked_identifiers <- String.split(list), - {:ok, _} = Task.start(fn -> User.blocks_import(blocker, blocked_identifiers) end) do + :ok <- + PleromaJobQueue.enqueue(:background, User, [ + :blocks_import, + blocker, + blocked_identifiers + ]) do json(conn, "job started") end end From a18b2c0b12b413c9a8d0aa0d4fd3b15e0e843cdf Mon Sep 17 00:00:00 2001 From: Aaron Tinio Date: Tue, 14 May 2019 06:40:59 +0800 Subject: [PATCH 10/18] Fix Pleroma.Config.get!/1 raising an error when value is false --- lib/pleroma/config.ex | 8 ++++++-- test/config_test.exs | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/lib/pleroma/config.ex b/lib/pleroma/config.ex index 189faa15f..71a47b9fb 100644 --- a/lib/pleroma/config.ex +++ b/lib/pleroma/config.ex @@ -12,8 +12,12 @@ def get(key), do: get(key, nil) def get([key], default), do: get(key, default) def get([parent_key | keys], default) do - Application.get_env(:pleroma, parent_key) - |> get_in(keys) || default + case :pleroma + |> Application.get_env(parent_key) + |> get_in(keys) do + nil -> default + any -> any + end end def get(key, default) do diff --git a/test/config_test.exs b/test/config_test.exs index 0a6f0395a..73f3fcb0a 100644 --- a/test/config_test.exs +++ b/test/config_test.exs @@ -28,6 +28,15 @@ test "get/1 with a list of keys" do assert Pleroma.Config.get([:azerty, :uiop], true) == true end + test "get/1 when value is false" do + Pleroma.Config.put([:instance, :false_test], false) + Pleroma.Config.put([:instance, :nested], []) + Pleroma.Config.put([:instance, :nested, :false_test], false) + + assert Pleroma.Config.get([:instance, :false_test]) == false + assert Pleroma.Config.get([:instance, :nested, :false_test]) == false + end + test "get!/1" do assert Pleroma.Config.get!(:instance) == Application.get_env(:pleroma, :instance) @@ -43,6 +52,15 @@ test "get!/1" do end) end + test "get!/1 when value is false" do + Pleroma.Config.put([:instance, :false_test], false) + Pleroma.Config.put([:instance, :nested], []) + Pleroma.Config.put([:instance, :nested, :false_test], false) + + assert Pleroma.Config.get!([:instance, :false_test]) == false + assert Pleroma.Config.get!([:instance, :nested, :false_test]) == false + end + test "put/2 with a key" do Pleroma.Config.put(:config_test, true) From b92c004ea8a9ecd066b8eddf755a07a175338416 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Tue, 14 May 2019 18:29:10 +0700 Subject: [PATCH 11/18] Reuse query from User.restrict_deactivated/1 --- lib/pleroma/user.ex | 2 +- lib/pleroma/user/query.ex | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index cf378d467..3eb684c3a 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -115,7 +115,7 @@ def user_info(%User{} = user) do } end - defp restrict_deactivated(query) do + def restrict_deactivated(query) do from(u in query, where: not fragment("? \\? 'deactivated' AND ?->'deactivated' @> 'true'", u.info, u.info) ) diff --git a/lib/pleroma/user/query.ex b/lib/pleroma/user/query.ex index 3873ef80c..ace9c05f2 100644 --- a/lib/pleroma/user/query.ex +++ b/lib/pleroma/user/query.ex @@ -119,9 +119,7 @@ defp compose_query({:active, _}, query) do end defp compose_query({:deactivated, false}, query) do - from(u in query, - where: not fragment("? \\? 'deactivated' AND ?->'deactivated' @> 'true'", u.info, u.info) - ) + User.restrict_deactivated(query) end defp compose_query({:deactivated, true}, query) do From c1665fd94de456768ddd59b8873d1bd26878970d Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Tue, 14 May 2019 18:40:21 +0700 Subject: [PATCH 12/18] Update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c0baa317..17e913648 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -64,6 +64,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Deps: Updated Ecto to 3.0.7 - Don't ship finmoji by default, they can be installed as an emoji pack - Admin API: Move the user related API to `api/pleroma/admin/users` +- Hide deactivated users and their statuses ### Fixed - Added an FTS index on objects. Running `vacuum analyze` and setting a larger `work_mem` is recommended. From 52297920e74ad7f51bcd3b118522e5e3a8e1c794 Mon Sep 17 00:00:00 2001 From: Maksim Date: Tue, 14 May 2019 14:49:45 +0000 Subject: [PATCH 13/18] Refactoring oauth response. --- lib/pleroma/web/oauth/oauth_controller.ex | 77 ++++------------------- lib/pleroma/web/oauth/token/response.ex | 32 ++++++++++ lib/pleroma/web/oauth/token/utils.ex | 38 +++++++++++ test/web/oauth/token/utils_test.exs | 53 ++++++++++++++++ 4 files changed, 136 insertions(+), 64 deletions(-) create mode 100644 lib/pleroma/web/oauth/token/response.ex create mode 100644 test/web/oauth/token/utils_test.exs diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex index 4ee8339e2..ae2b80d95 100644 --- a/lib/pleroma/web/oauth/oauth_controller.ex +++ b/lib/pleroma/web/oauth/oauth_controller.ex @@ -19,8 +19,6 @@ defmodule Pleroma.Web.OAuth.OAuthController do if Pleroma.Config.oauth_consumer_enabled?(), do: plug(Ueberauth) - @expires_in Pleroma.Config.get([:oauth2, :token_expires_in], 600) - plug(:fetch_session) plug(:fetch_flash) @@ -144,14 +142,14 @@ defp handle_create_authorization_error(conn, error, %{"authorization" => _}) do @doc "Renew access_token with refresh_token" def token_exchange( conn, - %{"grant_type" => "refresh_token", "refresh_token" => token} = params + %{"grant_type" => "refresh_token", "refresh_token" => token} = _params ) do - with %App{} = app <- get_app_from_request(conn, params), + with {:ok, app} <- Token.Utils.fetch_app(conn), {:ok, %{user: user} = token} <- Token.get_by_refresh_token(app, token), {:ok, token} <- RefreshToken.grant(token) do response_attrs = %{created_at: Token.Utils.format_created_at(token)} - json(conn, response_token(user, token, response_attrs)) + json(conn, Token.Response.build(user, token, response_attrs)) else _error -> put_status(conn, 400) @@ -160,14 +158,14 @@ def token_exchange( end def token_exchange(conn, %{"grant_type" => "authorization_code"} = params) do - with %App{} = app <- get_app_from_request(conn, params), + with {:ok, app} <- Token.Utils.fetch_app(conn), fixed_token = Token.Utils.fix_padding(params["code"]), {:ok, auth} <- Authorization.get_by_token(app, fixed_token), %User{} = user <- User.get_cached_by_id(auth.user_id), {:ok, token} <- Token.exchange_token(app, auth) do response_attrs = %{created_at: Token.Utils.format_created_at(token)} - json(conn, response_token(user, token, response_attrs)) + json(conn, Token.Response.build(user, token, response_attrs)) else _error -> put_status(conn, 400) @@ -179,14 +177,14 @@ def token_exchange( conn, %{"grant_type" => "password"} = params ) do - with {_, {:ok, %User{} = user}} <- {:get_user, Authenticator.get_user(conn)}, - %App{} = app <- get_app_from_request(conn, params), + with {:ok, %User{} = user} <- Authenticator.get_user(conn), + {:ok, app} <- Token.Utils.fetch_app(conn), {:auth_active, true} <- {:auth_active, User.auth_active?(user)}, {:user_active, true} <- {:user_active, !user.info.deactivated}, {:ok, scopes} <- validate_scopes(app, params), {:ok, auth} <- Authorization.create_authorization(app, user, scopes), {:ok, token} <- Token.exchange_token(app, auth) do - json(conn, response_token(user, token)) + json(conn, Token.Response.build(user, token)) else {:auth_active, false} -> # Per https://github.com/tootsuite/mastodon/blob/ @@ -218,21 +216,11 @@ def token_exchange( token_exchange(conn, params) end - def token_exchange(conn, %{"grant_type" => "client_credentials"} = params) do - with %App{} = app <- get_app_from_request(conn, params), + def token_exchange(conn, %{"grant_type" => "client_credentials"} = _params) do + with {:ok, app} <- Token.Utils.fetch_app(conn), {:ok, auth} <- Authorization.create_authorization(app, %User{}), - {:ok, token} <- Token.exchange_token(app, auth), - {:ok, inserted_at} <- DateTime.from_naive(token.inserted_at, "Etc/UTC") do - response = %{ - token_type: "Bearer", - access_token: token.token, - refresh_token: token.refresh_token, - created_at: DateTime.to_unix(inserted_at), - expires_in: 60 * 10, - scope: Enum.join(token.scopes, " ") - } - - json(conn, response) + {:ok, token} <- Token.exchange_token(app, auth) do + json(conn, Token.Response.build_for_client_credentials(token)) else _error -> put_status(conn, 400) @@ -244,7 +232,7 @@ def token_exchange(conn, %{"grant_type" => "client_credentials"} = params) do def token_exchange(conn, params), do: bad_request(conn, params) def token_revoke(conn, %{"token" => _token} = params) do - with %App{} = app <- get_app_from_request(conn, params), + with {:ok, app} <- Token.Utils.fetch_app(conn), {:ok, _token} <- RevokeToken.revoke(app, params) do json(conn, %{}) else @@ -427,33 +415,6 @@ defp do_create_authorization( end end - defp get_app_from_request(conn, params) do - conn - |> fetch_client_credentials(params) - |> fetch_client - end - - defp fetch_client({id, secret}) when is_binary(id) and is_binary(secret) do - Repo.get_by(App, client_id: id, client_secret: secret) - end - - defp fetch_client({_id, _secret}), do: nil - - defp fetch_client_credentials(conn, params) do - # Per RFC 6749, HTTP Basic is preferred to body params - with ["Basic " <> encoded] <- get_req_header(conn, "authorization"), - {:ok, decoded} <- Base.decode64(encoded), - [id, secret] <- - Enum.map( - String.split(decoded, ":"), - fn s -> URI.decode_www_form(s) end - ) do - {id, secret} - else - _ -> {params["client_id"], params["client_secret"]} - end - end - # Special case: Local MastodonFE defp redirect_uri(conn, "."), do: mastodon_api_url(conn, :login) @@ -464,18 +425,6 @@ defp get_session_registration_id(conn), do: get_session(conn, :registration_id) defp put_session_registration_id(conn, registration_id), do: put_session(conn, :registration_id, registration_id) - defp response_token(%User{} = user, token, opts \\ %{}) do - %{ - token_type: "Bearer", - access_token: token.token, - refresh_token: token.refresh_token, - expires_in: @expires_in, - scope: Enum.join(token.scopes, " "), - me: user.ap_id - } - |> Map.merge(opts) - end - @spec validate_scopes(App.t(), map()) :: {:ok, list()} | {:error, :missing_scopes | :unsupported_scopes} defp validate_scopes(app, params) do diff --git a/lib/pleroma/web/oauth/token/response.ex b/lib/pleroma/web/oauth/token/response.ex new file mode 100644 index 000000000..64e78b183 --- /dev/null +++ b/lib/pleroma/web/oauth/token/response.ex @@ -0,0 +1,32 @@ +defmodule Pleroma.Web.OAuth.Token.Response do + @moduledoc false + + alias Pleroma.User + alias Pleroma.Web.OAuth.Token.Utils + + @expires_in Pleroma.Config.get([:oauth2, :token_expires_in], 600) + + @doc false + def build(%User{} = user, token, opts \\ %{}) do + %{ + token_type: "Bearer", + access_token: token.token, + refresh_token: token.refresh_token, + expires_in: @expires_in, + scope: Enum.join(token.scopes, " "), + me: user.ap_id + } + |> Map.merge(opts) + end + + def build_for_client_credentials(token) do + %{ + token_type: "Bearer", + access_token: token.token, + refresh_token: token.refresh_token, + created_at: Utils.format_created_at(token), + expires_in: @expires_in, + scope: Enum.join(token.scopes, " ") + } + end +end diff --git a/lib/pleroma/web/oauth/token/utils.ex b/lib/pleroma/web/oauth/token/utils.ex index a81560a1c..7a4fddafd 100644 --- a/lib/pleroma/web/oauth/token/utils.ex +++ b/lib/pleroma/web/oauth/token/utils.ex @@ -3,6 +3,44 @@ defmodule Pleroma.Web.OAuth.Token.Utils do Auxiliary functions for dealing with tokens. """ + alias Pleroma.Repo + alias Pleroma.Web.OAuth.App + + @doc "Fetch app by client credentials from request" + @spec fetch_app(Plug.Conn.t()) :: {:ok, App.t()} | {:error, :not_found} + def fetch_app(conn) do + res = + conn + |> fetch_client_credentials() + |> fetch_client + + case res do + %App{} = app -> {:ok, app} + _ -> {:error, :not_found} + end + end + + defp fetch_client({id, secret}) when is_binary(id) and is_binary(secret) do + Repo.get_by(App, client_id: id, client_secret: secret) + end + + defp fetch_client({_id, _secret}), do: nil + + defp fetch_client_credentials(conn) do + # Per RFC 6749, HTTP Basic is preferred to body params + with ["Basic " <> encoded] <- Plug.Conn.get_req_header(conn, "authorization"), + {:ok, decoded} <- Base.decode64(encoded), + [id, secret] <- + Enum.map( + String.split(decoded, ":"), + fn s -> URI.decode_www_form(s) end + ) do + {id, secret} + else + _ -> {conn.params["client_id"], conn.params["client_secret"]} + end + end + @doc "convert token inserted_at to unix timestamp" def format_created_at(%{inserted_at: inserted_at} = _token) do inserted_at diff --git a/test/web/oauth/token/utils_test.exs b/test/web/oauth/token/utils_test.exs new file mode 100644 index 000000000..20e338cab --- /dev/null +++ b/test/web/oauth/token/utils_test.exs @@ -0,0 +1,53 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2018 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.OAuth.Token.UtilsTest do + use Pleroma.DataCase + alias Pleroma.Web.OAuth.Token.Utils + import Pleroma.Factory + + describe "fetch_app/1" do + test "returns error when credentials is invalid" do + assert {:error, :not_found} = + Utils.fetch_app(%Plug.Conn{params: %{"client_id" => 1, "client_secret" => "x"}}) + end + + test "returns App by params credentails" do + app = insert(:oauth_app) + + assert {:ok, load_app} = + Utils.fetch_app(%Plug.Conn{ + params: %{"client_id" => app.client_id, "client_secret" => app.client_secret} + }) + + assert load_app == app + end + + test "returns App by header credentails" do + app = insert(:oauth_app) + header = "Basic " <> Base.encode64("#{app.client_id}:#{app.client_secret}") + + conn = + %Plug.Conn{} + |> Plug.Conn.put_req_header("authorization", header) + + assert {:ok, load_app} = Utils.fetch_app(conn) + assert load_app == app + end + end + + describe "format_created_at/1" do + test "returns formatted created at" do + token = insert(:oauth_token) + date = Utils.format_created_at(token) + + token_date = + token.inserted_at + |> DateTime.from_naive!("Etc/UTC") + |> DateTime.to_unix() + + assert token_date == date + end + end +end From ac3a3abf6bfae5a6217e0a212abd6be0b4a17309 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Tue, 14 May 2019 15:07:38 +0000 Subject: [PATCH 14/18] clean up follow/block imports a little --- lib/pleroma/user.ex | 16 +++++++++++ .../controllers/util_controller.ex | 28 +++++++++---------- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index c94660de4..417d57d72 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1085,6 +1085,22 @@ def perform(:follow_import, %User{} = follower, followed_identifiers) ) end + def blocks_import(%User{} = blocker, blocked_identifiers) when is_list(blocked_identifiers), + do: + PleromaJobQueue.enqueue(:background, __MODULE__, [ + :blocks_import, + blocker, + blocked_identifiers + ]) + + def follow_import(%User{} = follower, followed_identifiers) when is_list(followed_identifiers), + do: + PleromaJobQueue.enqueue(:background, __MODULE__, [ + :follow_import, + follower, + followed_identifiers + ]) + def delete_user_activities(%User{ap_id: ap_id} = user) do stream = ap_id diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index 143960206..deaacd946 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -309,13 +309,13 @@ def follow_import(%{assigns: %{user: follower}} = conn, %{"list" => list}) do Enum.map(lines, fn line -> String.split(line, ",") |> List.first() end) - |> List.delete("Account address"), - :ok <- - PleromaJobQueue.enqueue(:background, User, [ - :follow_import, - follower, - followed_identifiers - ]) do + |> List.delete("Account address") do + PleromaJobQueue.enqueue(:background, User, [ + :follow_import, + follower, + followed_identifiers + ]) + json(conn, "job started") end end @@ -325,13 +325,13 @@ def blocks_import(conn, %{"list" => %Plug.Upload{} = listfile}) do end def blocks_import(%{assigns: %{user: blocker}} = conn, %{"list" => list}) do - with blocked_identifiers <- String.split(list), - :ok <- - PleromaJobQueue.enqueue(:background, User, [ - :blocks_import, - blocker, - blocked_identifiers - ]) do + with blocked_identifiers <- String.split(list) do + PleromaJobQueue.enqueue(:background, User, [ + :blocks_import, + blocker, + blocked_identifiers + ]) + json(conn, "job started") end end From 51325fd60cf96e2ae99e09f53264f2ca1e69781b Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Tue, 14 May 2019 15:35:06 +0000 Subject: [PATCH 15/18] gopher: fix rendering of post content (closes #895) --- lib/pleroma/gopher/server.ex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/pleroma/gopher/server.ex b/lib/pleroma/gopher/server.ex index 1d2e0785c..b3319e137 100644 --- a/lib/pleroma/gopher/server.ex +++ b/lib/pleroma/gopher/server.ex @@ -77,13 +77,13 @@ def render_activities(activities) do user = User.get_cached_by_ap_id(activity.data["actor"]) object = Object.normalize(activity) - like_count = object["like_count"] || 0 - announcement_count = object["announcement_count"] || 0 + like_count = object.data["like_count"] || 0 + announcement_count = object.data["announcement_count"] || 0 link("Post ##{activity.id} by #{user.nickname}", "/notices/#{activity.id}") <> info("#{like_count} likes, #{announcement_count} repeats") <> "i\tfake\t(NULL)\t0\r\n" <> - info(HTML.strip_tags(String.replace(object["content"], "
", "\r"))) + info(HTML.strip_tags(String.replace(object.data["content"], "
", "\r"))) end) |> Enum.join("i\tfake\t(NULL)\t0\r\n") end From 1caa6331eaba71db5a04b2097ef06fd6e4a54739 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Tue, 14 May 2019 12:33:03 -0500 Subject: [PATCH 16/18] Group def perform() together to fix the build --- lib/pleroma/user.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 19f91d63c..c6a562a61 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1014,8 +1014,6 @@ def deactivate_async(user, status \\ true) do PleromaJobQueue.enqueue(:background, __MODULE__, [:deactivate_async, user, status]) end - def perform(:deactivate_async, user, status), do: deactivate(user, status) - def deactivate(%User{} = user, status \\ true) do info_cng = User.Info.set_activation_status(user.info, status) @@ -1074,6 +1072,8 @@ def perform(:fetch_initial_posts, %User{} = user) do {:ok, user} end + def perform(:deactivate_async, user, status), do: deactivate(user, status) + @spec perform(atom(), User.t(), list()) :: list() | {:error, any()} def perform(:blocks_import, %User{} = blocker, blocked_identifiers) when is_list(blocked_identifiers) do From 38f3393e934330454fb942048c19ee5640563a08 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Tue, 14 May 2019 22:47:23 +0300 Subject: [PATCH 17/18] Make rate limiting for Mastodon Registration API less agressive and enable it by default. As discussed on irc. Unlike Mastodon our web interface for registrations is using the same APIs regular apps would be using, so 5 requests per 30 minutes per IP could hurt valid use-cases when Pleroma-FE switches to it. Also enable the endpoint by default, it makes no sense to have it disabled when 1. TwitterAPI endpoint is there and always enabled 2. Unlike Mastodon, there is no way to get an account without using the APIs (makes me wonder why the setting is even there) Also in this commit: minor changelog improvements. --- CHANGELOG.md | 12 ++++++------ config/config.exs | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 17e913648..c563c39da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,16 +22,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Admin API: Endpoints for listing/revoking invite tokens - Admin API: Endpoints for making users follow/unfollow each other - Admin API: added filters (role, tags, email, name) for users endpoint +- AdminFE: initial release with basic user management accessible at /pleroma/admin/ - Mastodon API: [Scheduled statuses](https://docs.joinmastodon.org/api/rest/scheduled-statuses/) - Mastodon API: `/api/v1/notifications/destroy_multiple` (glitch-soc extension) - Mastodon API: `/api/v1/pleroma/accounts/:id/favourites` (API extension) - Mastodon API: [Reports](https://docs.joinmastodon.org/api/rest/reports/) -- Mastodon API: REST API for creating an account +- Mastodon API: `POST /api/v1/accounts` (account creation API) - ActivityPub C2S: OAuth endpoints -- Metadata RelMe provider +- Metadata: RelMe provider - OAuth: added support for refresh tokens - Emoji packs and emoji pack manager -- AdminFE: initial release with basic user management accessible at /pleroma/admin/ ### Changed - **Breaking:** Configuration: move from Pleroma.Mailer to Pleroma.Emails.Mailer @@ -44,8 +44,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Federation: Removed `inReplyToStatusId` from objects - Configuration: Dedupe enabled by default - Configuration: Added `extra_cookie_attrs` for setting non-standard cookie attributes. Defaults to ["SameSite=Lax"] so that remote follows work. -- Pleroma API: Support for emoji tags in `/api/pleroma/emoji` resulting in a breaking API change - Timelines: Messages involving people you have blocked will be excluded from the timeline in all cases instead of just repeats. +- Admin API: Move the user related API to `api/pleroma/admin/users` +- Pleroma API: Support for emoji tags in `/api/pleroma/emoji` resulting in a breaking API change - Mastodon API: Support for `exclude_types`, `limit` and `min_id` in `/api/v1/notifications` - Mastodon API: Add `languages` and `registrations` to `/api/v1/instance` - Mastodon API: Provide plaintext versions of cw/content in the Status entity @@ -63,7 +64,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Deps: Updated Cowboy to 2.6 - Deps: Updated Ecto to 3.0.7 - Don't ship finmoji by default, they can be installed as an emoji pack -- Admin API: Move the user related API to `api/pleroma/admin/users` - Hide deactivated users and their statuses ### Fixed @@ -71,7 +71,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Followers counter not being updated when a follower is blocked - Deactivated users being able to request an access token - Limit on request body in rich media/relme parsers being ignored resulting in a possible memory leak -- proper Twitter Card generation instead of a dummy +- Proper Twitter Card generation instead of a dummy - Deletions failing for users with a large number of posts - NodeInfo: Include admins in `staffAccounts` - ActivityPub: Crashing when requesting empty local user's outbox diff --git a/config/config.exs b/config/config.exs index 8d44c96de..32c7fecb8 100644 --- a/config/config.exs +++ b/config/config.exs @@ -239,7 +239,7 @@ safe_dm_mentions: false, healthcheck: false -config :pleroma, :app_account_creation, enabled: false, max_requests: 5, interval: 1800 +config :pleroma, :app_account_creation, enabled: true, max_requests: 25, interval: 1800 config :pleroma, :markup, # XXX - unfortunately, inline images must be enabled by default right now, because From 2ca8d20053ef2abda070b8aba0e6937cf2f07991 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Tue, 14 May 2019 23:16:34 +0300 Subject: [PATCH 18/18] Fix rate-limiting tests --- config/test.exs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config/test.exs b/config/test.exs index f93bc5994..a0c90c371 100644 --- a/config/test.exs +++ b/config/test.exs @@ -59,6 +59,8 @@ total_user_limit: 3, enabled: false +config :pleroma, :app_account_creation, max_requests: 5 + try do import_config "test.secret.exs" rescue