Disable rate limiter for socket/localhost (unless RemoteIp is enabled)
authorMaxim Filippov <colixer@gmail.com>
Fri, 13 Dec 2019 16:00:26 +0000 (19:00 +0300)
committerMaxim Filippov <colixer@gmail.com>
Sat, 14 Dec 2019 00:06:43 +0000 (03:06 +0300)
CHANGELOG.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 21374254513f557c8931108dba67f05704e2535e..664c101a70b01b2358ce1f469132f81aae19eb45 100644 (file)
@@ -21,6 +21,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 - Deprecated `User.Info` embedded schema (fields moved to `User`)
 - Store status data inside Flag activity
 - Deprecated (reorganized as `UserRelationship` entity) User fields with user AP IDs (`blocks`, `mutes`, `muted_reblogs`, `muted_notifications`, `subscribers`).
+- Rate limiter is now disabled for localhost/socket (unless remoteip plug is enabled)
 <details>
   <summary>API Changes</summary>
 
index d720508c8aafa12bdd14776a81b4be9f4598cc9e..7fb92489c4ff2822dea813337ee61e147a0105f1 100644 (file)
@@ -67,6 +67,8 @@ defmodule Pleroma.Plugs.RateLimiter do
   alias Pleroma.Plugs.RateLimiter.LimiterSupervisor
   alias Pleroma.User
 
+  require Logger
+
   def init(opts) do
     limiter_name = Keyword.get(opts, :name)
 
@@ -89,18 +91,39 @@ defmodule Pleroma.Plugs.RateLimiter do
   def call(conn, nil), do: conn
 
   def call(conn, settings) do
-    settings
-    |> incorporate_conn_info(conn)
-    |> check_rate()
-    |> case do
-      {:ok, _count} ->
+    case disabled?() do
+      true ->
+        if Pleroma.Config.get(:env) == :prod,
+          do: Logger.warn("Rate limiter is disabled for localhost/socket")
+
         conn
 
-      {:error, _count} ->
-        render_throttled_error(conn)
+      false ->
+        settings
+        |> incorporate_conn_info(conn)
+        |> check_rate()
+        |> case do
+          {:ok, _count} ->
+            conn
+
+          {:error, _count} ->
+            render_throttled_error(conn)
+        end
     end
   end
 
+  def disabled? do
+    localhost_or_socket =
+      Pleroma.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])
+
+    localhost_or_socket and remote_ip_disabled
+  end
+
   def inspect_bucket(conn, name_root, settings) do
     settings =
       settings
index 49f63c424aa08079479646bdff8ae5b0a7802f2c..f3343abcab90a9874e87bef4c069818668fcdaa1 100644 (file)
@@ -16,6 +16,7 @@ defmodule Pleroma.Plugs.RateLimiterTest do
     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})
 
       assert %{limits: {1, 1}, name: :test_init, opts: [name: :test_init]} ==
                RateLimiter.init(name: limiter_name)
@@ -23,11 +24,39 @@ defmodule Pleroma.Plugs.RateLimiterTest do
       assert nil == RateLimiter.init(name: :foo)
     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)
+
+      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)
+
+      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)
+
+      assert RateLimiter.disabled?() == false
+    end
+
     test "it restricts based on config values" do
       limiter_name = :test_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})
 
       opts = RateLimiter.init(name: limiter_name)
@@ -61,6 +90,7 @@ defmodule Pleroma.Plugs.RateLimiterTest 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})
 
       base_bucket_name = "#{limiter_name}:group1"
       opts = RateLimiter.init(name: limiter_name, bucket_name: base_bucket_name)
@@ -75,6 +105,7 @@ defmodule Pleroma.Plugs.RateLimiterTest do
     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})
 
       opts = RateLimiter.init(name: limiter_name, params: ["id"])
 
@@ -90,6 +121,7 @@ defmodule Pleroma.Plugs.RateLimiterTest do
     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})
 
       base_bucket_name = "#{limiter_name}:group1"
       opts = RateLimiter.init(name: limiter_name, bucket_name: base_bucket_name, params: ["id"])
@@ -109,6 +141,7 @@ defmodule Pleroma.Plugs.RateLimiterTest 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})
 
       opts = RateLimiter.init(name: limiter_name)
 
@@ -147,6 +180,7 @@ defmodule Pleroma.Plugs.RateLimiterTest do
 
       scale = 1000
       limit = 5
+      Pleroma.Config.put([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8})
       Pleroma.Config.put([:rate_limit, limiter_name], [{1, 10}, {scale, limit}])
 
       opts = RateLimiter.init(name: limiter_name)
@@ -179,6 +213,7 @@ defmodule Pleroma.Plugs.RateLimiterTest do
     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})
 
       opts = RateLimiter.init(name: limiter_name)
 
index fa08ae4df5ba4764a202358423275d64aed2ff3f..14d97e248adb9ae7d3c245ed6ea49cc00294af4d 100644 (file)
@@ -766,6 +766,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
     end
 
     test "rate limit", %{conn: conn} do
+      Pleroma.Config.put([Pleroma.Plugs.RemoteIp, :enabled], true)
       app_token = insert(:oauth_token, user: nil)
 
       conn =