Fork of Pleroma with site-specific changes and feature branches https://git.pleroma.social/pleroma/pleroma
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

175 lines
5.7KB

  1. # Pleroma: A lightweight social networking server
  2. # Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
  3. # SPDX-License-Identifier: AGPL-3.0-only
  4. defmodule Pleroma.Plugs.RateLimiterTest do
  5. use ExUnit.Case, async: true
  6. use Plug.Test
  7. alias Pleroma.Plugs.RateLimiter
  8. import Pleroma.Factory
  9. # Note: each example must work with separate buckets in order to prevent concurrency issues
  10. test "init/1" do
  11. limiter_name = :test_init
  12. Pleroma.Config.put([:rate_limit, limiter_name], {1, 1})
  13. assert {limiter_name, {1, 1}, []} == RateLimiter.init(limiter_name)
  14. assert nil == RateLimiter.init(:foo)
  15. end
  16. test "ip/1" do
  17. assert "127.0.0.1" == RateLimiter.ip(%{remote_ip: {127, 0, 0, 1}})
  18. end
  19. test "it restricts by opts" do
  20. limiter_name = :test_opts
  21. scale = 1000
  22. limit = 5
  23. Pleroma.Config.put([:rate_limit, limiter_name], {scale, limit})
  24. opts = RateLimiter.init(limiter_name)
  25. conn = conn(:get, "/")
  26. bucket_name = "#{limiter_name}:#{RateLimiter.ip(conn)}"
  27. conn = RateLimiter.call(conn, opts)
  28. assert {1, 4, _, _, _} = ExRated.inspect_bucket(bucket_name, scale, limit)
  29. conn = RateLimiter.call(conn, opts)
  30. assert {2, 3, _, _, _} = ExRated.inspect_bucket(bucket_name, scale, limit)
  31. conn = RateLimiter.call(conn, opts)
  32. assert {3, 2, _, _, _} = ExRated.inspect_bucket(bucket_name, scale, limit)
  33. conn = RateLimiter.call(conn, opts)
  34. assert {4, 1, _, _, _} = ExRated.inspect_bucket(bucket_name, scale, limit)
  35. conn = RateLimiter.call(conn, opts)
  36. assert {5, 0, to_reset, _, _} = ExRated.inspect_bucket(bucket_name, scale, limit)
  37. conn = RateLimiter.call(conn, opts)
  38. assert %{"error" => "Throttled"} = Phoenix.ConnTest.json_response(conn, :too_many_requests)
  39. assert conn.halted
  40. Process.sleep(to_reset)
  41. conn = conn(:get, "/")
  42. conn = RateLimiter.call(conn, opts)
  43. assert {1, 4, _, _, _} = ExRated.inspect_bucket(bucket_name, scale, limit)
  44. refute conn.status == Plug.Conn.Status.code(:too_many_requests)
  45. refute conn.resp_body
  46. refute conn.halted
  47. end
  48. test "`bucket_name` option overrides default bucket name" do
  49. limiter_name = :test_bucket_name
  50. scale = 1000
  51. limit = 5
  52. Pleroma.Config.put([:rate_limit, limiter_name], {scale, limit})
  53. base_bucket_name = "#{limiter_name}:group1"
  54. opts = RateLimiter.init({limiter_name, bucket_name: base_bucket_name})
  55. conn = conn(:get, "/")
  56. default_bucket_name = "#{limiter_name}:#{RateLimiter.ip(conn)}"
  57. customized_bucket_name = "#{base_bucket_name}:#{RateLimiter.ip(conn)}"
  58. RateLimiter.call(conn, opts)
  59. assert {1, 4, _, _, _} = ExRated.inspect_bucket(customized_bucket_name, scale, limit)
  60. assert {0, 5, _, _, _} = ExRated.inspect_bucket(default_bucket_name, scale, limit)
  61. end
  62. test "`params` option appends specified params' values to bucket name" do
  63. limiter_name = :test_params
  64. scale = 1000
  65. limit = 5
  66. Pleroma.Config.put([:rate_limit, limiter_name], {scale, limit})
  67. opts = RateLimiter.init({limiter_name, params: ["id"]})
  68. id = "1"
  69. conn = conn(:get, "/?id=#{id}")
  70. conn = Plug.Conn.fetch_query_params(conn)
  71. default_bucket_name = "#{limiter_name}:#{RateLimiter.ip(conn)}"
  72. parametrized_bucket_name = "#{limiter_name}:#{id}:#{RateLimiter.ip(conn)}"
  73. RateLimiter.call(conn, opts)
  74. assert {1, 4, _, _, _} = ExRated.inspect_bucket(parametrized_bucket_name, scale, limit)
  75. assert {0, 5, _, _, _} = ExRated.inspect_bucket(default_bucket_name, scale, limit)
  76. end
  77. test "it supports combination of options modifying bucket name" do
  78. limiter_name = :test_options_combo
  79. scale = 1000
  80. limit = 5
  81. Pleroma.Config.put([:rate_limit, limiter_name], {scale, limit})
  82. base_bucket_name = "#{limiter_name}:group1"
  83. opts = RateLimiter.init({limiter_name, bucket_name: base_bucket_name, params: ["id"]})
  84. id = "100"
  85. conn = conn(:get, "/?id=#{id}")
  86. conn = Plug.Conn.fetch_query_params(conn)
  87. default_bucket_name = "#{limiter_name}:#{RateLimiter.ip(conn)}"
  88. parametrized_bucket_name = "#{base_bucket_name}:#{id}:#{RateLimiter.ip(conn)}"
  89. RateLimiter.call(conn, opts)
  90. assert {1, 4, _, _, _} = ExRated.inspect_bucket(parametrized_bucket_name, scale, limit)
  91. assert {0, 5, _, _, _} = ExRated.inspect_bucket(default_bucket_name, scale, limit)
  92. end
  93. test "optional limits for authenticated users" do
  94. limiter_name = :test_authenticated
  95. Ecto.Adapters.SQL.Sandbox.checkout(Pleroma.Repo)
  96. scale = 1000
  97. limit = 5
  98. Pleroma.Config.put([:rate_limit, limiter_name], [{1, 10}, {scale, limit}])
  99. opts = RateLimiter.init(limiter_name)
  100. user = insert(:user)
  101. conn = conn(:get, "/") |> assign(:user, user)
  102. bucket_name = "#{limiter_name}:#{user.id}"
  103. conn = RateLimiter.call(conn, opts)
  104. assert {1, 4, _, _, _} = ExRated.inspect_bucket(bucket_name, scale, limit)
  105. conn = RateLimiter.call(conn, opts)
  106. assert {2, 3, _, _, _} = ExRated.inspect_bucket(bucket_name, scale, limit)
  107. conn = RateLimiter.call(conn, opts)
  108. assert {3, 2, _, _, _} = ExRated.inspect_bucket(bucket_name, scale, limit)
  109. conn = RateLimiter.call(conn, opts)
  110. assert {4, 1, _, _, _} = ExRated.inspect_bucket(bucket_name, scale, limit)
  111. conn = RateLimiter.call(conn, opts)
  112. assert {5, 0, to_reset, _, _} = ExRated.inspect_bucket(bucket_name, scale, limit)
  113. conn = RateLimiter.call(conn, opts)
  114. assert %{"error" => "Throttled"} = Phoenix.ConnTest.json_response(conn, :too_many_requests)
  115. assert conn.halted
  116. Process.sleep(to_reset)
  117. conn = conn(:get, "/") |> assign(:user, user)
  118. conn = RateLimiter.call(conn, opts)
  119. assert {1, 4, _, _, _} = ExRated.inspect_bucket(bucket_name, scale, limit)
  120. refute conn.status == Plug.Conn.Status.code(:too_many_requests)
  121. refute conn.resp_body
  122. refute conn.halted
  123. end
  124. end