Merge branch '1041-status-actions-rate-limit' into 'develop'
Rate-limited status actions (per user and per user+status). Closes #1041 See merge request pleroma/pleroma!1410
This commit is contained in:
commit
f4c001062e
6 changed files with 155 additions and 27 deletions
|
|
@ -31,12 +31,28 @@ defmodule Pleroma.Plugs.RateLimiter do
|
|||
|
||||
## Usage
|
||||
|
||||
AllowedSyntax:
|
||||
|
||||
plug(Pleroma.Plugs.RateLimiter, :limiter_name)
|
||||
plug(Pleroma.Plugs.RateLimiter, {:limiter_name, options})
|
||||
|
||||
Allowed options:
|
||||
|
||||
* `bucket_name` overrides bucket name (e.g. to have a separate limit for a set of actions)
|
||||
* `params` appends values of specified request params (e.g. ["id"]) to bucket name
|
||||
|
||||
Inside a controller:
|
||||
|
||||
plug(Pleroma.Plugs.RateLimiter, :one when action == :one)
|
||||
plug(Pleroma.Plugs.RateLimiter, :two when action in [:two, :three])
|
||||
|
||||
or inside a router pipiline:
|
||||
plug(
|
||||
Pleroma.Plugs.RateLimiter,
|
||||
{:status_id_action, bucket_name: "status_id_action:fav_unfav", params: ["id"]}
|
||||
when action in ~w(fav_status unfav_status)a
|
||||
)
|
||||
|
||||
or inside a router pipeline:
|
||||
|
||||
pipeline :api do
|
||||
...
|
||||
|
|
@ -49,33 +65,56 @@ defmodule Pleroma.Plugs.RateLimiter do
|
|||
|
||||
alias Pleroma.User
|
||||
|
||||
def init(limiter_name) do
|
||||
def init(limiter_name) when is_atom(limiter_name) do
|
||||
init({limiter_name, []})
|
||||
end
|
||||
|
||||
def init({limiter_name, opts}) do
|
||||
case Pleroma.Config.get([:rate_limit, limiter_name]) do
|
||||
nil -> nil
|
||||
config -> {limiter_name, config}
|
||||
config -> {limiter_name, config, opts}
|
||||
end
|
||||
end
|
||||
|
||||
# do not limit if there is no limiter configuration
|
||||
# Do not limit if there is no limiter configuration
|
||||
def call(conn, nil), do: conn
|
||||
|
||||
def call(conn, opts) do
|
||||
case check_rate(conn, opts) do
|
||||
{:ok, _count} -> conn
|
||||
{:error, _count} -> render_throttled_error(conn)
|
||||
def call(conn, settings) do
|
||||
case check_rate(conn, settings) do
|
||||
{:ok, _count} ->
|
||||
conn
|
||||
|
||||
{:error, _count} ->
|
||||
render_throttled_error(conn)
|
||||
end
|
||||
end
|
||||
|
||||
defp check_rate(%{assigns: %{user: %User{id: user_id}}}, {limiter_name, [_, {scale, limit}]}) do
|
||||
ExRated.check_rate("#{limiter_name}:#{user_id}", scale, limit)
|
||||
defp bucket_name(conn, limiter_name, opts) do
|
||||
bucket_name = opts[:bucket_name] || limiter_name
|
||||
|
||||
if params_names = opts[:params] do
|
||||
params_values = for p <- Enum.sort(params_names), do: conn.params[p]
|
||||
Enum.join([bucket_name] ++ params_values, ":")
|
||||
else
|
||||
bucket_name
|
||||
end
|
||||
end
|
||||
|
||||
defp check_rate(conn, {limiter_name, [{scale, limit} | _]}) do
|
||||
ExRated.check_rate("#{limiter_name}:#{ip(conn)}", scale, limit)
|
||||
defp check_rate(
|
||||
%{assigns: %{user: %User{id: user_id}}} = conn,
|
||||
{limiter_name, [_, {scale, limit}], opts}
|
||||
) do
|
||||
bucket_name = bucket_name(conn, limiter_name, opts)
|
||||
ExRated.check_rate("#{bucket_name}:#{user_id}", scale, limit)
|
||||
end
|
||||
|
||||
defp check_rate(conn, {limiter_name, {scale, limit}}) do
|
||||
check_rate(conn, {limiter_name, [{scale, limit}]})
|
||||
defp check_rate(conn, {limiter_name, [{scale, limit} | _], opts}) do
|
||||
bucket_name = bucket_name(conn, limiter_name, opts)
|
||||
ExRated.check_rate("#{bucket_name}:#{ip(conn)}", scale, limit)
|
||||
end
|
||||
|
||||
defp check_rate(conn, {limiter_name, {scale, limit}, opts}) do
|
||||
check_rate(conn, {limiter_name, [{scale, limit}, {scale, limit}], opts})
|
||||
end
|
||||
|
||||
def ip(%{remote_ip: remote_ip}) do
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
alias Pleroma.Notification
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.Pagination
|
||||
alias Pleroma.Plugs.RateLimiter
|
||||
alias Pleroma.Repo
|
||||
alias Pleroma.ScheduledActivity
|
||||
alias Pleroma.Stats
|
||||
|
|
@ -46,8 +47,24 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
|
||||
require Logger
|
||||
|
||||
plug(Pleroma.Plugs.RateLimiter, :app_account_creation when action == :account_register)
|
||||
plug(Pleroma.Plugs.RateLimiter, :search when action in [:search, :search2, :account_search])
|
||||
@rate_limited_status_actions ~w(reblog_status unreblog_status fav_status unfav_status
|
||||
post_status delete_status)a
|
||||
|
||||
plug(
|
||||
RateLimiter,
|
||||
{:status_id_action, bucket_name: "status_id_action:reblog_unreblog", params: ["id"]}
|
||||
when action in ~w(reblog_status unreblog_status)a
|
||||
)
|
||||
|
||||
plug(
|
||||
RateLimiter,
|
||||
{:status_id_action, bucket_name: "status_id_action:fav_unfav", params: ["id"]}
|
||||
when action in ~w(fav_status unfav_status)a
|
||||
)
|
||||
|
||||
plug(RateLimiter, :statuses_actions when action in @rate_limited_status_actions)
|
||||
plug(RateLimiter, :app_account_creation when action == :account_register)
|
||||
plug(RateLimiter, :search when action in [:search, :search2, :account_search])
|
||||
|
||||
@local_mastodon_name "Mastodon-Local"
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue