Runtime configurability of RateLimiter. Refactoring. Disabled default rate limits...
authorIvan Tashkinov <ivantashkinov@gmail.com>
Thu, 27 Feb 2020 15:46:05 +0000 (18:46 +0300)
committerIvan Tashkinov <ivantashkinov@gmail.com>
Thu, 27 Feb 2020 15:46:05 +0000 (18:46 +0300)
config/test.exs
docs/configuration/i2p.md
docs/configuration/onion_federation.md
lib/pleroma/plugs/rate_limiter/rate_limiter.ex
test/plugs/rate_limiter_test.exs
test/web/mastodon_api/controllers/account_controller_test.exs

index 6bea0938061cc7afa07e64923ed342808fd482c9..a17886265e44de5d938115601a906d825c9e832b 100644 (file)
@@ -74,11 +74,7 @@ config :pleroma, Pleroma.ScheduledActivity,
   total_user_limit: 3,
   enabled: false
 
-config :pleroma, :rate_limit,
-  search: [{1000, 30}, {1000, 30}],
-  app_account_creation: {10_000, 5},
-  password_reset: {1000, 30},
-  ap_routes: nil
+config :pleroma, :rate_limit, %{}
 
 config :pleroma, :http_security, report_uri: "https://endpoint.com"
 
index 62ced8b7a0e8feb7e2e582595802ef18acbd6796..8c5207d67d11c5a4214a2d74bfd654dba2332a84 100644 (file)
@@ -123,7 +123,7 @@ In addition to that, replace the existing nginx config's contents with the examp
 
 If not an I2P-only instance, add the nginx config below to your existing config at `/etc/nginx/sites-enabled/pleroma.nginx`.
 
-And for both cases, disable CSP in Pleroma's config (STS is disabled by default) so you can define those yourself seperately from the clearnet (if your instance is also on the clearnet).
+And for both cases, disable CSP in Pleroma's config (STS is disabled by default) so you can define those yourself separately from the clearnet (if your instance is also on the clearnet).
 Copy the following into the `config/prod.secret.exs` in your Pleroma folder (/home/pleroma/pleroma/):
 ```
 config :pleroma, :http_security,
index 99f104995bb1dadf2d3e6b0d404e4db6c187df30..37673211a2d83f562cfda17ff20c9989c3dc4601 100644 (file)
@@ -75,7 +75,7 @@ If not a Tor-only instance,
 add the nginx config below to your existing config at `/etc/nginx/sites-enabled/pleroma.nginx`.
 
 ---
-For both cases, disable CSP in Pleroma's config (STS is disabled by default) so you can define those yourself seperately from the clearnet (if your instance is also on the clearnet).
+For both cases, disable CSP in Pleroma's config (STS is disabled by default) so you can define those yourself separately from the clearnet (if your instance is also on the clearnet).
 Copy the following into the `config/prod.secret.exs` in your Pleroma folder (/home/pleroma/pleroma/):
 ```
 config :pleroma, :http_security,
index 7fb92489c4ff2822dea813337ee61e147a0105f1..d2067060d6e0d1f1113ce125aa713160d25b5ba5 100644 (file)
@@ -7,12 +7,14 @@ defmodule Pleroma.Plugs.RateLimiter do
 
   ## Configuration
 
-  A keyword list of rate limiters where a key is a limiter name and value is the limiter configuration. The basic configuration is a tuple where:
+  A keyword list of rate limiters where a key is a limiter name and value is the limiter configuration.
+  The basic configuration is a tuple where:
 
   * The first element: `scale` (Integer). The time scale in milliseconds.
   * The second element: `limit` (Integer). How many requests to limit in the time scale provided.
 
-  It is also possible to have different limits for unauthenticated and authenticated users: the keyword value must be a list of two tuples where the first one is a config for unauthenticated users and the second one is for authenticated.
+  It is also possible to have different limits for unauthenticated and authenticated users: the keyword value must be a
+  list of two tuples where the first one is a config for unauthenticated users and the second one is for authenticated.
 
   To disable a limiter set its value to `nil`.
 
@@ -64,91 +66,100 @@ defmodule Pleroma.Plugs.RateLimiter do
   import Pleroma.Web.TranslationHelpers
   import Plug.Conn
 
+  alias Pleroma.Config
   alias Pleroma.Plugs.RateLimiter.LimiterSupervisor
   alias Pleroma.User
 
   require Logger
 
-  def init(opts) do
-    limiter_name = Keyword.get(opts, :name)
-
-    case Pleroma.Config.get([:rate_limit, limiter_name]) do
-      nil ->
-        nil
-
-      config ->
-        name_root = Keyword.get(opts, :bucket_name, limiter_name)
+  @doc false
+  def init(plug_opts) do
+    plug_opts
+  end
 
-        %{
-          name: name_root,
-          limits: config,
-          opts: opts
-        }
+  def call(conn, plug_opts) do
+    if disabled?() do
+      handle_disabled(conn)
+    else
+      action_settings = action_settings(plug_opts)
+      handle(conn, action_settings)
     end
   end
 
-  # Do not limit if there is no limiter configuration
-  def call(conn, nil), do: conn
+  defp handle_disabled(conn) do
+    if Config.get(:env) == :prod do
+      Logger.warn("Rate limiter is disabled for localhost/socket")
+    end
+
+    conn
+  end
 
-  def call(conn, settings) do
-    case disabled?() do
-      true ->
-        if Pleroma.Config.get(:env) == :prod,
-          do: Logger.warn("Rate limiter is disabled for localhost/socket")
+  defp handle(conn, nil), do: conn
 
+  defp handle(conn, action_settings) do
+    action_settings
+    |> incorporate_conn_info(conn)
+    |> check_rate()
+    |> case do
+      {:ok, _count} ->
         conn
 
-      false ->
-        settings
-        |> incorporate_conn_info(conn)
-        |> check_rate()
-        |> case do
-          {:ok, _count} ->
-            conn
-
-          {:error, _count} ->
-            render_throttled_error(conn)
-        end
+      {:error, _count} ->
+        render_throttled_error(conn)
     end
   end
 
   def disabled? do
     localhost_or_socket =
-      Pleroma.Config.get([Pleroma.Web.Endpoint, :http, :ip])
+      Config.get([Pleroma.Web.Endpoint, :http, :ip])
       |> Tuple.to_list()
       |> Enum.join(".")
       |> String.match?(~r/^local|^127.0.0.1/)
 
-    remote_ip_disabled = not Pleroma.Config.get([Pleroma.Plugs.RemoteIp, :enabled])
+    remote_ip_disabled = not Config.get([Pleroma.Plugs.RemoteIp, :enabled])
 
     localhost_or_socket and remote_ip_disabled
   end
 
-  def inspect_bucket(conn, name_root, settings) do
-    settings =
-      settings
-      |> incorporate_conn_info(conn)
+  def inspect_bucket(conn, bucket_name_root, plug_opts) do
+    with %{name: _} = action_settings <- action_settings(plug_opts) do
+      action_settings = incorporate_conn_info(action_settings, conn)
+      bucket_name = make_bucket_name(%{action_settings | name: bucket_name_root})
+      key_name = make_key_name(action_settings)
+      limit = get_limits(action_settings)
 
-    bucket_name = make_bucket_name(%{settings | name: name_root})
-    key_name = make_key_name(settings)
-    limit = get_limits(settings)
+      case Cachex.get(bucket_name, key_name) do
+        {:error, :no_cache} ->
+          {:err, :not_found}
 
-    case Cachex.get(bucket_name, key_name) do
-      {:error, :no_cache} ->
-        {:err, :not_found}
+        {:ok, nil} ->
+          {0, limit}
+
+        {:ok, value} ->
+          {value, limit - value}
+      end
+    else
+      _ -> {:err, :not_found}
+    end
+  end
 
-      {:ok, nil} ->
-        {0, limit}
+  def action_settings(plug_opts) do
+    with limiter_name when not is_nil(limiter_name) <- plug_opts[:name],
+         limits when not is_nil(limits) <- Config.get([:rate_limit, limiter_name]) do
+      bucket_name_root = Keyword.get(plug_opts, :bucket_name, limiter_name)
 
-      {:ok, value} ->
-        {value, limit - value}
+      %{
+        name: bucket_name_root,
+        limits: limits,
+        opts: plug_opts
+      }
     end
   end
 
-  defp check_rate(settings) do
-    bucket_name = make_bucket_name(settings)
-    key_name = make_key_name(settings)
-    limit = get_limits(settings)
+  defp check_rate(action_settings) do
+    bucket_name = make_bucket_name(action_settings)
+    key_name = make_key_name(action_settings)
+    limit = get_limits(action_settings)
 
     case Cachex.get_and_update(bucket_name, key_name, &increment_value(&1, limit)) do
       {:commit, value} ->
@@ -158,8 +169,8 @@ defmodule Pleroma.Plugs.RateLimiter do
         {:error, value}
 
       {:error, :no_cache} ->
-        initialize_buckets(settings)
-        check_rate(settings)
+        initialize_buckets(action_settings)
+        check_rate(action_settings)
     end
   end
 
@@ -169,16 +180,19 @@ defmodule Pleroma.Plugs.RateLimiter do
 
   defp increment_value(val, _limit), do: {:commit, val + 1}
 
-  defp incorporate_conn_info(settings, %{assigns: %{user: %User{id: user_id}}, params: params}) do
-    Map.merge(settings, %{
+  defp incorporate_conn_info(action_settings, %{
+         assigns: %{user: %User{id: user_id}},
+         params: params
+       }) do
+    Map.merge(action_settings, %{
       mode: :user,
       conn_params: params,
       conn_info: "#{user_id}"
     })
   end
 
-  defp incorporate_conn_info(settings, %{params: params} = conn) do
-    Map.merge(settings, %{
+  defp incorporate_conn_info(action_settings, %{params: params} = conn) do
+    Map.merge(action_settings, %{
       mode: :anon,
       conn_params: params,
       conn_info: "#{ip(conn)}"
@@ -197,10 +211,10 @@ defmodule Pleroma.Plugs.RateLimiter do
     |> halt()
   end
 
-  defp make_key_name(settings) do
+  defp make_key_name(action_settings) do
     ""
-    |> attach_params(settings)
-    |> attach_identity(settings)
+    |> attach_selected_params(action_settings)
+    |> attach_identity(action_settings)
   end
 
   defp get_scale(_, {scale, _}), do: scale
@@ -215,21 +229,23 @@ defmodule Pleroma.Plugs.RateLimiter do
 
   defp get_limits(%{limits: [{_, limit}, _]}), do: limit
 
-  defp make_bucket_name(%{mode: :user, name: name_root}),
-    do: user_bucket_name(name_root)
+  defp make_bucket_name(%{mode: :user, name: bucket_name_root}),
+    do: user_bucket_name(bucket_name_root)
 
-  defp make_bucket_name(%{mode: :anon, name: name_root}),
-    do: anon_bucket_name(name_root)
+  defp make_bucket_name(%{mode: :anon, name: bucket_name_root}),
+    do: anon_bucket_name(bucket_name_root)
 
-  defp attach_params(input, %{conn_params: conn_params, opts: opts}) do
-    param_string =
-      opts
+  defp attach_selected_params(input, %{conn_params: conn_params, opts: plug_opts}) do
+    params_string =
+      plug_opts
       |> Keyword.get(:params, [])
       |> Enum.sort()
       |> Enum.map(&Map.get(conn_params, &1, ""))
       |> Enum.join(":")
 
-    "#{input}#{param_string}"
+    [input, params_string]
+    |> Enum.join(":")
+    |> String.replace_leading(":", "")
   end
 
   defp initialize_buckets(%{name: _name, limits: nil}), do: :ok
@@ -245,6 +261,6 @@ defmodule Pleroma.Plugs.RateLimiter do
   defp attach_identity(base, %{mode: :anon, conn_info: conn_info}),
     do: "ip:#{base}:#{conn_info}"
 
-  defp user_bucket_name(name_root), do: "user:#{name_root}" |> String.to_atom()
-  defp anon_bucket_name(name_root), do: "anon:#{name_root}" |> String.to_atom()
+  defp user_bucket_name(bucket_name_root), do: "user:#{bucket_name_root}" |> String.to_atom()
+  defp anon_bucket_name(bucket_name_root), do: "anon:#{bucket_name_root}" |> String.to_atom()
 end
index 06ffa7b7037476dae35822526982748855714354..c0630c0393808dd0e17a46a9e03dc6594cc29363 100644 (file)
@@ -6,69 +6,79 @@ defmodule Pleroma.Plugs.RateLimiterTest do
   use ExUnit.Case, async: true
   use Plug.Test
 
+  alias Pleroma.Config
   alias Pleroma.Plugs.RateLimiter
 
   import Pleroma.Factory
+  import Pleroma.Tests.Helpers, only: [clear_config: 1, clear_config: 2]
 
   # Note: each example must work with separate buckets in order to prevent concurrency issues
 
+  clear_config([Pleroma.Web.Endpoint, :http, :ip])
+  clear_config(:rate_limit)
+
   describe "config" do
+    @limiter_name :test_init
+
+    clear_config([Pleroma.Plugs.RemoteIp, :enabled])
+
     test "config is required for plug to work" do
-      limiter_name = :test_init
-      Pleroma.Config.put([:rate_limit, limiter_name], {1, 1})
-      Pleroma.Config.put([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8})
+      Config.put([:rate_limit, @limiter_name], {1, 1})
+      Config.put([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8})
 
       assert %{limits: {1, 1}, name: :test_init, opts: [name: :test_init]} ==
-               RateLimiter.init(name: limiter_name)
-
-      assert nil == RateLimiter.init(name: :foo)
+               [name: @limiter_name]
+               |> RateLimiter.init()
+               |> RateLimiter.action_settings()
+
+      assert nil ==
+               [name: :nonexisting_limiter]
+               |> RateLimiter.init()
+               |> RateLimiter.action_settings()
     end
 
     test "it is disabled for localhost" do
-      limiter_name = :test_init
-      Pleroma.Config.put([:rate_limit, limiter_name], {1, 1})
-      Pleroma.Config.put([Pleroma.Web.Endpoint, :http, :ip], {127, 0, 0, 1})
-      Pleroma.Config.put([Pleroma.Plugs.RemoteIp, :enabled], false)
+      Config.put([:rate_limit, @limiter_name], {1, 1})
+      Config.put([Pleroma.Web.Endpoint, :http, :ip], {127, 0, 0, 1})
+      Config.put([Pleroma.Plugs.RemoteIp, :enabled], false)
 
       assert RateLimiter.disabled?() == true
     end
 
     test "it is disabled for socket" do
-      limiter_name = :test_init
-      Pleroma.Config.put([:rate_limit, limiter_name], {1, 1})
-      Pleroma.Config.put([Pleroma.Web.Endpoint, :http, :ip], {:local, "/path/to/pleroma.sock"})
-      Pleroma.Config.put([Pleroma.Plugs.RemoteIp, :enabled], false)
+      Config.put([:rate_limit, @limiter_name], {1, 1})
+      Config.put([Pleroma.Web.Endpoint, :http, :ip], {:local, "/path/to/pleroma.sock"})
+      Config.put([Pleroma.Plugs.RemoteIp, :enabled], false)
 
       assert RateLimiter.disabled?() == true
     end
 
     test "it is enabled for socket when remote ip is enabled" do
-      limiter_name = :test_init
-      Pleroma.Config.put([:rate_limit, limiter_name], {1, 1})
-      Pleroma.Config.put([Pleroma.Web.Endpoint, :http, :ip], {:local, "/path/to/pleroma.sock"})
-      Pleroma.Config.put([Pleroma.Plugs.RemoteIp, :enabled], true)
+      Config.put([:rate_limit, @limiter_name], {1, 1})
+      Config.put([Pleroma.Web.Endpoint, :http, :ip], {:local, "/path/to/pleroma.sock"})
+      Config.put([Pleroma.Plugs.RemoteIp, :enabled], true)
 
       assert RateLimiter.disabled?() == false
     end
 
     test "it restricts based on config values" do
-      limiter_name = :test_opts
+      limiter_name = :test_plug_opts
       scale = 80
       limit = 5
 
-      Pleroma.Config.put([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8})
-      Pleroma.Config.put([:rate_limit, limiter_name], {scale, limit})
+      Config.put([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8})
+      Config.put([:rate_limit, limiter_name], {scale, limit})
 
-      opts = RateLimiter.init(name: limiter_name)
+      plug_opts = RateLimiter.init(name: limiter_name)
       conn = conn(:get, "/")
 
       for i <- 1..5 do
-        conn = RateLimiter.call(conn, opts)
-        assert {^i, _} = RateLimiter.inspect_bucket(conn, limiter_name, opts)
+        conn = RateLimiter.call(conn, plug_opts)
+        assert {^i, _} = RateLimiter.inspect_bucket(conn, limiter_name, plug_opts)
         Process.sleep(10)
       end
 
-      conn = RateLimiter.call(conn, opts)
+      conn = RateLimiter.call(conn, plug_opts)
       assert %{"error" => "Throttled"} = Phoenix.ConnTest.json_response(conn, :too_many_requests)
       assert conn.halted
 
@@ -76,8 +86,8 @@ defmodule Pleroma.Plugs.RateLimiterTest do
 
       conn = conn(:get, "/")
 
-      conn = RateLimiter.call(conn, opts)
-      assert {1, 4} = RateLimiter.inspect_bucket(conn, limiter_name, opts)
+      conn = RateLimiter.call(conn, plug_opts)
+      assert {1, 4} = RateLimiter.inspect_bucket(conn, limiter_name, plug_opts)
 
       refute conn.status == Plug.Conn.Status.code(:too_many_requests)
       refute conn.resp_body
@@ -89,78 +99,81 @@ defmodule Pleroma.Plugs.RateLimiterTest do
     test "`bucket_name` option overrides default bucket name" do
       limiter_name = :test_bucket_name
 
-      Pleroma.Config.put([:rate_limit, limiter_name], {1000, 5})
-      Pleroma.Config.put([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8})
+      Config.put([:rate_limit, limiter_name], {1000, 5})
+      Config.put([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8})
 
       base_bucket_name = "#{limiter_name}:group1"
-      opts = RateLimiter.init(name: limiter_name, bucket_name: base_bucket_name)
+      plug_opts = RateLimiter.init(name: limiter_name, bucket_name: base_bucket_name)
 
       conn = conn(:get, "/")
 
-      RateLimiter.call(conn, opts)
-      assert {1, 4} = RateLimiter.inspect_bucket(conn, base_bucket_name, opts)
-      assert {:err, :not_found} = RateLimiter.inspect_bucket(conn, limiter_name, opts)
+      RateLimiter.call(conn, plug_opts)
+      assert {1, 4} = RateLimiter.inspect_bucket(conn, base_bucket_name, plug_opts)
+      assert {:err, :not_found} = RateLimiter.inspect_bucket(conn, limiter_name, plug_opts)
     end
 
     test "`params` option allows different queries to be tracked independently" do
       limiter_name = :test_params
-      Pleroma.Config.put([:rate_limit, limiter_name], {1000, 5})
-      Pleroma.Config.put([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8})
+      Config.put([:rate_limit, limiter_name], {1000, 5})
+      Config.put([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8})
 
-      opts = RateLimiter.init(name: limiter_name, params: ["id"])
+      plug_opts = RateLimiter.init(name: limiter_name, params: ["id"])
 
       conn = conn(:get, "/?id=1")
       conn = Plug.Conn.fetch_query_params(conn)
       conn_2 = conn(:get, "/?id=2")
 
-      RateLimiter.call(conn, opts)
-      assert {1, 4} = RateLimiter.inspect_bucket(conn, limiter_name, opts)
-      assert {0, 5} = RateLimiter.inspect_bucket(conn_2, limiter_name, opts)
+      RateLimiter.call(conn, plug_opts)
+      assert {1, 4} = RateLimiter.inspect_bucket(conn, limiter_name, plug_opts)
+      assert {0, 5} = RateLimiter.inspect_bucket(conn_2, limiter_name, plug_opts)
     end
 
     test "it supports combination of options modifying bucket name" do
       limiter_name = :test_options_combo
-      Pleroma.Config.put([:rate_limit, limiter_name], {1000, 5})
-      Pleroma.Config.put([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8})
+      Config.put([:rate_limit, limiter_name], {1000, 5})
+      Config.put([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8})
 
       base_bucket_name = "#{limiter_name}:group1"
-      opts = RateLimiter.init(name: limiter_name, bucket_name: base_bucket_name, params: ["id"])
+
+      plug_opts =
+        RateLimiter.init(name: limiter_name, bucket_name: base_bucket_name, params: ["id"])
+
       id = "100"
 
       conn = conn(:get, "/?id=#{id}")
       conn = Plug.Conn.fetch_query_params(conn)
       conn_2 = conn(:get, "/?id=#{101}")
 
-      RateLimiter.call(conn, opts)
-      assert {1, 4} = RateLimiter.inspect_bucket(conn, base_bucket_name, opts)
-      assert {0, 5} = RateLimiter.inspect_bucket(conn_2, base_bucket_name, opts)
+      RateLimiter.call(conn, plug_opts)
+      assert {1, 4} = RateLimiter.inspect_bucket(conn, base_bucket_name, plug_opts)
+      assert {0, 5} = RateLimiter.inspect_bucket(conn_2, base_bucket_name, plug_opts)
     end
   end
 
   describe "unauthenticated users" do
     test "are restricted based on remote IP" do
       limiter_name = :test_unauthenticated
-      Pleroma.Config.put([:rate_limit, limiter_name], [{1000, 5}, {1, 10}])
-      Pleroma.Config.put([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8})
+      Config.put([:rate_limit, limiter_name], [{1000, 5}, {1, 10}])
+      Config.put([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8})
 
-      opts = RateLimiter.init(name: limiter_name)
+      plug_opts = RateLimiter.init(name: limiter_name)
 
       conn = %{conn(:get, "/") | remote_ip: {127, 0, 0, 2}}
       conn_2 = %{conn(:get, "/") | remote_ip: {127, 0, 0, 3}}
 
       for i <- 1..5 do
-        conn = RateLimiter.call(conn, opts)
-        assert {^i, _} = RateLimiter.inspect_bucket(conn, limiter_name, opts)
+        conn = RateLimiter.call(conn, plug_opts)
+        assert {^i, _} = RateLimiter.inspect_bucket(conn, limiter_name, plug_opts)
         refute conn.halted
       end
 
-      conn = RateLimiter.call(conn, opts)
+      conn = RateLimiter.call(conn, plug_opts)
 
       assert %{"error" => "Throttled"} = Phoenix.ConnTest.json_response(conn, :too_many_requests)
       assert conn.halted
 
-      conn_2 = RateLimiter.call(conn_2, opts)
-      assert {1, 4} = RateLimiter.inspect_bucket(conn_2, limiter_name, opts)
+      conn_2 = RateLimiter.call(conn_2, plug_opts)
+      assert {1, 4} = RateLimiter.inspect_bucket(conn_2, limiter_name, plug_opts)
 
       refute conn_2.status == Plug.Conn.Status.code(:too_many_requests)
       refute conn_2.resp_body
@@ -175,37 +188,37 @@ defmodule Pleroma.Plugs.RateLimiterTest do
       :ok
     end
 
-    test "can have limits seperate from unauthenticated connections" do
-      limiter_name = :test_authenticated
+    test "can have limits separate from unauthenticated connections" do
+      limiter_name = :test_authenticated1
 
       scale = 50
       limit = 5
-      Pleroma.Config.put([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8})
-      Pleroma.Config.put([:rate_limit, limiter_name], [{1000, 1}, {scale, limit}])
+      Config.put([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8})
+      Config.put([:rate_limit, limiter_name], [{1000, 1}, {scale, limit}])
 
-      opts = RateLimiter.init(name: limiter_name)
+      plug_opts = RateLimiter.init(name: limiter_name)
 
       user = insert(:user)
       conn = conn(:get, "/") |> assign(:user, user)
 
       for i <- 1..5 do
-        conn = RateLimiter.call(conn, opts)
-        assert {^i, _} = RateLimiter.inspect_bucket(conn, limiter_name, opts)
+        conn = RateLimiter.call(conn, plug_opts)
+        assert {^i, _} = RateLimiter.inspect_bucket(conn, limiter_name, plug_opts)
         refute conn.halted
       end
 
-      conn = RateLimiter.call(conn, opts)
+      conn = RateLimiter.call(conn, plug_opts)
 
       assert %{"error" => "Throttled"} = Phoenix.ConnTest.json_response(conn, :too_many_requests)
       assert conn.halted
     end
 
-    test "diffrerent users are counted independently" do
-      limiter_name = :test_authenticated
-      Pleroma.Config.put([:rate_limit, limiter_name], [{1, 10}, {1000, 5}])
-      Pleroma.Config.put([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8})
+    test "different users are counted independently" do
+      limiter_name = :test_authenticated2
+      Config.put([:rate_limit, limiter_name], [{1, 10}, {1000, 5}])
+      Config.put([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8})
 
-      opts = RateLimiter.init(name: limiter_name)
+      plug_opts = RateLimiter.init(name: limiter_name)
 
       user = insert(:user)
       conn = conn(:get, "/") |> assign(:user, user)
@@ -214,16 +227,16 @@ defmodule Pleroma.Plugs.RateLimiterTest do
       conn_2 = conn(:get, "/") |> assign(:user, user_2)
 
       for i <- 1..5 do
-        conn = RateLimiter.call(conn, opts)
-        assert {^i, _} = RateLimiter.inspect_bucket(conn, limiter_name, opts)
+        conn = RateLimiter.call(conn, plug_opts)
+        assert {^i, _} = RateLimiter.inspect_bucket(conn, limiter_name, plug_opts)
       end
 
-      conn = RateLimiter.call(conn, opts)
+      conn = RateLimiter.call(conn, plug_opts)
       assert %{"error" => "Throttled"} = Phoenix.ConnTest.json_response(conn, :too_many_requests)
       assert conn.halted
 
-      conn_2 = RateLimiter.call(conn_2, opts)
-      assert {1, 4} = RateLimiter.inspect_bucket(conn_2, limiter_name, opts)
+      conn_2 = RateLimiter.call(conn_2, plug_opts)
+      assert {1, 4} = RateLimiter.inspect_bucket(conn_2, limiter_name, plug_opts)
       refute conn_2.status == Plug.Conn.Status.code(:too_many_requests)
       refute conn_2.resp_body
       refute conn_2.halted
index 8625bb9cf00ae410e2ba866df2c5e3c2be2f0315..b3e796d3791c57dd3332adbe66d6ddc88ea87aac 100644 (file)
@@ -673,10 +673,48 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
       assert json_response(res, 400) == %{"error" => "{\"email\":[\"has already been taken\"]}"}
     end
 
-    clear_config([Pleroma.Plugs.RemoteIp, :enabled])
+    test "returns bad_request if missing required params", %{
+      conn: conn,
+      valid_params: valid_params
+    } do
+      app_token = insert(:oauth_token, user: nil)
 
-    test "rate limit", %{conn: conn} do
+      conn = put_req_header(conn, "authorization", "Bearer " <> app_token.token)
+
+      res = post(conn, "/api/v1/accounts", valid_params)
+      assert json_response(res, 200)
+
+      [{127, 0, 0, 1}, {127, 0, 0, 2}, {127, 0, 0, 3}, {127, 0, 0, 4}]
+      |> Stream.zip(valid_params)
+      |> Enum.each(fn {ip, {attr, _}} ->
+        res =
+          conn
+          |> Map.put(:remote_ip, ip)
+          |> post("/api/v1/accounts", Map.delete(valid_params, attr))
+          |> json_response(400)
+
+        assert res == %{"error" => "Missing parameters"}
+      end)
+    end
+
+    test "returns forbidden if token is invalid", %{conn: conn, valid_params: valid_params} do
+      conn = put_req_header(conn, "authorization", "Bearer " <> "invalid-token")
+
+      res = post(conn, "/api/v1/accounts", valid_params)
+      assert json_response(res, 403) == %{"error" => "Invalid credentials"}
+    end
+  end
+
+  describe "create account by app / rate limit" do
+    clear_config([Pleroma.Plugs.RemoteIp, :enabled]) do
       Pleroma.Config.put([Pleroma.Plugs.RemoteIp, :enabled], true)
+    end
+
+    clear_config([:rate_limit, :app_account_creation]) do
+      Pleroma.Config.put([:rate_limit, :app_account_creation], {10_000, 2})
+    end
+
+    test "respects rate limit setting", %{conn: conn} do
       app_token = insert(:oauth_token, user: nil)
 
       conn =
@@ -684,7 +722,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
         |> put_req_header("authorization", "Bearer " <> app_token.token)
         |> Map.put(:remote_ip, {15, 15, 15, 15})
 
-      for i <- 1..5 do
+      for i <- 1..2 do
         conn =
           post(conn, "/api/v1/accounts", %{
             username: "#{i}lain",
@@ -718,37 +756,6 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
 
       assert json_response(conn, :too_many_requests) == %{"error" => "Throttled"}
     end
-
-    test "returns bad_request if missing required params", %{
-      conn: conn,
-      valid_params: valid_params
-    } do
-      app_token = insert(:oauth_token, user: nil)
-
-      conn = put_req_header(conn, "authorization", "Bearer " <> app_token.token)
-
-      res = post(conn, "/api/v1/accounts", valid_params)
-      assert json_response(res, 200)
-
-      [{127, 0, 0, 1}, {127, 0, 0, 2}, {127, 0, 0, 3}, {127, 0, 0, 4}]
-      |> Stream.zip(valid_params)
-      |> Enum.each(fn {ip, {attr, _}} ->
-        res =
-          conn
-          |> Map.put(:remote_ip, ip)
-          |> post("/api/v1/accounts", Map.delete(valid_params, attr))
-          |> json_response(400)
-
-        assert res == %{"error" => "Missing parameters"}
-      end)
-    end
-
-    test "returns forbidden if token is invalid", %{conn: conn, valid_params: valid_params} do
-      conn = put_req_header(conn, "authorization", "Bearer " <> "invalid-token")
-
-      res = post(conn, "/api/v1/accounts", valid_params)
-      assert json_response(res, 403) == %{"error" => "Invalid credentials"}
-    end
   end
 
   describe "GET /api/v1/accounts/:id/lists - account_lists" do