diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex index dd5f6028f..5ee93eabf 100644 --- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex +++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex @@ -26,6 +26,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do alias Pleroma.Web.Plugs.EnsureAuthenticatedPlug alias Pleroma.Web.Plugs.FederatingPlug alias Pleroma.Web.Plugs.OAuthScopesPlug + alias Pleroma.Web.Plugs.RateLimiter require Logger @@ -66,6 +67,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do when action in [:followers, :following] ) + # Shares the per-user bucket with Mastodon API status actions and emoji reactions. + plug(RateLimiter, [name: :statuses_actions] when action == :update_outbox) + plug(Majic.Plug, [pool: Pleroma.MajicPool] when action in [:upload_media]) plug( diff --git a/test/pleroma/web/activity_pub/activity_pub_controller_test.exs b/test/pleroma/web/activity_pub/activity_pub_controller_test.exs index 606d47c8d..b72fb6424 100644 --- a/test/pleroma/web/activity_pub/activity_pub_controller_test.exs +++ b/test/pleroma/web/activity_pub/activity_pub_controller_test.exs @@ -2685,6 +2685,43 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do assert result == "Character limit (5 characters) exceeded, contains 11 characters" end + + test "it is rate limited", %{conn: conn, activity: activity} do + clear_config([:rate_limit, :statuses_actions], {60_000, 2}) + user = insert(:user) + + conn = + conn + |> assign(:user, user) + |> put_req_header("content-type", "application/activity+json") + + for _ <- 1..2 do + conn + |> post("/users/#{user.nickname}/outbox", activity) + |> json_response(201) + end + + assert conn + |> post("/users/#{user.nickname}/outbox", activity) + |> json_response(429) == %{"error" => "Throttled"} + end + + test "it shares the rate limit with the Mastodon API", %{activity: activity} do + clear_config([:rate_limit, :statuses_actions], {60_000, 2}) + %{user: user, conn: conn} = oauth_access(["write"]) + + for _ <- 1..2 do + conn + |> put_req_header("content-type", "application/json") + |> post("/api/v1/statuses", %{status: "cofe"}) + |> json_response(200) + end + + assert conn + |> put_req_header("content-type", "application/activity+json") + |> post("/users/#{user.nickname}/outbox", activity) + |> json_response(429) == %{"error" => "Throttled"} + end end describe "/relay/followers" do