From 108a39c8766402dcbd0235d8746e2100a18e5813 Mon Sep 17 00:00:00 2001
From: Maksim Pechnikov <parallel588@gmail.com>
Date: Fri, 17 Jan 2020 14:55:36 +0300
Subject: [PATCH 1/6] updated error messages for authentication process

---
 lib/pleroma/plugs/user_enabled_plug.ex    |   8 +-
 lib/pleroma/user.ex                       |  24 +++--
 lib/pleroma/web/oauth/oauth_controller.ex | 103 ++++++++++++++--------
 test/user_test.exs                        |  36 +++++---
 test/web/oauth/oauth_controller_test.exs  |  51 ++++++++---
 5 files changed, 149 insertions(+), 73 deletions(-)

diff --git a/lib/pleroma/plugs/user_enabled_plug.ex b/lib/pleroma/plugs/user_enabled_plug.ex
index 8d102ee5b..7b304eebc 100644
--- a/lib/pleroma/plugs/user_enabled_plug.ex
+++ b/lib/pleroma/plugs/user_enabled_plug.ex
@@ -11,11 +11,9 @@ defmodule Pleroma.Plugs.UserEnabledPlug do
   end
 
   def call(%{assigns: %{user: %User{} = user}} = conn, _) do
-    if User.auth_active?(user) do
-      conn
-    else
-      conn
-      |> assign(:user, nil)
+    case User.account_status(user) do
+      :active -> conn
+      _ -> assign(conn, :user, nil)
     end
   end
 
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index 430f04ae9..3899c34c2 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -12,6 +12,7 @@ defmodule Pleroma.User do
   alias Comeonin.Pbkdf2
   alias Ecto.Multi
   alias Pleroma.Activity
+  alias Pleroma.Config
   alias Pleroma.Conversation.Participation
   alias Pleroma.Delivery
   alias Pleroma.FollowingRelationship
@@ -35,7 +36,7 @@ defmodule Pleroma.User do
   require Logger
 
   @type t :: %__MODULE__{}
-
+  @type account_status :: :active | :deactivated | :password_reset_pending | :confirmation_pending
   @primary_key {:id, FlakeId.Ecto.CompatType, autogenerate: true}
 
   # credo:disable-for-next-line Credo.Check.Readability.MaxLineLength
@@ -216,14 +217,21 @@ defmodule Pleroma.User do
     end
   end
 
-  @doc "Returns if the user should be allowed to authenticate"
-  def auth_active?(%User{deactivated: true}), do: false
+  @doc "Returns status account"
+  @spec account_status(User.t()) :: account_status()
+  def account_status(%User{deactivated: true}), do: :deactivated
+  def account_status(%User{password_reset_pending: true}), do: :password_reset_pending
 
-  def auth_active?(%User{confirmation_pending: true}),
-    do: !Pleroma.Config.get([:instance, :account_activation_required])
+  def account_status(%User{confirmation_pending: true}) do
+    case Config.get([:instance, :account_activation_required]) do
+      true -> :confirmation_pending
+      _ -> :active
+    end
+  end
 
-  def auth_active?(%User{}), do: true
+  def account_status(%User{}), do: :active
 
+  @spec visible_for?(User.t(), User.t() | nil) :: boolean()
   def visible_for?(user, for_user \\ nil)
 
   def visible_for?(%User{invisible: true}, _), do: false
@@ -231,15 +239,17 @@ defmodule Pleroma.User do
   def visible_for?(%User{id: user_id}, %User{id: for_id}) when user_id == for_id, do: true
 
   def visible_for?(%User{} = user, for_user) do
-    auth_active?(user) || superuser?(for_user)
+    account_status(user) == :active || superuser?(for_user)
   end
 
   def visible_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
 
diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex
index d31a3d91c..d5c0d97c0 100644
--- a/lib/pleroma/web/oauth/oauth_controller.ex
+++ b/lib/pleroma/web/oauth/oauth_controller.ex
@@ -167,17 +167,37 @@ defmodule Pleroma.Web.OAuth.OAuthController do
 
   defp handle_create_authorization_error(
          %Plug.Conn{} = conn,
-         {:auth_active, false},
+         {:account_status, :confirmation_pending},
          %{"authorization" => _} = params
        ) do
-    # Per https://github.com/tootsuite/mastodon/blob/
-    #   51e154f5e87968d6bb115e053689767ab33e80cd/app/controllers/api/base_controller.rb#L76
     conn
     |> put_flash(:error, dgettext("errors", "Your login is missing a confirmed e-mail address"))
     |> put_status(:forbidden)
     |> authorize(params)
   end
 
+  defp handle_create_authorization_error(
+         %Plug.Conn{} = conn,
+         {:account_status, :password_reset_pending},
+         %{"authorization" => _} = params
+       ) do
+    conn
+    |> put_flash(:error, dgettext("errors", "Password reset is required"))
+    |> put_status(:forbidden)
+    |> authorize(params)
+  end
+
+  defp handle_create_authorization_error(
+         %Plug.Conn{} = conn,
+         {:account_status, :deactivated},
+         %{"authorization" => _} = params
+       ) do
+    conn
+    |> put_flash(:error, dgettext("errors", "Your account is currently disabled"))
+    |> put_status(:forbidden)
+    |> authorize(params)
+  end
+
   defp handle_create_authorization_error(%Plug.Conn{} = conn, error, %{"authorization" => _}) do
     Authenticator.handle_error(conn, error)
   end
@@ -218,46 +238,14 @@ defmodule Pleroma.Web.OAuth.OAuthController do
       ) do
     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.deactivated},
-         {:password_reset_pending, false} <-
-           {:password_reset_pending, user.password_reset_pending},
+         {:account_status, :active} <- {:account_status, User.account_status(user)},
          {:ok, scopes} <- validate_scopes(app, params),
          {:ok, auth} <- Authorization.create_authorization(app, user, scopes),
          {:ok, token} <- Token.exchange_token(app, auth) do
       json(conn, Token.Response.build(user, token))
     else
-      {:auth_active, false} ->
-        # Per https://github.com/tootsuite/mastodon/blob/
-        #   51e154f5e87968d6bb115e053689767ab33e80cd/app/controllers/api/base_controller.rb#L76
-        render_error(
-          conn,
-          :forbidden,
-          "Your login is missing a confirmed e-mail address",
-          %{},
-          "missing_confirmed_email"
-        )
-
-      {:user_active, false} ->
-        render_error(
-          conn,
-          :forbidden,
-          "Your account is currently disabled",
-          %{},
-          "account_is_disabled"
-        )
-
-      {:password_reset_pending, true} ->
-        render_error(
-          conn,
-          :forbidden,
-          "Password reset is required",
-          %{},
-          "password_reset_required"
-        )
-
-      _error ->
-        render_invalid_credentials_error(conn)
+      error ->
+        handle_token_exchange_error(conn, error)
     end
   end
 
@@ -286,6 +274,43 @@ defmodule Pleroma.Web.OAuth.OAuthController do
   # Bad request
   def token_exchange(%Plug.Conn{} = conn, params), do: bad_request(conn, params)
 
+  defp handle_token_exchange_error(%Plug.Conn{} = conn, {:account_status, :deactivated}) do
+    render_error(
+      conn,
+      :forbidden,
+      "Your account is currently disabled",
+      %{},
+      "account_is_disabled"
+    )
+  end
+
+  defp handle_token_exchange_error(
+         %Plug.Conn{} = conn,
+         {:account_status, :password_reset_pending}
+       ) do
+    render_error(
+      conn,
+      :forbidden,
+      "Password reset is required",
+      %{},
+      "password_reset_required"
+    )
+  end
+
+  defp handle_token_exchange_error(%Plug.Conn{} = conn, {:account_status, :confirmation_pending}) do
+    render_error(
+      conn,
+      :forbidden,
+      "Your login is missing a confirmed e-mail address",
+      %{},
+      "missing_confirmed_email"
+    )
+  end
+
+  defp handle_token_exchange_error(%Plug.Conn{} = conn, _error) do
+    render_invalid_credentials_error(conn)
+  end
+
   def token_revoke(%Plug.Conn{} = conn, %{"token" => _token} = params) do
     with {:ok, app} <- Token.Utils.fetch_app(conn),
          {:ok, _token} <- RevokeToken.revoke(app, params) do
@@ -472,7 +497,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
          %App{} = app <- Repo.get_by(App, client_id: client_id),
          true <- redirect_uri in String.split(app.redirect_uris),
          {:ok, scopes} <- validate_scopes(app, auth_attrs),
-         {:auth_active, true} <- {:auth_active, User.auth_active?(user)} do
+         {:account_status, :active} <- {:account_status, User.account_status(user)} do
       Authorization.create_authorization(app, user, scopes)
     end
   end
diff --git a/test/user_test.exs b/test/user_test.exs
index 9da1e02a9..158f98e66 100644
--- a/test/user_test.exs
+++ b/test/user_test.exs
@@ -1286,23 +1286,35 @@ defmodule Pleroma.UserTest do
     end
   end
 
-  test "auth_active?/1 works correctly" do
-    Pleroma.Config.put([:instance, :account_activation_required], true)
+  describe "account_status/1" do
+    clear_config([:instance, :account_activation_required])
 
-    local_user = insert(:user, local: true, confirmation_pending: true)
-    confirmed_user = insert(:user, local: true, confirmation_pending: false)
-    remote_user = insert(:user, local: false)
+    test "return confirmation_pending for unconfirm user" do
+      Pleroma.Config.put([:instance, :account_activation_required], true)
+      user = insert(:user, confirmation_pending: true)
+      assert User.account_status(user) == :confirmation_pending
+    end
 
-    refute User.auth_active?(local_user)
-    assert User.auth_active?(confirmed_user)
-    assert User.auth_active?(remote_user)
+    test "return active for confirmed user" do
+      Pleroma.Config.put([:instance, :account_activation_required], true)
+      user = insert(:user, confirmation_pending: false)
+      assert User.account_status(user) == :active
+    end
 
-    # also shows unactive for deactivated users
+    test "return active for remote user" do
+      user = insert(:user, local: false)
+      assert User.account_status(user) == :active
+    end
 
-    deactivated_but_confirmed =
-      insert(:user, local: true, confirmation_pending: false, deactivated: true)
+    test "returns :password_reset_pending for user with reset password" do
+      user = insert(:user, password_reset_pending: true)
+      assert User.account_status(user) == :password_reset_pending
+    end
 
-    refute User.auth_active?(deactivated_but_confirmed)
+    test "returns :deactivated for deactivated user" do
+      user = insert(:user, local: true, confirmation_pending: false, deactivated: true)
+      assert User.account_status(user) == :deactivated
+    end
   end
 
   describe "superuser?/1" do
diff --git a/test/web/oauth/oauth_controller_test.exs b/test/web/oauth/oauth_controller_test.exs
index 59f4674eb..adeff8e25 100644
--- a/test/web/oauth/oauth_controller_test.exs
+++ b/test/web/oauth/oauth_controller_test.exs
@@ -819,7 +819,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
         |> User.confirmation_changeset(need_confirmation: true)
         |> User.update_and_set_cache()
 
-      refute Pleroma.User.auth_active?(user)
+      refute Pleroma.User.account_status(user) == :active
 
       app = insert(:oauth_app)
 
@@ -849,7 +849,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
 
       app = insert(:oauth_app)
 
-      conn =
+      resp =
         build_conn()
         |> post("/oauth/token", %{
           "grant_type" => "password",
@@ -858,10 +858,12 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
           "client_id" => app.client_id,
           "client_secret" => app.client_secret
         })
+        |> json_response(403)
 
-      assert resp = json_response(conn, 403)
-      assert %{"error" => _} = resp
-      refute Map.has_key?(resp, "access_token")
+      assert resp == %{
+               "error" => "Your account is currently disabled",
+               "identifier" => "account_is_disabled"
+             }
     end
 
     test "rejects token exchange for user with password_reset_pending set to true" do
@@ -875,7 +877,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
 
       app = insert(:oauth_app, scopes: ["read", "write"])
 
-      conn =
+      resp =
         build_conn()
         |> post("/oauth/token", %{
           "grant_type" => "password",
@@ -884,12 +886,41 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
           "client_id" => app.client_id,
           "client_secret" => app.client_secret
         })
+        |> json_response(403)
 
-      assert resp = json_response(conn, 403)
+      assert resp == %{
+               "error" => "Password reset is required",
+               "identifier" => "password_reset_required"
+             }
+    end
 
-      assert resp["error"] == "Password reset is required"
-      assert resp["identifier"] == "password_reset_required"
-      refute Map.has_key?(resp, "access_token")
+    test "rejects token exchange for user with confirmation_pending set to true" do
+      Pleroma.Config.put([:instance, :account_activation_required], true)
+      password = "testpassword"
+
+      user =
+        insert(:user,
+          password_hash: Comeonin.Pbkdf2.hashpwsalt(password),
+          confirmation_pending: true
+        )
+
+      app = insert(:oauth_app, scopes: ["read", "write"])
+
+      resp =
+        build_conn()
+        |> post("/oauth/token", %{
+          "grant_type" => "password",
+          "username" => user.nickname,
+          "password" => password,
+          "client_id" => app.client_id,
+          "client_secret" => app.client_secret
+        })
+        |> json_response(403)
+
+      assert resp == %{
+               "error" => "Your login is missing a confirmed e-mail address",
+               "identifier" => "missing_confirmed_email"
+             }
     end
 
     test "rejects an invalid authorization code" do

From 6252e82f85d84c909871d3741da5c835ca2ca944 Mon Sep 17 00:00:00 2001
From: Alexander Strizhakov <alex.strizhakov@gmail.com>
Date: Sat, 25 Jan 2020 10:33:27 +0300
Subject: [PATCH 2/6] respect settings from database in mix tasks

---
 lib/mix/tasks/pleroma/emoji.ex     | 2 ++
 lib/mix/tasks/pleroma/robotstxt.ex | 1 +
 2 files changed, 3 insertions(+)

diff --git a/lib/mix/tasks/pleroma/emoji.ex b/lib/mix/tasks/pleroma/emoji.ex
index 35669af27..24d999707 100644
--- a/lib/mix/tasks/pleroma/emoji.ex
+++ b/lib/mix/tasks/pleroma/emoji.ex
@@ -9,6 +9,7 @@ defmodule Mix.Tasks.Pleroma.Emoji do
   @moduledoc File.read!("docs/administration/CLI_tasks/emoji.md")
 
   def run(["ls-packs" | args]) do
+    Mix.Pleroma.start_pleroma()
     Application.ensure_all_started(:hackney)
 
     {options, [], []} = parse_global_opts(args)
@@ -35,6 +36,7 @@ defmodule Mix.Tasks.Pleroma.Emoji do
   end
 
   def run(["get-packs" | args]) do
+    Mix.Pleroma.start_pleroma()
     Application.ensure_all_started(:hackney)
 
     {options, pack_names, []} = parse_global_opts(args)
diff --git a/lib/mix/tasks/pleroma/robotstxt.ex b/lib/mix/tasks/pleroma/robotstxt.ex
index 2128e1cd6..e99dd8502 100644
--- a/lib/mix/tasks/pleroma/robotstxt.ex
+++ b/lib/mix/tasks/pleroma/robotstxt.ex
@@ -18,6 +18,7 @@ defmodule Mix.Tasks.Pleroma.RobotsTxt do
 
   """
   def run(["disallow_all"]) do
+    Mix.Pleroma.start_pleroma()
     static_dir = Pleroma.Config.get([:instance, :static_dir], "instance/static/")
 
     if !File.exists?(static_dir) do

From de4102b2475f46fff238cfa3aec7aae1bdfd60f4 Mon Sep 17 00:00:00 2001
From: Alexander Strizhakov <alex.strizhakov@gmail.com>
Date: Sat, 25 Jan 2020 10:39:10 +0300
Subject: [PATCH 3/6] can be changed in runtime

---
 lib/pleroma/web/mastodon_api/views/app_view.ex | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/lib/pleroma/web/mastodon_api/views/app_view.ex b/lib/pleroma/web/mastodon_api/views/app_view.ex
index f52b693a6..beba89edb 100644
--- a/lib/pleroma/web/mastodon_api/views/app_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/app_view.ex
@@ -7,10 +7,6 @@ defmodule Pleroma.Web.MastodonAPI.AppView do
 
   alias Pleroma.Web.OAuth.App
 
-  @vapid_key :web_push_encryption
-             |> Application.get_env(:vapid_details, [])
-             |> Keyword.get(:public_key)
-
   def render("show.json", %{app: %App{} = app}) do
     %{
       id: app.id |> to_string,
@@ -32,8 +28,10 @@ defmodule Pleroma.Web.MastodonAPI.AppView do
   end
 
   defp with_vapid_key(data) do
-    if @vapid_key do
-      Map.put(data, "vapid_key", @vapid_key)
+    vapid_key = Application.get_env(:web_push_encryption, :vapid_details, [])[:public_key]
+
+    if vapid_key do
+      Map.put(data, "vapid_key", vapid_key)
     else
       data
     end

From 5943d78c74c7ee429545a400d2739e58656ec7d7 Mon Sep 17 00:00:00 2001
From: Alexander Strizhakov <alex.strizhakov@gmail.com>
Date: Sat, 25 Jan 2020 19:45:51 +0300
Subject: [PATCH 4/6] description typos, Oban verbose type fix, new keys

---
 config/description.exs | 272 +++++++++++++++++++++++------------------
 1 file changed, 153 insertions(+), 119 deletions(-)

diff --git a/config/description.exs b/config/description.exs
index 6c931c152..531f5d7e7 100644
--- a/config/description.exs
+++ b/config/description.exs
@@ -39,7 +39,7 @@ config :pleroma, :config_description, [
         key: :link_name,
         type: :boolean,
         description:
-          "If enabled, a name parameter will be added to the url of the upload. For example `https://instance.tld/media/imagehash.png?name=realname.png`"
+          "If enabled, a name parameter will be added to the url of the upload. For example `https://instance.tld/media/imagehash.png?name=realname.png`."
       },
       %{
         key: :base_url,
@@ -53,7 +53,7 @@ config :pleroma, :config_description, [
         key: :proxy_remote,
         type: :boolean,
         description:
-          "If enabled, requests to media stored using a remote uploader will be proxied instead of being redirected."
+          "If enabled, requests to media stored using a remote uploader will be proxied instead of being redirected"
       },
       %{
         key: :proxy_opts,
@@ -73,14 +73,14 @@ config :pleroma, :config_description, [
             type: :boolean,
             description:
               "Redirects the client to the real remote URL if there's any HTTP errors. " <>
-                "Any error during body processing will not be redirected as the response is chunked"
+                "Any error during body processing will not be redirected as the response is chunked."
           },
           %{
             key: :max_body_length,
             type: :integer,
             description:
-              "limits the content length to be approximately the " <>
-                "specified length. It is validated with the `content-length` header and also verified when proxying"
+              "Limits the content length to be approximately the " <>
+                "specified length. It is validated with the `content-length` header and also verified when proxying."
           },
           %{
             key: :http,
@@ -130,7 +130,7 @@ config :pleroma, :config_description, [
       %{
         key: :uploads,
         type: :string,
-        description: "Path where user uploads will be saved",
+        description: "Path where user's uploads will be saved",
         suggestions: [
           "uploads"
         ]
@@ -207,7 +207,7 @@ config :pleroma, :config_description, [
         type: :string,
         description:
           "Text to replace filenames in links. If no setting, {random}.extension will be used. You can get the original" <>
-            " filename extension by using {extension}, for example custom-file-name.{extension}",
+            " filename extension by using {extension}, for example custom-file-name.{extension}.",
         suggestions: [
           "custom-file-name.{extension}"
         ]
@@ -637,12 +637,12 @@ config :pleroma, :config_description, [
       %{
         key: :registrations_open,
         type: :boolean,
-        description: "Enable registrations for anyone, invitations can be enabled when false"
+        description: "Enable registrations for anyone, invitations can be enabled when `false`"
       },
       %{
         key: :invites_enabled,
         type: :boolean,
-        description: "Enable user invitations for admins (depends on registrations_open: false)"
+        description: "Enable user invitations for admins (depends on `registrations_open: false`)"
       },
       %{
         key: :account_activation_required,
@@ -660,7 +660,7 @@ config :pleroma, :config_description, [
         type: :integer,
         description:
           "Max. depth of reply-to activities fetching on incoming federation, to prevent out-of-memory situations while" <>
-            " fetching very long threads. If set to nil, threads of any depth will be fetched. Lower this value if you experience out-of-memory crashes",
+            " fetching very long threads. If set to `nil`, threads of any depth will be fetched. Lower this value if you experience out-of-memory crashes.",
         suggestions: [
           100
         ]
@@ -670,7 +670,7 @@ config :pleroma, :config_description, [
         label: "Fed. reachability timeout days",
         type: :integer,
         description:
-          "Timeout (in days) of each external federation target being unreachable prior to pausing federating to it",
+          "Timeout (in days) of each external federation target being unreachable prior to pausing federating to it.",
         suggestions: [
           7
         ]
@@ -703,13 +703,13 @@ config :pleroma, :config_description, [
         type: :boolean,
         description:
           "Makes the client API in authentificated mode-only except for user-profiles." <>
-            " Useful for disabling the Local Timeline and The Whole Known Network"
+            " Useful for disabling the Local Timeline and The Whole Known Network."
       },
       %{
         key: :quarantined_instances,
         type: {:list, :string},
         description:
-          "List of ActivityPub instances where private(DMs, followers-only) activities will not be send",
+          "List of ActivityPub instances where private (DMs, followers-only) activities will not be send",
         suggestions: [
           "quarantined.com",
           "*.quarantined.com"
@@ -752,7 +752,7 @@ config :pleroma, :config_description, [
         label: "MRF transparency exclusions",
         type: {:list, :string},
         description:
-          "Exclude specific instance names from MRF transparency. The use of the exclusions feature will be disclosed in nodeinfo as a boolean value",
+          "Exclude specific instance names from MRF transparency. The use of the exclusions feature will be disclosed in nodeinfo as a boolean value.",
         suggestions: [
           "exclusion.com"
         ]
@@ -761,13 +761,13 @@ config :pleroma, :config_description, [
         key: :extended_nickname_format,
         type: :boolean,
         description:
-          "Set to true to use extended local nicknames format (allows underscores/dashes)." <>
-            " This will break federation with older software for theses nicknames"
+          "Set to `true` to use extended local nicknames format (allows underscores/dashes)." <>
+            " This will break federation with older software for theses nicknames."
       },
       %{
         key: :max_pinned_statuses,
         type: :integer,
-        description: "The maximum number of pinned statuses. 0 will disable the feature",
+        description: "The maximum number of pinned statuses. 0 will disable the feature.",
         suggestions: [
           0,
           1,
@@ -790,13 +790,13 @@ config :pleroma, :config_description, [
         key: :no_attachment_links,
         type: :boolean,
         description:
-          "Set to true to disable automatically adding attachment link text to statuses"
+          "Set to `true` to disable automatically adding attachment link text to statuses"
       },
       %{
         key: :welcome_message,
         type: :string,
         description:
-          "A message that will be send to a newly registered users as a direct message",
+          "A message that will be sent to a newly registered users as a direct message",
         suggestions: [
           "Hi, @username! Welcome on board!"
         ]
@@ -812,7 +812,7 @@ config :pleroma, :config_description, [
       %{
         key: :max_report_comment_size,
         type: :integer,
-        description: "The maximum size of the report comment (Default: 1000)",
+        description: "The maximum size of the report comment. Default: 1000.",
         suggestions: [
           1_000
         ]
@@ -821,14 +821,14 @@ config :pleroma, :config_description, [
         key: :safe_dm_mentions,
         type: :boolean,
         description:
-          "If set to true, only mentions at the beginning of a post will be used to address people in direct messages." <>
-            " This is to prevent accidental mentioning of people when talking about them (e.g. \"@friend hey i really don't like @enemy\")." <>
-            " Default: false"
+          "If set to `true`, only mentions at the beginning of a post will be used to address people in direct messages." <>
+            " This is to prevent accidental mentioning of people when talking about them (e.g. \"@admin please keep an eye on @bad_actor\")." <>
+            " Default: `false`"
       },
       %{
         key: :healthcheck,
         type: :boolean,
-        description: "If set to true, system data will be shown on /api/pleroma/healthcheck"
+        description: "If set to `true`, system data will be shown on /api/pleroma/healthcheck"
       },
       %{
         key: :remote_post_retention_days,
@@ -842,7 +842,7 @@ config :pleroma, :config_description, [
       %{
         key: :user_bio_length,
         type: :integer,
-        description: "A user bio maximum length (default: 5000)",
+        description: "A user bio maximum length. Default: 5000.",
         suggestions: [
           5_000
         ]
@@ -850,7 +850,7 @@ config :pleroma, :config_description, [
       %{
         key: :user_name_length,
         type: :integer,
-        description: "A user name maximum length (default: 100)",
+        description: "A user name maximum length. Default: 100.",
         suggestions: [
           100
         ]
@@ -858,13 +858,13 @@ config :pleroma, :config_description, [
       %{
         key: :skip_thread_containment,
         type: :boolean,
-        description: "Skip filter out broken threads. The default is true"
+        description: "Skip filter out broken threads. Default: `true`"
       },
       %{
         key: :limit_to_local_content,
         type: [:atom, false],
         description:
-          "Limit unauthenticated users to search for local statutes and users only. The default is :unauthenticated ",
+          "Limit unauthenticated users to search for local statutes and users only. Default: `:unauthenticated`.",
         suggestions: [
           :unauthenticated,
           :all,
@@ -874,7 +874,7 @@ config :pleroma, :config_description, [
       %{
         key: :max_account_fields,
         type: :integer,
-        description: "The maximum number of custom fields in the user profile (default: 10)",
+        description: "The maximum number of custom fields in the user profile. Default: 10.",
         suggestions: [
           10
         ]
@@ -883,7 +883,7 @@ config :pleroma, :config_description, [
         key: :max_remote_account_fields,
         type: :integer,
         description:
-          "The maximum number of custom fields in the remote user profile (default: 20)",
+          "The maximum number of custom fields in the remote user profile. Default: 20.",
         suggestions: [
           20
         ]
@@ -891,7 +891,7 @@ config :pleroma, :config_description, [
       %{
         key: :account_field_name_length,
         type: :integer,
-        description: "An account field name maximum length (default: 512)",
+        description: "An account field name maximum length. Default: 512.",
         suggestions: [
           512
         ]
@@ -899,7 +899,7 @@ config :pleroma, :config_description, [
       %{
         key: :account_field_value_length,
         type: :integer,
-        description: "An account field value maximum length (default: 2048)",
+        description: "An account field value maximum length. Default: 2048.",
         suggestions: [
           2048
         ]
@@ -920,7 +920,7 @@ config :pleroma, :config_description, [
         key: :backends,
         type: [:atom, :tuple, :module],
         description:
-          "Where logs will be send, :console - send logs to stdout, {ExSyslogger, :ex_syslogger} - to syslog, Quack.Logger - to Slack.",
+          "Where logs will be sent, :console - send logs to stdout, { ExSyslogger, :ex_syslogger } - to syslog, Quack.Logger - to Slack.",
         suggestions: [:console, {ExSyslogger, :ex_syslogger}, Quack.Logger]
       }
     ]
@@ -947,7 +947,7 @@ config :pleroma, :config_description, [
       %{
         key: :format,
         type: :string,
-        description: "It defaults to \"$date $time [$level] $levelpad$node $metadata $message\"",
+        description: "Default: \"$date $time [$level] $levelpad$node $metadata $message\".",
         suggestions: ["$metadata[$level] $message"]
       },
       %{
@@ -972,7 +972,7 @@ config :pleroma, :config_description, [
       %{
         key: :format,
         type: :string,
-        description: "It defaults to \"$date $time [$level] $levelpad$node $metadata $message\"",
+        description: "Default: \"$date $time [$level] $levelpad$node $metadata $message\".",
         suggestions: ["$metadata[$level] $message"]
       },
       %{
@@ -1026,7 +1026,7 @@ config :pleroma, :config_description, [
     description:
       "This form can be used to configure a keyword list that keeps the configuration data for any " <>
         "kind of frontend. By default, settings for pleroma_fe and masto_fe are configured. If you want to " <>
-        "add your own configuration your settings need to be complete as they will override the defaults.",
+        "add your own configuration your settings all fields must be complete.",
     children: [
       %{
         key: :pleroma_fe,
@@ -1048,7 +1048,11 @@ config :pleroma, :config_description, [
             hideUserStats: false,
             scopeCopy: true,
             subjectLineBehavior: "email",
-            alwaysShowSubjectInput: true
+            alwaysShowSubjectInput: true,
+            logoMask: false,
+            logoMargin: ".1em",
+            stickers: false,
+            enableEmojiPicker: false
           }
         ],
         children: [
@@ -1076,7 +1080,7 @@ config :pleroma, :config_description, [
             label: "Redirect root no login",
             type: :string,
             description:
-              "relative URL which indicates where to redirect when a user isn't logged in",
+              "Relative URL which indicates where to redirect when a user isn't logged in",
             suggestions: ["/main/all"]
           },
           %{
@@ -1084,7 +1088,7 @@ config :pleroma, :config_description, [
             label: "Redirect root login",
             type: :string,
             description:
-              "relative URL which indicates where to redirect when a user is logged in",
+              "Relative URL which indicates where to redirect when a user is logged in",
             suggestions: ["/main/friends"]
           },
           %{
@@ -1097,34 +1101,34 @@ config :pleroma, :config_description, [
             key: :scopeOptionsEnabled,
             label: "Scope options enabled",
             type: :boolean,
-            description: "Enable setting an notice visibility and subject/CW when posting"
+            description: "Enable setting a notice visibility and subject/CW when posting"
           },
           %{
             key: :formattingOptionsEnabled,
             label: "Formatting options enabled",
             type: :boolean,
             description:
-              "Enable setting a formatting different than plain-text (ie. HTML, Markdown) when posting, relates to :instance, allowed_post_formats"
+              "Enable setting a formatting different than plain-text (ie. HTML, Markdown) when posting, relates to `:instance`, `allowed_post_formats`"
           },
           %{
             key: :collapseMessageWithSubject,
             label: "Collapse message with subject",
             type: :boolean,
             description:
-              "When a message has a subject(aka Content Warning), collapse it by default"
+              "When a message has a subject (aka Content Warning), collapse it by default"
           },
           %{
             key: :hidePostStats,
             label: "Hide post stats",
             type: :boolean,
-            description: "Hide notices statistics(repeats, favorites, ...)"
+            description: "Hide notices statistics (repeats, favorites, ...)"
           },
           %{
             key: :hideUserStats,
             label: "Hide user stats",
             type: :boolean,
             description:
-              "Hide profile statistics(posts, posts per day, followers, followings, ...)"
+              "Hide profile statistics (posts, posts per day, followers, followings, ...)"
           },
           %{
             key: :scopeCopy,
@@ -1137,16 +1141,46 @@ config :pleroma, :config_description, [
             label: "Subject line behavior",
             type: :string,
             description: "Allows changing the default behaviour of subject lines in replies.
-          `email`: Copy and preprend re:, as in email,
-          `masto`: Copy verbatim, as in Mastodon,
-          `noop`: Don't copy the subjec",
+          `email`: copy and preprend re:, as in email,
+          `masto`: copy verbatim, as in Mastodon,
+          `noop`: don't copy the subject.",
             suggestions: ["email", "masto", "noop"]
           },
           %{
             key: :alwaysShowSubjectInput,
             label: "Always show subject input",
             type: :boolean,
-            description: "When set to false, auto-hide the subject field when it's empty"
+            description: "When set to `false`, auto-hide the subject field when it's empty"
+          },
+          %{
+            key: :logoMask,
+            label: "Logo mask",
+            type: :boolean,
+            description:
+              "By default it assumes logo used will be monochrome-with-alpha one, this is done to be compatible with both light and dark themes, " <>
+                "so that white logo designed with dark theme in mind won't be invisible over light theme, this is done via CSS3 Masking. " <>
+                "Basically - it will take alpha channel of the image and fill non-transparent areas of it with solid color. " <>
+                "If you really want colorful logo - it can be done by setting logoMask to false."
+          },
+          %{
+            key: :logoMargin,
+            label: "Logo margin",
+            type: :string,
+            description:
+              "allows you to adjust vertical margins between logo boundary and navbar borders. " <>
+                "The idea is that to have logo's image without any extra margins and instead adjust them to your need in layout.",
+            suggestions: [".1em"]
+          },
+          %{
+            key: :stickers,
+            type: :boolean,
+            description: "Enables/disables stickers."
+          },
+          %{
+            key: :enableEmojiPicker,
+            label: "Emoji picker",
+            type: :boolean,
+            description: "Enables/disables emoji picker."
           }
         ]
       },
@@ -1182,7 +1216,7 @@ config :pleroma, :config_description, [
         key: :mascots,
         type: {:keyword, :map},
         description:
-          "Keyword of mascots, each element MUST contain both a url and a mime_type key",
+          "Keyword of mascots, each element must contain both an url and a mime_type key",
         suggestions: [
           pleroma_fox_tan: %{
             url: "/images/pleroma-fox-tan-smol.png",
@@ -1198,7 +1232,7 @@ config :pleroma, :config_description, [
         key: :default_mascot,
         type: :atom,
         description:
-          "This will be used as the default mascot on MastoFE (default: :pleroma_fox_tan)",
+          "This will be used as the default mascot on MastoFE. Default: `:pleroma_fox_tan`",
         suggestions: [
           :pleroma_fox_tan
         ]
@@ -1261,7 +1295,7 @@ config :pleroma, :config_description, [
         key: :media_nsfw,
         label: "Media NSFW",
         type: {:list, :string},
-        description: "List of instances to put medias as NSFW(sensitive) from",
+        description: "List of instances to put medias as NSFW (sensitive) from",
         suggestions: ["example.com", "*.example.com"]
       },
       %{
@@ -1336,12 +1370,12 @@ config :pleroma, :config_description, [
         key: :allow_followersonly,
         label: "Allow followers-only",
         type: :boolean,
-        description: "whether to allow followers-only posts"
+        description: "Whether to allow followers-only posts"
       },
       %{
         key: :allow_direct,
         type: :boolean,
-        description: "whether to allow direct messages"
+        description: "Whether to allow direct messages"
       }
     ]
   },
@@ -1357,14 +1391,14 @@ config :pleroma, :config_description, [
         type: :integer,
         description:
           "Number of mentioned users after which the message gets delisted (the message can still be seen, " <>
-            " but it will not show up in public timelines and mentioned users won't get notifications about it). Set to 0 to disable",
+            " but it will not show up in public timelines and mentioned users won't get notifications about it). Set to 0 to disable.",
         suggestions: [10]
       },
       %{
         key: :reject_threshold,
         type: :integer,
         description:
-          "Number of mentioned users after which the messaged gets rejected. Set to 0 to disable",
+          "Number of mentioned users after which the messaged gets rejected. Set to 0 to disable.",
         suggestions: [20]
       }
     ]
@@ -1380,14 +1414,14 @@ config :pleroma, :config_description, [
         key: :reject,
         type: [:string, :regex],
         description:
-          "A list of patterns which result in message being rejected, each pattern can be a string or a regular expression",
+          "A list of patterns which result in message being rejected, each pattern can be a string or a regular expression.",
         suggestions: ["foo", ~r/foo/iu]
       },
       %{
         key: :federated_timeline_removal,
         type: [:string, :regex],
         description:
-          "A list of patterns which result in message being removed from federated timelines (a.k.a unlisted), each pattern can be a string or a regular expression",
+          "A list of patterns which result in message being removed from federated timelines (a.k.a unlisted), each pattern can be a string or a regular expression.",
         suggestions: ["foo", ~r/foo/iu]
       },
       %{
@@ -1466,7 +1500,7 @@ config :pleroma, :config_description, [
         key: :base_url,
         type: :string,
         description:
-          "The base URL to access a user-uploaded file. Useful when you want to proxy the media files via another host/CDN fronts",
+          "The base URL to access a user-uploaded file. Useful when you want to proxy the media files via another host/CDN fronts.",
         suggestions: ["https://example.com"]
       },
       %{
@@ -1487,14 +1521,14 @@ config :pleroma, :config_description, [
             type: :boolean,
             description:
               "Redirects the client to the real remote URL if there's any HTTP errors. " <>
-                "Any error during body processing will not be redirected as the response is chunked"
+                "Any error during body processing will not be redirected as the response is chunked."
           },
           %{
             key: :max_body_length,
             type: :integer,
             description:
-              "limits the content length to be approximately the " <>
-                "specified length. It is validated with the `content-length` header and also verified when proxying"
+              "Limits the content length to be approximately the " <>
+                "specified length. It is validated with the `content-length` header and also verified when proxying."
           },
           %{
             key: :http,
@@ -1812,9 +1846,9 @@ config :pleroma, :config_description, [
         key: :subject,
         type: :string,
         description:
-          "a mailto link for the administrative contact." <>
+          "A mailto link for the administrative contact." <>
             " It's best if this email is not a personal email address, but rather a group email so that if a person leaves an organization," <>
-            " is unavailable for an extended period, or otherwise can't respond, someone else on the list can",
+            " is unavailable for an extended period, or otherwise can't respond, someone else on the list can.",
         suggestions: ["Subject"]
       },
       %{
@@ -1862,12 +1896,12 @@ config :pleroma, :config_description, [
     type: :group,
     description:
       "Kocaptcha is a very simple captcha service with a single API endpoint, the source code is" <>
-        " here: https://github.com/koto-bank/kocaptcha. The default endpoint https://captcha.kotobank.ch is hosted by the developer",
+        " here: https://github.com/koto-bank/kocaptcha. The default endpoint (https://captcha.kotobank.ch) is hosted by the developer.",
     children: [
       %{
         key: :endpoint,
         type: :string,
-        description: "the kocaptcha endpoint to use",
+        description: "The kocaptcha endpoint to use",
         suggestions: ["https://captcha.kotobank.ch"]
       }
     ]
@@ -1876,7 +1910,7 @@ config :pleroma, :config_description, [
     group: :pleroma,
     type: :group,
     description:
-      "Allows to set a token that can be used to authenticate with the admin api without using an actual user by giving it as the 'admin_token' parameter",
+      "Allows to set a token that can be used to authenticate with the admin api without using an actual user by giving it as the `admin_token` parameter",
     children: [
       %{
         key: :admin_token,
@@ -1926,8 +1960,9 @@ config :pleroma, :config_description, [
       },
       %{
         key: :verbose,
-        type: :boolean,
-        description: "Logs verbose mode"
+        type: :atom,
+        description: "Logs verbose mode",
+        suggestions: [false, :error, :warn, :info, :debug]
       },
       %{
         key: :prune,
@@ -2042,7 +2077,7 @@ config :pleroma, :config_description, [
         key: :unfurl_nsfw,
         label: "Unfurl NSFW",
         type: :boolean,
-        description: "If set to true nsfw attachments will be shown in previews"
+        description: "If set to `true` NSFW attachments will be shown in previews"
       }
     ]
   },
@@ -2086,7 +2121,7 @@ config :pleroma, :config_description, [
         key: :ttl_setters,
         label: "TTL setters",
         type: {:list, :module},
-        description: "List of rich media ttl setters.",
+        description: "List of rich media TTL setters.",
         suggestions: [
           Pleroma.Web.RichMedia.Parser.TTL.AwsSignedUrl
         ]
@@ -2103,12 +2138,12 @@ config :pleroma, :config_description, [
         key: :enabled,
         type: :boolean,
         description:
-          "if enabled, when a new user is federated with, fetch some of their latest posts"
+          "If enabled, when a new user is federated with, fetch some of their latest posts"
       },
       %{
         key: :pages,
         type: :integer,
-        description: "the amount of pages to fetch",
+        description: "The amount of pages to fetch",
         suggestions: [5]
       }
     ]
@@ -2122,24 +2157,24 @@ config :pleroma, :config_description, [
       %{
         key: :class,
         type: [:string, false],
-        description: "specify the class to be added to the generated link. false to clear",
+        description: "Specify the class to be added to the generated link. `False` to clear",
         suggestions: ["auto-linker", false]
       },
       %{
         key: :rel,
         type: [:string, false],
-        description: "override the rel attribute. false to clear",
+        description: "Override the rel attribute. `False` to clear",
         suggestions: ["ugc", "noopener noreferrer", false]
       },
       %{
         key: :new_window,
         type: :boolean,
-        description: "set to false to remove target='_blank' attribute"
+        description: "Set to `false` to remove target='_blank' attribute"
       },
       %{
         key: :scheme,
         type: :boolean,
-        description: "Set to true to link urls with schema http://google.com"
+        description: "Set to `true` to link urls with schema http://google.com"
       },
       %{
         key: :truncate,
@@ -2156,7 +2191,7 @@ config :pleroma, :config_description, [
       %{
         key: :extra,
         type: :boolean,
-        description: "link urls with rarely used schemes (magnet, ipfs, irc, etc.)"
+        description: "Link urls with rarely used schemes (magnet, ipfs, irc, etc.)"
       }
     ]
   },
@@ -2170,20 +2205,20 @@ config :pleroma, :config_description, [
         key: :daily_user_limit,
         type: :integer,
         description:
-          "the number of scheduled activities a user is allowed to create in a single day (Default: 25)",
+          "The number of scheduled activities a user is allowed to create in a single day. Default: 25.",
         suggestions: [25]
       },
       %{
         key: :total_user_limit,
         type: :integer,
         description:
-          "the number of scheduled activities a user is allowed to create in total (Default: 300)",
+          "The number of scheduled activities a user is allowed to create in total. Default: 300.",
         suggestions: [300]
       },
       %{
         key: :enabled,
         type: :boolean,
-        description: "whether scheduled activities are sent to the job queue to be executed"
+        description: "Whether scheduled activities are sent to the job queue to be executed"
       }
     ]
   },
@@ -2196,7 +2231,7 @@ config :pleroma, :config_description, [
       %{
         key: :enabled,
         type: :boolean,
-        description: "whether expired activities will be sent to the job queue to be deleted"
+        description: "Whether expired activities will be sent to the job queue to be deleted"
       }
     ]
   },
@@ -2218,14 +2253,14 @@ config :pleroma, :config_description, [
     type: :group,
     description:
       "Use LDAP for user authentication. When a user logs in to the Pleroma instance, the name and password" <>
-        " will be verified by trying to authenticate (bind) to an LDAP server." <>
+        " will be verified by trying to authenticate (bind) to a LDAP server." <>
         " If a user exists in the LDAP directory but there is no account with the same name yet on the" <>
         " Pleroma instance then a new Pleroma account will be created with the same name as the LDAP user name.",
     children: [
       %{
         key: :enabled,
         type: :boolean,
-        description: "enables LDAP authentication"
+        description: "Enables LDAP authentication"
       },
       %{
         key: :host,
@@ -2243,13 +2278,13 @@ config :pleroma, :config_description, [
         key: :ssl,
         label: "SSL",
         type: :boolean,
-        description: "true to use SSL, usually implies the port 636"
+        description: "`True` to use SSL, usually implies the port 636"
       },
       %{
         key: :sslopts,
         label: "SSL options",
         type: :keyword,
-        description: "additional SSL options",
+        description: "Additional SSL options",
         suggestions: [cacertfile: "path/to/file/with/PEM/cacerts", verify: :verify_peer],
         children: [
           %{
@@ -2270,13 +2305,13 @@ config :pleroma, :config_description, [
         key: :tls,
         label: "TLS",
         type: :boolean,
-        description: "true to start TLS, usually implies the port 389"
+        description: "`True` to start TLS, usually implies the port 389"
       },
       %{
         key: :tlsopts,
         label: "TLS options",
         type: :keyword,
-        description: "additional TLS options",
+        description: "Additional TLS options",
         suggestions: [cacertfile: "path/to/file/with/PEM/cacerts", verify: :verify_peer],
         children: [
           %{
@@ -2327,23 +2362,23 @@ config :pleroma, :config_description, [
         key: :auth_template,
         type: :string,
         description:
-          "authentication form template. By default it's show.html which corresponds to lib/pleroma/web/templates/o_auth/o_auth/show.html.ee",
+          "Authentication form template. By default it's `show.html` which corresponds to `lib/pleroma/web/templates/o_auth/o_auth/show.html.ee`.",
         suggestions: ["show.html"]
       },
       %{
         key: :oauth_consumer_template,
         type: :string,
         description:
-          "OAuth consumer mode authentication form template. By default it's consumer.html which corresponds to" <>
-            " lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex",
+          "OAuth consumer mode authentication form template. By default it's `consumer.html` which corresponds to" <>
+            " `lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex`.",
         suggestions: ["consumer.html"]
       },
       %{
         key: :oauth_consumer_strategies,
         type: {:list, :string},
         description:
-          "the list of enabled OAuth consumer strategies; by default it's set by OAUTH_CONSUMER_STRATEGIES environment variable." <>
-            " Each entry in this space-delimited string should be of format <strategy> or <strategy>:<dependency>" <>
+          "The list of enabled OAuth consumer strategies; by default it's set by OAUTH_CONSUMER_STRATEGIES environment variable." <>
+            " Each entry in this space-delimited string should be of format \"strategy\" or \"strategy:dependency\"" <>
             " (e.g. twitter or keycloak:ueberauth_keycloak_strategy in case dependency is named differently than ueberauth_<strategy>).",
         suggestions: ["twitter", "keycloak:ueberauth_keycloak_strategy"]
       }
@@ -2372,13 +2407,13 @@ config :pleroma, :config_description, [
           %{
             key: :active,
             type: :boolean,
-            description: "globally enable or disable digest emails"
+            description: "Globally enable or disable digest emails"
           },
           %{
             key: :schedule,
             type: :string,
             description:
-              "When to send digest email, in crontab format. \"0 0 0\" is the default, meaning \"once a week at midnight on Sunday morning\"",
+              "When to send digest email, in crontab format. \"0 0 0\" is the default, meaning \"once a week at midnight on Sunday morning\".",
             suggestions: ["0 0 * * 0"]
           },
           %{
@@ -2406,7 +2441,7 @@ config :pleroma, :config_description, [
       %{
         key: :logo,
         type: :string,
-        description: "a path to a custom logo. Set it to nil to use the default Pleroma logo",
+        description: "A path to a custom logo. Set it to `nil` to use the default Pleroma logo.",
         suggestions: ["some/path/logo.png"]
       },
       %{
@@ -2479,13 +2514,13 @@ config :pleroma, :config_description, [
       %{
         key: :clean_expired_tokens,
         type: :boolean,
-        description: "Enable a background job to clean expired oauth tokens. Defaults to false"
+        description: "Enable a background job to clean expired oauth tokens. Default: `false`."
       },
       %{
         key: :clean_expired_tokens_interval,
         type: :integer,
         description:
-          "Interval to run the job to clean expired tokens. Defaults to 86_400_000 (24 hours).",
+          "Interval to run the job to clean expired tokens. Default: 86_400_000 (24 hours).",
         suggestions: [86_400_000]
       }
     ]
@@ -2498,7 +2533,7 @@ config :pleroma, :config_description, [
       %{
         key: :shortcode_globs,
         type: {:list, :string},
-        description: "Location of custom emoji files. * can be used as a wildcard",
+        description: "Location of custom emoji files. * can be used as a wildcard.",
         suggestions: ["/emoji/custom/**/*.png"]
       },
       %{
@@ -2512,8 +2547,8 @@ config :pleroma, :config_description, [
         key: :groups,
         type: {:keyword, :string, {:list, :string}},
         description:
-          "Emojis are ordered in groups (tags). This is an array of key-value pairs where the key is the groupname" <>
-            " and the value the location or array of locations. * can be used as a wildcard",
+          "Emojis are ordered in groups (tags). This is an array of key-value pairs where the key is the group name" <>
+            " and the value is the location or array of locations. * can be used as a wildcard.",
         suggestions: [
           Custom: ["/emoji/*.png", "/emoji/**/*.png"]
         ]
@@ -2523,7 +2558,7 @@ config :pleroma, :config_description, [
         type: :string,
         description:
           "Location of the JSON-manifest. This manifest contains information about the emoji-packs you can download." <>
-            " Currently only one manifest can be added (no arrays)",
+            " Currently only one manifest can be added (no arrays).",
         suggestions: ["https://git.pleroma.social/pleroma/emoji-index/raw/master/index.json"]
       },
       %{
@@ -2546,7 +2581,7 @@ config :pleroma, :config_description, [
       %{
         key: :rum_enabled,
         type: :boolean,
-        description: "If RUM indexes should be used. Defaults to false"
+        description: "If RUM indexes should be used. Default: `false`"
       }
     ]
   },
@@ -2560,45 +2595,45 @@ config :pleroma, :config_description, [
       %{
         key: :search,
         type: [:tuple, {:list, :tuple}],
-        description: "for the search requests (account & status search etc.)",
+        description: "For the search requests (account & status search etc.)",
         suggestions: [{1000, 10}, [{10_000, 10}, {10_000, 50}]]
       },
       %{
         key: :app_account_creation,
         type: [:tuple, {:list, :tuple}],
-        description: "for registering user accounts from the same IP address",
+        description: "For registering user accounts from the same IP address",
         suggestions: [{1000, 10}, [{10_000, 10}, {10_000, 50}]]
       },
       %{
         key: :relations_actions,
         type: [:tuple, {:list, :tuple}],
-        description: "for actions on relations with all users (follow, unfollow)",
+        description: "For actions on relations with all users (follow, unfollow)",
         suggestions: [{1000, 10}, [{10_000, 10}, {10_000, 50}]]
       },
       %{
         key: :relation_id_action,
         type: [:tuple, {:list, :tuple}],
-        description: "for actions on relation with a specific user (follow, unfollow)",
+        description: "For actions on relation with a specific user (follow, unfollow)",
         suggestions: [{1000, 10}, [{10_000, 10}, {10_000, 50}]]
       },
       %{
         key: :statuses_actions,
         type: [:tuple, {:list, :tuple}],
         description:
-          "for create / delete / fav / unfav / reblog / unreblog actions on any statuses",
+          "For create / delete / fav / unfav / reblog / unreblog actions on any statuses",
         suggestions: [{1000, 10}, [{10_000, 10}, {10_000, 50}]]
       },
       %{
         key: :status_id_action,
         type: [:tuple, {:list, :tuple}],
         description:
-          "for fav / unfav or reblog / unreblog actions on the same status by the same user",
+          "For fav / unfav or reblog / unreblog actions on the same status by the same user",
         suggestions: [{1000, 10}, [{10_000, 10}, {10_000, 50}]]
       },
       %{
         key: :authentication,
         type: [:tuple, {:list, :tuple}],
-        description: "for authentication create / password check / user existence check requests",
+        description: "For authentication create / password check / user existence check requests",
         suggestions: [{60_000, 15}]
       }
     ]
@@ -2613,12 +2648,12 @@ config :pleroma, :config_description, [
       %{
         key: :enabled,
         type: :boolean,
-        description: "Enables ssh"
+        description: "Enables SSH"
       },
       %{
         key: :priv_dir,
         type: :string,
-        description: "Dir with ssh keys",
+        description: "Dir with SSH keys",
         suggestions: ["/some/path/ssh_keys"]
       },
       %{
@@ -2797,7 +2832,7 @@ config :pleroma, :config_description, [
         key: :user_agent,
         type: [:string, :atom],
         description:
-          "What user agent to use. Must be a string or an atom `:default`. Default value is `:default`",
+          "What user agent to use. Must be a string or an atom `:default`. Default value is `:default`.",
         suggestions: ["Pleroma", :default]
       },
       %{
@@ -2969,19 +3004,19 @@ config :pleroma, :config_description, [
       %{
         key: :enabled,
         type: :boolean,
-        description: "Enable/disable the plug. Defaults to `false`."
+        description: "Enable/disable the plug. Default: `false`."
       },
       %{
         key: :headers,
         type: {:list, :string},
         description:
-          "A list of strings naming the `req_headers` to use when deriving the `remote_ip`. Order does not matter. Defaults to `~w[forwarded x-forwarded-for x-client-ip x-real-ip]`."
+          "A list of strings naming the `req_headers` to use when deriving the `remote_ip`. Order does not matter. Default: `~w[forwarded x-forwarded-for x-client-ip x-real-ip]`."
       },
       %{
         key: :proxies,
         type: {:list, :string},
         description:
-          "A list of strings in [CIDR](https://en.wikipedia.org/wiki/CIDR) notation specifying the IPs of known proxies. Defaults to `[]`."
+          "A list of strings in [CIDR](https://en.wikipedia.org/wiki/CIDR) notation specifying the IPs of known proxies. Default: `[]`."
       },
       %{
         key: :reserved,
@@ -3002,14 +3037,13 @@ config :pleroma, :config_description, [
         key: :activity_pub,
         type: :integer,
         description:
-          "activity pub routes (except question activities). Defaults to `nil` (no expiration).",
-        suggestions: [30_000]
+          "Activity pub routes (except question activities). Default: `nil` (no expiration).",
+        suggestions: [30_000, nil]
       },
       %{
         key: :activity_pub_question,
         type: :integer,
-        description:
-          "activity pub routes (question activities). Defaults to `30_000` (30 seconds).",
+        description: "Activity pub routes (question activities). Default: `30_000` (30 seconds).",
         suggestions: [30_000]
       }
     ]

From f72727a40992d518eb2d2c5a1ad7ade15cd57a8f Mon Sep 17 00:00:00 2001
From: Alexander Strizhakov <alex.strizhakov@gmail.com>
Date: Mon, 27 Jan 2020 12:53:21 +0300
Subject: [PATCH 5/6] little fixes

---
 config/description.exs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/config/description.exs b/config/description.exs
index 531f5d7e7..b9b696e42 100644
--- a/config/description.exs
+++ b/config/description.exs
@@ -1167,7 +1167,7 @@ config :pleroma, :config_description, [
             label: "Logo margin",
             type: :string,
             description:
-              "allows you to adjust vertical margins between logo boundary and navbar borders. " <>
+              "Allows you to adjust vertical margins between logo boundary and navbar borders. " <>
                 "The idea is that to have logo's image without any extra margins and instead adjust them to your need in layout.",
             suggestions: [".1em"]
           },
@@ -1960,7 +1960,7 @@ config :pleroma, :config_description, [
       },
       %{
         key: :verbose,
-        type: :atom,
+        type: [:atom, false],
         description: "Logs verbose mode",
         suggestions: [false, :error, :warn, :info, :debug]
       },

From dabd535e436789e64f6630460bfadd2f49dcf069 Mon Sep 17 00:00:00 2001
From: Hakaba Hitoyo <hakabahitoyo@yahoo.co.jp>
Date: Mon, 27 Jan 2020 13:21:50 +0000
Subject: [PATCH 6/6] Remove user recommendation by third party engine

---
 CHANGELOG.md                                  |  1 +
 config/config.exs                             |  8 ---
 config/description.exs                        | 37 ------------
 .../configuration/howto_user_recomendation.md | 31 ----------
 .../controllers/suggestion_controller.ex      | 58 +------------------
 .../web/nodeinfo/nodeinfo_controller.ex       |  9 +--
 .../suggestion_controller_test.exs            | 45 +-------------
 7 files changed, 5 insertions(+), 184 deletions(-)
 delete mode 100644 docs/configuration/howto_user_recomendation.md

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4d626a683..8d9f7d1b5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 - **Breaking**: Removed 1.0+ deprecated configurations `Pleroma.Upload, :strip_exif` and `:instance, :dedupe_media`
 - **Breaking**: OStatus protocol support
 - **Breaking**: MDII uploader
+- **Breaking**: Using third party engines for user recommendation
 
 ### Changed
 - **Breaking:** Pleroma won't start if it detects unapplied migrations
diff --git a/config/config.exs b/config/config.exs
index 2c154eb45..f4e307e18 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -425,14 +425,6 @@ config :pleroma, Pleroma.Web.Metadata,
   ],
   unfurl_nsfw: false
 
-config :pleroma, :suggestions,
-  enabled: false,
-  third_party_engine:
-    "http://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-suggestions-api.cgi?{{host}}+{{user}}",
-  timeout: 300_000,
-  limit: 40,
-  web: "https://vinayaka.distsn.org"
-
 config :pleroma, :http_security,
   enabled: true,
   sts: false,
diff --git a/config/description.exs b/config/description.exs
index b9b696e42..5f3c58b08 100644
--- a/config/description.exs
+++ b/config/description.exs
@@ -2748,43 +2748,6 @@ config :pleroma, :config_description, [
       }
     ]
   },
-  %{
-    group: :pleroma,
-    key: :suggestions,
-    type: :group,
-    children: [
-      %{
-        key: :enabled,
-        type: :boolean,
-        description: "Enables suggestions"
-      },
-      %{
-        key: :third_party_engine,
-        type: :string,
-        description: "URL for third party engine",
-        suggestions: [
-          "http://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-suggestions-api.cgi?{{host}}+{{user}}"
-        ]
-      },
-      %{
-        key: :timeout,
-        type: :integer,
-        description: "Request timeout to third party engine",
-        suggestions: [300_000]
-      },
-      %{
-        key: :limit,
-        type: :integer,
-        description: "Limit for suggestions",
-        suggestions: [40]
-      },
-      %{
-        key: :web,
-        type: :string,
-        suggestions: ["https://vinayaka.distsn.org"]
-      }
-    ]
-  },
   %{
     group: :prometheus,
     key: Pleroma.Web.Endpoint.MetricsExporter,
diff --git a/docs/configuration/howto_user_recomendation.md b/docs/configuration/howto_user_recomendation.md
deleted file mode 100644
index c4d749d0c..000000000
--- a/docs/configuration/howto_user_recomendation.md
+++ /dev/null
@@ -1,31 +0,0 @@
-# How to activate user recommendation (Who to follow panel)
-![who-to-follow-panel-small](/uploads/9de1b1300436c32461d272945f1bc23e/who-to-follow-panel-small.png)
-
-To show the *who to follow* panel, edit `config/prod.secret.exs` in the Pleroma backend. Following code activates the *who to follow* panel:
-
-```elixir
-config :pleroma, :suggestions,
-  enabled: true,
-  third_party_engine:
-    "http://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-suggestions-api.cgi?{{host}}+{{user}}",
-  timeout: 300_000,
-  limit: 40,
-  web: "https://vinayaka.distsn.org"
-
-```
-
-`config/config.exs` already includes this code, but `enabled:` is `false`.
-
-`/api/v1/suggestions` is also provided when *who to follow* panel is enabled.
-
-For advanced customization, following code shows the newcomers of the fediverse at the *who to follow* panel:
-
-```elixir
-config :pleroma, :suggestions,
-  enabled: true,
-  third_party_engine:
-    "http://vinayaka.distsn.org/cgi-bin/vinayaka-user-new-suggestions-api.cgi?{{host}}+{{user}}",
-  timeout: 60_000,
-  limit: 40,
-  web: "https://vinayaka.distsn.org/user-new.html"
-```
diff --git a/lib/pleroma/web/mastodon_api/controllers/suggestion_controller.ex b/lib/pleroma/web/mastodon_api/controllers/suggestion_controller.ex
index fe71c36af..b9cc8f104 100644
--- a/lib/pleroma/web/mastodon_api/controllers/suggestion_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/suggestion_controller.ex
@@ -7,62 +7,8 @@ defmodule Pleroma.Web.MastodonAPI.SuggestionController do
 
   require Logger
 
-  alias Pleroma.Config
-  alias Pleroma.Plugs.OAuthScopesPlug
-  alias Pleroma.User
-  alias Pleroma.Web.MediaProxy
-
-  action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
-
-  plug(OAuthScopesPlug, %{scopes: ["read"]} when action == :index)
-
-  plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug)
-
   @doc "GET /api/v1/suggestions"
-  def index(%{assigns: %{user: user}} = conn, _) do
-    if Config.get([:suggestions, :enabled], false) do
-      with {:ok, data} <- fetch_suggestions(user) do
-        limit = Config.get([:suggestions, :limit], 23)
-
-        data =
-          data
-          |> Enum.slice(0, limit)
-          |> Enum.map(fn x ->
-            x
-            |> Map.put("id", fetch_suggestion_id(x))
-            |> Map.put("avatar", MediaProxy.url(x["avatar"]))
-            |> Map.put("avatar_static", MediaProxy.url(x["avatar_static"]))
-          end)
-
-        json(conn, data)
-      end
-    else
-      json(conn, [])
-    end
-  end
-
-  defp fetch_suggestions(user) do
-    api = Config.get([:suggestions, :third_party_engine], "")
-    timeout = Config.get([:suggestions, :timeout], 5000)
-    host = Config.get([Pleroma.Web.Endpoint, :url, :host])
-
-    url =
-      api
-      |> String.replace("{{host}}", host)
-      |> String.replace("{{user}}", user.nickname)
-
-    with {:ok, %{status: 200, body: body}} <-
-           Pleroma.HTTP.get(url, [], adapter: [recv_timeout: timeout, pool: :default]) do
-      Jason.decode(body)
-    else
-      e -> Logger.error("Could not retrieve suggestions at fetch #{url}, #{inspect(e)}")
-    end
-  end
-
-  defp fetch_suggestion_id(attrs) do
-    case User.get_or_fetch(attrs["acct"]) do
-      {:ok, %User{id: id}} -> id
-      _ -> 0
-    end
+  def index(conn, _) do
+    json(conn, [])
   end
 end
diff --git a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex
index abcf46034..03c35cc2a 100644
--- a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex
+++ b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex
@@ -69,9 +69,6 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do
         if Config.get([:chat, :enabled]) do
           "chat"
         end,
-        if Config.get([:suggestions, :enabled]) do
-          "suggestions"
-        end,
         if Config.get([:instance, :allow_relay]) do
           "relay"
         end,
@@ -104,11 +101,7 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do
         nodeDescription: Config.get([:instance, :description]),
         private: !Config.get([:instance, :public], true),
         suggestions: %{
-          enabled: Config.get([:suggestions, :enabled], false),
-          thirdPartyEngine: Config.get([:suggestions, :third_party_engine], ""),
-          timeout: Config.get([:suggestions, :timeout], 5000),
-          limit: Config.get([:suggestions, :limit], 23),
-          web: Config.get([:suggestions, :web], "")
+          enabled: false
         },
         staffAccounts: staff_accounts,
         federation: federation_response,
diff --git a/test/web/mastodon_api/controllers/suggestion_controller_test.exs b/test/web/mastodon_api/controllers/suggestion_controller_test.exs
index c4118a576..c288c2fff 100644
--- a/test/web/mastodon_api/controllers/suggestion_controller_test.exs
+++ b/test/web/mastodon_api/controllers/suggestion_controller_test.exs
@@ -36,11 +36,7 @@ defmodule Pleroma.Web.MastodonAPI.SuggestionControllerTest do
     [other_user: other_user]
   end
 
-  clear_config(:suggestions)
-
-  test "returns empty result when suggestions disabled", %{conn: conn} do
-    Config.put([:suggestions, :enabled], false)
-
+  test "returns empty result", %{conn: conn} do
     res =
       conn
       |> get("/api/v1/suggestions")
@@ -48,43 +44,4 @@ defmodule Pleroma.Web.MastodonAPI.SuggestionControllerTest do
 
     assert res == []
   end
-
-  test "returns error", %{conn: conn} do
-    Config.put([:suggestions, :enabled], true)
-    Config.put([:suggestions, :third_party_engine], "http://test500?{{host}}&{{user}}")
-
-    assert capture_log(fn ->
-             res =
-               conn
-               |> get("/api/v1/suggestions")
-               |> json_response(500)
-
-             assert res == "Something went wrong"
-           end) =~ "Could not retrieve suggestions"
-  end
-
-  test "returns suggestions", %{conn: conn, other_user: other_user} do
-    Config.put([:suggestions, :enabled], true)
-    Config.put([:suggestions, :third_party_engine], "http://test200?{{host}}&{{user}}")
-
-    res =
-      conn
-      |> get("/api/v1/suggestions")
-      |> json_response(200)
-
-    assert res == [
-             %{
-               "acct" => "yj455",
-               "avatar" => "https://social.heldscal.la/avatar/201.jpeg",
-               "avatar_static" => "https://social.heldscal.la/avatar/s/201.jpeg",
-               "id" => 0
-             },
-             %{
-               "acct" => other_user.ap_id,
-               "avatar" => "https://social.heldscal.la/avatar/202.jpeg",
-               "avatar_static" => "https://social.heldscal.la/avatar/s/202.jpeg",
-               "id" => other_user.id
-             }
-           ]
-  end
 end