From 3e150488432bae5f4acd5277b0c143af48c71a11 Mon Sep 17 00:00:00 2001
From: Thomas Citharel <tcit@tcit.fr>
Date: Mon, 21 Nov 2022 16:56:20 +0100
Subject: [PATCH] Prevent AP collection page number being < 1

Closes #1184

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
---
 .../controllers/activity_pub_controller.ex    |  1 +
 .../activity_pub_controller_test.exs          | 28 +++++++++++++++++++
 2 files changed, 29 insertions(+)

diff --git a/lib/web/controllers/activity_pub_controller.ex b/lib/web/controllers/activity_pub_controller.ex
index 296d774db..93f132826 100644
--- a/lib/web/controllers/activity_pub_controller.ex
+++ b/lib/web/controllers/activity_pub_controller.ex
@@ -191,6 +191,7 @@ defmodule Mobilizon.Web.ActivityPubController do
 
   defp actor_collection(conn, collection, %{"name" => name, "page" => page}) do
     with {page, ""} <- Integer.parse(page),
+         page <- max(page, 1),
          %Actor{} = actor <- Actors.get_local_actor_by_name_with_preload(name) do
       conn
       |> put_resp_header("content-type", "application/activity+json")
diff --git a/test/web/controllers/activity_pub_controller_test.exs b/test/web/controllers/activity_pub_controller_test.exs
index 95367865c..d44ddeefa 100644
--- a/test/web/controllers/activity_pub_controller_test.exs
+++ b/test/web/controllers/activity_pub_controller_test.exs
@@ -243,6 +243,34 @@ defmodule Mobilizon.Web.ActivityPubControllerTest do
       assert length(result["orderedItems"]) == 5
     end
 
+    test "it can't be called for a page < 1", %{conn: conn} do
+      actor = insert(:actor, visibility: :public)
+
+      Enum.each(1..15, fn _ ->
+        insert(:event, organizer_actor: actor)
+      end)
+
+      result =
+        conn
+        |> get(Actor.build_url(actor.preferred_username, :outbox))
+        |> json_response(200)
+
+      assert length(result["first"]["orderedItems"]) == 10
+      assert result["totalItems"] == 15
+
+      page_0_result =
+        conn
+        |> get(Actor.build_url(actor.preferred_username, :outbox, page: 0))
+        |> json_response(200)
+
+      page_1_result =
+        conn
+        |> get(Actor.build_url(actor.preferred_username, :outbox, page: 1))
+        |> json_response(200)
+
+      assert page_0_result == page_1_result
+    end
+
     test "it returns an empty collection if the actor has private visibility", %{conn: conn} do
       actor = insert(:actor, visibility: :private)
       insert(:event, organizer_actor: actor)