From 3e4768efca88124b3ae418d41da923c428598275 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Sun, 4 Aug 2024 13:59:13 -0400
Subject: [PATCH 001/212] Revert "Remove invalid test"

This reverts commit d0f4b2b02fc3aee3f08239d9c188ca5a2e8ad482.
---
 test/pleroma/integration/mastodon_websocket_test.exs | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/test/pleroma/integration/mastodon_websocket_test.exs b/test/pleroma/integration/mastodon_websocket_test.exs
index f499f54ad..88f32762d 100644
--- a/test/pleroma/integration/mastodon_websocket_test.exs
+++ b/test/pleroma/integration/mastodon_websocket_test.exs
@@ -268,6 +268,17 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do
       end)
     end
 
+    test "accepts valid token on Sec-WebSocket-Protocol header", %{token: token} do
+      assert {:ok, _} = start_socket("?stream=user", [{"Sec-WebSocket-Protocol", token.token}])
+
+      capture_log(fn ->
+        assert {:error, %WebSockex.RequestError{code: 401}} =
+                 start_socket("?stream=user", [{"Sec-WebSocket-Protocol", "I am a friend"}])
+
+        Process.sleep(30)
+      end)
+    end
+
     test "accepts valid token on client-sent event", %{token: token} do
       assert {:ok, pid} = start_socket()
 

From 8c91fd8785c25e694d9341b17b5182041c575166 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Sun, 4 Aug 2024 14:58:16 -0400
Subject: [PATCH 002/212] Fix Mastodon WebSocket authentication

Mastodon uses the Sec-Websocket-Protocol header to send the auth token. It is not clear if this is a violation of the RFC, but Mastodon is not the first application in the wild to use this header for authentication purposes. Phoenix does not allow accessing this header, so we work around it temporarily with a minor patch to Phoenix 1.7.14. We will reach out to Phoenix to discuss how to make this use case possible.
---
 changelog.d/mastodon-websocket.fix                |  1 +
 lib/pleroma/web/endpoint.ex                       |  1 +
 lib/pleroma/web/mastodon_api/websocket_handler.ex | 11 ++++++++++-
 mix.exs                                           |  3 ++-
 mix.lock                                          |  4 ++--
 5 files changed, 16 insertions(+), 4 deletions(-)
 create mode 100644 changelog.d/mastodon-websocket.fix

diff --git a/changelog.d/mastodon-websocket.fix b/changelog.d/mastodon-websocket.fix
new file mode 100644
index 000000000..2c4fe86ef
--- /dev/null
+++ b/changelog.d/mastodon-websocket.fix
@@ -0,0 +1 @@
+Fix Mastodon WebSocket authentication
diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex
index fef907ace..bab3c9fd0 100644
--- a/lib/pleroma/web/endpoint.ex
+++ b/lib/pleroma/web/endpoint.ex
@@ -14,6 +14,7 @@ defmodule Pleroma.Web.Endpoint do
     websocket: [
       path: "/",
       compress: false,
+      connect_info: [:sec_websocket_protocol],
       error_handler: {Pleroma.Web.MastodonAPI.WebsocketHandler, :handle_error, []},
       fullsweep_after: 20
     ]
diff --git a/lib/pleroma/web/mastodon_api/websocket_handler.ex b/lib/pleroma/web/mastodon_api/websocket_handler.ex
index 730295a4c..3ed1cdd6c 100644
--- a/lib/pleroma/web/mastodon_api/websocket_handler.ex
+++ b/lib/pleroma/web/mastodon_api/websocket_handler.ex
@@ -22,7 +22,7 @@ defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do
   # This only prepares the connection and is not in the process yet
   @impl Phoenix.Socket.Transport
   def connect(%{params: params} = transport_info) do
-    with access_token <- Map.get(params, "access_token"),
+    with access_token <- find_access_token(transport_info),
          {:ok, user, oauth_token} <- authenticate_request(access_token),
          {:ok, topic} <-
            Streamer.get_topic(params["stream"], user, oauth_token, params) do
@@ -244,4 +244,13 @@ defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do
   def handle_error(conn, _reason) do
     Plug.Conn.send_resp(conn, 404, "Not Found")
   end
+
+  defp find_access_token(%{
+         connect_info: %{sec_websocket_protocol: [token]}
+       }),
+       do: token
+
+  defp find_access_token(%{params: %{"access_token" => token}}), do: token
+
+  defp find_access_token(_), do: nil
 end
diff --git a/mix.exs b/mix.exs
index 69e52e526..88b558a75 100644
--- a/mix.exs
+++ b/mix.exs
@@ -132,7 +132,8 @@ defmodule Pleroma.Mixfile do
   # Type `mix help deps` for examples and options.
   defp deps do
     [
-      {:phoenix, "~> 1.7.3"},
+      {:phoenix,
+       git: "https://github.com/feld/phoenix", branch: "v1.7.14-websocket-headers", override: true},
       {:phoenix_ecto, "~> 4.4"},
       {:ecto_sql, "~> 3.10"},
       {:ecto_enum, "~> 1.4"},
diff --git a/mix.lock b/mix.lock
index 61ede9e5e..a26ac0e84 100644
--- a/mix.lock
+++ b/mix.lock
@@ -65,7 +65,7 @@
   "httpoison": {:hex, :httpoison, "1.8.2", "9eb9c63ae289296a544842ef816a85d881d4a31f518a0fec089aaa744beae290", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "2bb350d26972e30c96e2ca74a1aaf8293d61d0742ff17f01e0279fef11599921"},
   "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
   "inet_cidr": {:hex, :inet_cidr, "1.0.8", "d26bb7bdbdf21ae401ead2092bf2bb4bf57fe44a62f5eaa5025280720ace8a40", [:mix], [], "hexpm", "d5b26da66603bb56c933c65214c72152f0de9a6ea53618b56d63302a68f6a90e"},
-  "jason": {:hex, :jason, "1.4.3", "d3f984eeb96fe53b85d20e0b049f03e57d075b5acda3ac8d465c969a2536c17b", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "9a90e868927f7c777689baa16d86f4d0e086d968db5c05d917ccff6d443e58a3"},
+  "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"},
   "joken": {:hex, :joken, "2.6.0", "b9dd9b6d52e3e6fcb6c65e151ad38bf4bc286382b5b6f97079c47ade6b1bcc6a", [:mix], [{:jose, "~> 1.11.5", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "5a95b05a71cd0b54abd35378aeb1d487a23a52c324fa7efdffc512b655b5aaa7"},
   "jose": {:hex, :jose, "1.11.6", "613fda82552128aa6fb804682e3a616f4bc15565a048dabd05b1ebd5827ed965", [:mix, :rebar3], [], "hexpm", "6275cb75504f9c1e60eeacb771adfeee4905a9e182103aa59b53fed651ff9738"},
   "jumper": {:hex, :jumper, "1.0.2", "68cdcd84472a00ac596b4e6459a41b3062d4427cbd4f1e8c8793c5b54f1406a7", [:mix], [], "hexpm", "9b7782409021e01ab3c08270e26f36eb62976a38c1aa64b2eaf6348422f165e1"},
@@ -94,7 +94,7 @@
   "open_api_spex": {:hex, :open_api_spex, "3.18.2", "8c855e83bfe8bf81603d919d6e892541eafece3720f34d1700b58024dadde247", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 3.0 or ~> 4.0 or ~> 5.0", [hex: :poison, repo: "hexpm", optional: true]}, {:ymlr, "~> 2.0 or ~> 3.0 or ~> 4.0", [hex: :ymlr, repo: "hexpm", optional: true]}], "hexpm", "aa3e6dcfc0ad6a02596b2172662da21c9dd848dac145ea9e603f54e3d81b8d2b"},
   "parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"},
   "pbkdf2_elixir": {:hex, :pbkdf2_elixir, "1.2.1", "9cbe354b58121075bd20eb83076900a3832324b7dd171a6895fab57b6bb2752c", [:mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}], "hexpm", "d3b40a4a4630f0b442f19eca891fcfeeee4c40871936fed2f68e1c4faa30481f"},
-  "phoenix": {:hex, :phoenix, "1.7.14", "a7d0b3f1bc95987044ddada111e77bd7f75646a08518942c72a8440278ae7825", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "c7859bc56cc5dfef19ecfc240775dae358cbaa530231118a9e014df392ace61a"},
+  "phoenix": {:git, "https://github.com/feld/phoenix", "fb6dc76c657422e49600896c64aab4253fceaef6", [branch: "v1.7.14-websocket-headers"]},
   "phoenix_ecto": {:hex, :phoenix_ecto, "4.4.3", "86e9878f833829c3f66da03d75254c155d91d72a201eb56ae83482328dc7ca93", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "d36c401206f3011fefd63d04e8ef626ec8791975d9d107f9a0817d426f61ac07"},
   "phoenix_html": {:hex, :phoenix_html, "3.3.4", "42a09fc443bbc1da37e372a5c8e6755d046f22b9b11343bf885067357da21cb3", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "0249d3abec3714aff3415e7ee3d9786cb325be3151e6c4b3021502c585bf53fb"},
   "phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.8.3", "7ff51c9b6609470f681fbea20578dede0e548302b0c8bdf338b5a753a4f045bf", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.5", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:ecto_sqlite3_extras, "~> 1.1.7 or ~> 1.2.0", [hex: :ecto_sqlite3_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.19 or ~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "f9470a0a8bae4f56430a23d42f977b5a6205fdba6559d76f932b876bfaec652d"},

From 71ef9f9519e2617a0c05d7447bbc406ae4a8d849 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= <git@mkljczk.pl>
Date: Sat, 17 Aug 2024 16:36:27 +0200
Subject: [PATCH 003/212] Allow providing avatar/header descriptions
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
---
 lib/pleroma/user.ex                           | 28 ++++++++++++++++---
 .../api_spec/operations/account_operation.ex  | 10 +++++++
 .../controllers/account_controller.ex         |  2 ++
 .../web/mastodon_api/views/account_view.ex    | 10 ++++++-
 4 files changed, 45 insertions(+), 5 deletions(-)

diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index c6c536943..f443b64ae 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -589,13 +589,21 @@ defmodule Pleroma.User do
     |> put_fields()
     |> put_emoji()
     |> put_change_if_present(:bio, &{:ok, parse_bio(&1, struct)})
-    |> put_change_if_present(:avatar, &put_upload(&1, :avatar))
-    |> put_change_if_present(:banner, &put_upload(&1, :banner))
+    |> put_change_if_present(
+      :avatar,
+      &put_upload(&1, :avatar, Map.get(params, :avatar_description, nil))
+    )
+    |> put_change_if_present(
+      :banner,
+      &put_upload(&1, :banner, Map.get(params, :header_description, nil))
+    )
     |> put_change_if_present(:background, &put_upload(&1, :background))
     |> put_change_if_present(
       :pleroma_settings_store,
       &{:ok, Map.merge(struct.pleroma_settings_store, &1)}
     )
+    |> maybe_update_image_description(:avatar, Map.get(params, :avatar_description))
+    |> maybe_update_image_description(:banner, Map.get(params, :header_description))
     |> validate_fields(false)
   end
 
@@ -674,13 +682,25 @@ defmodule Pleroma.User do
     end
   end
 
-  defp put_upload(value, type) do
+  defp put_upload(value, type, description \\ nil) do
     with %Plug.Upload{} <- value,
-         {:ok, object} <- ActivityPub.upload(value, type: type) do
+         {:ok, object} <- ActivityPub.upload(value, type: type, description: description) do
       {:ok, object.data}
     end
   end
 
+  defp maybe_update_image_description(changeset, image_field, description) do
+    with {:image_missing, true} <- {:image_missing, not changed?(changeset, image_field)},
+         {:existing_image, %{"id" => id}} <-
+           {:existing_image, Map.get(changeset.data, image_field)},
+         {:object, %Object{} = object} <- {:object, Object.get_by_ap_id(id)},
+         {:ok, object} <- Object.update_data(object, %{"name" => description}) do
+      put_change(changeset, image_field, object.data)
+    else
+      e -> changeset
+    end
+  end
+
   def update_as_admin_changeset(struct, params) do
     struct
     |> update_changeset(params)
diff --git a/lib/pleroma/web/api_spec/operations/account_operation.ex b/lib/pleroma/web/api_spec/operations/account_operation.ex
index d9614bc48..21a779dcb 100644
--- a/lib/pleroma/web/api_spec/operations/account_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/account_operation.ex
@@ -813,6 +813,16 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
           allOf: [BooleanLike],
           nullable: true,
           description: "User's birthday will be visible"
+        },
+        avatar_description: %Schema{
+          type: :string,
+          nullable: true,
+          description: "Avatar image description."
+        },
+        header_description: %Schema{
+          type: :string,
+          nullable: true,
+          description: "Header image description."
         }
       },
       example: %{
diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex
index 54d46c86b..2302d6ed8 100644
--- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex
@@ -232,6 +232,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
       |> Maps.put_if_present(:is_discoverable, params[:discoverable])
       |> Maps.put_if_present(:birthday, params[:birthday])
       |> Maps.put_if_present(:language, Pleroma.Web.Gettext.normalize_locale(params[:language]))
+      |> Maps.put_if_present(:avatar_description, params[:avatar_description])
+      |> Maps.put_if_present(:header_description, params[:header_description])
 
     # What happens here:
     #
diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex
index 6976ca6e5..bd8af265a 100644
--- a/lib/pleroma/web/mastodon_api/views/account_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/account_view.ex
@@ -220,8 +220,10 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
 
     avatar = User.avatar_url(user) |> MediaProxy.url()
     avatar_static = User.avatar_url(user) |> MediaProxy.preview_url(static: true)
+    avatar_description = image_description(user.avatar)
     header = User.banner_url(user) |> MediaProxy.url()
     header_static = User.banner_url(user) |> MediaProxy.preview_url(static: true)
+    header_description = image_description(user.banner)
 
     following_count =
       if !user.hide_follows_count or !user.hide_follows or self,
@@ -323,7 +325,9 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
         background_image: image_url(user.background) |> MediaProxy.url(),
         accepts_chat_messages: user.accepts_chat_messages,
         favicon: favicon
-      }
+      },
+      avatar_description: avatar_description,
+      header_description: header_description
     }
     |> maybe_put_role(user, opts[:for])
     |> maybe_put_settings(user, opts[:for], opts)
@@ -346,6 +350,10 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
 
   defp username_from_nickname(_), do: nil
 
+  defp image_description(%{"name" => name}), do: name
+
+  defp image_description(_), do: ""
+
   defp maybe_put_follow_requests_count(
          data,
          %User{id: user_id} = user,

From 681765669c5b5bdc92079357d76c859e60bb49d8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= <git@mkljczk.pl>
Date: Sat, 17 Aug 2024 17:02:44 +0200
Subject: [PATCH 004/212] Add test for avatar description
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
---
 lib/pleroma/user.ex                           |  2 +-
 lib/pleroma/web/api_spec/schemas/account.ex   |  4 ++
 .../mastodon_api/update_credentials_test.exs  | 42 +++++++++++++++++++
 3 files changed, 47 insertions(+), 1 deletion(-)

diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index f443b64ae..c3cb72fab 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -697,7 +697,7 @@ defmodule Pleroma.User do
          {:ok, object} <- Object.update_data(object, %{"name" => description}) do
       put_change(changeset, image_field, object.data)
     else
-      e -> changeset
+      _ -> changeset
     end
   end
 
diff --git a/lib/pleroma/web/api_spec/schemas/account.ex b/lib/pleroma/web/api_spec/schemas/account.ex
index 8aeb821a8..32a0dd6cb 100644
--- a/lib/pleroma/web/api_spec/schemas/account.ex
+++ b/lib/pleroma/web/api_spec/schemas/account.ex
@@ -148,10 +148,13 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Account do
           }
         }
       }
+      avatar_description: %Schema{type: :string},
+      header_description: %Schema{type: :string}
     },
     example: %{
       "acct" => "foobar",
       "avatar" => "https://mypleroma.com/images/avi.png",
+      "avatar_description" => "",
       "avatar_static" => "https://mypleroma.com/images/avi.png",
       "bot" => false,
       "created_at" => "2020-03-24T13:05:58.000Z",
@@ -162,6 +165,7 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Account do
       "followers_count" => 0,
       "following_count" => 1,
       "header" => "https://mypleroma.com/images/banner.png",
+      "header_description" => "",
       "header_static" => "https://mypleroma.com/images/banner.png",
       "id" => "9tKi3esbG7OQgZ2920",
       "locked" => false,
diff --git a/test/pleroma/web/mastodon_api/update_credentials_test.exs b/test/pleroma/web/mastodon_api/update_credentials_test.exs
index bea0cae69..28d3b00db 100644
--- a/test/pleroma/web/mastodon_api/update_credentials_test.exs
+++ b/test/pleroma/web/mastodon_api/update_credentials_test.exs
@@ -430,6 +430,48 @@ defmodule Pleroma.Web.MastodonAPI.UpdateCredentialsTest do
       assert :ok == File.rm(Path.absname("test/tmp/large_binary.data"))
     end
 
+    test "adds avatar description with a new avatar", %{user: user, conn: conn} do
+      new_avatar = %Plug.Upload{
+        content_type: "image/jpeg",
+        path: Path.absname("test/fixtures/image.jpg"),
+        filename: "an_image.jpg"
+      }
+
+      res =
+        patch(conn, "/api/v1/accounts/update_credentials", %{
+          "avatar" => new_avatar,
+          "avatar_description" => "me and pleroma tan"
+        })
+
+      assert json_response_and_validate_schema(res, 200)
+
+      user = User.get_by_id(user.id)
+      assert user.avatar["name"] == "me and pleroma tan"
+    end
+
+    test "adds avatar description to existing avatar", %{user: user, conn: conn} do
+      new_avatar = %Plug.Upload{
+        content_type: "image/jpeg",
+        path: Path.absname("test/fixtures/image.jpg"),
+        filename: "an_image.jpg"
+      }
+
+      assert user.avatar == %{}
+
+      conn
+      |> patch("/api/v1/accounts/update_credentials", %{"avatar" => new_avatar})
+
+      assert conn
+             |> assign(:user, User.get_by_id(user.id))
+             |> patch("/api/v1/accounts/update_credentials", %{
+               "avatar_description" => "me and pleroma tan"
+             })
+             |> json_response_and_validate_schema(200)
+
+      user = User.get_by_id(user.id)
+      assert user.avatar["name"] == "me and pleroma tan"
+    end
+
     test "Strip / from upload files", %{user: user, conn: conn} do
       new_image = %Plug.Upload{
         content_type: "image/jpeg",

From 071452a5d5e4e8d38d9c31bad171085574327fee Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= <git@mkljczk.pl>
Date: Sat, 17 Aug 2024 17:03:12 +0200
Subject: [PATCH 005/212] Update changelog
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
---
 changelog.d/profile-image-descriptions.add | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 changelog.d/profile-image-descriptions.add

diff --git a/changelog.d/profile-image-descriptions.add b/changelog.d/profile-image-descriptions.add
new file mode 100644
index 000000000..85cc48083
--- /dev/null
+++ b/changelog.d/profile-image-descriptions.add
@@ -0,0 +1 @@
+Allow providing avatar/header descriptions
\ No newline at end of file

From 855c5a234f4ca743303f1b88974665d7b9f58684 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= <git@mkljczk.pl>
Date: Sat, 17 Aug 2024 17:05:47 +0200
Subject: [PATCH 006/212] Update docs
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
---
 .../development/API/differences_in_mastoapi_responses.md | 9 ++++++++-
 lib/pleroma/web/api_spec/schemas/account.ex              | 2 +-
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/docs/development/API/differences_in_mastoapi_responses.md b/docs/development/API/differences_in_mastoapi_responses.md
index 41464e802..114d6e32d 100644
--- a/docs/development/API/differences_in_mastoapi_responses.md
+++ b/docs/development/API/differences_in_mastoapi_responses.md
@@ -97,13 +97,18 @@ Endpoints which accept `with_relationships` parameter:
 - `/api/v1/accounts/:id/following`
 - `/api/v1/mutes`
 
+Has these additional fields:
+
+- `avatar_description`: string, image description for user avatar, defaults to empty string
+- `header_description`: string, image description for user banner, defaults to empty string
+
 Has these additional fields under the `pleroma` object:
 
 - `ap_id`: nullable URL string, ActivityPub id of the user
 - `background_image`: nullable URL string, background image of the user
 - `tags`: Lists an array of tags for the user
 - `relationship` (object): Includes fields as documented for Mastodon API https://docs.joinmastodon.org/entities/relationship/
-- `is_moderator`: boolean, nullable,  true if user is a moderator
+- `is_moderator`: boolean, nullable, true if user is a moderator
 - `is_admin`: boolean, nullable, true if user is an admin
 - `confirmation_pending`: boolean, true if a new user account is waiting on email confirmation to be activated
 - `hide_favorites`: boolean, true when the user has hiding favorites enabled
@@ -255,6 +260,8 @@ Additional parameters can be added to the JSON body/Form data:
 - `actor_type` - the type of this account.
 - `accepts_chat_messages` - if false, this account will reject all chat messages.
 - `language` - user's preferred language for receiving emails (digest, confirmation, etc.)
+- `avatar_description` - image description for user avatar
+- `header_description` - image description for user banner
 
 All images (avatar, banner and background) can be reset to the default by sending an empty string ("") instead of a file.
 
diff --git a/lib/pleroma/web/api_spec/schemas/account.ex b/lib/pleroma/web/api_spec/schemas/account.ex
index 32a0dd6cb..3f2310df9 100644
--- a/lib/pleroma/web/api_spec/schemas/account.ex
+++ b/lib/pleroma/web/api_spec/schemas/account.ex
@@ -147,7 +147,7 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Account do
             }
           }
         }
-      }
+      },
       avatar_description: %Schema{type: :string},
       header_description: %Schema{type: :string}
     },

From c802f3b7f61e1c4bbe2f4eec757802e30f88b6a5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= <git@mkljczk.pl>
Date: Sat, 17 Aug 2024 19:58:32 +0200
Subject: [PATCH 007/212] Validate media description length
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
---
 lib/pleroma/user.ex                           | 24 ++++++++++++++---
 .../controllers/account_controller.ex         |  6 +++++
 .../mastodon_api/update_credentials_test.exs  | 27 +++++++++++++++++++
 3 files changed, 54 insertions(+), 3 deletions(-)

diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index c3cb72fab..517009253 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -586,16 +586,18 @@ defmodule Pleroma.User do
     |> validate_length(:bio, max: bio_limit)
     |> validate_length(:name, min: 1, max: name_limit)
     |> validate_inclusion(:actor_type, Pleroma.Constants.allowed_user_actor_types())
+    |> validate_image_description(:avatar_description, params)
+    |> validate_image_description(:header_description, params)
     |> put_fields()
     |> put_emoji()
     |> put_change_if_present(:bio, &{:ok, parse_bio(&1, struct)})
     |> put_change_if_present(
       :avatar,
-      &put_upload(&1, :avatar, Map.get(params, :avatar_description, nil))
+      &put_upload(&1, :avatar, Map.get(params, :avatar_description))
     )
     |> put_change_if_present(
       :banner,
-      &put_upload(&1, :banner, Map.get(params, :header_description, nil))
+      &put_upload(&1, :banner, Map.get(params, :header_description))
     )
     |> put_change_if_present(:background, &put_upload(&1, :background))
     |> put_change_if_present(
@@ -689,7 +691,20 @@ defmodule Pleroma.User do
     end
   end
 
-  defp maybe_update_image_description(changeset, image_field, description) do
+  defp validate_image_description(changeset, key, params) do
+    description_limit = Config.get([:instance, :description_limit], 5_000)
+    description = Map.get(params, key)
+
+    if is_binary(description) and String.length(description) > description_limit do
+      changeset
+      |> add_error(key, "#{key} is too long")
+    else
+      changeset
+    end
+  end
+
+  defp maybe_update_image_description(changeset, image_field, description)
+       when is_binary(description) do
     with {:image_missing, true} <- {:image_missing, not changed?(changeset, image_field)},
          {:existing_image, %{"id" => id}} <-
            {:existing_image, Map.get(changeset.data, image_field)},
@@ -697,10 +712,13 @@ defmodule Pleroma.User do
          {:ok, object} <- Object.update_data(object, %{"name" => description}) do
       put_change(changeset, image_field, object.data)
     else
+      {:description_too_long, true} -> {:error}
       _ -> changeset
     end
   end
 
+  defp maybe_update_image_description(changeset, _, _), do: changeset
+
   def update_as_admin_changeset(struct, params) do
     struct
     |> update_changeset(params)
diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex
index 2302d6ed8..68157b0c4 100644
--- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex
@@ -279,6 +279,12 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
       {:error, %Ecto.Changeset{errors: [{:name, {_, _}} | _]}} ->
         render_error(conn, :request_entity_too_large, "Name is too long")
 
+      {:error, %Ecto.Changeset{errors: [{:avatar_description, {_, _}} | _]}} ->
+        render_error(conn, :request_entity_too_large, "Avatar description is too long")
+
+      {:error, %Ecto.Changeset{errors: [{:header_description, {_, _}} | _]}} ->
+        render_error(conn, :request_entity_too_large, "Banner description is too long")
+
       {:error, %Ecto.Changeset{errors: [{:fields, {"invalid", _}} | _]}} ->
         render_error(conn, :request_entity_too_large, "One or more field entries are too long")
 
diff --git a/test/pleroma/web/mastodon_api/update_credentials_test.exs b/test/pleroma/web/mastodon_api/update_credentials_test.exs
index 28d3b00db..97ad2e849 100644
--- a/test/pleroma/web/mastodon_api/update_credentials_test.exs
+++ b/test/pleroma/web/mastodon_api/update_credentials_test.exs
@@ -472,6 +472,33 @@ defmodule Pleroma.Web.MastodonAPI.UpdateCredentialsTest do
       assert user.avatar["name"] == "me and pleroma tan"
     end
 
+    test "limit", %{user: user, conn: conn} do
+      new_header = %Plug.Upload{
+        content_type: "image/jpeg",
+        path: Path.absname("test/fixtures/image.jpg"),
+        filename: "an_image.jpg"
+      }
+
+      assert user.banner == %{}
+
+      conn
+      |> patch("/api/v1/accounts/update_credentials", %{"header" => new_header})
+
+      description_limit = Config.get([:instance, :description_limit], 100)
+
+      description = String.duplicate(".", description_limit + 1)
+
+      conn =
+        conn
+        |> assign(:user, User.get_by_id(user.id))
+        |> patch("/api/v1/accounts/update_credentials", %{
+          "header_description" => description
+        })
+
+      assert %{"error" => "Banner description is too long"} =
+               json_response_and_validate_schema(conn, 413)
+    end
+
     test "Strip / from upload files", %{user: user, conn: conn} do
       new_image = %Plug.Upload{
         content_type: "image/jpeg",

From 3498662712c088cf578e7241c12aa1e5da42745a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= <git@mkljczk.pl>
Date: Sat, 17 Aug 2024 19:59:39 +0200
Subject: [PATCH 008/212] Move new fields to pleroma object
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
---
 docs/development/API/differences_in_mastoapi_responses.md | 7 ++-----
 lib/pleroma/web/api_spec/schemas/account.ex               | 8 ++++----
 lib/pleroma/web/mastodon_api/views/account_view.ex        | 8 ++++----
 3 files changed, 10 insertions(+), 13 deletions(-)

diff --git a/docs/development/API/differences_in_mastoapi_responses.md b/docs/development/API/differences_in_mastoapi_responses.md
index 114d6e32d..22a26b77b 100644
--- a/docs/development/API/differences_in_mastoapi_responses.md
+++ b/docs/development/API/differences_in_mastoapi_responses.md
@@ -97,11 +97,6 @@ Endpoints which accept `with_relationships` parameter:
 - `/api/v1/accounts/:id/following`
 - `/api/v1/mutes`
 
-Has these additional fields:
-
-- `avatar_description`: string, image description for user avatar, defaults to empty string
-- `header_description`: string, image description for user banner, defaults to empty string
-
 Has these additional fields under the `pleroma` object:
 
 - `ap_id`: nullable URL string, ActivityPub id of the user
@@ -125,6 +120,8 @@ Has these additional fields under the `pleroma` object:
 - `notification_settings`: object, can be absent. See `/api/v1/pleroma/notification_settings` for the parameters/keys returned.
 - `accepts_chat_messages`: boolean, but can be null if we don't have that information about a user
 - `favicon`: nullable URL string, Favicon image of the user's instance
+- `avatar_description`: string, image description for user avatar, defaults to empty string
+- `header_description`: string, image description for user banner, defaults to empty string
 
 ### Source
 
diff --git a/lib/pleroma/web/api_spec/schemas/account.ex b/lib/pleroma/web/api_spec/schemas/account.ex
index 3f2310df9..1f73ef60c 100644
--- a/lib/pleroma/web/api_spec/schemas/account.ex
+++ b/lib/pleroma/web/api_spec/schemas/account.ex
@@ -111,7 +111,9 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Account do
             format: :uri,
             nullable: true,
             description: "Favicon image of the user's instance"
-          }
+          },
+          avatar_description: %Schema{type: :string},
+          header_description: %Schema{type: :string}
         }
       },
       source: %Schema{
@@ -147,9 +149,7 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Account do
             }
           }
         }
-      },
-      avatar_description: %Schema{type: :string},
-      header_description: %Schema{type: :string}
+      }
     },
     example: %{
       "acct" => "foobar",
diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex
index bd8af265a..0643b8f14 100644
--- a/lib/pleroma/web/mastodon_api/views/account_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/account_view.ex
@@ -324,10 +324,10 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
         skip_thread_containment: user.skip_thread_containment,
         background_image: image_url(user.background) |> MediaProxy.url(),
         accepts_chat_messages: user.accepts_chat_messages,
-        favicon: favicon
-      },
-      avatar_description: avatar_description,
-      header_description: header_description
+        favicon: favicon,
+        avatar_description: avatar_description,
+        header_description: header_description
+      }
     }
     |> maybe_put_role(user, opts[:for])
     |> maybe_put_settings(user, opts[:for], opts)

From 917ac89b4f944a80b1d168fd07d94c762ee04ed9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= <git@mkljczk.pl>
Date: Sat, 17 Aug 2024 20:01:25 +0200
Subject: [PATCH 009/212] Update tests
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
---
 test/pleroma/web/mastodon_api/views/account_view_test.exs | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/test/pleroma/web/mastodon_api/views/account_view_test.exs b/test/pleroma/web/mastodon_api/views/account_view_test.exs
index dca64853d..0301a4cca 100644
--- a/test/pleroma/web/mastodon_api/views/account_view_test.exs
+++ b/test/pleroma/web/mastodon_api/views/account_view_test.exs
@@ -96,7 +96,9 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
         hide_follows_count: false,
         relationship: %{},
         skip_thread_containment: false,
-        accepts_chat_messages: nil
+        accepts_chat_messages: nil,
+        avatar_description: "",
+        header_description: ""
       }
     }
 
@@ -340,7 +342,9 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
         hide_follows_count: false,
         relationship: %{},
         skip_thread_containment: false,
-        accepts_chat_messages: nil
+        accepts_chat_messages: nil,
+        avatar_description: "",
+        header_description: ""
       }
     }
 

From 010edcbcb51dfddc83d5a3810c257c1678429c2d Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Wed, 21 Aug 2024 14:50:19 -0400
Subject: [PATCH 010/212] Use Map.filter now that minimum Elixir version is
 1.13

---
 lib/pleroma/maps.ex | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/lib/pleroma/maps.ex b/lib/pleroma/maps.ex
index 5020a8ff8..1afbde484 100644
--- a/lib/pleroma/maps.ex
+++ b/lib/pleroma/maps.ex
@@ -20,15 +20,13 @@ defmodule Pleroma.Maps do
   end
 
   def filter_empty_values(data) do
-    # TODO: Change to Map.filter in Elixir 1.13+
     data
-    |> Enum.filter(fn
+    |> Map.filter(fn
       {_k, nil} -> false
       {_k, ""} -> false
       {_k, []} -> false
       {_k, %{} = v} -> Map.keys(v) != []
       {_k, _v} -> true
     end)
-    |> Map.new()
   end
 end

From e65555e8c5cacb36a404579f56fb501a7fba0781 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Wed, 21 Aug 2024 15:11:41 -0400
Subject: [PATCH 011/212] Remove workaround for URI.merge bug on nil fields
 before Elixir 1.13

https://github.com/elixir-lang/elixir/issues/10771
---
 lib/pleroma/web/mastodon_api/views/status_view.ex | 14 +-------------
 1 file changed, 1 insertion(+), 13 deletions(-)

diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex
index 747638c53..1b78477d0 100644
--- a/lib/pleroma/web/mastodon_api/views/status_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/status_view.ex
@@ -803,19 +803,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
 
   defp build_application(_), do: nil
 
-  # Workaround for Elixir issue #10771
-  # Avoid applying URI.merge unless necessary
-  # TODO: revert to always attempting URI.merge(image_url_data, page_url_data)
-  # when Elixir 1.12 is the minimum supported version
-  @spec build_image_url(struct() | nil, struct()) :: String.t() | nil
-  defp build_image_url(
-         %URI{scheme: image_scheme, host: image_host} = image_url_data,
-         %URI{} = _page_url_data
-       )
-       when not is_nil(image_scheme) and not is_nil(image_host) do
-    image_url_data |> to_string
-  end
-
+  @spec build_image_url(URI.t(), URI.t()) :: String.t()
   defp build_image_url(%URI{} = image_url_data, %URI{} = page_url_data) do
     URI.merge(page_url_data, image_url_data) |> to_string
   end

From 5138a4984ba8cf04e0b6015a7a9253a9013e013e Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Wed, 21 Aug 2024 15:24:33 -0400
Subject: [PATCH 012/212] Skip changelog

---
 changelog.d/todo-cleanup.skip | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 changelog.d/todo-cleanup.skip

diff --git a/changelog.d/todo-cleanup.skip b/changelog.d/todo-cleanup.skip
new file mode 100644
index 000000000..e69de29bb

From 649e51b581327eb34d31e0160ea70d1cba281f9a Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Thu, 22 Aug 2024 11:29:44 -0400
Subject: [PATCH 013/212] Fix Oban jobs for imports

---
 changelog.d/user-imports.fix      | 1 +
 lib/pleroma/user/import.ex        | 6 +++---
 test/pleroma/user/import_test.exs | 6 +++---
 3 files changed, 7 insertions(+), 6 deletions(-)
 create mode 100644 changelog.d/user-imports.fix

diff --git a/changelog.d/user-imports.fix b/changelog.d/user-imports.fix
new file mode 100644
index 000000000..9f39dfeda
--- /dev/null
+++ b/changelog.d/user-imports.fix
@@ -0,0 +1 @@
+Imports of blocks, mutes, and following would retry until Oban runs out of attempts due to incorrect return value being considered an error.
diff --git a/lib/pleroma/user/import.ex b/lib/pleroma/user/import.ex
index 11905237c..bee586234 100644
--- a/lib/pleroma/user/import.ex
+++ b/lib/pleroma/user/import.ex
@@ -18,7 +18,7 @@ defmodule Pleroma.User.Import do
       fn identifier ->
         with {:ok, %User{} = muted_user} <- User.get_or_fetch(identifier),
              {:ok, _} <- User.mute(user, muted_user) do
-          muted_user
+          {:ok, muted_user}
         else
           error -> handle_error(:mutes_import, identifier, error)
         end
@@ -32,7 +32,7 @@ defmodule Pleroma.User.Import do
       fn identifier ->
         with {:ok, %User{} = blocked} <- User.get_or_fetch(identifier),
              {:ok, _block} <- CommonAPI.block(blocked, blocker) do
-          blocked
+          {:ok, blocked}
         else
           error -> handle_error(:blocks_import, identifier, error)
         end
@@ -47,7 +47,7 @@ defmodule Pleroma.User.Import do
         with {:ok, %User{} = followed} <- User.get_or_fetch(identifier),
              {:ok, follower, followed} <- User.maybe_direct_follow(follower, followed),
              {:ok, _, _, _} <- CommonAPI.follow(followed, follower) do
-          followed
+          {:ok, followed}
         else
           error -> handle_error(:follow_import, identifier, error)
         end
diff --git a/test/pleroma/user/import_test.exs b/test/pleroma/user/import_test.exs
index f75305e0e..54c521698 100644
--- a/test/pleroma/user/import_test.exs
+++ b/test/pleroma/user/import_test.exs
@@ -29,7 +29,7 @@ defmodule Pleroma.User.ImportTest do
 
       assert {:ok, result} = ObanHelpers.perform(job)
       assert is_list(result)
-      assert result == [refresh_record(user2), refresh_record(user3)]
+      assert result == [{:ok, refresh_record(user2)}, {:ok, refresh_record(user3)}]
       assert User.following?(user1, user2)
       assert User.following?(user1, user3)
     end
@@ -48,7 +48,7 @@ defmodule Pleroma.User.ImportTest do
 
       assert {:ok, result} = ObanHelpers.perform(job)
       assert is_list(result)
-      assert result == [user2, user3]
+      assert result == [{:ok, user2}, {:ok, user3}]
       assert User.blocks?(user1, user2)
       assert User.blocks?(user1, user3)
     end
@@ -67,7 +67,7 @@ defmodule Pleroma.User.ImportTest do
 
       assert {:ok, result} = ObanHelpers.perform(job)
       assert is_list(result)
-      assert result == [user2, user3]
+      assert result == [{:ok, user2}, {:ok, user3}]
       assert User.mutes?(user1, user2)
       assert User.mutes?(user1, user3)
     end

From a9aa810d3dadaac5a40d18f56ab41b6276206db1 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Thu, 22 Aug 2024 12:49:32 -0400
Subject: [PATCH 014/212] Change imports to generate an Oban job per each task

---
 changelog.d/user-imports.fix                  |   2 +-
 lib/pleroma/user/import.ex                    | 144 ++++++++++--------
 .../controllers/user_import_controller.ex     |   8 +-
 lib/pleroma/workers/background_worker.ex      |   6 +-
 test/pleroma/user/import_test.exs             |  27 ++--
 .../user_import_controller_test.exs           |  92 +++++++----
 6 files changed, 170 insertions(+), 109 deletions(-)

diff --git a/changelog.d/user-imports.fix b/changelog.d/user-imports.fix
index 9f39dfeda..0076c73d7 100644
--- a/changelog.d/user-imports.fix
+++ b/changelog.d/user-imports.fix
@@ -1 +1 @@
-Imports of blocks, mutes, and following would retry until Oban runs out of attempts due to incorrect return value being considered an error.
+Imports of blocks, mutes, and follows would retry repeatedly due to incorrect error handling and all work executed in a single job
diff --git a/lib/pleroma/user/import.ex b/lib/pleroma/user/import.ex
index bee586234..400e62153 100644
--- a/lib/pleroma/user/import.ex
+++ b/lib/pleroma/user/import.ex
@@ -5,6 +5,7 @@
 defmodule Pleroma.User.Import do
   use Ecto.Schema
 
+  alias Pleroma.Repo
   alias Pleroma.User
   alias Pleroma.Web.CommonAPI
   alias Pleroma.Workers.BackgroundWorker
@@ -12,80 +13,103 @@ defmodule Pleroma.User.Import do
   require Logger
 
   @spec perform(atom(), User.t(), list()) :: :ok | list() | {:error, any()}
-  def perform(:mutes_import, %User{} = user, [_ | _] = identifiers) do
-    Enum.map(
-      identifiers,
-      fn identifier ->
-        with {:ok, %User{} = muted_user} <- User.get_or_fetch(identifier),
-             {:ok, _} <- User.mute(user, muted_user) do
-          {:ok, muted_user}
-        else
-          error -> handle_error(:mutes_import, identifier, error)
-        end
-      end
-    )
+  def perform(:mute_import, %User{} = user, actor) do
+    with {:ok, %User{} = muted_user} <- User.get_or_fetch(actor),
+         {_, false} <- {:existing_mute, User.mutes_user?(user, muted_user)},
+         {:ok, _} <- User.mute(user, muted_user),
+         # User.mute/2 returns a FollowingRelationship not a %User{} like we get
+         # from CommonAPI.block/2 or CommonAPI.follow/2, so we fetch again to
+         # return the target actor for consistency
+         {:ok, muted_user} <- User.get_or_fetch(actor) do
+      {:ok, muted_user}
+    else
+      {:existing_mute, true} -> :ok
+      error -> handle_error(:mutes_import, actor, error)
+    end
   end
 
-  def perform(:blocks_import, %User{} = blocker, [_ | _] = identifiers) do
-    Enum.map(
-      identifiers,
-      fn identifier ->
-        with {:ok, %User{} = blocked} <- User.get_or_fetch(identifier),
-             {:ok, _block} <- CommonAPI.block(blocked, blocker) do
-          {:ok, blocked}
-        else
-          error -> handle_error(:blocks_import, identifier, error)
-        end
-      end
-    )
+  def perform(:block_import, %User{} = user, actor) do
+    with {:ok, %User{} = blocked} <- User.get_or_fetch(actor),
+         {_, false} <- {:existing_block, User.blocks_user?(user, blocked)},
+         {:ok, _block} <- CommonAPI.block(blocked, user) do
+      {:ok, blocked}
+    else
+      {:existing_block, true} -> :ok
+      error -> handle_error(:blocks_import, actor, error)
+    end
   end
 
-  def perform(:follow_import, %User{} = follower, [_ | _] = identifiers) do
-    Enum.map(
-      identifiers,
-      fn identifier ->
-        with {:ok, %User{} = followed} <- User.get_or_fetch(identifier),
-             {:ok, follower, followed} <- User.maybe_direct_follow(follower, followed),
-             {:ok, _, _, _} <- CommonAPI.follow(followed, follower) do
-          {:ok, followed}
-        else
-          error -> handle_error(:follow_import, identifier, error)
-        end
-      end
-    )
+  def perform(:follow_import, %User{} = user, actor) do
+    with {:ok, %User{} = followed} <- User.get_or_fetch(actor),
+         {_, false} <- {:existing_follow, User.following?(user, followed)},
+         {:ok, user, followed} <- User.maybe_direct_follow(user, followed),
+         {:ok, _, _, _} <- CommonAPI.follow(followed, user) do
+      {:ok, followed}
+    else
+      {:existing_follow, true} -> :ok
+      error -> handle_error(:follow_import, actor, error)
+    end
   end
 
-  def perform(_, _, _), do: :ok
-
   defp handle_error(op, user_id, error) do
     Logger.debug("#{op} failed for #{user_id} with: #{inspect(error)}")
     error
   end
 
-  def blocks_import(%User{} = blocker, [_ | _] = identifiers) do
-    BackgroundWorker.new(%{
-      "op" => "blocks_import",
-      "user_id" => blocker.id,
-      "identifiers" => identifiers
-    })
-    |> Oban.insert()
+  def blocks_import(%User{} = user, [_ | _] = actors) do
+    jobs =
+      Repo.checkout(fn ->
+        Enum.reduce(actors, [], fn actor, acc ->
+          {:ok, job} =
+            BackgroundWorker.new(%{
+              "op" => "block_import",
+              "user_id" => user.id,
+              "actor" => actor
+            })
+            |> Oban.insert()
+
+          acc ++ [job]
+        end)
+      end)
+
+    {:ok, jobs}
   end
 
-  def follow_import(%User{} = follower, [_ | _] = identifiers) do
-    BackgroundWorker.new(%{
-      "op" => "follow_import",
-      "user_id" => follower.id,
-      "identifiers" => identifiers
-    })
-    |> Oban.insert()
+  def follows_import(%User{} = user, [_ | _] = actors) do
+    jobs =
+      Repo.checkout(fn ->
+        Enum.reduce(actors, [], fn actor, acc ->
+          {:ok, job} =
+            BackgroundWorker.new(%{
+              "op" => "follow_import",
+              "user_id" => user.id,
+              "actor" => actor
+            })
+            |> Oban.insert()
+
+          acc ++ [job]
+        end)
+      end)
+
+    {:ok, jobs}
   end
 
-  def mutes_import(%User{} = user, [_ | _] = identifiers) do
-    BackgroundWorker.new(%{
-      "op" => "mutes_import",
-      "user_id" => user.id,
-      "identifiers" => identifiers
-    })
-    |> Oban.insert()
+  def mutes_import(%User{} = user, [_ | _] = actors) do
+    jobs =
+      Repo.checkout(fn ->
+        Enum.reduce(actors, [], fn actor, acc ->
+          {:ok, job} =
+            BackgroundWorker.new(%{
+              "op" => "mute_import",
+              "user_id" => user.id,
+              "actor" => actor
+            })
+            |> Oban.insert()
+
+          acc ++ [job]
+        end)
+      end)
+
+    {:ok, jobs}
   end
 end
diff --git a/lib/pleroma/web/pleroma_api/controllers/user_import_controller.ex b/lib/pleroma/web/pleroma_api/controllers/user_import_controller.ex
index 96466f192..d65c30dab 100644
--- a/lib/pleroma/web/pleroma_api/controllers/user_import_controller.ex
+++ b/lib/pleroma/web/pleroma_api/controllers/user_import_controller.ex
@@ -38,8 +38,8 @@ defmodule Pleroma.Web.PleromaAPI.UserImportController do
       |> Enum.map(&(&1 |> String.trim() |> String.trim_leading("@")))
       |> Enum.reject(&(&1 == ""))
 
-    User.Import.follow_import(follower, identifiers)
-    json(conn, "job started")
+    User.Import.follows_import(follower, identifiers)
+    json(conn, "jobs started")
   end
 
   def blocks(
@@ -55,7 +55,7 @@ defmodule Pleroma.Web.PleromaAPI.UserImportController do
 
   defp do_block(%{assigns: %{user: blocker}} = conn, list) do
     User.Import.blocks_import(blocker, prepare_user_identifiers(list))
-    json(conn, "job started")
+    json(conn, "jobs started")
   end
 
   def mutes(
@@ -71,7 +71,7 @@ defmodule Pleroma.Web.PleromaAPI.UserImportController do
 
   defp do_mute(%{assigns: %{user: user}} = conn, list) do
     User.Import.mutes_import(user, prepare_user_identifiers(list))
-    json(conn, "job started")
+    json(conn, "jobs started")
   end
 
   defp prepare_user_identifiers(list) do
diff --git a/lib/pleroma/workers/background_worker.ex b/lib/pleroma/workers/background_worker.ex
index 60da2d5ca..4737c6ea2 100644
--- a/lib/pleroma/workers/background_worker.ex
+++ b/lib/pleroma/workers/background_worker.ex
@@ -19,10 +19,10 @@ defmodule Pleroma.Workers.BackgroundWorker do
     User.perform(:force_password_reset, user)
   end
 
-  def perform(%Job{args: %{"op" => op, "user_id" => user_id, "identifiers" => identifiers}})
-      when op in ["blocks_import", "follow_import", "mutes_import"] do
+  def perform(%Job{args: %{"op" => op, "user_id" => user_id, "actor" => actor}})
+      when op in ["block_import", "follow_import", "mute_import"] do
     user = User.get_cached_by_id(user_id)
-    {:ok, User.Import.perform(String.to_existing_atom(op), user, identifiers)}
+    User.Import.perform(String.to_existing_atom(op), user, actor)
   end
 
   def perform(%Job{
diff --git a/test/pleroma/user/import_test.exs b/test/pleroma/user/import_test.exs
index 54c521698..1d6469a4f 100644
--- a/test/pleroma/user/import_test.exs
+++ b/test/pleroma/user/import_test.exs
@@ -25,11 +25,12 @@ defmodule Pleroma.User.ImportTest do
         user3.nickname
       ]
 
-      {:ok, job} = User.Import.follow_import(user1, identifiers)
+      {:ok, jobs} = User.Import.follows_import(user1, identifiers)
+
+      for job <- jobs do
+        assert {:ok, %User{}} = ObanHelpers.perform(job)
+      end
 
-      assert {:ok, result} = ObanHelpers.perform(job)
-      assert is_list(result)
-      assert result == [{:ok, refresh_record(user2)}, {:ok, refresh_record(user3)}]
       assert User.following?(user1, user2)
       assert User.following?(user1, user3)
     end
@@ -44,11 +45,12 @@ defmodule Pleroma.User.ImportTest do
         user3.nickname
       ]
 
-      {:ok, job} = User.Import.blocks_import(user1, identifiers)
+      {:ok, jobs} = User.Import.blocks_import(user1, identifiers)
+
+      for job <- jobs do
+        assert {:ok, %User{}} = ObanHelpers.perform(job)
+      end
 
-      assert {:ok, result} = ObanHelpers.perform(job)
-      assert is_list(result)
-      assert result == [{:ok, user2}, {:ok, user3}]
       assert User.blocks?(user1, user2)
       assert User.blocks?(user1, user3)
     end
@@ -63,11 +65,12 @@ defmodule Pleroma.User.ImportTest do
         user3.nickname
       ]
 
-      {:ok, job} = User.Import.mutes_import(user1, identifiers)
+      {:ok, jobs} = User.Import.mutes_import(user1, identifiers)
+
+      for job <- jobs do
+        assert {:ok, %User{}} = ObanHelpers.perform(job)
+      end
 
-      assert {:ok, result} = ObanHelpers.perform(job)
-      assert is_list(result)
-      assert result == [{:ok, user2}, {:ok, user3}]
       assert User.mutes?(user1, user2)
       assert User.mutes?(user1, user3)
     end
diff --git a/test/pleroma/web/pleroma_api/controllers/user_import_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/user_import_controller_test.exs
index 52a62e416..efdc743e3 100644
--- a/test/pleroma/web/pleroma_api/controllers/user_import_controller_test.exs
+++ b/test/pleroma/web/pleroma_api/controllers/user_import_controller_test.exs
@@ -22,7 +22,7 @@ defmodule Pleroma.Web.PleromaAPI.UserImportControllerTest do
     test "it returns HTTP 200", %{conn: conn} do
       user2 = insert(:user)
 
-      assert "job started" ==
+      assert "jobs started" ==
                conn
                |> put_req_header("content-type", "application/json")
                |> post("/api/pleroma/follow_import", %{"list" => "#{user2.ap_id}"})
@@ -38,7 +38,7 @@ defmodule Pleroma.Web.PleromaAPI.UserImportControllerTest do
            "Account address,Show boosts\n#{user2.ap_id},true"
          end}
       ]) do
-        assert "job started" ==
+        assert "jobs started" ==
                  conn
                  |> put_req_header("content-type", "application/json")
                  |> post("/api/pleroma/follow_import", %{
@@ -46,9 +46,9 @@ defmodule Pleroma.Web.PleromaAPI.UserImportControllerTest do
                  })
                  |> json_response_and_validate_schema(200)
 
-        assert [{:ok, job_result}] = ObanHelpers.perform_all()
-        assert job_result == [refresh_record(user2)]
-        assert [%Pleroma.User{follower_count: 1}] = job_result
+        assert [{:ok, updated_user}] = ObanHelpers.perform_all()
+        assert updated_user.id == user2.id
+        assert updated_user.follower_count == 1
       end
     end
 
@@ -63,7 +63,7 @@ defmodule Pleroma.Web.PleromaAPI.UserImportControllerTest do
         })
         |> json_response_and_validate_schema(200)
 
-      assert response == "job started"
+      assert response == "jobs started"
     end
 
     test "requires 'follow' or 'write:follows' permissions" do
@@ -102,14 +102,20 @@ defmodule Pleroma.Web.PleromaAPI.UserImportControllerTest do
         ]
         |> Enum.join("\n")
 
-      assert "job started" ==
+      assert "jobs started" ==
                conn
                |> put_req_header("content-type", "application/json")
                |> post("/api/pleroma/follow_import", %{"list" => identifiers})
                |> json_response_and_validate_schema(200)
 
-      assert [{:ok, job_result}] = ObanHelpers.perform_all()
-      assert job_result == Enum.map(users, &refresh_record/1)
+      results = ObanHelpers.perform_all()
+
+      returned_users =
+        for {_, returned_user} <- results do
+          returned_user
+        end
+
+      assert returned_users == Enum.map(users, &refresh_record/1)
     end
   end
 
@@ -120,7 +126,7 @@ defmodule Pleroma.Web.PleromaAPI.UserImportControllerTest do
     test "it returns HTTP 200", %{conn: conn} do
       user2 = insert(:user)
 
-      assert "job started" ==
+      assert "jobs started" ==
                conn
                |> put_req_header("content-type", "application/json")
                |> post("/api/pleroma/blocks_import", %{"list" => "#{user2.ap_id}"})
@@ -133,7 +139,7 @@ defmodule Pleroma.Web.PleromaAPI.UserImportControllerTest do
       with_mocks([
         {File, [], read!: fn "blocks_list.txt" -> "#{user2.ap_id} #{user3.ap_id}" end}
       ]) do
-        assert "job started" ==
+        assert "jobs started" ==
                  conn
                  |> put_req_header("content-type", "application/json")
                  |> post("/api/pleroma/blocks_import", %{
@@ -141,8 +147,14 @@ defmodule Pleroma.Web.PleromaAPI.UserImportControllerTest do
                  })
                  |> json_response_and_validate_schema(200)
 
-        assert [{:ok, job_result}] = ObanHelpers.perform_all()
-        assert job_result == users
+        results = ObanHelpers.perform_all()
+
+        returned_users =
+          for {_, returned_user} <- results do
+            returned_user
+          end
+
+        assert returned_users == users
       end
     end
 
@@ -159,14 +171,25 @@ defmodule Pleroma.Web.PleromaAPI.UserImportControllerTest do
         ]
         |> Enum.join(" ")
 
-      assert "job started" ==
+      assert "jobs started" ==
                conn
                |> put_req_header("content-type", "application/json")
                |> post("/api/pleroma/blocks_import", %{"list" => identifiers})
                |> json_response_and_validate_schema(200)
 
-      assert [{:ok, job_result}] = ObanHelpers.perform_all()
-      assert job_result == users
+      results = ObanHelpers.perform_all()
+
+      returned_user_ids =
+        for {_, user} <- results do
+          user.id
+        end
+
+      original_user_ids =
+        for user <- users do
+          user.id
+        end
+
+      assert match?(^original_user_ids, returned_user_ids)
     end
   end
 
@@ -177,24 +200,25 @@ defmodule Pleroma.Web.PleromaAPI.UserImportControllerTest do
     test "it returns HTTP 200", %{user: user, conn: conn} do
       user2 = insert(:user)
 
-      assert "job started" ==
+      assert "jobs started" ==
                conn
                |> put_req_header("content-type", "application/json")
                |> post("/api/pleroma/mutes_import", %{"list" => "#{user2.ap_id}"})
                |> json_response_and_validate_schema(200)
 
-      assert [{:ok, job_result}] = ObanHelpers.perform_all()
-      assert job_result == [user2]
+      [{:ok, result_user}] = ObanHelpers.perform_all()
+
+      assert result_user == refresh_record(user2)
       assert Pleroma.User.mutes?(user, user2)
     end
 
     test "it imports mutes users from file", %{user: user, conn: conn} do
-      users = [user2, user3] = insert_list(2, :user)
+      [user2, user3] = insert_list(2, :user)
 
       with_mocks([
         {File, [], read!: fn "mutes_list.txt" -> "#{user2.ap_id} #{user3.ap_id}" end}
       ]) do
-        assert "job started" ==
+        assert "jobs started" ==
                  conn
                  |> put_req_header("content-type", "application/json")
                  |> post("/api/pleroma/mutes_import", %{
@@ -202,14 +226,19 @@ defmodule Pleroma.Web.PleromaAPI.UserImportControllerTest do
                  })
                  |> json_response_and_validate_schema(200)
 
-        assert [{:ok, job_result}] = ObanHelpers.perform_all()
-        assert job_result == users
-        assert Enum.all?(users, &Pleroma.User.mutes?(user, &1))
+        results = ObanHelpers.perform_all()
+
+        returned_users =
+          for {_, returned_user} <- results do
+            returned_user
+          end
+
+        assert Enum.all?(returned_users, &Pleroma.User.mutes?(user, &1))
       end
     end
 
     test "it imports mutes with different nickname variations", %{user: user, conn: conn} do
-      users = [user2, user3, user4, user5, user6] = insert_list(5, :user)
+      [user2, user3, user4, user5, user6] = insert_list(5, :user)
 
       identifiers =
         [
@@ -221,15 +250,20 @@ defmodule Pleroma.Web.PleromaAPI.UserImportControllerTest do
         ]
         |> Enum.join(" ")
 
-      assert "job started" ==
+      assert "jobs started" ==
                conn
                |> put_req_header("content-type", "application/json")
                |> post("/api/pleroma/mutes_import", %{"list" => identifiers})
                |> json_response_and_validate_schema(200)
 
-      assert [{:ok, job_result}] = ObanHelpers.perform_all()
-      assert job_result == users
-      assert Enum.all?(users, &Pleroma.User.mutes?(user, &1))
+      results = ObanHelpers.perform_all()
+
+      returned_users =
+        for {_, returned_user} <- results do
+          returned_user
+        end
+
+      assert Enum.all?(returned_users, &Pleroma.User.mutes?(user, &1))
     end
   end
 end

From 39108c5f128d9d5933f038773dc72d2e25a49564 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Thu, 22 Aug 2024 13:43:01 -0400
Subject: [PATCH 015/212] Remove unnecessary re-fetch of the actor

---
 lib/pleroma/user/import.ex | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/lib/pleroma/user/import.ex b/lib/pleroma/user/import.ex
index 400e62153..b79fa88eb 100644
--- a/lib/pleroma/user/import.ex
+++ b/lib/pleroma/user/import.ex
@@ -16,11 +16,7 @@ defmodule Pleroma.User.Import do
   def perform(:mute_import, %User{} = user, actor) do
     with {:ok, %User{} = muted_user} <- User.get_or_fetch(actor),
          {_, false} <- {:existing_mute, User.mutes_user?(user, muted_user)},
-         {:ok, _} <- User.mute(user, muted_user),
-         # User.mute/2 returns a FollowingRelationship not a %User{} like we get
-         # from CommonAPI.block/2 or CommonAPI.follow/2, so we fetch again to
-         # return the target actor for consistency
-         {:ok, muted_user} <- User.get_or_fetch(actor) do
+         {:ok, _} <- User.mute(user, muted_user) do
       {:ok, muted_user}
     else
       {:existing_mute, true} -> :ok

From 99ace19ca96e64edd25ad0ceb024be6375dc5e01 Mon Sep 17 00:00:00 2001
From: Eric Zhang <ericzhang456@disroot.org>
Date: Thu, 1 Aug 2024 07:12:38 +0000
Subject: [PATCH 016/212] Added translation using Weblate (Chinese
 (Simplified))

---
 .../zh_Hans/LC_MESSAGES/oauth_scopes.po       | 273 ++++++++++++++++++
 1 file changed, 273 insertions(+)
 create mode 100644 priv/gettext/zh_Hans/LC_MESSAGES/oauth_scopes.po

diff --git a/priv/gettext/zh_Hans/LC_MESSAGES/oauth_scopes.po b/priv/gettext/zh_Hans/LC_MESSAGES/oauth_scopes.po
new file mode 100644
index 000000000..f2acac90a
--- /dev/null
+++ b/priv/gettext/zh_Hans/LC_MESSAGES/oauth_scopes.po
@@ -0,0 +1,273 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2024-08-01 10:12+0300\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: Automatically generated\n"
+"Language-Team: none\n"
+"Language: zh_Hans\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 3.7.2\n"
+
+## This file is a PO Template file.
+##
+## "msgid"s here are often extracted from source code.
+## Add new translations manually only if they're dynamic
+## translations that can't be statically extracted.
+##
+## Run "mix gettext.extract" to bring this file up to
+## date. Leave "msgstr"s empty as changing them here has no
+## effect: edit them in PO (.po) files instead.
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "admin"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "admin:read"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "admin:write"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "follow"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "read"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "read:accounts"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "read:blocks"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "read:bookmarks"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "read:favourites"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "read:filters"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "read:follows"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "read:lists"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "read:notifications"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "read:search"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "read:statuses"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "write"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "write:accounts"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "write:blocks"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "write:bookmarks"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "write:conversations"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "write:favourites"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "write:filters"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "write:follows"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "write:lists"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "write:media"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "write:mutes"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "write:notifications"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "write:statuses"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "admin:read:accounts"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "admin:read:chats"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "admin:read:invites"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "admin:read:media_proxy_caches"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "admin:read:reports"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "admin:read:statuses"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "admin:write:accounts"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "admin:write:chats"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "admin:write:follows"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "admin:write:invites"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "admin:write:media_proxy_caches"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "admin:write:reports"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "admin:write:statuses"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "read:mutes"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "push"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "read:backups"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "read:chats"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "read:media"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "read:reports"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "write:chats"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "write:follow"
+msgstr ""
+
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+#, elixir-autogen, elixir-format
+msgid "write:reports"
+msgstr ""

From 743c4f2f5fefc496f695bc5183ffdae996e4f308 Mon Sep 17 00:00:00 2001
From: Eric Zhang <ericzhang456@disroot.org>
Date: Thu, 1 Aug 2024 06:49:21 +0000
Subject: [PATCH 017/212] Translated using Weblate (Chinese (Simplified))

Currently translated at 19.8% (193 of 974 strings)

Translation: Pleroma/Pleroma Backend (domain config_descriptions)
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-backend-domain-config_descriptions/zh_Hans/
---
 .../LC_MESSAGES/config_descriptions.po        | 26 ++++++++++---------
 1 file changed, 14 insertions(+), 12 deletions(-)

diff --git a/priv/gettext/zh_Hans/LC_MESSAGES/config_descriptions.po b/priv/gettext/zh_Hans/LC_MESSAGES/config_descriptions.po
index ff9ad5245..281fad932 100644
--- a/priv/gettext/zh_Hans/LC_MESSAGES/config_descriptions.po
+++ b/priv/gettext/zh_Hans/LC_MESSAGES/config_descriptions.po
@@ -3,9 +3,9 @@ msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2022-07-21 04:21+0300\n"
-"PO-Revision-Date: 2022-07-24 10:04+0000\n"
-"Last-Translator: Yating Zhan <thestrandedvalley@protonmail.com>\n"
-"Language-Team: Chinese (Simplified) <http://weblate.pleroma-dev.ebin.club/"
+"PO-Revision-Date: 2024-08-01 08:17+0000\n"
+"Last-Translator: Eric Zhang <ericzhang456@disroot.org>\n"
+"Language-Team: Chinese (Simplified) <https://translate.pleroma.social/"
 "projects/pleroma/pleroma-backend-domain-config_descriptions/zh_Hans/>\n"
 "Language: zh_Hans\n"
 "MIME-Version: 1.0\n"
@@ -49,6 +49,8 @@ msgstr "Mime 类型设置"
 msgctxt "config description at :pleroma"
 msgid "Allows setting a token that can be used to authenticate requests with admin privileges without a normal user account token. Append the `admin_token` parameter to requests to utilize it. (Please reconsider using HTTP Basic Auth or OAuth-based authentication if possible)"
 msgstr ""
+"允许设置令牌以不使用普通用户令牌来授权管理员权限。在参数后加上 `admin_token` "
+"来启用该功能。(可用时可以考虑使用 HTTP Basic Auth 或 基于 OAuth 的鉴定方式)"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -126,7 +128,7 @@ msgstr "ActivityPub 相关设置"
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:assets"
 msgid "This section configures assets to be used with various frontends. Currently the only option relates to mascots on the mastodon frontend"
-msgstr ""
+msgstr "该部分配置不同前端使用的资源。目前该选项只对 Mastodon 前端的吉祥物有效"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -226,7 +228,7 @@ msgid "Majic/libmagic configuration"
 msgstr "Majic/libmagic 配置"
 
 #: lib/pleroma/docs/translator.ex:5
-#, elixir-autogen, elixir-format, fuzzy
+#, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:manifest"
 msgid "This section describe PWA manifest instance-specific values. Currently this option relate only for MastoFE."
 msgstr "此处提供针对特定实例的 PWA manifest 数值。目前相关设定尚只支持 MastoFE。"
@@ -244,10 +246,10 @@ msgid "Media proxy"
 msgstr "媒体代理"
 
 #: lib/pleroma/docs/translator.ex:5
-#, elixir-autogen, elixir-format, fuzzy
+#, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:modules"
 msgid "Custom Runtime Modules"
-msgstr "自定义 Runtime 模块"
+msgstr "自定义运行库模块"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -299,7 +301,7 @@ msgstr "拒绝提及特定用户的讯息"
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:mrf_normalize_markup"
 msgid "MRF NormalizeMarkup settings. Scrub configured hypertext markup."
-msgstr ""
+msgstr "MRF NomalizeMarkup 设置。清楚超文本标记。"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -317,7 +319,7 @@ msgstr "RejectNonPublic 丢弃有非公开的可见性设置的文章。"
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:mrf_simple"
 msgid "Simple ingress policies"
-msgstr ""
+msgstr "简单入口流量控制"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -608,13 +610,13 @@ msgstr "邮件通知"
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-:emoji"
 msgid "Emoji"
-msgstr "Emoji"
+msgstr "表情符号"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-:features"
 msgid "Features"
-msgstr "特性"
+msgstr "功能"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -3607,7 +3609,7 @@ msgstr ""
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-:assets > :mascots"
 msgid "Mascots"
-msgstr ""
+msgstr "吉祥物"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format

From 1902323e97f36c71414304113473c4daddd166b1 Mon Sep 17 00:00:00 2001
From: Yating Zhan <thestrandedvalley@protonmail.com>
Date: Thu, 1 Aug 2024 08:13:38 +0000
Subject: [PATCH 018/212] Translated using Weblate (Chinese (Simplified))

Currently translated at 19.8% (193 of 974 strings)

Translation: Pleroma/Pleroma Backend (domain config_descriptions)
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-backend-domain-config_descriptions/zh_Hans/
---
 priv/gettext/zh_Hans/LC_MESSAGES/config_descriptions.po | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/priv/gettext/zh_Hans/LC_MESSAGES/config_descriptions.po b/priv/gettext/zh_Hans/LC_MESSAGES/config_descriptions.po
index 281fad932..808dd8bdc 100644
--- a/priv/gettext/zh_Hans/LC_MESSAGES/config_descriptions.po
+++ b/priv/gettext/zh_Hans/LC_MESSAGES/config_descriptions.po
@@ -4,7 +4,7 @@ msgstr ""
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2022-07-21 04:21+0300\n"
 "PO-Revision-Date: 2024-08-01 08:17+0000\n"
-"Last-Translator: Eric Zhang <ericzhang456@disroot.org>\n"
+"Last-Translator: Yating Zhan <thestrandedvalley@protonmail.com>\n"
 "Language-Team: Chinese (Simplified) <https://translate.pleroma.social/"
 "projects/pleroma/pleroma-backend-domain-config_descriptions/zh_Hans/>\n"
 "Language: zh_Hans\n"
@@ -331,7 +331,7 @@ msgstr "从选择的实例偷取看到的 emoji。"
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:mrf_subchain"
 msgid "This policy processes messages through an alternate pipeline when a given message matches certain criteria. All criteria are configured as a map of regular expressions to lists of policy modules."
-msgstr ""
+msgstr "此策略将会把满足特定条件的信息通过另一管线处理。"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format

From 6ba1b792596184cc1d37efffd55b30d56417602a Mon Sep 17 00:00:00 2001
From: Eric Zhang <ericzhang456@disroot.org>
Date: Thu, 1 Aug 2024 07:52:28 +0000
Subject: [PATCH 019/212] Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (47 of 47 strings)

Translation: Pleroma/Pleroma Backend (domain posix_errors)
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-backend-domain-posix_errors/zh_Hans/
---
 .../zh_Hans/LC_MESSAGES/posix_errors.po       | 48 +++++++++----------
 1 file changed, 24 insertions(+), 24 deletions(-)

diff --git a/priv/gettext/zh_Hans/LC_MESSAGES/posix_errors.po b/priv/gettext/zh_Hans/LC_MESSAGES/posix_errors.po
index c486a5486..930f5db1e 100644
--- a/priv/gettext/zh_Hans/LC_MESSAGES/posix_errors.po
+++ b/priv/gettext/zh_Hans/LC_MESSAGES/posix_errors.po
@@ -8,9 +8,9 @@
 ## to merge POT files into PO files.
 msgid ""
 msgstr ""
-"PO-Revision-Date: 2022-07-22 19:00+0000\n"
-"Last-Translator: Yating Zhan <thestrandedvalley@protonmail.com>\n"
-"Language-Team: Chinese (Simplified) <http://weblate.pleroma-dev.ebin.club/"
+"PO-Revision-Date: 2024-08-01 08:19+0000\n"
+"Last-Translator: Eric Zhang <ericzhang456@disroot.org>\n"
+"Language-Team: Chinese (Simplified) <https://translate.pleroma.social/"
 "projects/pleroma/pleroma-backend-domain-posix_errors/zh_Hans/>\n"
 "Language: zh_Hans\n"
 "Content-Type: text/plain; charset=UTF-8\n"
@@ -22,19 +22,19 @@ msgid "eperm"
 msgstr "不允许的操作"
 
 msgid "eacces"
-msgstr "权限不够"
+msgstr "拒绝访问"
 
 msgid "eagain"
 msgstr "资源暂时不可用"
 
 msgid "ebadf"
-msgstr "坏的文件描述符"
+msgstr "非法的文件描述符"
 
 msgid "ebadmsg"
-msgstr "坏讯息"
+msgstr "非法消息"
 
 msgid "ebusy"
-msgstr "设备或资源忙"
+msgstr "设备或资源繁忙"
 
 msgid "edeadlk"
 msgstr "避免了资源死锁"
@@ -46,10 +46,10 @@ msgid "edquot"
 msgstr "超出了磁盘配额"
 
 msgid "eexist"
-msgstr "文件存在"
+msgstr "文件已存在"
 
 msgid "efault"
-msgstr "坏地址"
+msgstr "非法地址"
 
 msgid "efbig"
 msgstr "文件太大"
@@ -61,7 +61,7 @@ msgid "eintr"
 msgstr "系统调用被中断"
 
 msgid "einval"
-msgstr "不合法的参数"
+msgstr "非法参数"
 
 msgid "eio"
 msgstr "输入/输出错误"
@@ -79,7 +79,7 @@ msgid "emlink"
 msgstr "太多链接"
 
 msgid "emultihop"
-msgstr ""
+msgstr "已尝试多跳"
 
 msgid "enametoolong"
 msgstr "文件名太长"
@@ -97,7 +97,7 @@ msgid "enolck"
 msgstr "没有可用的锁"
 
 msgid "enolink"
-msgstr "链接被切断了"
+msgstr "链接被切断"
 
 msgid "enoent"
 msgstr "没这文件或目录"
@@ -109,19 +109,19 @@ msgid "enospc"
 msgstr "设备上没剩余空间"
 
 msgid "enosr"
-msgstr ""
+msgstr "流资源不足"
 
 msgid "enostr"
 msgstr "设备不是流"
 
 msgid "enosys"
-msgstr "功能没实现"
+msgstr "功能未实现"
 
 msgid "enotblk"
-msgstr ""
+msgstr "需要块设备"
 
 msgid "enotdir"
-msgstr ""
+msgstr "不是目录"
 
 msgid "enotsup"
 msgstr "不受支持的操作"
@@ -136,25 +136,25 @@ msgid "eoverflow"
 msgstr "请为给定类型的数据指定较小的数值"
 
 msgid "epipe"
-msgstr ""
+msgstr "管道中断"
 
 msgid "erange"
-msgstr ""
+msgstr "数值超过范围"
 
 msgid "erofs"
-msgstr "只读权限文件系统"
+msgstr "只读文件系统"
 
 msgid "espipe"
-msgstr ""
+msgstr "非法搜寻"
 
 msgid "esrch"
-msgstr "具体进程不存在"
+msgstr "进程不存在"
 
 msgid "estale"
-msgstr ""
+msgstr "过时的文件句柄"
 
 msgid "etxtbsy"
-msgstr "文本文件忙碌"
+msgstr "文本文件繁忙"
 
 msgid "exdev"
-msgstr "该多设备链接不可用"
+msgstr "非法多设备链接"

From 73c6d7eaeb368d18a5624e9668f9a8c9842dfa58 Mon Sep 17 00:00:00 2001
From: Eric Zhang <ericzhang456@disroot.org>
Date: Thu, 1 Aug 2024 07:47:25 +0000
Subject: [PATCH 020/212] Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (34 of 34 strings)

Translation: Pleroma/Pleroma Backend (domain default)
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-backend-domain-default/zh_Hans/
---
 priv/gettext/zh_Hans/LC_MESSAGES/default.po | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/priv/gettext/zh_Hans/LC_MESSAGES/default.po b/priv/gettext/zh_Hans/LC_MESSAGES/default.po
index ed0d1576b..ed98dfbd3 100644
--- a/priv/gettext/zh_Hans/LC_MESSAGES/default.po
+++ b/priv/gettext/zh_Hans/LC_MESSAGES/default.po
@@ -8,9 +8,9 @@
 ## to merge POT files into PO files.
 msgid ""
 msgstr ""
-"PO-Revision-Date: 2022-07-22 19:00+0000\n"
-"Last-Translator: Yating Zhan <thestrandedvalley@protonmail.com>\n"
-"Language-Team: Chinese (Simplified) <http://weblate.pleroma-dev.ebin.club/"
+"PO-Revision-Date: 2024-08-01 08:19+0000\n"
+"Last-Translator: Eric Zhang <ericzhang456@disroot.org>\n"
+"Language-Team: Chinese (Simplified) <https://translate.pleroma.social/"
 "projects/pleroma/pleroma-backend-domain-default/zh_Hans/>\n"
 "Language: zh_Hans\n"
 "Content-Type: text/plain; charset=UTF-8\n"
@@ -106,7 +106,7 @@ msgstr "转换到 %{polymorphic_type} 中的任一 schema 失败"
 #: lib/pleroma/web/api_spec/render_error.ex:71
 #, elixir-format
 msgid "Failed to cast value as %{invalid_schema}. Value must be castable using `allOf` schemas listed."
-msgstr "把值转换成 %{invalid_schema} 失败。值必须可以被转换成在列的「所有」schema。"
+msgstr "把值转换成 %{invalid_schema} 失败。值必须可以被转换成在列的 `allOf` schema。"
 
 #: lib/pleroma/web/api_spec/render_error.ex:84
 #, elixir-format
@@ -136,17 +136,17 @@ msgstr "缺少头:%{name}。"
 #: lib/pleroma/web/api_spec/render_error.ex:196
 #, elixir-format
 msgid "No value provided for required discriminator `%{field}`."
-msgstr ""
+msgstr "没有提供给鉴别器 `%{field}` 提供所需要的值。"
 
 #: lib/pleroma/web/api_spec/render_error.ex:216
 #, elixir-format
 msgid "Object property count %{property_count} is greater than maxProperties: %{max_properties}."
-msgstr ""
+msgstr "对象属性数 %{property_count} 大于 maxProperties: %{max_properties}。"
 
 #: lib/pleroma/web/api_spec/render_error.ex:224
 #, elixir-format
 msgid "Object property count %{property_count} is less than minProperties: %{min_properties}"
-msgstr ""
+msgstr "对象属性数 %{property_count} 小于 minProperties: %{min_properties}。"
 
 #: lib/pleroma/web/templates/static_fe/static_fe/error.html.eex:2
 #, elixir-format
@@ -166,7 +166,7 @@ msgstr "未知的 schema:%{name}。"
 #: lib/pleroma/web/api_spec/render_error.ex:192
 #, elixir-format
 msgid "Value used as discriminator for `%{field}` matches no schemas."
-msgstr ""
+msgstr "用于 `%{field}` 鉴别器的值无法匹配到任何 schema。"
 
 #: lib/pleroma/web/templates/embed/show.html.eex:43
 #: lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex:37

From 030be7130773d5b50087b7ada6c62ce582fc008c Mon Sep 17 00:00:00 2001
From: Eric Zhang <ericzhang456@disroot.org>
Date: Thu, 1 Aug 2024 07:11:09 +0000
Subject: [PATCH 021/212] Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (100 of 100 strings)

Translation: Pleroma/Pleroma Backend (domain errors)
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-backend-domain-errors/zh_Hans/
---
 priv/gettext/zh_Hans/LC_MESSAGES/errors.po | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/priv/gettext/zh_Hans/LC_MESSAGES/errors.po b/priv/gettext/zh_Hans/LC_MESSAGES/errors.po
index 4431445e3..668472939 100644
--- a/priv/gettext/zh_Hans/LC_MESSAGES/errors.po
+++ b/priv/gettext/zh_Hans/LC_MESSAGES/errors.po
@@ -3,9 +3,9 @@ msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2020-09-20 13:18+0000\n"
-"PO-Revision-Date: 2022-07-22 19:00+0000\n"
-"Last-Translator: Yating Zhan <thestrandedvalley@protonmail.com>\n"
-"Language-Team: Chinese (Simplified) <http://weblate.pleroma-dev.ebin.club/"
+"PO-Revision-Date: 2024-08-01 08:19+0000\n"
+"Last-Translator: Eric Zhang <ericzhang456@disroot.org>\n"
+"Language-Team: Chinese (Simplified) <https://translate.pleroma.social/"
 "projects/pleroma/pleroma-backend-domain-errors/zh_Hans/>\n"
 "Language: zh_Hans\n"
 "MIME-Version: 1.0\n"
@@ -392,7 +392,7 @@ msgid "Invalid answer data"
 msgstr "无效的回答数据"
 
 #: lib/pleroma/web/nodeinfo/nodeinfo_controller.ex:33
-#, elixir-format, fuzzy
+#, elixir-format
 msgid "Nodeinfo schema version not handled"
 msgstr "Nodeinfo schema 版本没被处理"
 

From 914fdc508def533e9fd1609f7c52202c58a5ea75 Mon Sep 17 00:00:00 2001
From: Eric Zhang <ericzhang456@disroot.org>
Date: Thu, 1 Aug 2024 08:17:35 +0000
Subject: [PATCH 022/212] Translated using Weblate (Chinese (Simplified))

Currently translated at 19.8% (193 of 974 strings)

Translation: Pleroma/Pleroma Backend (domain config_descriptions)
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-backend-domain-config_descriptions/zh_Hans/
---
 priv/gettext/zh_Hans/LC_MESSAGES/config_descriptions.po | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/priv/gettext/zh_Hans/LC_MESSAGES/config_descriptions.po b/priv/gettext/zh_Hans/LC_MESSAGES/config_descriptions.po
index 808dd8bdc..c880c1e5e 100644
--- a/priv/gettext/zh_Hans/LC_MESSAGES/config_descriptions.po
+++ b/priv/gettext/zh_Hans/LC_MESSAGES/config_descriptions.po
@@ -3,8 +3,8 @@ msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2022-07-21 04:21+0300\n"
-"PO-Revision-Date: 2024-08-01 08:17+0000\n"
-"Last-Translator: Yating Zhan <thestrandedvalley@protonmail.com>\n"
+"PO-Revision-Date: 2024-08-01 08:19+0000\n"
+"Last-Translator: Eric Zhang <ericzhang456@disroot.org>\n"
 "Language-Team: Chinese (Simplified) <https://translate.pleroma.social/"
 "projects/pleroma/pleroma-backend-domain-config_descriptions/zh_Hans/>\n"
 "Language: zh_Hans\n"
@@ -331,7 +331,8 @@ msgstr "从选择的实例偷取看到的 emoji。"
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:mrf_subchain"
 msgid "This policy processes messages through an alternate pipeline when a given message matches certain criteria. All criteria are configured as a map of regular expressions to lists of policy modules."
-msgstr "此策略将会把满足特定条件的信息通过另一管线处理。"
+msgstr "此策略将会把满足特定条件的信息通过另一管线处理。所有条件都以正则表达式来对应"
+"列出的策略模块配置。"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format

From 7b979ac09d6caf7e06100574ca79cc9e5438bfb5 Mon Sep 17 00:00:00 2001
From: Eric Zhang <ericzhang456@disroot.org>
Date: Thu, 1 Aug 2024 07:13:57 +0000
Subject: [PATCH 023/212] Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (50 of 50 strings)

Translation: Pleroma/Pleroma Backend (domain oauth_scopes)
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-backend-domain-oauth_scopes/zh_Hans/
---
 .../zh_Hans/LC_MESSAGES/oauth_scopes.po       | 111 +++++++++---------
 1 file changed, 56 insertions(+), 55 deletions(-)

diff --git a/priv/gettext/zh_Hans/LC_MESSAGES/oauth_scopes.po b/priv/gettext/zh_Hans/LC_MESSAGES/oauth_scopes.po
index f2acac90a..204414836 100644
--- a/priv/gettext/zh_Hans/LC_MESSAGES/oauth_scopes.po
+++ b/priv/gettext/zh_Hans/LC_MESSAGES/oauth_scopes.po
@@ -3,14 +3,16 @@ msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2024-08-01 10:12+0300\n"
-"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
-"Last-Translator: Automatically generated\n"
-"Language-Team: none\n"
+"PO-Revision-Date: 2024-08-01 08:19+0000\n"
+"Last-Translator: Eric Zhang <ericzhang456@disroot.org>\n"
+"Language-Team: Chinese (Simplified) <https://translate.pleroma.social/"
+"projects/pleroma/pleroma-backend-domain-oauth_scopes/zh_Hans/>\n"
 "Language: zh_Hans\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: Translate Toolkit 3.7.2\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+"X-Generator: Weblate 4.13.1\n"
 
 ## This file is a PO Template file.
 ##
@@ -21,253 +23,252 @@ msgstr ""
 ## Run "mix gettext.extract" to bring this file up to
 ## date. Leave "msgstr"s empty as changing them here has no
 ## effect: edit them in PO (.po) files instead.
-
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "admin"
-msgstr ""
+msgstr "全部管理员权限"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "admin:read"
-msgstr ""
+msgstr "使用管理员 API 读取"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "admin:write"
-msgstr ""
+msgstr "使用管理员 API 写入"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "follow"
-msgstr ""
+msgstr "读取并写入用户关系"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "read"
-msgstr ""
+msgstr "读取任何信息"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "read:accounts"
-msgstr ""
+msgstr "读取所有账号的信息"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "read:blocks"
-msgstr ""
+msgstr "读取块关系"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "read:bookmarks"
-msgstr ""
+msgstr "读取您的书签"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "read:favourites"
-msgstr ""
+msgstr "读取您喜欢的帖子"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "read:filters"
-msgstr ""
+msgstr "读取您的过滤器设置"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "read:follows"
-msgstr ""
+msgstr "读取关注关系"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "read:lists"
-msgstr ""
+msgstr "读取您的列表"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "read:notifications"
-msgstr ""
+msgstr "读取您的通知"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "read:search"
-msgstr ""
+msgstr "执行搜索"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "read:statuses"
-msgstr ""
+msgstr "读取您可以看到的动态"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "write"
-msgstr ""
+msgstr "写入任何信息"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "write:accounts"
-msgstr ""
+msgstr "更改您的账号信息"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "write:blocks"
-msgstr ""
+msgstr "屏蔽或取消屏蔽任何人"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "write:bookmarks"
-msgstr ""
+msgstr "从您的书签中添加或移除"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "write:conversations"
-msgstr ""
+msgstr "更改收件人,标记为已阅,或删除聊天"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "write:favourites"
-msgstr ""
+msgstr "喜欢或取消喜欢动态"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "write:filters"
-msgstr ""
+msgstr "更改您的过滤器设置"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "write:follows"
-msgstr ""
+msgstr "关注或取消关注任何人"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "write:lists"
-msgstr ""
+msgstr "创建,更改或删除您的列表"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "write:media"
-msgstr ""
+msgstr "上传媒体文件或更改您上传的媒体文件"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "write:mutes"
-msgstr ""
+msgstr "隐藏或取消隐藏任何人"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "write:notifications"
-msgstr ""
+msgstr "标记通知为已读"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "write:statuses"
-msgstr ""
+msgstr "发表,编辑,转发帖子或对帖子做出回应"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "admin:read:accounts"
-msgstr ""
+msgstr "使用管理员 API 读取所有账号"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "admin:read:chats"
-msgstr ""
+msgstr "使用管理员 API 读取所有聊天"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "admin:read:invites"
-msgstr ""
+msgstr "使用管理员 API 读取所有邀请码"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "admin:read:media_proxy_caches"
-msgstr ""
+msgstr "使用管理员 API 读取媒体代理缓存"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "admin:read:reports"
-msgstr ""
+msgstr "使用管理员 API 读取所有举报"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "admin:read:statuses"
-msgstr ""
+msgstr "使用管理员 API 读取所有动态"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "admin:write:accounts"
-msgstr ""
+msgstr "使用管理员 API 更改所有账号"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "admin:write:chats"
-msgstr ""
+msgstr "使用管理员 API 更改所有聊天"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "admin:write:follows"
-msgstr ""
+msgstr "使用管理员 API 更改关注关系"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "admin:write:invites"
-msgstr ""
+msgstr "使用管理员 API 创建或吊销邀请码"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "admin:write:media_proxy_caches"
-msgstr ""
+msgstr "使用管理员 API 更改媒体代理缓存"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "admin:write:reports"
-msgstr ""
+msgstr "使用管理员 API 处理举报"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "admin:write:statuses"
-msgstr ""
+msgstr "使用管理员 API 删除动态,更改动态的范围,或标记为敏感动态"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "read:mutes"
-msgstr ""
+msgstr "读取隐藏关系"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "push"
-msgstr ""
+msgstr "推送通知"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "read:backups"
-msgstr ""
+msgstr "读取您的备份"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "read:chats"
-msgstr ""
+msgstr "读取您的聊天"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "read:media"
-msgstr ""
+msgstr "读取媒体附件"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "read:reports"
-msgstr ""
+msgstr "读取您的举报"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "write:chats"
-msgstr ""
+msgstr "添加或移除聊天信息,或者标记它们为已阅"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "write:follow"
-msgstr ""
+msgstr "关注或取消关注任何人"
 
 #: lib/pleroma/web/api_spec/scopes/translator.ex:5
 #, elixir-autogen, elixir-format
 msgid "write:reports"
-msgstr ""
+msgstr "提交举报"

From 9e3fa8924332a6ef1217b3ead2cd94c5b5ac1b4b Mon Sep 17 00:00:00 2001
From: Eric Zhang <ericzhang456@disroot.org>
Date: Thu, 1 Aug 2024 08:20:04 +0000
Subject: [PATCH 024/212] Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (34 of 34 strings)

Translation: Pleroma/Pleroma Backend (domain default)
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-backend-domain-default/zh_Hans/
---
 priv/gettext/zh_Hans/LC_MESSAGES/default.po | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/priv/gettext/zh_Hans/LC_MESSAGES/default.po b/priv/gettext/zh_Hans/LC_MESSAGES/default.po
index ed98dfbd3..7d5828fae 100644
--- a/priv/gettext/zh_Hans/LC_MESSAGES/default.po
+++ b/priv/gettext/zh_Hans/LC_MESSAGES/default.po
@@ -8,7 +8,7 @@
 ## to merge POT files into PO files.
 msgid ""
 msgstr ""
-"PO-Revision-Date: 2024-08-01 08:19+0000\n"
+"PO-Revision-Date: 2024-08-02 09:02+0000\n"
 "Last-Translator: Eric Zhang <ericzhang456@disroot.org>\n"
 "Language-Team: Chinese (Simplified) <https://translate.pleroma.social/"
 "projects/pleroma/pleroma-backend-domain-default/zh_Hans/>\n"
@@ -146,7 +146,7 @@ msgstr "对象属性数 %{property_count} 大于 maxProperties: %{max_properties
 #: lib/pleroma/web/api_spec/render_error.ex:224
 #, elixir-format
 msgid "Object property count %{property_count} is less than minProperties: %{min_properties}"
-msgstr "对象属性数 %{property_count} 小于 minProperties: %{min_properties}。"
+msgstr "对象属性数 %{property_count} 小于 minProperties: %{min_properties}"
 
 #: lib/pleroma/web/templates/static_fe/static_fe/error.html.eex:2
 #, elixir-format

From 16c6942df90391894e4c6eb0de6b9bffc7d8c30e Mon Sep 17 00:00:00 2001
From: Eric Zhang <ericzhang456@disroot.org>
Date: Thu, 1 Aug 2024 08:44:57 +0000
Subject: [PATCH 025/212] Translated using Weblate (Chinese (Simplified))

Currently translated at 28.1% (274 of 974 strings)

Translation: Pleroma/Pleroma Backend (domain config_descriptions)
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-backend-domain-config_descriptions/zh_Hans/
---
 .../LC_MESSAGES/config_descriptions.po        | 201 +++++++++---------
 1 file changed, 105 insertions(+), 96 deletions(-)

diff --git a/priv/gettext/zh_Hans/LC_MESSAGES/config_descriptions.po b/priv/gettext/zh_Hans/LC_MESSAGES/config_descriptions.po
index c880c1e5e..a56c90724 100644
--- a/priv/gettext/zh_Hans/LC_MESSAGES/config_descriptions.po
+++ b/priv/gettext/zh_Hans/LC_MESSAGES/config_descriptions.po
@@ -3,7 +3,7 @@ msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2022-07-21 04:21+0300\n"
-"PO-Revision-Date: 2024-08-01 08:19+0000\n"
+"PO-Revision-Date: 2024-08-02 09:02+0000\n"
 "Last-Translator: Eric Zhang <ericzhang456@disroot.org>\n"
 "Language-Team: Chinese (Simplified) <https://translate.pleroma.social/"
 "projects/pleroma/pleroma-backend-domain-config_descriptions/zh_Hans/>\n"
@@ -140,7 +140,7 @@ msgstr "鉴权/授权设置"
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:connections_pool"
 msgid "Advanced settings for `Gun` connections pool"
-msgstr "「Gun」连接池的高级设置"
+msgstr "`Gun` 连接池的高级设置"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -185,7 +185,7 @@ msgstr "Gopher 设置"
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:hackney_pools"
 msgid "Advanced settings for `Hackney` connections pools"
-msgstr "「Hackney」连接池的高级设置"
+msgstr "`Hackney` 连接池的高级设置"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -328,7 +328,7 @@ msgid "Steals emojis from selected instances when it sees them."
 msgstr "从选择的实例偷取看到的 emoji。"
 
 #: lib/pleroma/docs/translator.ex:5
-#, elixir-autogen, elixir-format
+#, elixir-autogen, elixir-format, fuzzy
 msgctxt "config description at :pleroma-:mrf_subchain"
 msgid "This policy processes messages through an alternate pipeline when a given message matches certain criteria. All criteria are configured as a map of regular expressions to lists of policy modules."
 msgstr "此策略将会把满足特定条件的信息通过另一管线处理。所有条件都以正则表达式来对应"
@@ -350,13 +350,13 @@ msgstr "配置 OAuth 2 提供者的能力"
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:pools"
 msgid "Advanced settings for `Gun` workers pools"
-msgstr "「Gun」工人池的高级设置"
+msgstr "`Gun` worker 池的高级设置"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:populate_hashtags_table"
 msgid "`populate_hashtags_table` background migration settings"
-msgstr "「populate_hashtags_table」后台迁移设置"
+msgstr "`populate_hashtags_table` 后台迁移设置"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -398,13 +398,13 @@ msgstr ""
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:uri_schemes"
 msgid "URI schemes related settings"
-msgstr ""
+msgstr "URI scheme 相关设置"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:web_cache_ttl"
 msgid "The expiration time for the web responses cache. Values should be in milliseconds or `nil` to disable expiration."
-msgstr "web 回应缓存的过期时间。值应该以毫秒为单位,或者用「nil」来禁用过期。"
+msgstr "网页回应缓存的过期时间。以毫秒为单位,或者用 `nil` 来禁用过期。"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -416,7 +416,7 @@ msgstr "欢迎讯息设置"
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:workers"
 msgid "Includes custom worker options not interpretable directly by `Oban`"
-msgstr "包含不能直接被「Oban」解读的自定工人选项"
+msgstr "包含不能直接被 `Oban` 解读的自定 worker 选项"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -491,7 +491,7 @@ msgstr "过滤器将会匿名化上传文件的文件名"
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-Pleroma.Upload.Filter.Mogrify"
 msgid "Uploads mogrify filter settings"
-msgstr ""
+msgstr "morgify 上传过滤器设置"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -534,6 +534,9 @@ msgstr "元数据相关设定"
 msgctxt "config description at :pleroma-Pleroma.Web.Plugs.RemoteIp"
 msgid "`Pleroma.Web.Plugs.RemoteIp` is a shim to call [`RemoteIp`](https://git.pleroma.social/pleroma/remote_ip) but with runtime configuration.\n**If your instance is not behind at least one reverse proxy, you should not enable this plug.**\n"
 msgstr ""
+"`Pleroma.Web.Plugs.RemoteIp` 是一个呼叫 [`RemoteIp`](https://git.pleroma."
+"social/pleroma/remote_ip) 的 shim 但是包含运行库配置。\n"
+"**如果您的实例不在至少一个反向代理后面,您不应该启用这个插件。**\n"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -551,13 +554,13 @@ msgstr "失效活动设定"
 #, elixir-autogen, elixir-format
 msgctxt "config description at :prometheus-Pleroma.Web.Endpoint.MetricsExporter"
 msgid "Prometheus app metrics endpoint configuration"
-msgstr ""
+msgstr "Prometheus 服务监控端点配置"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :web_push_encryption-:vapid_details"
 msgid "Web Push Notifications configuration. You can use the mix task mix web_push.gen.keypair to generate it."
-msgstr ""
+msgstr "网页推送通知配置。您可以使用 mix task mix web_push.gen.keypair 来生成它。"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -587,7 +590,7 @@ msgstr "ActivityPub"
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-:assets"
 msgid "Assets"
-msgstr ""
+msgstr "资源"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -647,7 +650,7 @@ msgstr "Gopher"
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-:hackney_pools"
 msgid "Hackney pools"
-msgstr ""
+msgstr "Hackney 池"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -677,25 +680,25 @@ msgstr "实例图标"
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-:ldap"
 msgid "LDAP"
-msgstr ""
+msgstr "LDAP"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-:majic_pool"
 msgid "Majic pool"
-msgstr ""
+msgstr "Majic 池"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-:manifest"
 msgid "Manifest"
-msgstr ""
+msgstr "Manifest"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-:markup"
 msgid "Markup Settings"
-msgstr ""
+msgstr "标记设置"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -713,25 +716,25 @@ msgstr "媒体文件代理"
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-:modules"
 msgid "Modules"
-msgstr ""
+msgstr "模块"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-:mrf"
 msgid "MRF"
-msgstr ""
+msgstr "MRF"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-:mrf_activity_expiration"
 msgid "MRF Activity Expiration Policy"
-msgstr ""
+msgstr "MRF 活动过期策略"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-:mrf_follow_bot"
 msgid "MRF FollowBot Policy"
-msgstr ""
+msgstr "MRF FollowBot 策略"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -743,49 +746,49 @@ msgstr "MRF 标签"
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-:mrf_hellthread"
 msgid "MRF Hellthread"
-msgstr ""
+msgstr "MRF Hellthread"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-:mrf_keyword"
 msgid "MRF Keyword"
-msgstr ""
+msgstr "MRF 关键词"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-:mrf_mention"
 msgid "MRF Mention"
-msgstr ""
+msgstr "MRF 提及"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-:mrf_normalize_markup"
 msgid "MRF Normalize Markup"
-msgstr ""
+msgstr "MRF 标记标准化"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-:mrf_object_age"
 msgid "MRF Object Age"
-msgstr ""
+msgstr "MRF 对象年龄"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-:mrf_rejectnonpublic"
 msgid "MRF Reject Non Public"
-msgstr ""
+msgstr "MRF 拒绝非公开帖子"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-:mrf_simple"
 msgid "MRF Simple"
-msgstr ""
+msgstr "MRF 简单"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-:mrf_steal_emoji"
 msgid "MRF Emojis"
-msgstr ""
+msgstr "MRF 表情符号"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -803,13 +806,13 @@ msgstr ""
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-:oauth2"
 msgid "OAuth2"
-msgstr ""
+msgstr "OAuth2"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-:pools"
 msgid "Pools"
-msgstr ""
+msgstr "池"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -821,13 +824,13 @@ msgstr "本站话题标签列表"
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-:rate_limit"
 msgid "Rate limit"
-msgstr ""
+msgstr "限流"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-:restrict_unauthenticated"
 msgid "Restrict Unauthenticated"
-msgstr ""
+msgstr "限制未授权用户"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -845,7 +848,7 @@ msgstr "留言板"
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-:static_fe"
 msgid "Static FE"
-msgstr ""
+msgstr "静态 FE"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -857,7 +860,7 @@ msgstr ""
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-:uri_schemes"
 msgid "URI Schemes"
-msgstr ""
+msgstr "URI Schemes"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -869,7 +872,7 @@ msgstr "用户"
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-:web_cache_ttl"
 msgid "Web cache TTL"
-msgstr ""
+msgstr "网页缓存 TTL"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -881,13 +884,13 @@ msgstr "欢迎"
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-:workers"
 msgid "Workers"
-msgstr "工人"
+msgstr "Workers"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-ConcurrentLimiter"
 msgid "ConcurrentLimiter"
-msgstr ""
+msgstr "ConcurrentLimiter"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -899,133 +902,133 @@ msgstr "Oban"
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-Pleroma.Captcha"
 msgid "Pleroma.Captcha"
-msgstr ""
+msgstr "Pleroma.Captcha"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-Pleroma.Captcha.Kocaptcha"
 msgid "Pleroma.Captcha.Kocaptcha"
-msgstr ""
+msgstr "Pleroma.Captcha.Kocaptcha"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-Pleroma.Emails.Mailer"
 msgid "Pleroma.Emails.Mailer"
-msgstr ""
+msgstr "Pleroma.Emails.Mailer"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-Pleroma.Emails.NewUsersDigestEmail"
 msgid "Pleroma.Emails.NewUsersDigestEmail"
-msgstr ""
+msgstr "Pleroma.Emails.NewUsersDigestEmail"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-Pleroma.Emails.UserEmail"
 msgid "Pleroma.Emails.UserEmail"
-msgstr ""
+msgstr "Pleroma.Emails.UserEmail"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-Pleroma.Formatter"
 msgid "Linkify"
-msgstr ""
+msgstr "Linkify"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-Pleroma.ScheduledActivity"
 msgid "Pleroma.ScheduledActivity"
-msgstr ""
+msgstr "Pleroma.ScheduledActivity"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-Pleroma.Upload"
 msgid "Pleroma.Upload"
-msgstr ""
+msgstr "Pleroma.Upload"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-Pleroma.Upload.Filter.AnonymizeFilename"
 msgid "Pleroma.Upload.Filter.AnonymizeFilename"
-msgstr ""
+msgstr "Pleroma.Upload.Filter.AnonymizeFilename"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-Pleroma.Upload.Filter.Mogrify"
 msgid "Pleroma.Upload.Filter.Mogrify"
-msgstr ""
+msgstr "Pleroma.Upload.Filter.Mogrify"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-Pleroma.Uploaders.Local"
 msgid "Pleroma.Uploaders.Local"
-msgstr ""
+msgstr "Pleroma.Uploaders.Local"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-Pleroma.Uploaders.S3"
 msgid "Pleroma.Uploaders.S3"
-msgstr ""
+msgstr "Pleroma.Uploaders.S3"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-Pleroma.User"
 msgid "Pleroma.User"
-msgstr ""
+msgstr "Pleroma.User"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-Pleroma.User.Backup"
 msgid "Pleroma.User.Backup"
-msgstr ""
+msgstr "Pleroma.User.Backup"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-Pleroma.Web.ApiSpec.CastAndValidate"
 msgid "Pleroma.Web.ApiSpec.CastAndValidate"
-msgstr ""
+msgstr "Pleroma.Web.ApiSpec.CastAndValidate"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Http"
 msgid "Pleroma.Web.MediaProxy.Invalidation.Http"
-msgstr ""
+msgstr "Pleroma.Web.MediaProxy.Invalidation.Http"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Script"
 msgid "Pleroma.Web.MediaProxy.Invalidation.Script"
-msgstr ""
+msgstr "Pleroma.Web.MediaProxy.Invalidation.Script"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-Pleroma.Web.Metadata"
 msgid "Pleroma.Web.Metadata"
-msgstr ""
+msgstr "Pleroma.Web.Metadata"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-Pleroma.Web.Plugs.RemoteIp"
 msgid "Pleroma.Web.Plugs.RemoteIp"
-msgstr ""
+msgstr "Pleroma.Web.Plugs.RemoteIp"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-Pleroma.Web.Preload"
 msgid "Pleroma.Web.Preload"
-msgstr ""
+msgstr "Pleroma.Web.Preload"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma-Pleroma.Workers.PurgeExpiredActivity"
 msgid "Pleroma.Workers.PurgeExpiredActivity"
-msgstr ""
+msgstr "Pleroma.Workers.PurgeExpiredActivity"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config label at :prometheus-Pleroma.Web.Endpoint.MetricsExporter"
 msgid "Pleroma.Web.Endpoint.MetricsExporter"
-msgstr ""
+msgstr "Pleroma.Web.Endpoint.MetricsExporter"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -1067,37 +1070,39 @@ msgstr ""
 #, elixir-autogen, elixir-format
 msgctxt "config description at :ex_aws-:s3 > :access_key_id"
 msgid "S3 access key ID"
-msgstr ""
+msgstr "S3 访问密钥 ID"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :ex_aws-:s3 > :host"
 msgid "S3 host"
-msgstr ""
+msgstr "S3 主机"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :ex_aws-:s3 > :region"
 msgid "S3 region (for AWS)"
-msgstr ""
+msgstr "S3 区域(AWS)"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :ex_aws-:s3 > :secret_access_key"
 msgid "Secret access key"
-msgstr ""
+msgstr "访问密钥"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :logger > :backends"
 msgid "Where logs will be sent, :console - send logs to stdout, { ExSyslogger, :ex_syslogger } - to syslog, Quack.Logger - to Slack."
 msgstr ""
+"日志发送的地点,:console - 将日志发送到 stdout, { ExSyslogger, :ex_syslogger "
+"} - 发送到 syslog, Quack.Logger - 发送到 Slack."
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :logger-:console > :format"
 msgid "Default: \"$date $time [$level] $levelpad$node $metadata $message\""
-msgstr ""
+msgstr "默认:\"$date $time [$level] $levelpad$node $metadata $message\""
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -1109,13 +1114,13 @@ msgstr "日志等级"
 #, elixir-autogen, elixir-format
 msgctxt "config description at :logger-:ex_syslogger > :format"
 msgid "Default: \"$date $time [$level] $levelpad$node $metadata $message\""
-msgstr ""
+msgstr "默认:\"$date $time [$level] $levelpad$node $metadata $message\""
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :logger-:ex_syslogger > :ident"
 msgid "A string that's prepended to every message, and is typically set to the app name"
-msgstr ""
+msgstr "注入在每一个消息前面的字符串,通常设为应用程序的名称"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -1151,13 +1156,13 @@ msgstr ""
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:activitypub > :outgoing_blocks"
 msgid "Whether to federate blocks to other instances"
-msgstr ""
+msgstr "是否与其他实例同步屏蔽列表"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:activitypub > :sign_object_fetches"
 msgid "Sign object fetches with HTTP signatures"
-msgstr ""
+msgstr "为对象获取进行 HTTP 签名"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -1169,7 +1174,7 @@ msgstr "屏蔽对象时是否同时取消对其的关注"
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:assets > :default_mascot"
 msgid "This will be used as the default mascot on MastoFE. Default: `:pleroma_fox_tan`"
-msgstr ""
+msgstr "这将是 MastoFE 的默认吉祥物。默认:`:pleroma_fox_tan`"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -1181,13 +1186,15 @@ msgstr "默认用户头像的网址"
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:assets > :mascots"
 msgid "Keyword of mascots, each element must contain both an URL and a mime_type key"
-msgstr ""
+msgstr "吉祥物关键词,每一个元素必须包含一个 URL 和 mine_type 值"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:auth > :auth_template"
 msgid "Authentication form template. By default it's `show.html` which corresponds to `lib/pleroma/web/templates/o_auth/o_auth/show.html.ee`."
 msgstr ""
+"授权表达模板。默认是 `show.html`,对应于 `lib/pleroma/web/templates/o_auth/"
+"o_auth/show.html.ee`。"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -1211,7 +1218,7 @@ msgstr ""
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:connections_pool > :connect_timeout"
 msgid "Timeout while `gun` will wait until connection is up. Default: 5000ms."
-msgstr "「Gun」等待连接时触发超时的上限。默认为5000ms。"
+msgstr "`gun` 等待连接时触发超时的上限。默认:5000ms。"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -1229,7 +1236,7 @@ msgstr ""
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:connections_pool > :max_connections"
 msgid "Maximum number of connections in the pool. Default: 250 connections."
-msgstr ""
+msgstr "池的最大连接数量。默认:250 连接。"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -1265,13 +1272,15 @@ msgstr "单个用户每次收到摘要邮件的间隔"
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:email_notifications > :digest > :schedule"
 msgid "When to send digest email, in crontab format. \"0 0 0\" is the default, meaning \"once a week at midnight on Sunday morning\"."
-msgstr ""
+msgstr "发送摘要邮件的时间,以 crontab 格式。默认为“0 0 "
+"0”,意味着“每周在周日的午夜时分”。"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:emoji > :default_manifest"
 msgid "Location of the JSON-manifest. This manifest contains information about the emoji-packs you can download. Currently only one manifest can be added (no arrays)."
-msgstr ""
+msgstr "JSON-manifest 的位置。manifest 包含您可以下载的表情包信息。目前只能添加一个 "
+"manifest(无数列)。"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -1289,7 +1298,7 @@ msgstr ""
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:emoji > :shortcode_globs"
 msgid "Location of custom emoji files. * can be used as a wildcard."
-msgstr ""
+msgstr "自定义表情符号位置。* 可以当作通配符使用。"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -1301,7 +1310,7 @@ msgstr ""
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:feed > :post_title"
 msgid "Configure title rendering"
-msgstr ""
+msgstr "配置标题渲染"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -1471,7 +1480,7 @@ msgstr "管理员前端"
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:frontends > :admin > name"
 msgid "Name of the installed frontend. Valid config must include both `Name` and `Reference` values."
-msgstr "已安装的前端名称。只有包含了「名称」与「引用」数值才能被算作有效配置。"
+msgstr "已安装的前端名称。有效配置必须包含 `Name` 和 `Reference` 数值。"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -1501,13 +1510,13 @@ msgstr ""
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:frontends > :available > custom-http-headers"
 msgid "The custom HTTP headers for the frontend"
-msgstr ""
+msgstr "前端的自定义 HTTP 响应头"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:frontends > :available > git"
 msgid "URL of the git repository of the frontend"
-msgstr ""
+msgstr "前端 git 仓库的 URL"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -1525,13 +1534,13 @@ msgstr ""
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:frontends > :primary"
 msgid "Primary frontend, the one that is served for all pages by default"
-msgstr ""
+msgstr "主要前端,这是默认服务所有页面的前端"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:frontends > :primary > name"
 msgid "Name of the installed frontend. Valid config must include both `Name` and `Reference` values."
-msgstr "已安装的前端名称。只有包含了「名称」与「引用」数值才能被算作有效配置。"
+msgstr "已安装的前端名称。有效配置必须包含 `Name` 和 `Reference` 数值。"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -1543,7 +1552,7 @@ msgstr ""
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:gopher > :dstport"
 msgid "Port advertised in URLs (optional, defaults to port)"
-msgstr ""
+msgstr "URL 中宣传的端口(可选,默认为端口)"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -1573,7 +1582,7 @@ msgstr ""
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:hackney_pools > :federation > :max_connections"
 msgid "Number workers in the pool."
-msgstr "池内的工人数量。"
+msgstr "池内的 worker 数量。"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -1591,7 +1600,7 @@ msgstr "媒体池设定。"
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:hackney_pools > :media > :max_connections"
 msgid "Number workers in the pool."
-msgstr "池内的工人数量。"
+msgstr "池内的 worker 数量。"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -1603,7 +1612,7 @@ msgstr ""
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:hackney_pools > :upload"
 msgid "Settings for upload pool."
-msgstr ""
+msgstr "上传池设置。"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -1783,7 +1792,7 @@ msgstr ""
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:instance > :email"
 msgid "Email used to reach an Administrator/Moderator of the instance"
-msgstr ""
+msgstr "用于联系实例管理员/监管员的电子邮箱"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -1816,10 +1825,10 @@ msgid "Timeout (in days) of each external federation target being unreachable pr
 msgstr ""
 
 #: lib/pleroma/docs/translator.ex:5
-#, elixir-autogen, elixir-format, fuzzy
+#, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:instance > :healthcheck"
 msgid "If enabled, system data will be shown on `/api/pleroma/healthcheck`"
-msgstr "若启用,「/api/pleroma/healthcheck」下将显示系统数据"
+msgstr "若启用,`/api/pleroma/healthcheck` 下将显示系统数据"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -1831,7 +1840,7 @@ msgstr ""
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:instance > :invites_enabled"
 msgid "Enable user invitations for admins (depends on `registrations_open` being disabled)"
-msgstr "只有管理员邀请的用户方能注册(需要关闭「registrations_open」选项)"
+msgstr "只有管理员邀请的用户才能注册(需要关闭 `registrations_open` 选项)"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -1903,13 +1912,13 @@ msgstr ""
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:instance > :multi_factor_authentication > :backup_codes > :number"
 msgid "Number of backup codes to generate."
-msgstr ""
+msgstr "生成的备份密钥数目。"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:instance > :multi_factor_authentication > :totp"
 msgid "TOTP settings"
-msgstr ""
+msgstr "TOTP 设置"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -1976,7 +1985,7 @@ msgstr "允许管理员访问敏感信息(例,更新用户凭据、取得密
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:instance > :profile_directory"
 msgid "Enable profile directory."
-msgstr ""
+msgstr "启用用户主页配置。"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -2023,10 +2032,10 @@ msgstr ""
 "用户(例,“@admin 请留意 @bad_actor”)。默认下为关闭状态"
 
 #: lib/pleroma/docs/translator.ex:5
-#, elixir-autogen, elixir-format, fuzzy
+#, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:instance > :show_reactions"
 msgid "Let favourites and emoji reactions be viewed through the API."
-msgstr "允许通过此API来看见喜欢数量与表情反应。"
+msgstr "允许通过此 API 来看见喜欢数量与表情回应。"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format

From 5f6506d864239408e9fa3705c5dd7b241307241a Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Tue, 27 Aug 2024 20:39:32 -0400
Subject: [PATCH 026/212] Pleroma.HTTP: option stream: true will return a
 stream as the body for Gun adapter

---
 lib/pleroma/http/adapter_helper/gun.ex | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/lib/pleroma/http/adapter_helper/gun.ex b/lib/pleroma/http/adapter_helper/gun.ex
index 1fe8dd4b2..f9a8180f2 100644
--- a/lib/pleroma/http/adapter_helper/gun.ex
+++ b/lib/pleroma/http/adapter_helper/gun.ex
@@ -32,6 +32,7 @@ defmodule Pleroma.HTTP.AdapterHelper.Gun do
     |> AdapterHelper.maybe_add_proxy(proxy)
     |> Keyword.merge(incoming_opts)
     |> put_timeout()
+    |> maybe_stream()
   end
 
   defp add_scheme_opts(opts, %{scheme: "http"}), do: opts
@@ -47,6 +48,14 @@ defmodule Pleroma.HTTP.AdapterHelper.Gun do
     Keyword.put(opts, :timeout, recv_timeout)
   end
 
+  # Tesla Gun adapter uses body_as: :stream
+  defp maybe_stream(opts) do
+    case Keyword.pop(opts, :stream, nil) do
+      {true, opts} -> Keyword.put(opts, :body_as, :stream)
+      {_, opts} -> opts
+    end
+  end
+
   @spec pool_timeout(pool()) :: non_neg_integer()
   def pool_timeout(pool) do
     default = Config.get([:pools, :default, :recv_timeout], 5_000)

From bb279c28025522764272468e3177a5f6701bc155 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Tue, 27 Aug 2024 21:08:25 -0400
Subject: [PATCH 027/212] Pleroma.HTTP add AdapterHelper.can_stream? to assist
 with discovering if the current adapter supports returning a Stream body

---
 lib/pleroma/http/adapter_helper.ex | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/lib/pleroma/http/adapter_helper.ex b/lib/pleroma/http/adapter_helper.ex
index dcb27a29d..f8bde2ac3 100644
--- a/lib/pleroma/http/adapter_helper.ex
+++ b/lib/pleroma/http/adapter_helper.ex
@@ -118,4 +118,13 @@ defmodule Pleroma.HTTP.AdapterHelper do
         host_charlist
     end
   end
+
+  #TODO add Finch support once we have an AdapterHelper for it
+  @spec can_stream? :: bool()
+  def can_stream? do
+    case Application.get_env(:tesla, :adapter) do
+      Tesla.Adapter.Gun -> true
+      _ -> false
+    end
+  end
 end

From ec8db9d4eedfade5a8b74425b21b07b3f4e44992 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Tue, 27 Aug 2024 21:09:15 -0400
Subject: [PATCH 028/212] RichMedia: skip the HTTP HEAD request for adapters
 that support streaming the response body

---
 lib/pleroma/web/rich_media/helpers.ex | 38 +++++++++++++++++++++++----
 1 file changed, 33 insertions(+), 5 deletions(-)

diff --git a/lib/pleroma/web/rich_media/helpers.ex b/lib/pleroma/web/rich_media/helpers.ex
index e2889b351..88bfbae68 100644
--- a/lib/pleroma/web/rich_media/helpers.ex
+++ b/lib/pleroma/web/rich_media/helpers.ex
@@ -11,16 +11,39 @@ defmodule Pleroma.Web.RichMedia.Helpers do
 
   @spec rich_media_get(String.t()) :: {:ok, String.t()} | get_errors()
   def rich_media_get(url) do
-    headers = [{"user-agent", Pleroma.Application.user_agent() <> "; Bot"}]
+      case Pleroma.HTTP.AdapterHelper.can_stream?() do
+        true -> stream(url)
+        false -> head_first(url)
+      end
+    |> handle_result(url)
+  end
 
+  defp stream(url) do
+    with {_, {:ok, %Tesla.Env{status: 200, body: stream_body, headers: headers}}} <-
+           {:head, Pleroma.HTTP.get(url, req_headers(), http_options())},
+         {_, :ok} <- {:content_type, check_content_type(headers)},
+         {_, :ok} <- {:content_length, check_content_length(headers)} do
+      body = Enum.into(stream_body, <<>>)
+      {:ok, body}
+    end
+  end
+
+  defp head_first(url) do
     with {_, {:ok, %Tesla.Env{status: 200, headers: headers}}} <-
-           {:head, Pleroma.HTTP.head(url, headers, http_options())},
+           {:head, Pleroma.HTTP.head(url, req_headers(), http_options())},
          {_, :ok} <- {:content_type, check_content_type(headers)},
          {_, :ok} <- {:content_length, check_content_length(headers)},
          {_, {:ok, %Tesla.Env{status: 200, body: body}}} <-
-           {:get, Pleroma.HTTP.get(url, headers, http_options())} do
+           {:get, Pleroma.HTTP.get(url, req_headers(), http_options())} do
       {:ok, body}
-    else
+    end
+  end
+
+  defp handle_result(result, url) do
+    case result do
+      {:ok, body} ->
+        {:ok, body}
+
       {:head, _} ->
         Logger.debug("Rich media error for #{url}: HTTP HEAD failed")
         {:error, :head}
@@ -74,7 +97,12 @@ defmodule Pleroma.Web.RichMedia.Helpers do
     [
       pool: :rich_media,
       max_body: Config.get([:rich_media, :max_body], 5_000_000),
-      tesla_middleware: [{Tesla.Middleware.Timeout, timeout: timeout}]
+      tesla_middleware: [{Tesla.Middleware.Timeout, timeout: timeout}],
+      stream: true
     ]
   end
+
+  defp req_headers do
+    [{"user-agent", Pleroma.Application.user_agent() <> "; Bot"}]
+  end
 end

From 0a86d2b3ac9c90a16aec1237019ecfcb1e680728 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Tue, 27 Aug 2024 21:22:59 -0400
Subject: [PATCH 029/212] Handle streaming response errors

---
 lib/pleroma/http/adapter_helper.ex    |  2 +-
 lib/pleroma/web/rich_media/helpers.ex | 16 ++++++++++------
 2 files changed, 11 insertions(+), 7 deletions(-)

diff --git a/lib/pleroma/http/adapter_helper.ex b/lib/pleroma/http/adapter_helper.ex
index f8bde2ac3..4dbcccdcc 100644
--- a/lib/pleroma/http/adapter_helper.ex
+++ b/lib/pleroma/http/adapter_helper.ex
@@ -119,7 +119,7 @@ defmodule Pleroma.HTTP.AdapterHelper do
     end
   end
 
-  #TODO add Finch support once we have an AdapterHelper for it
+  # TODO add Finch support once we have an AdapterHelper for it
   @spec can_stream? :: bool()
   def can_stream? do
     case Application.get_env(:tesla, :adapter) do
diff --git a/lib/pleroma/web/rich_media/helpers.ex b/lib/pleroma/web/rich_media/helpers.ex
index 88bfbae68..db1310b23 100644
--- a/lib/pleroma/web/rich_media/helpers.ex
+++ b/lib/pleroma/web/rich_media/helpers.ex
@@ -11,10 +11,10 @@ defmodule Pleroma.Web.RichMedia.Helpers do
 
   @spec rich_media_get(String.t()) :: {:ok, String.t()} | get_errors()
   def rich_media_get(url) do
-      case Pleroma.HTTP.AdapterHelper.can_stream?() do
-        true -> stream(url)
-        false -> head_first(url)
-      end
+    case Pleroma.HTTP.AdapterHelper.can_stream?() do
+      true -> stream(url)
+      false -> head_first(url)
+    end
     |> handle_result(url)
   end
 
@@ -22,8 +22,8 @@ defmodule Pleroma.Web.RichMedia.Helpers do
     with {_, {:ok, %Tesla.Env{status: 200, body: stream_body, headers: headers}}} <-
            {:head, Pleroma.HTTP.get(url, req_headers(), http_options())},
          {_, :ok} <- {:content_type, check_content_type(headers)},
-         {_, :ok} <- {:content_length, check_content_length(headers)} do
-      body = Enum.into(stream_body, <<>>)
+         {_, :ok} <- {:content_length, check_content_length(headers)},
+         body <- Enum.into(stream_body, <<>>) do
       {:ok, body}
     end
   end
@@ -59,6 +59,10 @@ defmodule Pleroma.Web.RichMedia.Helpers do
       {:get, _} ->
         Logger.debug("Rich media error for #{url}: HTTP GET failed")
         {:error, :get}
+
+      {:error, :recv_chunk_timeout} ->
+        Logger.debug("Rich media error for #{url}: HTTP streaming response failed")
+        {:error, :get}
     end
   end
 

From 116fe77b77eedd2feb073d3be256fea08169c95b Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Tue, 27 Aug 2024 21:55:06 -0400
Subject: [PATCH 030/212] Tesla.Middleware.Timeout breaks streaming bodies

These are executed by Oban now and Oban can enforce the timeout if the regular HTTP timeout is not sufficient.
---
 lib/pleroma/web/rich_media/helpers.ex | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/lib/pleroma/web/rich_media/helpers.ex b/lib/pleroma/web/rich_media/helpers.ex
index db1310b23..880d19218 100644
--- a/lib/pleroma/web/rich_media/helpers.ex
+++ b/lib/pleroma/web/rich_media/helpers.ex
@@ -96,12 +96,9 @@ defmodule Pleroma.Web.RichMedia.Helpers do
   end
 
   defp http_options do
-    timeout = Config.get!([:rich_media, :timeout])
-
     [
       pool: :rich_media,
       max_body: Config.get([:rich_media, :max_body], 5_000_000),
-      tesla_middleware: [{Tesla.Middleware.Timeout, timeout: timeout}],
       stream: true
     ]
   end

From 44901502ffd7713d498976e2d2b9a55c298f1876 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Tue, 27 Aug 2024 21:56:02 -0400
Subject: [PATCH 031/212] Fix incorrect identifier for the with statement

---
 lib/pleroma/web/rich_media/helpers.ex | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/pleroma/web/rich_media/helpers.ex b/lib/pleroma/web/rich_media/helpers.ex
index 880d19218..b81984343 100644
--- a/lib/pleroma/web/rich_media/helpers.ex
+++ b/lib/pleroma/web/rich_media/helpers.ex
@@ -20,7 +20,7 @@ defmodule Pleroma.Web.RichMedia.Helpers do
 
   defp stream(url) do
     with {_, {:ok, %Tesla.Env{status: 200, body: stream_body, headers: headers}}} <-
-           {:head, Pleroma.HTTP.get(url, req_headers(), http_options())},
+           {:get, Pleroma.HTTP.get(url, req_headers(), http_options())},
          {_, :ok} <- {:content_type, check_content_type(headers)},
          {_, :ok} <- {:content_length, check_content_length(headers)},
          body <- Enum.into(stream_body, <<>>) do

From 0804b73c0ae5846a133386c09970546375e3d918 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Tue, 27 Aug 2024 22:08:29 -0400
Subject: [PATCH 032/212] This error is not returned by Tesla

Upstream has a bug filed for this as they aren't handling this error internally, so it was raising
---
 lib/pleroma/web/rich_media/helpers.ex | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/lib/pleroma/web/rich_media/helpers.ex b/lib/pleroma/web/rich_media/helpers.ex
index b81984343..a242ca640 100644
--- a/lib/pleroma/web/rich_media/helpers.ex
+++ b/lib/pleroma/web/rich_media/helpers.ex
@@ -59,10 +59,6 @@ defmodule Pleroma.Web.RichMedia.Helpers do
       {:get, _} ->
         Logger.debug("Rich media error for #{url}: HTTP GET failed")
         {:error, :get}
-
-      {:error, :recv_chunk_timeout} ->
-        Logger.debug("Rich media error for #{url}: HTTP streaming response failed")
-        {:error, :get}
     end
   end
 

From 3419e2cbdd3bf1c21e3bbf44ea5313ecfd03c989 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= <git@mkljczk.pl>
Date: Wed, 28 Aug 2024 17:37:42 +0200
Subject: [PATCH 033/212] Correct response in AdminAPI docs
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
---
 changelog.d/docs-fix.skip         |  0
 docs/development/API/admin_api.md | 31 +++++++++++++++++--------------
 2 files changed, 17 insertions(+), 14 deletions(-)
 create mode 100644 changelog.d/docs-fix.skip

diff --git a/changelog.d/docs-fix.skip b/changelog.d/docs-fix.skip
new file mode 100644
index 000000000..e69de29bb
diff --git a/docs/development/API/admin_api.md b/docs/development/API/admin_api.md
index 5b373b8e1..409e78a1e 100644
--- a/docs/development/API/admin_api.md
+++ b/docs/development/API/admin_api.md
@@ -433,7 +433,7 @@ Response:
 * On success: URL of the unfollowed relay
 
 ```json
-{"https://example.com/relay"}
+"https://example.com/relay"
 ```
 
 ## `POST /api/v1/pleroma/admin/users/invite_token`
@@ -1193,20 +1193,23 @@ Loads json generated from `config/descriptions.exs`.
 - Response:
 
 ```json
-[
-  {
-    "id": 1234,
-    "data": {
-      "actor": {
-        "id": 1,
-        "nickname": "lain"
+{
+  "items": [
+    {
+      "id": 1234,
+      "data": {
+        "actor": {
+          "id": 1,
+          "nickname": "lain"
+        },
+        "action": "relay_follow"
       },
-      "action": "relay_follow"
-    },
-    "time": 1502812026, // timestamp
-    "message": "[2017-08-15 15:47:06] @nick0 followed relay: https://example.org/relay" // log message
-  }
-]
+      "time": 1502812026, // timestamp
+      "message": "[2017-08-15 15:47:06] @nick0 followed relay: https://example.org/relay" // log message
+    }
+  ],
+  "total": 1
+}
 ```
 
 ## `POST /api/v1/pleroma/admin/reload_emoji`

From fc450fdefc2df2bbec20a79fb2c60a95e7f41833 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Wed, 28 Aug 2024 15:45:13 -0400
Subject: [PATCH 034/212] ReceiverWorker: cancel job if user fetch is forbidden

An instance block with authenticated fetch being required can cause this as we couldn't get the user to find their public key to verify the signature. Commonly observed if someone boosts/Announces a post from an instance that blocked you.
---
 lib/pleroma/workers/receiver_worker.ex        |  5 +-
 test/pleroma/workers/receiver_worker_test.exs | 48 +++++++++++++++++++
 2 files changed, 52 insertions(+), 1 deletion(-)

diff --git a/lib/pleroma/workers/receiver_worker.ex b/lib/pleroma/workers/receiver_worker.ex
index d4db97b63..7dce02a5f 100644
--- a/lib/pleroma/workers/receiver_worker.ex
+++ b/lib/pleroma/workers/receiver_worker.ex
@@ -56,17 +56,20 @@ defmodule Pleroma.Workers.ReceiverWorker do
 
   def timeout(_job), do: :timer.seconds(5)
 
+  defp process_errors({:error, {:error, _} = error}), do: process_errors(error)
+
   defp process_errors(errors) do
     case errors do
       {:error, :origin_containment_failed} -> {:cancel, :origin_containment_failed}
       {:error, :already_present} -> {:cancel, :already_present}
       {:error, {:validate_object, _} = reason} -> {:cancel, reason}
-      {:error, {:error, {:validate, {:error, _changeset} = reason}}} -> {:cancel, reason}
+      {:error, {:validate, {:error, _changeset} = reason}} -> {:cancel, reason}
       {:error, {:reject, _} = reason} -> {:cancel, reason}
       {:signature, false} -> {:cancel, :invalid_signature}
       {:error, "Object has been deleted"} = reason -> {:cancel, reason}
       {:error, {:side_effects, {:error, :no_object_actor}} = reason} -> {:cancel, reason}
       {:error, :not_found} = reason -> {:cancel, reason}
+      {:error, :forbidden} = reason -> {:cancel, reason}
       {:error, _} = e -> e
       e -> {:error, e}
     end
diff --git a/test/pleroma/workers/receiver_worker_test.exs b/test/pleroma/workers/receiver_worker_test.exs
index 33be91085..640cefb78 100644
--- a/test/pleroma/workers/receiver_worker_test.exs
+++ b/test/pleroma/workers/receiver_worker_test.exs
@@ -51,6 +51,54 @@ defmodule Pleroma.Workers.ReceiverWorkerTest do
              })
   end
 
+  test "it does not retry if a user fetch fails with a 403" do
+    Tesla.Mock.mock(fn
+      %{url: "https://simpsons.com/users/bart"} ->
+        %Tesla.Env{
+          status: 403,
+          body: ""
+        }
+    end)
+
+    params =
+      %{
+        "@context" => [
+          "https://www.w3.org/ns/activitystreams",
+          "https://w3id.org/security/v1"
+        ],
+        "actor" => "https://simpsons.com/users/bart",
+        "cc" => [],
+        "id" => "https://simpsons.com/activity/eat-my-shorts",
+        "object" => %{},
+        "to" => ["https://www.w3.org/ns/activitystreams#Public"],
+        "type" => "Create"
+      }
+
+    req_headers = [
+      ["accept-encoding", "gzip"],
+      ["content-length", "31337"],
+      ["content-type", "application/activity+json"],
+      ["date", "Wed, 28 Aug 2024 15:36:31 GMT"],
+      ["digest", "SHA-256=ouge/6HP2/QryG6F3JNtZ6vzs/hSwMk67xdxe87eH7A="],
+      ["host", "bikeshed.party"],
+      [
+        "signature",
+        "does not matter as user needs to be fetched first"
+      ]
+    ]
+
+    {:ok, oban_job} =
+      Federator.incoming_ap_doc(%{
+        method: "POST",
+        req_headers: req_headers,
+        request_path: "/inbox",
+        params: params,
+        query_string: ""
+      })
+
+    assert {:cancel, {:error, :forbidden}} = ReceiverWorker.perform(oban_job)
+  end
+
   test "it can validate the signature" do
     Tesla.Mock.mock(fn
       %{url: "https://mastodon.social/users/bastianallgeier"} ->

From 60101e240dea53c3496eda548dbe269fc22b2f72 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Wed, 28 Aug 2024 15:54:49 -0400
Subject: [PATCH 035/212] Add test confirming cancellation for activity by a
 deleted user

---
 test/pleroma/workers/receiver_worker_test.exs | 88 ++++++++++---------
 1 file changed, 46 insertions(+), 42 deletions(-)

diff --git a/test/pleroma/workers/receiver_worker_test.exs b/test/pleroma/workers/receiver_worker_test.exs
index 640cefb78..2c0da8887 100644
--- a/test/pleroma/workers/receiver_worker_test.exs
+++ b/test/pleroma/workers/receiver_worker_test.exs
@@ -51,52 +51,56 @@ defmodule Pleroma.Workers.ReceiverWorkerTest do
              })
   end
 
-  test "it does not retry if a user fetch fails with a 403" do
-    Tesla.Mock.mock(fn
-      %{url: "https://simpsons.com/users/bart"} ->
-        %Tesla.Env{
-          status: 403,
-          body: ""
-        }
-    end)
+  describe "cancels on a failed user fetch" do
+    setup do
+      Tesla.Mock.mock(fn
+        %{url: "https://springfield.social/users/bart"} ->
+          %Tesla.Env{
+            status: 403,
+            body: ""
+          }
 
-    params =
-      %{
-        "@context" => [
-          "https://www.w3.org/ns/activitystreams",
-          "https://w3id.org/security/v1"
-        ],
-        "actor" => "https://simpsons.com/users/bart",
-        "cc" => [],
-        "id" => "https://simpsons.com/activity/eat-my-shorts",
-        "object" => %{},
-        "to" => ["https://www.w3.org/ns/activitystreams#Public"],
-        "type" => "Create"
-      }
+        %{url: "https://springfield.social/users/troymcclure"} ->
+          %Tesla.Env{
+            status: 404,
+            body: ""
+          }
+      end)
+    end
 
-    req_headers = [
-      ["accept-encoding", "gzip"],
-      ["content-length", "31337"],
-      ["content-type", "application/activity+json"],
-      ["date", "Wed, 28 Aug 2024 15:36:31 GMT"],
-      ["digest", "SHA-256=ouge/6HP2/QryG6F3JNtZ6vzs/hSwMk67xdxe87eH7A="],
-      ["host", "bikeshed.party"],
-      [
-        "signature",
-        "does not matter as user needs to be fetched first"
-      ]
-    ]
+    test "when request returns a 403" do
+      params =
+        insert(:note_activity).data
+        |> Map.put("actor", "https://springfield.social/users/bart")
 
-    {:ok, oban_job} =
-      Federator.incoming_ap_doc(%{
-        method: "POST",
-        req_headers: req_headers,
-        request_path: "/inbox",
-        params: params,
-        query_string: ""
-      })
+      {:ok, oban_job} =
+        Federator.incoming_ap_doc(%{
+          method: "POST",
+          req_headers: [],
+          request_path: "/inbox",
+          params: params,
+          query_string: ""
+        })
 
-    assert {:cancel, {:error, :forbidden}} = ReceiverWorker.perform(oban_job)
+      assert {:cancel, {:error, :forbidden}} = ReceiverWorker.perform(oban_job)
+    end
+
+    test "when request returns a 404" do
+      params =
+        insert(:note_activity).data
+        |> Map.put("actor", "https://springfield.social/users/troymcclure")
+
+      {:ok, oban_job} =
+        Federator.incoming_ap_doc(%{
+          method: "POST",
+          req_headers: [],
+          request_path: "/inbox",
+          params: params,
+          query_string: ""
+        })
+
+      assert {:cancel, {:error, :not_found}} = ReceiverWorker.perform(oban_job)
+    end
   end
 
   test "it can validate the signature" do

From 66e1b4089528dcd5bcdb61343f111cea03f17ab8 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Wed, 28 Aug 2024 16:04:12 -0400
Subject: [PATCH 036/212] Cancel if the User fetch resulted in a 410

---
 test/pleroma/workers/receiver_worker_test.exs | 23 +++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/test/pleroma/workers/receiver_worker_test.exs b/test/pleroma/workers/receiver_worker_test.exs
index 2c0da8887..085108e37 100644
--- a/test/pleroma/workers/receiver_worker_test.exs
+++ b/test/pleroma/workers/receiver_worker_test.exs
@@ -65,6 +65,12 @@ defmodule Pleroma.Workers.ReceiverWorkerTest do
             status: 404,
             body: ""
           }
+
+        %{url: "https://springfield.social/users/hankscorpio"} ->
+          %Tesla.Env{
+            status: 410,
+            body: ""
+          }
       end)
     end
 
@@ -101,6 +107,23 @@ defmodule Pleroma.Workers.ReceiverWorkerTest do
 
       assert {:cancel, {:error, :not_found}} = ReceiverWorker.perform(oban_job)
     end
+
+    test "when request returns a 410" do
+      params =
+        insert(:note_activity).data
+        |> Map.put("actor", "https://springfield.social/users/hankscorpio")
+
+      {:ok, oban_job} =
+        Federator.incoming_ap_doc(%{
+          method: "POST",
+          req_headers: [],
+          request_path: "/inbox",
+          params: params,
+          query_string: ""
+        })
+
+      assert {:cancel, {:error, :not_found}} = ReceiverWorker.perform(oban_job)
+    end
   end
 
   test "it can validate the signature" do

From 48a46618858c9b0dee5ade61c0d9113c521be289 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Wed, 28 Aug 2024 16:22:38 -0400
Subject: [PATCH 037/212] Simplify test, move data into a json fixture

By removing the inReplyTo, tags, and cc we can simplify the test and it still passes signature validation
---
 test/fixtures/bastianallgeier.json            | 117 --------------
 .../receiver_worker_signature_activity.json   | 127 ++++++++++-----
 test/pleroma/workers/receiver_worker_test.exs | 147 +-----------------
 3 files changed, 89 insertions(+), 302 deletions(-)
 delete mode 100644 test/fixtures/bastianallgeier.json

diff --git a/test/fixtures/bastianallgeier.json b/test/fixtures/bastianallgeier.json
deleted file mode 100644
index 6b47e7db9..000000000
--- a/test/fixtures/bastianallgeier.json
+++ /dev/null
@@ -1,117 +0,0 @@
-{
-  "@context": [
-    "https://www.w3.org/ns/activitystreams",
-    "https://w3id.org/security/v1",
-    {
-      "Curve25519Key": "toot:Curve25519Key",
-      "Device": "toot:Device",
-      "Ed25519Key": "toot:Ed25519Key",
-      "Ed25519Signature": "toot:Ed25519Signature",
-      "EncryptedMessage": "toot:EncryptedMessage",
-      "PropertyValue": "schema:PropertyValue",
-      "alsoKnownAs": {
-        "@id": "as:alsoKnownAs",
-        "@type": "@id"
-      },
-      "cipherText": "toot:cipherText",
-      "claim": {
-        "@id": "toot:claim",
-        "@type": "@id"
-      },
-      "deviceId": "toot:deviceId",
-      "devices": {
-        "@id": "toot:devices",
-        "@type": "@id"
-      },
-      "discoverable": "toot:discoverable",
-      "featured": {
-        "@id": "toot:featured",
-        "@type": "@id"
-      },
-      "featuredTags": {
-        "@id": "toot:featuredTags",
-        "@type": "@id"
-      },
-      "fingerprintKey": {
-        "@id": "toot:fingerprintKey",
-        "@type": "@id"
-      },
-      "focalPoint": {
-        "@container": "@list",
-        "@id": "toot:focalPoint"
-      },
-      "identityKey": {
-        "@id": "toot:identityKey",
-        "@type": "@id"
-      },
-      "indexable": "toot:indexable",
-      "manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
-      "memorial": "toot:memorial",
-      "messageFranking": "toot:messageFranking",
-      "messageType": "toot:messageType",
-      "movedTo": {
-        "@id": "as:movedTo",
-        "@type": "@id"
-      },
-      "publicKeyBase64": "toot:publicKeyBase64",
-      "schema": "http://schema.org#",
-      "suspended": "toot:suspended",
-      "toot": "http://joinmastodon.org/ns#",
-      "value": "schema:value"
-    }
-  ],
-  "attachment": [
-    {
-      "name": "Website",
-      "type": "PropertyValue",
-      "value": "<a href=\"https://bastianallgeier.com\" target=\"_blank\" rel=\"nofollow noopener noreferrer me\" translate=\"no\"><span class=\"invisible\">https://</span><span class=\"\">bastianallgeier.com</span><span class=\"invisible\"></span></a>"
-    },
-    {
-      "name": "Project",
-      "type": "PropertyValue",
-      "value": "<a href=\"https://getkirby.com\" target=\"_blank\" rel=\"nofollow noopener noreferrer me\" translate=\"no\"><span class=\"invisible\">https://</span><span class=\"\">getkirby.com</span><span class=\"invisible\"></span></a>"
-    },
-    {
-      "name": "Github",
-      "type": "PropertyValue",
-      "value": "<a href=\"https://github.com/bastianallgeier\" target=\"_blank\" rel=\"nofollow noopener noreferrer me\" translate=\"no\"><span class=\"invisible\">https://</span><span class=\"\">github.com/bastianallgeier</span><span class=\"invisible\"></span></a>"
-    }
-  ],
-  "devices": "https://mastodon.social/users/bastianallgeier/collections/devices",
-  "discoverable": true,
-  "endpoints": {
-    "sharedInbox": "https://mastodon.social/inbox"
-  },
-  "featured": "https://mastodon.social/users/bastianallgeier/collections/featured",
-  "featuredTags": "https://mastodon.social/users/bastianallgeier/collections/tags",
-  "followers": "https://mastodon.social/users/bastianallgeier/followers",
-  "following": "https://mastodon.social/users/bastianallgeier/following",
-  "icon": {
-    "mediaType": "image/jpeg",
-    "type": "Image",
-    "url": "https://files.mastodon.social/accounts/avatars/000/007/393/original/0180a20079617c71.jpg"
-  },
-  "id": "https://mastodon.social/users/bastianallgeier",
-  "image": {
-    "mediaType": "image/jpeg",
-    "type": "Image",
-    "url": "https://files.mastodon.social/accounts/headers/000/007/393/original/13d644ab46d50478.jpeg"
-  },
-  "inbox": "https://mastodon.social/users/bastianallgeier/inbox",
-  "indexable": false,
-  "manuallyApprovesFollowers": false,
-  "memorial": false,
-  "name": "Bastian Allgeier",
-  "outbox": "https://mastodon.social/users/bastianallgeier/outbox",
-  "preferredUsername": "bastianallgeier",
-  "publicKey": {
-    "id": "https://mastodon.social/users/bastianallgeier#main-key",
-    "owner": "https://mastodon.social/users/bastianallgeier",
-    "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3fz+hpgVztO9z6HUhyzv\nwP++ERBBoIwSLKf1TyIM8bvzGFm2YXaO5uxu1HvumYFTYc3ACr3q4j8VUb7NMxkQ\nlzu4QwPjOFJ43O+fY+HSPORXEDW5fXDGC5DGpox4+i08LxRmx7L6YPRUSUuPN8nI\nWyq1Qsq1zOQrNY/rohMXkBdSXxqC3yIRqvtLt4otCgay/5tMogJWkkS6ZKyFhb9z\nwVVy1fsbV10c9C+SHy4NH26CKaTtpTYLRBMjhTCS8bX8iDSjGIf2aZgYs1ir7gEz\n9wf5CvLiENmVWGwm64t6KSEAkA4NJ1hzgHUZPCjPHZE2SmhO/oHaxokTzqtbbENJ\n1QIDAQAB\n-----END PUBLIC KEY-----\n"
-  },
-  "published": "2016-11-01T00:00:00Z",
-  "summary": "<p>Designer &amp; developer. Creator of Kirby CMS</p>",
-  "tag": [],
-  "type": "Person",
-  "url": "https://mastodon.social/@bastianallgeier"
-}
diff --git a/test/fixtures/receiver_worker_signature_activity.json b/test/fixtures/receiver_worker_signature_activity.json
index 3c3fb3fd2..19dc0087f 100644
--- a/test/fixtures/receiver_worker_signature_activity.json
+++ b/test/fixtures/receiver_worker_signature_activity.json
@@ -1,62 +1,109 @@
 {
   "@context": [
     "https://www.w3.org/ns/activitystreams",
+    "https://w3id.org/security/v1",
     {
+      "claim": {
+        "@id": "toot:claim",
+        "@type": "@id"
+      },
+      "memorial": "toot:memorial",
       "atomUri": "ostatus:atomUri",
+      "manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
       "blurhash": "toot:blurhash",
-      "conversation": "ostatus:conversation",
+      "ostatus": "http://ostatus.org#",
+      "discoverable": "toot:discoverable",
       "focalPoint": {
         "@container": "@list",
         "@id": "toot:focalPoint"
       },
-      "inReplyToAtomUri": "ostatus:inReplyToAtomUri",
-      "ostatus": "http://ostatus.org#",
+      "votersCount": "toot:votersCount",
+      "Hashtag": "as:Hashtag",
+      "Emoji": "toot:Emoji",
+      "alsoKnownAs": {
+        "@id": "as:alsoKnownAs",
+        "@type": "@id"
+      },
       "sensitive": "as:sensitive",
+      "movedTo": {
+        "@id": "as:movedTo",
+        "@type": "@id"
+      },
+      "inReplyToAtomUri": "ostatus:inReplyToAtomUri",
+      "conversation": "ostatus:conversation",
+      "Device": "toot:Device",
+      "schema": "http://schema.org#",
       "toot": "http://joinmastodon.org/ns#",
-      "votersCount": "toot:votersCount"
+      "cipherText": "toot:cipherText",
+      "suspended": "toot:suspended",
+      "messageType": "toot:messageType",
+      "featuredTags": {
+        "@id": "toot:featuredTags",
+        "@type": "@id"
+      },
+      "Curve25519Key": "toot:Curve25519Key",
+      "deviceId": "toot:deviceId",
+      "Ed25519Signature": "toot:Ed25519Signature",
+      "featured": {
+        "@id": "toot:featured",
+        "@type": "@id"
+      },
+      "devices": {
+        "@id": "toot:devices",
+        "@type": "@id"
+      },
+      "value": "schema:value",
+      "PropertyValue": "schema:PropertyValue",
+      "messageFranking": "toot:messageFranking",
+      "publicKeyBase64": "toot:publicKeyBase64",
+      "identityKey": {
+        "@id": "toot:identityKey",
+        "@type": "@id"
+      },
+      "Ed25519Key": "toot:Ed25519Key",
+      "indexable": "toot:indexable",
+      "EncryptedMessage": "toot:EncryptedMessage",
+      "fingerprintKey": {
+        "@id": "toot:fingerprintKey",
+        "@type": "@id"
+      }
     }
   ],
-  "atomUri": "https://chaos.social/users/distantnative/statuses/109336635639931467",
-  "attachment": [
-    {
-      "blurhash": "UAK1zS00OXIUxuMxIUM{?b-:-;W:Di?b%2M{",
-      "height": 960,
-      "mediaType": "image/jpeg",
-      "name": null,
-      "type": "Document",
-      "url": "https://assets.chaos.social/media_attachments/files/109/336/634/286/114/657/original/2e6122063d8bfb26.jpeg",
-      "width": 346
-    }
-  ],
-  "attributedTo": "https://chaos.social/users/distantnative",
-  "cc": [
-    "https://chaos.social/users/distantnative/followers"
-  ],
-  "content": "<p>Favorite piece of anthropology meta discourse.</p>",
-  "contentMap": {
-    "en": "<p>Favorite piece of anthropology meta discourse.</p>"
-  },
-  "conversation": "tag:chaos.social,2022-11-13:objectId=71843781:objectType=Conversation",
-  "id": "https://chaos.social/users/distantnative/statuses/109336635639931467",
+  "actor": "https://phpc.social/users/denniskoch",
+  "cc": [],
+  "id": "https://phpc.social/users/denniskoch/statuses/112847382711461301/activity",
   "inReplyTo": null,
   "inReplyToAtomUri": null,
-  "published": "2022-11-13T13:04:20Z",
-  "replies": {
-    "first": {
-      "items": [],
-      "next": "https://chaos.social/users/distantnative/statuses/109336635639931467/replies?only_other_accounts=true&page=true",
-      "partOf": "https://chaos.social/users/distantnative/statuses/109336635639931467/replies",
-      "type": "CollectionPage"
+  "object": {
+    "atomUri": "https://phpc.social/users/denniskoch/statuses/112847382711461301",
+    "attachment": [],
+    "attributedTo": "https://phpc.social/users/denniskoch",
+    "cc": [],
+    "content": "<p><span class=\"h-card\" translate=\"no\"><a href=\"https://mastodon.social/@bastianallgeier\" class=\"u-url mention\">@<span>bastianallgeier</span></a></span> <span class=\"h-card\" translate=\"no\"><a href=\"https://chaos.social/@distantnative\" class=\"u-url mention\">@<span>distantnative</span></a></span> <span class=\"h-card\" translate=\"no\"><a href=\"https://fosstodon.org/@kev\" class=\"u-url mention\">@<span>kev</span></a></span> Another main argument: Discord is popular. Many people have an account, so you can just join an server quickly. Also you know the app and how to get around.</p>",
+    "contentMap": {
+      "en": "<p><span class=\"h-card\" translate=\"no\"><a href=\"https://mastodon.social/@bastianallgeier\" class=\"u-url mention\">@<span>bastianallgeier</span></a></span> <span class=\"h-card\" translate=\"no\"><a href=\"https://chaos.social/@distantnative\" class=\"u-url mention\">@<span>distantnative</span></a></span> <span class=\"h-card\" translate=\"no\"><a href=\"https://fosstodon.org/@kev\" class=\"u-url mention\">@<span>kev</span></a></span> Another main argument: Discord is popular. Many people have an account, so you can just join an server quickly. Also you know the app and how to get around.</p>"
     },
-    "id": "https://chaos.social/users/distantnative/statuses/109336635639931467/replies",
-    "type": "Collection"
+    "conversation": "tag:mastodon.social,2024-07-25:objectId=760068442:objectType=Conversation",
+    "id": "https://phpc.social/users/denniskoch/statuses/112847382711461301",
+    "published": "2024-07-25T13:33:29Z",
+    "replies": null,
+    "sensitive": false,
+    "tag": [],
+    "to": [
+      "https://www.w3.org/ns/activitystreams#Public"
+    ],
+    "type": "Note",
+    "url": "https://phpc.social/@denniskoch/112847382711461301"
+  },
+  "published": "2024-07-25T13:33:29Z",
+  "signature": {
+    "created": "2024-07-25T13:33:29Z",
+    "creator": "https://phpc.social/users/denniskoch#main-key",
+    "signatureValue": "slz9BKJzd2n1S44wdXGOU+bV/wsskdgAaUpwxj8R16mYOL8+DTpE6VnfSKoZGsBBJT8uG5gnVfVEz1YsTUYtymeUgLMh7cvd8VnJnZPS+oixbmBRVky/Myf91TEgQQE7G4vDmTdB4ii54hZrHcOOYYf5FKPNRSkMXboKA6LMqNtekhbI+JTUJYIB02WBBK6PUyo15f6B1RJ6HGWVgud9NE0y1EZXfrkqUt682p8/9D49ORf7AwjXUJibKic2RbPvhEBj70qUGfBm4vvgdWhSUn1IG46xh+U0+NrTSUED82j1ZVOeua/2k/igkGs8cSBkY35quXTkPz6gbqCCH66CuA==",
+    "type": "RsaSignature2017"
   },
-  "sensitive": false,
-  "summary": null,
-  "tag": [],
   "to": [
     "https://www.w3.org/ns/activitystreams#Public"
   ],
-  "type": "Note",
-  "url": "https://chaos.social/@distantnative/109336635639931467"
+  "type": "Create"
 }
diff --git a/test/pleroma/workers/receiver_worker_test.exs b/test/pleroma/workers/receiver_worker_test.exs
index 085108e37..cb434f52e 100644
--- a/test/pleroma/workers/receiver_worker_test.exs
+++ b/test/pleroma/workers/receiver_worker_test.exs
@@ -128,23 +128,6 @@ defmodule Pleroma.Workers.ReceiverWorkerTest do
 
   test "it can validate the signature" do
     Tesla.Mock.mock(fn
-      %{url: "https://mastodon.social/users/bastianallgeier"} ->
-        %Tesla.Env{
-          status: 200,
-          body: File.read!("test/fixtures/bastianallgeier.json"),
-          headers: [{"content-type", "application/activity+json"}]
-        }
-
-      %{url: "https://mastodon.social/users/bastianallgeier/collections/featured"} ->
-        %Tesla.Env{
-          status: 200,
-          headers: [{"content-type", "application/activity+json"}],
-          body:
-            File.read!("test/fixtures/users_mock/masto_featured.json")
-            |> String.replace("{{domain}}", "mastodon.social")
-            |> String.replace("{{nickname}}", "bastianallgeier")
-        }
-
       %{url: "https://phpc.social/users/denniskoch"} ->
         %Tesla.Env{
           status: 200,
@@ -161,136 +144,10 @@ defmodule Pleroma.Workers.ReceiverWorkerTest do
             |> String.replace("{{domain}}", "phpc.social")
             |> String.replace("{{nickname}}", "denniskoch")
         }
-
-      %{url: "https://mastodon.social/users/bastianallgeier/statuses/112846516276907281"} ->
-        %Tesla.Env{
-          status: 200,
-          headers: [{"content-type", "application/activity+json"}],
-          body: File.read!("test/fixtures/receiver_worker_signature_activity.json")
-        }
     end)
 
-    params = %{
-      "@context" => [
-        "https://www.w3.org/ns/activitystreams",
-        "https://w3id.org/security/v1",
-        %{
-          "claim" => %{"@id" => "toot:claim", "@type" => "@id"},
-          "memorial" => "toot:memorial",
-          "atomUri" => "ostatus:atomUri",
-          "manuallyApprovesFollowers" => "as:manuallyApprovesFollowers",
-          "blurhash" => "toot:blurhash",
-          "ostatus" => "http://ostatus.org#",
-          "discoverable" => "toot:discoverable",
-          "focalPoint" => %{"@container" => "@list", "@id" => "toot:focalPoint"},
-          "votersCount" => "toot:votersCount",
-          "Hashtag" => "as:Hashtag",
-          "Emoji" => "toot:Emoji",
-          "alsoKnownAs" => %{"@id" => "as:alsoKnownAs", "@type" => "@id"},
-          "sensitive" => "as:sensitive",
-          "movedTo" => %{"@id" => "as:movedTo", "@type" => "@id"},
-          "inReplyToAtomUri" => "ostatus:inReplyToAtomUri",
-          "conversation" => "ostatus:conversation",
-          "Device" => "toot:Device",
-          "schema" => "http://schema.org#",
-          "toot" => "http://joinmastodon.org/ns#",
-          "cipherText" => "toot:cipherText",
-          "suspended" => "toot:suspended",
-          "messageType" => "toot:messageType",
-          "featuredTags" => %{"@id" => "toot:featuredTags", "@type" => "@id"},
-          "Curve25519Key" => "toot:Curve25519Key",
-          "deviceId" => "toot:deviceId",
-          "Ed25519Signature" => "toot:Ed25519Signature",
-          "featured" => %{"@id" => "toot:featured", "@type" => "@id"},
-          "devices" => %{"@id" => "toot:devices", "@type" => "@id"},
-          "value" => "schema:value",
-          "PropertyValue" => "schema:PropertyValue",
-          "messageFranking" => "toot:messageFranking",
-          "publicKeyBase64" => "toot:publicKeyBase64",
-          "identityKey" => %{"@id" => "toot:identityKey", "@type" => "@id"},
-          "Ed25519Key" => "toot:Ed25519Key",
-          "indexable" => "toot:indexable",
-          "EncryptedMessage" => "toot:EncryptedMessage",
-          "fingerprintKey" => %{"@id" => "toot:fingerprintKey", "@type" => "@id"}
-        }
-      ],
-      "actor" => "https://phpc.social/users/denniskoch",
-      "cc" => [
-        "https://phpc.social/users/denniskoch/followers",
-        "https://mastodon.social/users/bastianallgeier",
-        "https://chaos.social/users/distantnative",
-        "https://fosstodon.org/users/kev"
-      ],
-      "id" => "https://phpc.social/users/denniskoch/statuses/112847382711461301/activity",
-      "object" => %{
-        "atomUri" => "https://phpc.social/users/denniskoch/statuses/112847382711461301",
-        "attachment" => [],
-        "attributedTo" => "https://phpc.social/users/denniskoch",
-        "cc" => [
-          "https://phpc.social/users/denniskoch/followers",
-          "https://mastodon.social/users/bastianallgeier",
-          "https://chaos.social/users/distantnative",
-          "https://fosstodon.org/users/kev"
-        ],
-        "content" =>
-          "<p><span class=\"h-card\" translate=\"no\"><a href=\"https://mastodon.social/@bastianallgeier\" class=\"u-url mention\">@<span>bastianallgeier</span></a></span> <span class=\"h-card\" translate=\"no\"><a href=\"https://chaos.social/@distantnative\" class=\"u-url mention\">@<span>distantnative</span></a></span> <span class=\"h-card\" translate=\"no\"><a href=\"https://fosstodon.org/@kev\" class=\"u-url mention\">@<span>kev</span></a></span> Another main argument: Discord is popular. Many people have an account, so you can just join an server quickly. Also you know the app and how to get around.</p>",
-        "contentMap" => %{
-          "en" =>
-            "<p><span class=\"h-card\" translate=\"no\"><a href=\"https://mastodon.social/@bastianallgeier\" class=\"u-url mention\">@<span>bastianallgeier</span></a></span> <span class=\"h-card\" translate=\"no\"><a href=\"https://chaos.social/@distantnative\" class=\"u-url mention\">@<span>distantnative</span></a></span> <span class=\"h-card\" translate=\"no\"><a href=\"https://fosstodon.org/@kev\" class=\"u-url mention\">@<span>kev</span></a></span> Another main argument: Discord is popular. Many people have an account, so you can just join an server quickly. Also you know the app and how to get around.</p>"
-        },
-        "conversation" =>
-          "tag:mastodon.social,2024-07-25:objectId=760068442:objectType=Conversation",
-        "id" => "https://phpc.social/users/denniskoch/statuses/112847382711461301",
-        "inReplyTo" =>
-          "https://mastodon.social/users/bastianallgeier/statuses/112846516276907281",
-        "inReplyToAtomUri" =>
-          "https://mastodon.social/users/bastianallgeier/statuses/112846516276907281",
-        "published" => "2024-07-25T13:33:29Z",
-        "replies" => %{
-          "first" => %{
-            "items" => [],
-            "next" =>
-              "https://phpc.social/users/denniskoch/statuses/112847382711461301/replies?only_other_accounts=true&page=true",
-            "partOf" =>
-              "https://phpc.social/users/denniskoch/statuses/112847382711461301/replies",
-            "type" => "CollectionPage"
-          },
-          "id" => "https://phpc.social/users/denniskoch/statuses/112847382711461301/replies",
-          "type" => "Collection"
-        },
-        "sensitive" => false,
-        "tag" => [
-          %{
-            "href" => "https://mastodon.social/users/bastianallgeier",
-            "name" => "@bastianallgeier@mastodon.social",
-            "type" => "Mention"
-          },
-          %{
-            "href" => "https://chaos.social/users/distantnative",
-            "name" => "@distantnative@chaos.social",
-            "type" => "Mention"
-          },
-          %{
-            "href" => "https://fosstodon.org/users/kev",
-            "name" => "@kev@fosstodon.org",
-            "type" => "Mention"
-          }
-        ],
-        "to" => ["https://www.w3.org/ns/activitystreams#Public"],
-        "type" => "Note",
-        "url" => "https://phpc.social/@denniskoch/112847382711461301"
-      },
-      "published" => "2024-07-25T13:33:29Z",
-      "signature" => %{
-        "created" => "2024-07-25T13:33:29Z",
-        "creator" => "https://phpc.social/users/denniskoch#main-key",
-        "signatureValue" =>
-          "slz9BKJzd2n1S44wdXGOU+bV/wsskdgAaUpwxj8R16mYOL8+DTpE6VnfSKoZGsBBJT8uG5gnVfVEz1YsTUYtymeUgLMh7cvd8VnJnZPS+oixbmBRVky/Myf91TEgQQE7G4vDmTdB4ii54hZrHcOOYYf5FKPNRSkMXboKA6LMqNtekhbI+JTUJYIB02WBBK6PUyo15f6B1RJ6HGWVgud9NE0y1EZXfrkqUt682p8/9D49ORf7AwjXUJibKic2RbPvhEBj70qUGfBm4vvgdWhSUn1IG46xh+U0+NrTSUED82j1ZVOeua/2k/igkGs8cSBkY35quXTkPz6gbqCCH66CuA==",
-        "type" => "RsaSignature2017"
-      },
-      "to" => ["https://www.w3.org/ns/activitystreams#Public"],
-      "type" => "Create"
-    }
+    params =
+      File.read!("test/fixtures/receiver_worker_signature_activity.json") |> Jason.decode!()
 
     req_headers = [
       ["accept-encoding", "gzip"],

From 3dadb9ed086fb63a3e664a43be3bf30f9ffbfb2d Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Wed, 28 Aug 2024 16:37:46 -0400
Subject: [PATCH 038/212] Changelog

---
 changelog.d/oban-recevier-user-error.fix | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 changelog.d/oban-recevier-user-error.fix

diff --git a/changelog.d/oban-recevier-user-error.fix b/changelog.d/oban-recevier-user-error.fix
new file mode 100644
index 000000000..1ed0c5bb1
--- /dev/null
+++ b/changelog.d/oban-recevier-user-error.fix
@@ -0,0 +1 @@
+ReceiverWorker will cancel processing jobs instead of retrying if the user cannot be fetched due to 403, 404, or 410 errors.

From bb2f4a76b3af4ad5f0e2950ef8dc2567c6ad69ff Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Wed, 28 Aug 2024 17:01:30 -0400
Subject: [PATCH 039/212] Add test for origin containment failures

---
 test/pleroma/workers/receiver_worker_test.exs | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/test/pleroma/workers/receiver_worker_test.exs b/test/pleroma/workers/receiver_worker_test.exs
index cb434f52e..995f765a1 100644
--- a/test/pleroma/workers/receiver_worker_test.exs
+++ b/test/pleroma/workers/receiver_worker_test.exs
@@ -177,4 +177,21 @@ defmodule Pleroma.Workers.ReceiverWorkerTest do
 
     assert {:ok, %Pleroma.Activity{}} = ReceiverWorker.perform(oban_job)
   end
+
+  test "cancels due to origin containment" do
+    params =
+      insert(:note_activity).data
+      |> Map.put("id", "https://notorigindomain.com/activity")
+
+    {:ok, oban_job} =
+      Federator.incoming_ap_doc(%{
+        method: "POST",
+        req_headers: [],
+        request_path: "/inbox",
+        params: params,
+        query_string: ""
+      })
+
+    assert {:cancel, :origin_containment_failed} = ReceiverWorker.perform(oban_job)
+  end
 end

From 6ae629cfe072d236453d256017618fe9a8c44755 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Wed, 28 Aug 2024 17:24:59 -0400
Subject: [PATCH 040/212] Cancel ReceiverWorker jobs if the user account has
 been disabled / deactivated

---
 lib/pleroma/workers/receiver_worker.ex        |  4 ++-
 test/pleroma/workers/receiver_worker_test.exs | 26 +++++++++++++++++++
 2 files changed, 29 insertions(+), 1 deletion(-)

diff --git a/lib/pleroma/workers/receiver_worker.ex b/lib/pleroma/workers/receiver_worker.ex
index 7dce02a5f..80518f6fd 100644
--- a/lib/pleroma/workers/receiver_worker.ex
+++ b/lib/pleroma/workers/receiver_worker.ex
@@ -33,7 +33,8 @@ defmodule Pleroma.Workers.ReceiverWorker do
       query_string: query_string
     }
 
-    with {:ok, %User{} = _actor} <- User.get_or_fetch_by_ap_id(conn_data.params["actor"]),
+    with {:ok, %User{} = actor} <- User.get_or_fetch_by_ap_id(conn_data.params["actor"]),
+         {:user_active, true} <- {:user_active, match?(true, actor.is_active)},
          {:ok, _public_key} <- Signature.refetch_public_key(conn_data),
          {:signature, true} <- {:signature, Signature.validate_signature(conn_data)},
          {:ok, res} <- Federator.perform(:incoming_ap_doc, params) do
@@ -70,6 +71,7 @@ defmodule Pleroma.Workers.ReceiverWorker do
       {:error, {:side_effects, {:error, :no_object_actor}} = reason} -> {:cancel, reason}
       {:error, :not_found} = reason -> {:cancel, reason}
       {:error, :forbidden} = reason -> {:cancel, reason}
+      {:user_active, false} = reason -> {:cancel, reason}
       {:error, _} = e -> e
       e -> {:error, e}
     end
diff --git a/test/pleroma/workers/receiver_worker_test.exs b/test/pleroma/workers/receiver_worker_test.exs
index 995f765a1..adf90ec86 100644
--- a/test/pleroma/workers/receiver_worker_test.exs
+++ b/test/pleroma/workers/receiver_worker_test.exs
@@ -9,6 +9,7 @@ defmodule Pleroma.Workers.ReceiverWorkerTest do
   import Mock
   import Pleroma.Factory
 
+  alias Pleroma.User
   alias Pleroma.Web.Federator
   alias Pleroma.Workers.ReceiverWorker
 
@@ -124,6 +125,31 @@ defmodule Pleroma.Workers.ReceiverWorkerTest do
 
       assert {:cancel, {:error, :not_found}} = ReceiverWorker.perform(oban_job)
     end
+
+    test "when user account is disabled" do
+      user = insert(:user)
+
+      fake_activity = URI.parse(user.ap_id) |> Map.put(:path, "/fake-activity") |> to_string
+
+      params =
+        insert(:note_activity, user: user).data
+        |> Map.put("id", fake_activity)
+
+      {:ok, %User{}} = User.set_activation(user, false)
+
+      {:ok, oban_job} =
+        ReceiverWorker.new(%{
+          "op" => "incoming_ap_doc",
+          "method" => "POST",
+          "req_headers" => [],
+          "request_path" => "/inbox",
+          "params" => params,
+          "query_string" => ""
+        })
+        |> Oban.insert()
+
+      assert {:cancel, {:user_active, false}} = ReceiverWorker.perform(oban_job)
+    end
   end
 
   test "it can validate the signature" do

From 2e9515578a689428027ca7084d5c9b0d0b4a60ba Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Wed, 28 Aug 2024 17:38:13 -0400
Subject: [PATCH 041/212] ReceiverWorker job canceled due to deleted object

---
 test/pleroma/workers/receiver_worker_test.exs | 25 +++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/test/pleroma/workers/receiver_worker_test.exs b/test/pleroma/workers/receiver_worker_test.exs
index adf90ec86..779e83eaa 100644
--- a/test/pleroma/workers/receiver_worker_test.exs
+++ b/test/pleroma/workers/receiver_worker_test.exs
@@ -220,4 +220,29 @@ defmodule Pleroma.Workers.ReceiverWorkerTest do
 
     assert {:cancel, :origin_containment_failed} = ReceiverWorker.perform(oban_job)
   end
+
+  test "canceled due to deleted object" do
+    params =
+      insert(:announce_activity).data
+      |> Map.put("object", "http://localhost:4001/deleted")
+
+    Tesla.Mock.mock(fn
+      %{url: "http://localhost:4001/deleted"} ->
+        %Tesla.Env{
+          status: 404,
+          body: ""
+        }
+    end)
+
+    {:ok, oban_job} =
+      Federator.incoming_ap_doc(%{
+        method: "POST",
+        req_headers: [],
+        request_path: "/inbox",
+        params: params,
+        query_string: ""
+      })
+
+    assert {:cancel, _} = ReceiverWorker.perform(oban_job)
+  end
 end

From 2346807ac93d5acb9901823cceaffe5c305c1e20 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Wed, 28 Aug 2024 17:44:33 -0400
Subject: [PATCH 042/212] Annotate error cases

---
 lib/pleroma/workers/receiver_worker.ex | 20 ++++++++++++--------
 1 file changed, 12 insertions(+), 8 deletions(-)

diff --git a/lib/pleroma/workers/receiver_worker.ex b/lib/pleroma/workers/receiver_worker.ex
index 80518f6fd..4b1f74a27 100644
--- a/lib/pleroma/workers/receiver_worker.ex
+++ b/lib/pleroma/workers/receiver_worker.ex
@@ -61,17 +61,21 @@ defmodule Pleroma.Workers.ReceiverWorker do
 
   defp process_errors(errors) do
     case errors do
-      {:error, :origin_containment_failed} -> {:cancel, :origin_containment_failed}
-      {:error, :already_present} -> {:cancel, :already_present}
-      {:error, {:validate_object, _} = reason} -> {:cancel, reason}
-      {:error, {:validate, {:error, _changeset} = reason}} -> {:cancel, reason}
-      {:error, {:reject, _} = reason} -> {:cancel, reason}
-      {:signature, false} -> {:cancel, :invalid_signature}
-      {:error, "Object has been deleted"} = reason -> {:cancel, reason}
-      {:error, {:side_effects, {:error, :no_object_actor}} = reason} -> {:cancel, reason}
+      # User fetch failures
       {:error, :not_found} = reason -> {:cancel, reason}
       {:error, :forbidden} = reason -> {:cancel, reason}
+      # Inactive user
       {:user_active, false} = reason -> {:cancel, reason}
+      # Validator will error and return a changeset error
+      # e.g., duplicate activities or if the object was deleted
+      {:error, {:validate, {:error, _changeset} = reason}} -> {:cancel, reason}
+      # MRFs will return a reject
+      {:error, {:reject, _} = reason} -> {:cancel, reason}
+      # HTTP Sigs
+      {:signature, false} -> {:cancel, :invalid_signature}
+      {:error, :origin_containment_failed} -> {:cancel, :origin_containment_failed}
+      {:error, {:validate_object, _} = reason} -> {:cancel, reason}
+      {:error, {:side_effects, {:error, :no_object_actor}} = reason} -> {:cancel, reason}
       {:error, _} = e -> e
       e -> {:error, e}
     end

From 380a6a6df31a16a89f5c5cc497ddc1360cea3854 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Wed, 28 Aug 2024 17:45:31 -0400
Subject: [PATCH 043/212] :validate_object is not a real error returned from
 anywhere

---
 lib/pleroma/web/federator.ex           | 5 -----
 lib/pleroma/workers/receiver_worker.ex | 1 -
 2 files changed, 6 deletions(-)

diff --git a/lib/pleroma/web/federator.ex b/lib/pleroma/web/federator.ex
index 2df716556..e812b1a46 100644
--- a/lib/pleroma/web/federator.ex
+++ b/lib/pleroma/web/federator.ex
@@ -121,11 +121,6 @@ defmodule Pleroma.Web.Federator do
         Logger.debug("Unhandled actor #{actor}, #{inspect(e)}")
         {:error, e}
 
-      {:error, {:validate_object, _}} = e ->
-        Logger.error("Incoming AP doc validation error: #{inspect(e)}")
-        Logger.debug(Jason.encode!(params, pretty: true))
-        e
-
       e ->
         # Just drop those for now
         Logger.debug(fn -> "Unhandled activity\n" <> Jason.encode!(params, pretty: true) end)
diff --git a/lib/pleroma/workers/receiver_worker.ex b/lib/pleroma/workers/receiver_worker.ex
index 4b1f74a27..c7e6bc5ea 100644
--- a/lib/pleroma/workers/receiver_worker.ex
+++ b/lib/pleroma/workers/receiver_worker.ex
@@ -74,7 +74,6 @@ defmodule Pleroma.Workers.ReceiverWorker do
       # HTTP Sigs
       {:signature, false} -> {:cancel, :invalid_signature}
       {:error, :origin_containment_failed} -> {:cancel, :origin_containment_failed}
-      {:error, {:validate_object, _} = reason} -> {:cancel, reason}
       {:error, {:side_effects, {:error, :no_object_actor}} = reason} -> {:cancel, reason}
       {:error, _} = e -> e
       e -> {:error, e}

From c5ca806aa0023e25755947a3bf0d54242e45f65a Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Wed, 28 Aug 2024 17:57:34 -0400
Subject: [PATCH 044/212] Add back one of the duplicate checks to fix a test,
 document where it comes from

---
 lib/pleroma/workers/receiver_worker.ex | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/lib/pleroma/workers/receiver_worker.ex b/lib/pleroma/workers/receiver_worker.ex
index c7e6bc5ea..810fda67c 100644
--- a/lib/pleroma/workers/receiver_worker.ex
+++ b/lib/pleroma/workers/receiver_worker.ex
@@ -69,6 +69,8 @@ defmodule Pleroma.Workers.ReceiverWorker do
       # Validator will error and return a changeset error
       # e.g., duplicate activities or if the object was deleted
       {:error, {:validate, {:error, _changeset} = reason}} -> {:cancel, reason}
+      # Duplicate detection during Normalization
+      {:error, :already_present} -> {:cancel, :already_present}
       # MRFs will return a reject
       {:error, {:reject, _} = reason} -> {:cancel, reason}
       # HTTP Sigs

From 8a3efa7152488460934c1fadc8ab86efd7d47c04 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Wed, 28 Aug 2024 18:02:35 -0400
Subject: [PATCH 045/212] More error annotations

---
 lib/pleroma/workers/receiver_worker.ex | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/lib/pleroma/workers/receiver_worker.ex b/lib/pleroma/workers/receiver_worker.ex
index 810fda67c..6787a59ef 100644
--- a/lib/pleroma/workers/receiver_worker.ex
+++ b/lib/pleroma/workers/receiver_worker.ex
@@ -75,8 +75,11 @@ defmodule Pleroma.Workers.ReceiverWorker do
       {:error, {:reject, _} = reason} -> {:cancel, reason}
       # HTTP Sigs
       {:signature, false} -> {:cancel, :invalid_signature}
+      # Origin / URL validation failed somewhere possibly due to spoofing
       {:error, :origin_containment_failed} -> {:cancel, :origin_containment_failed}
+      # Unclear if this can be reached
       {:error, {:side_effects, {:error, :no_object_actor}} = reason} -> {:cancel, reason}
+      # Catchall
       {:error, _} = e -> e
       e -> {:error, e}
     end

From e498d252e44ddc1a85288b80dc65beefcd60edf2 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Wed, 28 Aug 2024 18:03:33 -0400
Subject: [PATCH 046/212] Changelog update

---
 changelog.d/oban-recevier-improvements.fix | 1 +
 changelog.d/oban-recevier-user-error.fix   | 1 -
 2 files changed, 1 insertion(+), 1 deletion(-)
 create mode 100644 changelog.d/oban-recevier-improvements.fix
 delete mode 100644 changelog.d/oban-recevier-user-error.fix

diff --git a/changelog.d/oban-recevier-improvements.fix b/changelog.d/oban-recevier-improvements.fix
new file mode 100644
index 000000000..f91502ed2
--- /dev/null
+++ b/changelog.d/oban-recevier-improvements.fix
@@ -0,0 +1 @@
+ReceiverWorker will cancel processing jobs instead of retrying if the user cannot be fetched due to 403, 404, or 410 errors or if the account is disabled locally.
diff --git a/changelog.d/oban-recevier-user-error.fix b/changelog.d/oban-recevier-user-error.fix
deleted file mode 100644
index 1ed0c5bb1..000000000
--- a/changelog.d/oban-recevier-user-error.fix
+++ /dev/null
@@ -1 +0,0 @@
-ReceiverWorker will cancel processing jobs instead of retrying if the user cannot be fetched due to 403, 404, or 410 errors.

From 1821ef4f157980bdf64f7540ee5aa8e26fa3102e Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Wed, 28 Aug 2024 18:35:01 -0400
Subject: [PATCH 047/212] Move user active check into Federator.perform/1

---
 lib/pleroma/web/federator.ex                  |  3 ++-
 lib/pleroma/workers/receiver_worker.ex        |  5 ++---
 test/pleroma/workers/receiver_worker_test.exs | 14 ++++++--------
 3 files changed, 10 insertions(+), 12 deletions(-)

diff --git a/lib/pleroma/web/federator.ex b/lib/pleroma/web/federator.ex
index e812b1a46..58260afa8 100644
--- a/lib/pleroma/web/federator.ex
+++ b/lib/pleroma/web/federator.ex
@@ -102,7 +102,8 @@ defmodule Pleroma.Web.Federator do
 
     # NOTE: we use the actor ID to do the containment, this is fine because an
     # actor shouldn't be acting on objects outside their own AP server.
-    with {_, {:ok, _user}} <- {:actor, User.get_or_fetch_by_ap_id(actor)},
+    with {_, {:ok, user}} <- {:actor, User.get_or_fetch_by_ap_id(actor)},
+         {:user_active, true} <- {:user_active, match?(true, user.is_active)},
          nil <- Activity.normalize(params["id"]),
          {_, :ok} <-
            {:correct_origin?, Containment.contain_origin_from_id(actor, params)},
diff --git a/lib/pleroma/workers/receiver_worker.ex b/lib/pleroma/workers/receiver_worker.ex
index 6787a59ef..0373ec15f 100644
--- a/lib/pleroma/workers/receiver_worker.ex
+++ b/lib/pleroma/workers/receiver_worker.ex
@@ -33,8 +33,7 @@ defmodule Pleroma.Workers.ReceiverWorker do
       query_string: query_string
     }
 
-    with {:ok, %User{} = actor} <- User.get_or_fetch_by_ap_id(conn_data.params["actor"]),
-         {:user_active, true} <- {:user_active, match?(true, actor.is_active)},
+    with {:ok, %User{}} <- User.get_or_fetch_by_ap_id(conn_data.params["actor"]),
          {:ok, _public_key} <- Signature.refetch_public_key(conn_data),
          {:signature, true} <- {:signature, Signature.validate_signature(conn_data)},
          {:ok, res} <- Federator.perform(:incoming_ap_doc, params) do
@@ -65,7 +64,7 @@ defmodule Pleroma.Workers.ReceiverWorker do
       {:error, :not_found} = reason -> {:cancel, reason}
       {:error, :forbidden} = reason -> {:cancel, reason}
       # Inactive user
-      {:user_active, false} = reason -> {:cancel, reason}
+      {:error, {:user_active, false} = reason} -> {:cancel, reason}
       # Validator will error and return a changeset error
       # e.g., duplicate activities or if the object was deleted
       {:error, {:validate, {:error, _changeset} = reason}} -> {:cancel, reason}
diff --git a/test/pleroma/workers/receiver_worker_test.exs b/test/pleroma/workers/receiver_worker_test.exs
index 779e83eaa..4d53c44ed 100644
--- a/test/pleroma/workers/receiver_worker_test.exs
+++ b/test/pleroma/workers/receiver_worker_test.exs
@@ -138,15 +138,13 @@ defmodule Pleroma.Workers.ReceiverWorkerTest do
       {:ok, %User{}} = User.set_activation(user, false)
 
       {:ok, oban_job} =
-        ReceiverWorker.new(%{
-          "op" => "incoming_ap_doc",
-          "method" => "POST",
-          "req_headers" => [],
-          "request_path" => "/inbox",
-          "params" => params,
-          "query_string" => ""
+        Federator.incoming_ap_doc(%{
+          method: "POST",
+          req_headers: [],
+          request_path: "/inbox",
+          params: params,
+          query_string: ""
         })
-        |> Oban.insert()
 
       assert {:cancel, {:user_active, false}} = ReceiverWorker.perform(oban_job)
     end

From 0bf82a1745a38a3752f5b7df645a7d266b8fd9c8 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Wed, 28 Aug 2024 19:50:51 -0400
Subject: [PATCH 048/212] Add an AdapterHelper for Finch so we can support
 streaming request bodies

---
 lib/pleroma/http/adapter_helper.ex       |  2 ++
 lib/pleroma/http/adapter_helper/finch.ex | 33 ++++++++++++++++++++++++
 2 files changed, 35 insertions(+)
 create mode 100644 lib/pleroma/http/adapter_helper/finch.ex

diff --git a/lib/pleroma/http/adapter_helper.ex b/lib/pleroma/http/adapter_helper.ex
index 4dbcccdcc..be00ba78a 100644
--- a/lib/pleroma/http/adapter_helper.ex
+++ b/lib/pleroma/http/adapter_helper.ex
@@ -52,6 +52,7 @@ defmodule Pleroma.HTTP.AdapterHelper do
     case adapter() do
       Tesla.Adapter.Gun -> AdapterHelper.Gun
       Tesla.Adapter.Hackney -> AdapterHelper.Hackney
+      {Tesla.Adapter.Finch, _} -> AdapterHelper.Finch
       _ -> AdapterHelper.Default
     end
   end
@@ -124,6 +125,7 @@ defmodule Pleroma.HTTP.AdapterHelper do
   def can_stream? do
     case Application.get_env(:tesla, :adapter) do
       Tesla.Adapter.Gun -> true
+      {Tesla.Adapter.Finch, _} -> true
       _ -> false
     end
   end
diff --git a/lib/pleroma/http/adapter_helper/finch.ex b/lib/pleroma/http/adapter_helper/finch.ex
new file mode 100644
index 000000000..10a988901
--- /dev/null
+++ b/lib/pleroma/http/adapter_helper/finch.ex
@@ -0,0 +1,33 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.HTTP.AdapterHelper.Finch do
+  @behaviour Pleroma.HTTP.AdapterHelper
+
+  alias Pleroma.Config
+  alias Pleroma.HTTP.AdapterHelper
+
+  @spec options(keyword(), URI.t()) :: keyword()
+  def options(incoming_opts \\ [], %URI{} = _uri) do
+    proxy =
+      [:http, :proxy_url]
+      |> Config.get()
+      |> AdapterHelper.format_proxy()
+
+    config_opts = Config.get([:http, :adapter], [])
+
+    config_opts
+    |> Keyword.merge(incoming_opts)
+    |> AdapterHelper.maybe_add_proxy(proxy)
+    |> maybe_stream()
+  end
+
+  # Tesla Finch adapter uses response: :stream
+  defp maybe_stream(opts) do
+    case Keyword.pop(opts, :stream, nil) do
+      {true, opts} -> Keyword.put(opts, :response, :stream)
+      {_, opts} -> opts
+    end
+  end
+end

From 8ab4dd20dfdd0cc92c18ade7d84bfb5364785a15 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Wed, 28 Aug 2024 19:52:29 -0400
Subject: [PATCH 049/212] Update comments, remove solved TODO

---
 lib/pleroma/http/adapter_helper.ex       | 1 -
 lib/pleroma/http/adapter_helper/finch.ex | 2 +-
 lib/pleroma/http/adapter_helper/gun.ex   | 2 +-
 3 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/lib/pleroma/http/adapter_helper.ex b/lib/pleroma/http/adapter_helper.ex
index be00ba78a..32c1080f7 100644
--- a/lib/pleroma/http/adapter_helper.ex
+++ b/lib/pleroma/http/adapter_helper.ex
@@ -120,7 +120,6 @@ defmodule Pleroma.HTTP.AdapterHelper do
     end
   end
 
-  # TODO add Finch support once we have an AdapterHelper for it
   @spec can_stream? :: bool()
   def can_stream? do
     case Application.get_env(:tesla, :adapter) do
diff --git a/lib/pleroma/http/adapter_helper/finch.ex b/lib/pleroma/http/adapter_helper/finch.ex
index 10a988901..181caed7e 100644
--- a/lib/pleroma/http/adapter_helper/finch.ex
+++ b/lib/pleroma/http/adapter_helper/finch.ex
@@ -23,7 +23,7 @@ defmodule Pleroma.HTTP.AdapterHelper.Finch do
     |> maybe_stream()
   end
 
-  # Tesla Finch adapter uses response: :stream
+  # Finch uses [response: :stream]
   defp maybe_stream(opts) do
     case Keyword.pop(opts, :stream, nil) do
       {true, opts} -> Keyword.put(opts, :response, :stream)
diff --git a/lib/pleroma/http/adapter_helper/gun.ex b/lib/pleroma/http/adapter_helper/gun.ex
index f9a8180f2..30ba26765 100644
--- a/lib/pleroma/http/adapter_helper/gun.ex
+++ b/lib/pleroma/http/adapter_helper/gun.ex
@@ -48,7 +48,7 @@ defmodule Pleroma.HTTP.AdapterHelper.Gun do
     Keyword.put(opts, :timeout, recv_timeout)
   end
 
-  # Tesla Gun adapter uses body_as: :stream
+  # Gun uses [body_as: :stream]
   defp maybe_stream(opts) do
     case Keyword.pop(opts, :stream, nil) do
       {true, opts} -> Keyword.put(opts, :body_as, :stream)

From d01569822e0dc45349c321ad306f6e19b4e967af Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Wed, 28 Aug 2024 19:56:09 -0400
Subject: [PATCH 050/212] Changelog

---
 changelog.d/rich-media-no-heads.change | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 changelog.d/rich-media-no-heads.change

diff --git a/changelog.d/rich-media-no-heads.change b/changelog.d/rich-media-no-heads.change
new file mode 100644
index 000000000..0bab323aa
--- /dev/null
+++ b/changelog.d/rich-media-no-heads.change
@@ -0,0 +1 @@
+Rich Media preview fetching will skip making an HTTP HEAD request to check a URL for allowed content type and length if the Tesla adapter is Gun or Finch

From c17a78c55a6b288c271923f730dc69aaf27e6556 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Thu, 29 Aug 2024 09:37:10 -0400
Subject: [PATCH 051/212] Rich Media: add stream byte counting as an extra
 protection against malicious URLs

---
 lib/pleroma/web/rich_media/helpers.ex | 34 +++++++++++++++++++++++----
 1 file changed, 30 insertions(+), 4 deletions(-)

diff --git a/lib/pleroma/web/rich_media/helpers.ex b/lib/pleroma/web/rich_media/helpers.ex
index a242ca640..d4be97957 100644
--- a/lib/pleroma/web/rich_media/helpers.ex
+++ b/lib/pleroma/web/rich_media/helpers.ex
@@ -23,7 +23,7 @@ defmodule Pleroma.Web.RichMedia.Helpers do
            {:get, Pleroma.HTTP.get(url, req_headers(), http_options())},
          {_, :ok} <- {:content_type, check_content_type(headers)},
          {_, :ok} <- {:content_length, check_content_length(headers)},
-         body <- Enum.into(stream_body, <<>>) do
+         {:read_stream, {:ok, body}} <- {:read_stream, read_stream(stream_body)} do
       {:ok, body}
     end
   end
@@ -52,8 +52,12 @@ defmodule Pleroma.Web.RichMedia.Helpers do
         Logger.debug("Rich media error for #{url}: content-type is #{type}")
         {:error, :content_type}
 
-      {:content_length, {_, length}} ->
-        Logger.debug("Rich media error for #{url}: content-length is #{length}")
+      {:content_length, :error} ->
+        Logger.debug("Rich media error for #{url}: content-length exceeded")
+        {:error, :body_too_large}
+
+      {:read_stream, :error} ->
+        Logger.debug("Rich media error for #{url}: content-length exceeded")
         {:error, :body_too_large}
 
       {:get, _} ->
@@ -82,7 +86,7 @@ defmodule Pleroma.Web.RichMedia.Helpers do
       {_, maybe_content_length} ->
         case Integer.parse(maybe_content_length) do
           {content_length, ""} when content_length <= max_body -> :ok
-          {_, ""} -> {:error, maybe_content_length}
+          {_, ""} -> :error
           _ -> :ok
         end
 
@@ -91,6 +95,28 @@ defmodule Pleroma.Web.RichMedia.Helpers do
     end
   end
 
+  defp read_stream(stream) do
+    max_body = Keyword.get(http_options(), :max_body)
+
+    try do
+      result =
+        Stream.transform(stream, 0, fn chunk, total_bytes ->
+          new_total = total_bytes + byte_size(chunk)
+
+          if new_total > max_body do
+            raise("Exceeds max body limit of #{max_body}")
+          else
+            {[chunk], new_total}
+          end
+        end)
+        |> Enum.into(<<>>)
+
+      {:ok, result}
+    rescue
+      _ -> :error
+    end
+  end
+
   defp http_options do
     [
       pool: :rich_media,

From ceffb8a8918b83d482e9c1da64fec22b428a61f3 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Fri, 23 Aug 2024 13:52:19 -0400
Subject: [PATCH 052/212] Drop incoming Delete activities from unknown actors

---
 changelog.d/drop-unknown-deletes.change       |  1 +
 lib/pleroma/workers/receiver_worker.ex        | 16 +++++++++++++-
 test/pleroma/workers/receiver_worker_test.exs | 22 +++++++++++++++++++
 3 files changed, 38 insertions(+), 1 deletion(-)
 create mode 100644 changelog.d/drop-unknown-deletes.change

diff --git a/changelog.d/drop-unknown-deletes.change b/changelog.d/drop-unknown-deletes.change
new file mode 100644
index 000000000..0be7f5450
--- /dev/null
+++ b/changelog.d/drop-unknown-deletes.change
@@ -0,0 +1 @@
+Drop incoming Delete activities from unknown actors
diff --git a/lib/pleroma/workers/receiver_worker.ex b/lib/pleroma/workers/receiver_worker.ex
index d4db97b63..ea86a3a12 100644
--- a/lib/pleroma/workers/receiver_worker.ex
+++ b/lib/pleroma/workers/receiver_worker.ex
@@ -33,7 +33,8 @@ defmodule Pleroma.Workers.ReceiverWorker do
       query_string: query_string
     }
 
-    with {:ok, %User{} = _actor} <- User.get_or_fetch_by_ap_id(conn_data.params["actor"]),
+    with {_, false} <- {:unknown_delete, unknown_delete?(params)},
+         User.get_or_fetch_by_ap_id(conn_data.params["actor"]),
          {:ok, _public_key} <- Signature.refetch_public_key(conn_data),
          {:signature, true} <- {:signature, Signature.validate_signature(conn_data)},
          {:ok, res} <- Federator.perform(:incoming_ap_doc, params) do
@@ -58,6 +59,7 @@ defmodule Pleroma.Workers.ReceiverWorker do
 
   defp process_errors(errors) do
     case errors do
+      {:unknown_delete, true} -> {:cancel, "Delete from unknown actor"}
       {:error, :origin_containment_failed} -> {:cancel, :origin_containment_failed}
       {:error, :already_present} -> {:cancel, :already_present}
       {:error, {:validate_object, _} = reason} -> {:cancel, reason}
@@ -71,4 +73,16 @@ defmodule Pleroma.Workers.ReceiverWorker do
       e -> {:error, e}
     end
   end
+
+  defp unknown_delete?(%{
+         "type" => "Delete",
+         "actor" => actor
+       }) do
+    case User.get_cached_by_ap_id(actor) do
+      %User{} -> false
+      _ -> true
+    end
+  end
+
+  defp unknown_delete?(_), do: false
 end
diff --git a/test/pleroma/workers/receiver_worker_test.exs b/test/pleroma/workers/receiver_worker_test.exs
index 33be91085..91fbb1fe8 100644
--- a/test/pleroma/workers/receiver_worker_test.exs
+++ b/test/pleroma/workers/receiver_worker_test.exs
@@ -245,4 +245,26 @@ defmodule Pleroma.Workers.ReceiverWorkerTest do
 
     assert {:ok, %Pleroma.Activity{}} = ReceiverWorker.perform(oban_job)
   end
+
+  # When activity is delivered to the inbox and we cannot immediately verify signature
+  # we capture all the params and process it later in the Oban job.
+  # This requires we replicate the same scenario by including additional fields in the params
+  test "Deletes cancelled for an unknown actor" do
+    params = %{
+      "type" => "Delete",
+      "actor" => "https://unknown.mastodon.instance/users/somebody"
+    }
+
+    assert {:cancel, "Delete from unknown actor"} =
+             ReceiverWorker.perform(%Oban.Job{
+               args: %{
+                 "op" => "incoming_ap_doc",
+                 "method" => :post,
+                 "req_headers" => [],
+                 "request_path" => "/inbox",
+                 "query_string" => "",
+                 "params" => params
+               }
+             })
+  end
 end

From 4bc6f334f49c27e1f466052fee6fa2f3d5d2ee74 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Fri, 23 Aug 2024 14:18:04 -0400
Subject: [PATCH 053/212] Revert unintentional change

---
 lib/pleroma/workers/receiver_worker.ex | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/pleroma/workers/receiver_worker.ex b/lib/pleroma/workers/receiver_worker.ex
index ea86a3a12..4033fec0f 100644
--- a/lib/pleroma/workers/receiver_worker.ex
+++ b/lib/pleroma/workers/receiver_worker.ex
@@ -34,7 +34,7 @@ defmodule Pleroma.Workers.ReceiverWorker do
     }
 
     with {_, false} <- {:unknown_delete, unknown_delete?(params)},
-         User.get_or_fetch_by_ap_id(conn_data.params["actor"]),
+         {:ok, %User{} = _actor} <- User.get_or_fetch_by_ap_id(conn_data.params["actor"]),
          {:ok, _public_key} <- Signature.refetch_public_key(conn_data),
          {:signature, true} <- {:signature, Signature.validate_signature(conn_data)},
          {:ok, res} <- Federator.perform(:incoming_ap_doc, params) do

From 1c394dd18c5d61dc716a9b9cda981a359de32456 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Fri, 23 Aug 2024 14:24:04 -0400
Subject: [PATCH 054/212] Move the check to the inbox

---
 .../activity_pub/activity_pub_controller.ex   | 32 +++++++++++++++----
 lib/pleroma/workers/receiver_worker.ex        | 15 +--------
 2 files changed, 26 insertions(+), 21 deletions(-)

diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex
index cdd054e1a..a24dcfc9c 100644
--- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex
@@ -294,13 +294,19 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
   end
 
   def inbox(%{assigns: %{valid_signature: false}} = conn, params) do
-    Federator.incoming_ap_doc(%{
-      method: conn.method,
-      req_headers: conn.req_headers,
-      request_path: conn.request_path,
-      params: params,
-      query_string: conn.query_string
-    })
+    case unknown_delete?(params) do
+      true ->
+        :ok
+
+      false ->
+        Federator.incoming_ap_doc(%{
+          method: conn.method,
+          req_headers: conn.req_headers,
+          request_path: conn.request_path,
+          params: params,
+          query_string: conn.query_string
+        })
+    end
 
     json(conn, "ok")
   end
@@ -558,4 +564,16 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
       |> json(UserView.render("featured.json", %{user: user}))
     end
   end
+
+  defp unknown_delete?(%{
+         "type" => "Delete",
+         "actor" => actor
+       }) do
+    case User.get_cached_by_ap_id(actor) do
+      %User{} -> false
+      _ -> true
+    end
+  end
+
+  defp unknown_delete?(_), do: false
 end
diff --git a/lib/pleroma/workers/receiver_worker.ex b/lib/pleroma/workers/receiver_worker.ex
index 4033fec0f..ce92ef9dd 100644
--- a/lib/pleroma/workers/receiver_worker.ex
+++ b/lib/pleroma/workers/receiver_worker.ex
@@ -33,8 +33,7 @@ defmodule Pleroma.Workers.ReceiverWorker do
       query_string: query_string
     }
 
-    with {_, false} <- {:unknown_delete, unknown_delete?(params)},
-         {:ok, %User{} = _actor} <- User.get_or_fetch_by_ap_id(conn_data.params["actor"]),
+    with {:ok, %User{} = _actor} <- User.get_or_fetch_by_ap_id(conn_data.params["actor"]),
          {:ok, _public_key} <- Signature.refetch_public_key(conn_data),
          {:signature, true} <- {:signature, Signature.validate_signature(conn_data)},
          {:ok, res} <- Federator.perform(:incoming_ap_doc, params) do
@@ -73,16 +72,4 @@ defmodule Pleroma.Workers.ReceiverWorker do
       e -> {:error, e}
     end
   end
-
-  defp unknown_delete?(%{
-         "type" => "Delete",
-         "actor" => actor
-       }) do
-    case User.get_cached_by_ap_id(actor) do
-      %User{} -> false
-      _ -> true
-    end
-  end
-
-  defp unknown_delete?(_), do: false
 end

From 27fcc421719062d5de9bf4dc90f3349595eb278d Mon Sep 17 00:00:00 2001
From: feld <feld@feld.me>
Date: Sat, 24 Aug 2024 16:53:22 +0000
Subject: [PATCH 055/212] Use Pleroma.Object.Containment.get_actor/1 to
 reliably find the actor of an incoming activity or object

---
 lib/pleroma/web/activity_pub/activity_pub_controller.ex | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex
index a24dcfc9c..77ec26f14 100644
--- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex
@@ -567,9 +567,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
 
   defp unknown_delete?(%{
          "type" => "Delete",
-         "actor" => actor
-       }) do
-    case User.get_cached_by_ap_id(actor) do
+       } = data) do
+    case data |> Pleroma.Object.Containment.get_actor() |> User.get_cached_by_ap_id() do
       %User{} -> false
       _ -> true
     end

From 7bcc21ad6f1fdf9dbc16990e9891f9de7a21011d Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Sat, 24 Aug 2024 13:01:28 -0400
Subject: [PATCH 056/212] Switch test to the inbox

---
 .../activity_pub_controller_test.exs          | 21 ++++++++++++++++++
 test/pleroma/workers/receiver_worker_test.exs | 22 -------------------
 2 files changed, 21 insertions(+), 22 deletions(-)

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 af1a32fed..b9067533c 100644
--- a/test/pleroma/web/activity_pub/activity_pub_controller_test.exs
+++ b/test/pleroma/web/activity_pub/activity_pub_controller_test.exs
@@ -684,6 +684,27 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
       |> json_response(400)
     end
 
+    # When activity is delivered to the inbox and we cannot immediately verify signature
+    # we capture all the params and process it later in the Oban job.
+    # Once we begin processing it through Oban we risk fetching the actor to validate the
+    # activity which just leads to inserting a new user to process a Delete not relevant to us.
+    test "Deletes from an unknown actor are discarded", %{conn: conn} do
+      params =
+        %{
+          "type" => "Delete",
+          "actor" => "https://unknown.mastodon.instance/users/somebody"
+        }
+        |> Jason.encode!()
+
+      conn
+      |> assign(:valid_signature, false)
+      |> put_req_header("content-type", "application/activity+json")
+      |> post("/inbox", params)
+      |> json_response(200)
+
+      assert all_enqueued() == []
+    end
+
     test "accepts Add/Remove activities", %{conn: conn} do
       object_id = "c61d6733-e256-4fe1-ab13-1e369789423f"
 
diff --git a/test/pleroma/workers/receiver_worker_test.exs b/test/pleroma/workers/receiver_worker_test.exs
index 91fbb1fe8..33be91085 100644
--- a/test/pleroma/workers/receiver_worker_test.exs
+++ b/test/pleroma/workers/receiver_worker_test.exs
@@ -245,26 +245,4 @@ defmodule Pleroma.Workers.ReceiverWorkerTest do
 
     assert {:ok, %Pleroma.Activity{}} = ReceiverWorker.perform(oban_job)
   end
-
-  # When activity is delivered to the inbox and we cannot immediately verify signature
-  # we capture all the params and process it later in the Oban job.
-  # This requires we replicate the same scenario by including additional fields in the params
-  test "Deletes cancelled for an unknown actor" do
-    params = %{
-      "type" => "Delete",
-      "actor" => "https://unknown.mastodon.instance/users/somebody"
-    }
-
-    assert {:cancel, "Delete from unknown actor"} =
-             ReceiverWorker.perform(%Oban.Job{
-               args: %{
-                 "op" => "incoming_ap_doc",
-                 "method" => :post,
-                 "req_headers" => [],
-                 "request_path" => "/inbox",
-                 "query_string" => "",
-                 "params" => params
-               }
-             })
-  end
 end

From 06deacd58e6aa676847530f24c6799162ed06777 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Sat, 24 Aug 2024 20:03:50 -0400
Subject: [PATCH 057/212] Formatting

---
 lib/pleroma/web/activity_pub/activity_pub_controller.ex | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex
index 77ec26f14..4c83d1927 100644
--- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex
@@ -565,9 +565,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
     end
   end
 
-  defp unknown_delete?(%{
-         "type" => "Delete",
-       } = data) do
+  defp unknown_delete?(
+         %{
+           "type" => "Delete"
+         } = data
+       ) do
     case data |> Pleroma.Object.Containment.get_actor() |> User.get_cached_by_ap_id() do
       %User{} -> false
       _ -> true

From 16a9b34876f3a9289c02253e802bffdac4901ac0 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Thu, 29 Aug 2024 14:16:59 -0400
Subject: [PATCH 058/212] Convert to an Plug called InboxGuard

---
 lib/pleroma/constants.ex                      | 12 ++++
 .../activity_pub/activity_pub_controller.ex   | 33 ++--------
 lib/pleroma/web/plugs/inbox_guard_plug.ex     | 66 +++++++++++++++++++
 lib/pleroma/web/router.ex                     |  6 +-
 .../activity_pub_controller_test.exs          |  2 +-
 5 files changed, 91 insertions(+), 28 deletions(-)
 create mode 100644 lib/pleroma/web/plugs/inbox_guard_plug.ex

diff --git a/lib/pleroma/constants.ex b/lib/pleroma/constants.ex
index 3a5e35301..f969bfdbb 100644
--- a/lib/pleroma/constants.ex
+++ b/lib/pleroma/constants.ex
@@ -85,6 +85,18 @@ defmodule Pleroma.Constants do
     ]
   )
 
+  const(allowed_activity_types_from_strangers,
+    do: [
+      "Block",
+      "Create",
+      "Flag",
+      "Follow",
+      "Like",
+      "Move",
+      "React"
+    ]
+  )
+
   # basic regex, just there to weed out potential mistakes
   # https://datatracker.ietf.org/doc/html/rfc2045#section-5.1
   const(mime_regex,
diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex
index 4c83d1927..cdd054e1a 100644
--- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex
@@ -294,19 +294,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
   end
 
   def inbox(%{assigns: %{valid_signature: false}} = conn, params) do
-    case unknown_delete?(params) do
-      true ->
-        :ok
-
-      false ->
-        Federator.incoming_ap_doc(%{
-          method: conn.method,
-          req_headers: conn.req_headers,
-          request_path: conn.request_path,
-          params: params,
-          query_string: conn.query_string
-        })
-    end
+    Federator.incoming_ap_doc(%{
+      method: conn.method,
+      req_headers: conn.req_headers,
+      request_path: conn.request_path,
+      params: params,
+      query_string: conn.query_string
+    })
 
     json(conn, "ok")
   end
@@ -564,17 +558,4 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
       |> json(UserView.render("featured.json", %{user: user}))
     end
   end
-
-  defp unknown_delete?(
-         %{
-           "type" => "Delete"
-         } = data
-       ) do
-    case data |> Pleroma.Object.Containment.get_actor() |> User.get_cached_by_ap_id() do
-      %User{} -> false
-      _ -> true
-    end
-  end
-
-  defp unknown_delete?(_), do: false
 end
diff --git a/lib/pleroma/web/plugs/inbox_guard_plug.ex b/lib/pleroma/web/plugs/inbox_guard_plug.ex
new file mode 100644
index 000000000..643b586d4
--- /dev/null
+++ b/lib/pleroma/web/plugs/inbox_guard_plug.ex
@@ -0,0 +1,66 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.Plugs.InboxGuardPlug do
+  import Plug.Conn
+  import Pleroma.Constants, only: [allowed_activity_types_from_strangers: 0]
+
+  alias Pleroma.Config
+  alias Pleroma.User
+
+  def init(options) do
+    options
+  end
+
+  def call(%{assigns: %{valid_signature: true}} = conn, _opts) do
+    conn
+  end
+
+  def call(conn, _opts) do
+    with {_, true} <- {:federating, Config.get!([:instance, :federating])},
+         true <- known_actor?(conn) do
+      conn
+    else
+      {:federating, false} ->
+        conn
+        |> json(403, "Not federating")
+
+      _ ->
+        conn
+        |> filter_from_strangers()
+    end
+  end
+
+  # If signature failed but we know this actor we should
+  # accept it as we may only need to refetch their public key
+  # during processing
+  defp known_actor?(%{body_params: data}) do
+    case Pleroma.Object.Containment.get_actor(data) |> User.get_cached_by_ap_id() do
+      %User{} -> true
+      _ -> false
+    end
+  end
+
+  # Only permit a subset of activity types from strangers
+  # or else it will add actors you've never interacted with
+  # to the database
+  defp filter_from_strangers(%{body_params: %{"type" => type}} = conn) do
+    with true <- type in allowed_activity_types_from_strangers() do
+      conn
+    else
+      _ ->
+        conn
+        |> json(400, "Invalid activity type for an unknown actor")
+    end
+  end
+
+  defp json(conn, status, resp) do
+    json_resp = Jason.encode!(resp)
+
+    conn
+    |> put_resp_content_type("application/json")
+    |> resp(status, json_resp)
+    |> halt()
+  end
+end
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index 6492e3861..9b9ee421c 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -217,6 +217,10 @@ defmodule Pleroma.Web.Router do
     plug(Pleroma.Web.Plugs.MappedSignatureToIdentityPlug)
   end
 
+  pipeline :inbox_guard do
+    plug(Pleroma.Web.Plugs.InboxGuardPlug)
+  end
+
   pipeline :static_fe do
     plug(Pleroma.Web.Plugs.StaticFEPlug)
   end
@@ -920,7 +924,7 @@ defmodule Pleroma.Web.Router do
   end
 
   scope "/", Pleroma.Web.ActivityPub do
-    pipe_through(:activitypub)
+    pipe_through([:activitypub, :inbox_guard])
     post("/inbox", ActivityPubController, :inbox)
     post("/users/:nickname/inbox", ActivityPubController, :inbox)
   end
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 b9067533c..1b959f324 100644
--- a/test/pleroma/web/activity_pub/activity_pub_controller_test.exs
+++ b/test/pleroma/web/activity_pub/activity_pub_controller_test.exs
@@ -700,7 +700,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
       |> assign(:valid_signature, false)
       |> put_req_header("content-type", "application/activity+json")
       |> post("/inbox", params)
-      |> json_response(200)
+      |> json_response(400)
 
       assert all_enqueued() == []
     end

From e2cdae2c88eb22588209923d83c2a9c52d16c48c Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Thu, 29 Aug 2024 14:23:07 -0400
Subject: [PATCH 059/212] Change relay inbox response when not federating to a
 403 for consistency

---
 lib/pleroma/web/activity_pub/activity_pub_controller.ex | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex
index cdd054e1a..a08eda5f4 100644
--- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex
@@ -311,7 +311,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
       post_inbox_relayed_create(conn, params)
     else
       conn
-      |> put_status(:bad_request)
+      |> put_status(403)
       |> json("Not federating")
     end
   end

From 990b2058df11cc32f260d0ffcf7dd0f342d435b4 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Thu, 29 Aug 2024 14:30:23 -0400
Subject: [PATCH 060/212] Remove unnecessary error match in ReceiverWorker

---
 lib/pleroma/workers/receiver_worker.ex | 1 -
 1 file changed, 1 deletion(-)

diff --git a/lib/pleroma/workers/receiver_worker.ex b/lib/pleroma/workers/receiver_worker.ex
index ce92ef9dd..d4db97b63 100644
--- a/lib/pleroma/workers/receiver_worker.ex
+++ b/lib/pleroma/workers/receiver_worker.ex
@@ -58,7 +58,6 @@ defmodule Pleroma.Workers.ReceiverWorker do
 
   defp process_errors(errors) do
     case errors do
-      {:unknown_delete, true} -> {:cancel, "Delete from unknown actor"}
       {:error, :origin_containment_failed} -> {:cancel, :origin_containment_failed}
       {:error, :already_present} -> {:cancel, :already_present}
       {:error, {:validate_object, _} = reason} -> {:cancel, reason}

From 2b39956acbc3ccd87a43cd4ddbd5976adcac5936 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Thu, 29 Aug 2024 14:40:31 -0400
Subject: [PATCH 061/212] Fix test title to be more specific as it has a
 broader but incorrect meaning

---
 test/pleroma/web/activity_pub/activity_pub_controller_test.exs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

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 1b959f324..762fca0a1 100644
--- a/test/pleroma/web/activity_pub/activity_pub_controller_test.exs
+++ b/test/pleroma/web/activity_pub/activity_pub_controller_test.exs
@@ -657,7 +657,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
     end
 
     test "without valid signature, " <>
-           "it only accepts Create activities and requires enabled federation",
+           "it accepts Create activities and requires enabled federation",
          %{conn: conn} do
       data = File.read!("test/fixtures/mastodon-post-activity.json") |> Jason.decode!()
       non_create_data = File.read!("test/fixtures/mastodon-announce.json") |> Jason.decode!()

From 012132303f79c0d693a8fba7236433443261b757 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Thu, 29 Aug 2024 14:40:45 -0400
Subject: [PATCH 062/212] Test more types we do not want to receive from
 strangers

---
 .../activity_pub_controller_test.exs          | 30 +++++++++++--------
 1 file changed, 17 insertions(+), 13 deletions(-)

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 762fca0a1..453dbaf0c 100644
--- a/test/pleroma/web/activity_pub/activity_pub_controller_test.exs
+++ b/test/pleroma/web/activity_pub/activity_pub_controller_test.exs
@@ -688,21 +688,25 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
     # we capture all the params and process it later in the Oban job.
     # Once we begin processing it through Oban we risk fetching the actor to validate the
     # activity which just leads to inserting a new user to process a Delete not relevant to us.
-    test "Deletes from an unknown actor are discarded", %{conn: conn} do
-      params =
-        %{
-          "type" => "Delete",
-          "actor" => "https://unknown.mastodon.instance/users/somebody"
-        }
-        |> Jason.encode!()
+    test "Activities of certain types from an unknown actor are discarded", %{conn: conn} do
+      example_bad_types = ["Announce", "Delete", "Undo"]
 
-      conn
-      |> assign(:valid_signature, false)
-      |> put_req_header("content-type", "application/activity+json")
-      |> post("/inbox", params)
-      |> json_response(400)
+      Enum.each(example_bad_types, fn bad_type ->
+        params =
+          %{
+            "type" => bad_type,
+            "actor" => "https://unknown.mastodon.instance/users/somebody"
+          }
+          |> Jason.encode!()
 
-      assert all_enqueued() == []
+        conn
+        |> assign(:valid_signature, false)
+        |> put_req_header("content-type", "application/activity+json")
+        |> post("/inbox", params)
+        |> json_response(400)
+
+        assert all_enqueued() == []
+      end)
     end
 
     test "accepts Add/Remove activities", %{conn: conn} do

From 094da5d6343507eb1540f0a6357accc67573e02e Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Thu, 29 Aug 2024 14:44:52 -0400
Subject: [PATCH 063/212] Update changelog

---
 changelog.d/drop-unknown-deletes.change | 1 -
 changelog.d/drop-unwanted.change        | 1 +
 2 files changed, 1 insertion(+), 1 deletion(-)
 delete mode 100644 changelog.d/drop-unknown-deletes.change
 create mode 100644 changelog.d/drop-unwanted.change

diff --git a/changelog.d/drop-unknown-deletes.change b/changelog.d/drop-unknown-deletes.change
deleted file mode 100644
index 0be7f5450..000000000
--- a/changelog.d/drop-unknown-deletes.change
+++ /dev/null
@@ -1 +0,0 @@
-Drop incoming Delete activities from unknown actors
diff --git a/changelog.d/drop-unwanted.change b/changelog.d/drop-unwanted.change
new file mode 100644
index 000000000..59447d68f
--- /dev/null
+++ b/changelog.d/drop-unwanted.change
@@ -0,0 +1 @@
+Restrict incoming activities from unknown actors to a subset that does not imply a previous relationship

From 5205e846eb5cfbd0adfa5031ad75e96fccbc86d8 Mon Sep 17 00:00:00 2001
From: feld <feld@feld.me>
Date: Fri, 30 Aug 2024 13:14:05 +0000
Subject: [PATCH 064/212] Update allowed activity types from strangers

Move is emitted from the old account
EmojiReact is ~ Like
Announced TBD
---
 lib/pleroma/constants.ex | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/pleroma/constants.ex b/lib/pleroma/constants.ex
index f969bfdbb..bbd183683 100644
--- a/lib/pleroma/constants.ex
+++ b/lib/pleroma/constants.ex
@@ -92,8 +92,8 @@ defmodule Pleroma.Constants do
       "Flag",
       "Follow",
       "Like",
-      "Move",
-      "React"
+      "EmojiReact",
+      "Announce"
     ]
   )
 

From e38f5f1a817d6da30e9a128ec74a2a7c78faf174 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Fri, 30 Aug 2024 09:35:04 -0400
Subject: [PATCH 065/212] Add recognized activity types to a constant and use
 it in the test

---
 lib/pleroma/constants.ex                       | 18 ++++++++++++++++++
 .../activity_pub_controller_test.exs           |  4 +++-
 2 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/lib/pleroma/constants.ex b/lib/pleroma/constants.ex
index bbd183683..5268ebe7a 100644
--- a/lib/pleroma/constants.ex
+++ b/lib/pleroma/constants.ex
@@ -85,6 +85,24 @@ defmodule Pleroma.Constants do
     ]
   )
 
+  const(activity_types,
+    do: [
+      "Create",
+      "Update",
+      "Delete",
+      "Follow",
+      "Accept",
+      "Reject",
+      "Add",
+      "Remove",
+      "Like",
+      "Announce",
+      "Undo",
+      "Flag",
+      "EmojiReact"
+    ]
+  )
+
   const(allowed_activity_types_from_strangers,
     do: [
       "Block",
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 453dbaf0c..c32f6c1a3 100644
--- a/test/pleroma/web/activity_pub/activity_pub_controller_test.exs
+++ b/test/pleroma/web/activity_pub/activity_pub_controller_test.exs
@@ -689,7 +689,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
     # Once we begin processing it through Oban we risk fetching the actor to validate the
     # activity which just leads to inserting a new user to process a Delete not relevant to us.
     test "Activities of certain types from an unknown actor are discarded", %{conn: conn} do
-      example_bad_types = ["Announce", "Delete", "Undo"]
+      example_bad_types =
+        Pleroma.Constants.activity_types() --
+          Pleroma.Constants.allowed_activity_types_from_strangers()
 
       Enum.each(example_bad_types, fn bad_type ->
         params =

From 11ee94ae17094a2bc33505a31671b8c705f768a4 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Fri, 30 Aug 2024 09:46:10 -0400
Subject: [PATCH 066/212] InboxGuardPlug: Add early rejection of unknown
 activity types

---
 lib/pleroma/web/plugs/inbox_guard_plug.ex     | 31 ++++++++++++++++---
 .../activity_pub_controller_test.exs          | 21 +++++++++++++
 2 files changed, 48 insertions(+), 4 deletions(-)

diff --git a/lib/pleroma/web/plugs/inbox_guard_plug.ex b/lib/pleroma/web/plugs/inbox_guard_plug.ex
index 643b586d4..0064cce76 100644
--- a/lib/pleroma/web/plugs/inbox_guard_plug.ex
+++ b/lib/pleroma/web/plugs/inbox_guard_plug.ex
@@ -4,7 +4,7 @@
 
 defmodule Pleroma.Web.Plugs.InboxGuardPlug do
   import Plug.Conn
-  import Pleroma.Constants, only: [allowed_activity_types_from_strangers: 0]
+  import Pleroma.Constants, only: [activity_types: 0, allowed_activity_types_from_strangers: 0]
 
   alias Pleroma.Config
   alias Pleroma.User
@@ -14,24 +14,46 @@ defmodule Pleroma.Web.Plugs.InboxGuardPlug do
   end
 
   def call(%{assigns: %{valid_signature: true}} = conn, _opts) do
-    conn
+    with {_, true} <- {:federating, Config.get!([:instance, :federating])} do
+      conn
+      |> filter_activity_types()
+    else
+      {:federating, false} ->
+        conn
+        |> json(403, "Not federating")
+        |> halt()
+    end
   end
 
   def call(conn, _opts) do
     with {_, true} <- {:federating, Config.get!([:instance, :federating])},
-         true <- known_actor?(conn) do
+         conn = filter_activity_types(conn),
+         {:known, true} <- {:known, known_actor?(conn)} do
       conn
     else
       {:federating, false} ->
         conn
         |> json(403, "Not federating")
+        |> halt()
 
-      _ ->
+      {:known, false} ->
         conn
         |> filter_from_strangers()
     end
   end
 
+  # Early rejection of unrecognized types
+  defp filter_activity_types(%{body_params: %{"type" => type}} = conn) do
+    with true <- type in activity_types() do
+      conn
+    else
+      _ ->
+        conn
+        |> json(400, "Invalid activity type")
+        |> halt()
+    end
+  end
+
   # If signature failed but we know this actor we should
   # accept it as we may only need to refetch their public key
   # during processing
@@ -52,6 +74,7 @@ defmodule Pleroma.Web.Plugs.InboxGuardPlug do
       _ ->
         conn
         |> json(400, "Invalid activity type for an unknown actor")
+        |> halt()
     end
   end
 
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 c32f6c1a3..3bd589f49 100644
--- a/test/pleroma/web/activity_pub/activity_pub_controller_test.exs
+++ b/test/pleroma/web/activity_pub/activity_pub_controller_test.exs
@@ -711,6 +711,27 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
       end)
     end
 
+    test "Unknown activity types are discarded", %{conn: conn} do
+      unknown_types = ["Poke", "Read", "Dazzle"]
+
+      Enum.each(unknown_types, fn bad_type ->
+        params =
+          %{
+            "type" => bad_type,
+            "actor" => "https://unknown.mastodon.instance/users/somebody"
+          }
+          |> Jason.encode!()
+
+        conn
+        |> assign(:valid_signature, true)
+        |> put_req_header("content-type", "application/activity+json")
+        |> post("/inbox", params)
+        |> json_response(400)
+
+        assert all_enqueued() == []
+      end)
+    end
+
     test "accepts Add/Remove activities", %{conn: conn} do
       object_id = "c61d6733-e256-4fe1-ab13-1e369789423f"
 

From bb235f913fb88f925abc791285808afe63d14bca Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Fri, 30 Aug 2024 10:03:51 -0400
Subject: [PATCH 067/212] Update changelog

---
 changelog.d/drop-unwanted.change | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/changelog.d/drop-unwanted.change b/changelog.d/drop-unwanted.change
index 59447d68f..459d4bfe6 100644
--- a/changelog.d/drop-unwanted.change
+++ b/changelog.d/drop-unwanted.change
@@ -1 +1 @@
-Restrict incoming activities from unknown actors to a subset that does not imply a previous relationship
+Restrict incoming activities from unknown actors to a subset that does not imply a previous relationship and early rejection of unrecognized activity types.

From 4ae17c62944eab89acfa96a0912819093c872436 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Fri, 30 Aug 2024 15:25:21 -0400
Subject: [PATCH 068/212] NodeInfo: Accept application/activity+json requests

---
 changelog.d/well-known.change       |  1 +
 lib/pleroma/web/router.ex           |  2 +-
 test/pleroma/web/node_info_test.exs | 13 +++++++++++++
 3 files changed, 15 insertions(+), 1 deletion(-)
 create mode 100644 changelog.d/well-known.change

diff --git a/changelog.d/well-known.change b/changelog.d/well-known.change
new file mode 100644
index 000000000..e928124fb
--- /dev/null
+++ b/changelog.d/well-known.change
@@ -0,0 +1 @@
+Accept application/activity+json for requests to .well-known/nodeinfo
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index 6492e3861..9e4b403e0 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -189,7 +189,7 @@ defmodule Pleroma.Web.Router do
   end
 
   pipeline :well_known do
-    plug(:accepts, ["json", "jrd", "jrd+json", "xml", "xrd+xml"])
+    plug(:accepts, ["activity+json", "json", "jrd", "jrd+json", "xml", "xrd+xml"])
   end
 
   pipeline :config do
diff --git a/test/pleroma/web/node_info_test.exs b/test/pleroma/web/node_info_test.exs
index f474220be..afe4ebb36 100644
--- a/test/pleroma/web/node_info_test.exs
+++ b/test/pleroma/web/node_info_test.exs
@@ -24,6 +24,19 @@ defmodule Pleroma.Web.NodeInfoTest do
       |> get(href)
       |> json_response(200)
     end)
+
+    accept_types = [
+      "application/activity+json",
+      "application/json",
+      "application/jrd+json"
+    ]
+
+    for type <- accept_types do
+      conn
+      |> put_req_header("accept", type)
+      |> get("/.well-known/nodeinfo")
+      |> json_response(200)
+    end
   end
 
   test "nodeinfo shows staff accounts", %{conn: conn} do

From 5a1144208d1007af2a2d2279c582adf9d2fa7246 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Sun, 1 Sep 2024 12:26:59 -0400
Subject: [PATCH 069/212] Prevent OAuth App flow from creating duplicate
 entries

---
 changelog.d/oauth-app.fix                     |  1 +
 .../controllers/app_controller.ex             |  4 +-
 .../controllers/app_controller_test.exs       | 47 +++++++++++++++++++
 3 files changed, 49 insertions(+), 3 deletions(-)
 create mode 100644 changelog.d/oauth-app.fix

diff --git a/changelog.d/oauth-app.fix b/changelog.d/oauth-app.fix
new file mode 100644
index 000000000..eb917462f
--- /dev/null
+++ b/changelog.d/oauth-app.fix
@@ -0,0 +1 @@
+Prevent OAuth App flow from creating duplicate entries
diff --git a/lib/pleroma/web/mastodon_api/controllers/app_controller.ex b/lib/pleroma/web/mastodon_api/controllers/app_controller.ex
index 844673ae0..e5e8ea8f5 100644
--- a/lib/pleroma/web/mastodon_api/controllers/app_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/app_controller.ex
@@ -33,11 +33,9 @@ defmodule Pleroma.Web.MastodonAPI.AppController do
     app_attrs =
       params
       |> Map.take([:client_name, :redirect_uris, :website])
-      |> Map.put(:scopes, scopes)
       |> Maps.put_if_present(:user_id, user_id)
 
-    with cs <- App.register_changeset(%App{}, app_attrs),
-         {:ok, app} <- Repo.insert(cs) do
+    with {:ok, app} <- App.get_or_make(app_attrs, scopes) do
       render(conn, "show.json", app: app)
     end
   end
diff --git a/test/pleroma/web/mastodon_api/controllers/app_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/app_controller_test.exs
index bc9d4048c..1e2e68791 100644
--- a/test/pleroma/web/mastodon_api/controllers/app_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/controllers/app_controller_test.exs
@@ -89,4 +89,51 @@ defmodule Pleroma.Web.MastodonAPI.AppControllerTest do
     assert expected == json_response_and_validate_schema(conn, 200)
     assert app.user_id == user.id
   end
+
+  test "creates an oauth app without a user", %{conn: conn} do
+    app_attrs = build(:oauth_app)
+
+    conn =
+      conn
+      |> put_req_header("content-type", "application/json")
+      |> post("/api/v1/apps", %{
+        client_name: app_attrs.client_name,
+        redirect_uris: app_attrs.redirect_uris
+      })
+
+    [app] = Repo.all(App)
+
+    expected = %{
+      "name" => app.client_name,
+      "website" => app.website,
+      "client_id" => app.client_id,
+      "client_secret" => app.client_secret,
+      "id" => app.id |> to_string(),
+      "redirect_uri" => app.redirect_uris,
+      "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
+    }
+
+    assert expected == json_response_and_validate_schema(conn, 200)
+  end
+
+  test "does not duplicate apps with the same client name", %{conn: conn} do
+    client_name = "BleromaSE"
+    redirect_uris = "https://bleroma.app/oauth-callback"
+
+    for _i <- 1..3 do
+      conn
+      |> put_req_header("content-type", "application/json")
+      |> post("/api/v1/apps", %{
+        client_name: client_name,
+        redirect_uris: redirect_uris
+      })
+      |> json_response_and_validate_schema(200)
+    end
+
+    apps = Repo.all(App)
+
+    assert length(apps) == 1
+    assert List.first(apps).client_name == client_name
+    assert List.first(apps).redirect_uris == redirect_uris
+  end
 end

From e3a7c1d906698d2f36661b60de4bdab5a475b871 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Sun, 1 Sep 2024 12:37:59 -0400
Subject: [PATCH 070/212] Test that app scopes can be updated

---
 .../controllers/app_controller_test.exs       | 33 +++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/test/pleroma/web/mastodon_api/controllers/app_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/app_controller_test.exs
index 1e2e68791..26c431673 100644
--- a/test/pleroma/web/mastodon_api/controllers/app_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/controllers/app_controller_test.exs
@@ -136,4 +136,37 @@ defmodule Pleroma.Web.MastodonAPI.AppControllerTest do
     assert List.first(apps).client_name == client_name
     assert List.first(apps).redirect_uris == redirect_uris
   end
+
+  test "app scopes can be updated", %{conn: conn} do
+    client_name = "BleromaSE"
+    redirect_uris = "https://bleroma.app/oauth-callback"
+    website = "https://bleromase.com"
+    scopes = "read write"
+
+    conn
+    |> put_req_header("content-type", "application/json")
+    |> post("/api/v1/apps", %{
+      client_name: client_name,
+      redirect_uris: redirect_uris,
+      website: website,
+      scopes: scopes
+    })
+    |> json_response_and_validate_schema(200)
+
+    assert List.first(Repo.all(App)).scopes == String.split(scopes, " ")
+
+    updated_scopes = "read write push"
+
+    conn
+    |> put_req_header("content-type", "application/json")
+    |> post("/api/v1/apps", %{
+      client_name: client_name,
+      redirect_uris: redirect_uris,
+      website: website,
+      scopes: updated_scopes
+    })
+    |> json_response_and_validate_schema(200)
+
+    assert List.first(Repo.all(App)).scopes == String.split(updated_scopes, " ")
+  end
 end

From 751d63d4bb05caececf52a3a3b134182e57a059d Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Sun, 1 Sep 2024 13:34:30 -0400
Subject: [PATCH 071/212] Support OAuth App updating the website URL

---
 .../controllers/app_controller.ex             |  3 +-
 lib/pleroma/web/o_auth/app.ex                 | 24 +++++----------
 .../controllers/app_controller_test.exs       | 30 +++++++++++++++++++
 test/pleroma/web/o_auth/app_test.exs          | 15 ++++++----
 4 files changed, 49 insertions(+), 23 deletions(-)

diff --git a/lib/pleroma/web/mastodon_api/controllers/app_controller.ex b/lib/pleroma/web/mastodon_api/controllers/app_controller.ex
index e5e8ea8f5..4677ac40a 100644
--- a/lib/pleroma/web/mastodon_api/controllers/app_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/app_controller.ex
@@ -33,9 +33,10 @@ defmodule Pleroma.Web.MastodonAPI.AppController do
     app_attrs =
       params
       |> Map.take([:client_name, :redirect_uris, :website])
+      |> Map.put(:scopes, scopes)
       |> Maps.put_if_present(:user_id, user_id)
 
-    with {:ok, app} <- App.get_or_make(app_attrs, scopes) do
+    with {:ok, app} <- App.get_or_make(app_attrs) do
       render(conn, "show.json", app: app)
     end
   end
diff --git a/lib/pleroma/web/o_auth/app.ex b/lib/pleroma/web/o_auth/app.ex
index d1bf6dd18..889850c73 100644
--- a/lib/pleroma/web/o_auth/app.ex
+++ b/lib/pleroma/web/o_auth/app.ex
@@ -67,35 +67,27 @@ defmodule Pleroma.Web.OAuth.App do
     with %__MODULE__{} = app <- Repo.get(__MODULE__, id) do
       app
       |> changeset(params)
+      |> validate_required([:scopes])
       |> Repo.update()
     end
   end
 
   @doc """
-  Gets app by attrs or create new  with attrs.
-  And updates the scopes if need.
+  Gets app by attrs or create new with attrs.
+  Updates the attrs if needed.
   """
-  @spec get_or_make(map(), list(String.t())) :: {:ok, t()} | {:error, Ecto.Changeset.t()}
-  def get_or_make(attrs, scopes) do
-    with %__MODULE__{} = app <- Repo.get_by(__MODULE__, attrs) do
-      update_scopes(app, scopes)
+  @spec get_or_make(map()) :: {:ok, t()} | {:error, Ecto.Changeset.t()}
+  def get_or_make(attrs) do
+    with %__MODULE__{} = app <- Repo.get_by(__MODULE__, client_name: attrs.client_name) do
+      __MODULE__.update(app.id, Map.take(attrs, [:scopes, :website]))
     else
       _e ->
         %__MODULE__{}
-        |> register_changeset(Map.put(attrs, :scopes, scopes))
+        |> register_changeset(attrs)
         |> Repo.insert()
     end
   end
 
-  defp update_scopes(%__MODULE__{} = app, []), do: {:ok, app}
-  defp update_scopes(%__MODULE__{scopes: scopes} = app, scopes), do: {:ok, app}
-
-  defp update_scopes(%__MODULE__{} = app, scopes) do
-    app
-    |> change(%{scopes: scopes})
-    |> Repo.update()
-  end
-
   @spec search(map()) :: {:ok, [t()], non_neg_integer()}
   def search(params) do
     query = from(a in __MODULE__)
diff --git a/test/pleroma/web/mastodon_api/controllers/app_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/app_controller_test.exs
index 26c431673..df28f2010 100644
--- a/test/pleroma/web/mastodon_api/controllers/app_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/controllers/app_controller_test.exs
@@ -169,4 +169,34 @@ defmodule Pleroma.Web.MastodonAPI.AppControllerTest do
 
     assert List.first(Repo.all(App)).scopes == String.split(updated_scopes, " ")
   end
+
+  test "app website URL can be updated", %{conn: conn} do
+    client_name = "BleromaSE"
+    redirect_uris = "https://bleroma.app/oauth-callback"
+    website = "https://bleromase.com"
+
+    conn
+    |> put_req_header("content-type", "application/json")
+    |> post("/api/v1/apps", %{
+      client_name: client_name,
+      redirect_uris: redirect_uris,
+      website: website
+    })
+    |> json_response_and_validate_schema(200)
+
+    assert List.first(Repo.all(App)).website == website
+
+    updated_website = "https://bleromase2ultimateedition.com"
+
+    conn
+    |> put_req_header("content-type", "application/json")
+    |> post("/api/v1/apps", %{
+      client_name: client_name,
+      redirect_uris: redirect_uris,
+      website: updated_website
+    })
+    |> json_response_and_validate_schema(200)
+
+    assert List.first(Repo.all(App)).website == updated_website
+  end
 end
diff --git a/test/pleroma/web/o_auth/app_test.exs b/test/pleroma/web/o_auth/app_test.exs
index 96a67de6b..423b660ea 100644
--- a/test/pleroma/web/o_auth/app_test.exs
+++ b/test/pleroma/web/o_auth/app_test.exs
@@ -12,20 +12,23 @@ defmodule Pleroma.Web.OAuth.AppTest do
     test "gets exist app" do
       attrs = %{client_name: "Mastodon-Local", redirect_uris: "."}
       app = insert(:oauth_app, Map.merge(attrs, %{scopes: ["read", "write"]}))
-      {:ok, %App{} = exist_app} = App.get_or_make(attrs, [])
+      {:ok, %App{} = exist_app} = App.get_or_make(attrs)
       assert exist_app == app
     end
 
     test "make app" do
-      attrs = %{client_name: "Mastodon-Local", redirect_uris: "."}
-      {:ok, %App{} = app} = App.get_or_make(attrs, ["write"])
+      attrs = %{client_name: "Mastodon-Local", redirect_uris: ".", scopes: ["write"]}
+      {:ok, %App{} = app} = App.get_or_make(attrs)
       assert app.scopes == ["write"]
     end
 
     test "gets exist app and updates scopes" do
-      attrs = %{client_name: "Mastodon-Local", redirect_uris: "."}
-      app = insert(:oauth_app, Map.merge(attrs, %{scopes: ["read", "write"]}))
-      {:ok, %App{} = exist_app} = App.get_or_make(attrs, ["read", "write", "follow", "push"])
+      attrs = %{client_name: "Mastodon-Local", redirect_uris: ".", scopes: ["read", "write"]}
+      app = insert(:oauth_app, attrs)
+
+      {:ok, %App{} = exist_app} =
+        App.get_or_make(%{attrs | scopes: ["read", "write", "follow", "push"]})
+
       assert exist_app.id == app.id
       assert exist_app.scopes == ["read", "write", "follow", "push"]
     end

From 37397a43be7e73efeb1004f59fc9e69bc75da927 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= <git@mkljczk.pl>
Date: Mon, 2 Sep 2024 12:39:29 +0200
Subject: [PATCH 072/212] scrubbers/default: Allow "mention hashtag" classes
 used by Mastodon
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
---
 changelog.d/scrubbers-allow-mention-hashtag.add | 1 +
 priv/scrubbers/default.ex                       | 3 ++-
 priv/scrubbers/twitter_text.ex                  | 3 ++-
 3 files changed, 5 insertions(+), 2 deletions(-)
 create mode 100644 changelog.d/scrubbers-allow-mention-hashtag.add

diff --git a/changelog.d/scrubbers-allow-mention-hashtag.add b/changelog.d/scrubbers-allow-mention-hashtag.add
new file mode 100644
index 000000000..c12ab1ffb
--- /dev/null
+++ b/changelog.d/scrubbers-allow-mention-hashtag.add
@@ -0,0 +1 @@
+scrubbers/default: Allow "mention hashtag" classes used by Mastodon
\ No newline at end of file
diff --git a/priv/scrubbers/default.ex b/priv/scrubbers/default.ex
index a75a6465d..dad9dc1a1 100644
--- a/priv/scrubbers/default.ex
+++ b/priv/scrubbers/default.ex
@@ -22,7 +22,8 @@ defmodule Pleroma.HTML.Scrubber.Default do
     "u-url",
     "mention",
     "u-url mention",
-    "mention u-url"
+    "mention u-url",
+    "mention hashtag"
   ])
 
   Meta.allow_tag_with_this_attribute_values(:a, "rel", [
diff --git a/priv/scrubbers/twitter_text.ex b/priv/scrubbers/twitter_text.ex
index 6e23b3efb..4df840735 100644
--- a/priv/scrubbers/twitter_text.ex
+++ b/priv/scrubbers/twitter_text.ex
@@ -23,7 +23,8 @@ defmodule Pleroma.HTML.Scrubber.TwitterText do
     "u-url",
     "mention",
     "u-url mention",
-    "mention u-url"
+    "mention u-url",
+    "mention hashtag"
   ])
 
   Meta.allow_tag_with_this_attribute_values(:a, "rel", [

From 6d5ae4d2e91f8ea75115c0ffcdd1d94a24c9dc31 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= <git@mkljczk.pl>
Date: Tue, 3 Sep 2024 15:17:45 +0200
Subject: [PATCH 073/212] Include list id in StatusView
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
---
 changelog.d/list-id-visibility.add                  |  1 +
 .../API/differences_in_mastoapi_responses.md        |  1 +
 lib/pleroma/web/api_spec/schemas/status.ex          |  6 ++++++
 lib/pleroma/web/mastodon_api/views/status_view.ex   | 13 ++++++++++++-
 .../web/mastodon_api/views/status_view_test.exs     |  8 +++++++-
 5 files changed, 27 insertions(+), 2 deletions(-)
 create mode 100644 changelog.d/list-id-visibility.add

diff --git a/changelog.d/list-id-visibility.add b/changelog.d/list-id-visibility.add
new file mode 100644
index 000000000..2fea2d771
--- /dev/null
+++ b/changelog.d/list-id-visibility.add
@@ -0,0 +1 @@
+Include list id in StatusView
\ No newline at end of file
diff --git a/docs/development/API/differences_in_mastoapi_responses.md b/docs/development/API/differences_in_mastoapi_responses.md
index 41464e802..3bf8637f8 100644
--- a/docs/development/API/differences_in_mastoapi_responses.md
+++ b/docs/development/API/differences_in_mastoapi_responses.md
@@ -42,6 +42,7 @@ Has these additional fields under the `pleroma` object:
 - `quotes_count`: the count of status quotes.
 - `non_anonymous`: true if the source post specifies the poll results are not anonymous. Currently only implemented by Smithereen.
 - `bookmark_folder`: the ID of the folder bookmark is stored within (if any).
+- `list_id`: the ID of the list the post is addressed to (if any, only returned to author).
 
 The `GET /api/v1/statuses/:id/source` endpoint additionally has the following attributes:
 
diff --git a/lib/pleroma/web/api_spec/schemas/status.ex b/lib/pleroma/web/api_spec/schemas/status.ex
index 6e537b5da..25548d75b 100644
--- a/lib/pleroma/web/api_spec/schemas/status.ex
+++ b/lib/pleroma/web/api_spec/schemas/status.ex
@@ -249,6 +249,12 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Status do
             nullable: true,
             description:
               "A datetime (ISO 8601) that states when the post was pinned or `null` if the post is not pinned"
+          },
+          list_id: %Schema{
+            type: :integer,
+            nullable: true,
+            description:
+              "The ID of the list the post is addressed to (if any, only returned to author)"
           }
         }
       },
diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex
index 1b78477d0..3bf870c24 100644
--- a/lib/pleroma/web/mastodon_api/views/status_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/status_view.ex
@@ -465,7 +465,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
         parent_visible: visible_for_user?(reply_to, opts[:for]),
         pinned_at: pinned_at,
         quotes_count: object.data["quotesCount"] || 0,
-        bookmark_folder: bookmark_folder
+        bookmark_folder: bookmark_folder,
+        list_id: get_list_id(object, client_posted_this_activity)
       }
     }
   end
@@ -835,4 +836,14 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
       nil
     end
   end
+
+  defp get_list_id(object, client_posted_this_activity) do
+    with true <- client_posted_this_activity,
+         %{data: %{"listMessage" => list_ap_id}} when is_binary(list_ap_id) <- object,
+         %{id: list_id} <- Pleroma.List.get_by_ap_id(list_ap_id) do
+      list_id
+    else
+      _ -> nil
+    end
+  end
 end
diff --git a/test/pleroma/web/mastodon_api/views/status_view_test.exs b/test/pleroma/web/mastodon_api/views/status_view_test.exs
index afe0ccb28..bc6dec32a 100644
--- a/test/pleroma/web/mastodon_api/views/status_view_test.exs
+++ b/test/pleroma/web/mastodon_api/views/status_view_test.exs
@@ -342,7 +342,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
         parent_visible: false,
         pinned_at: nil,
         quotes_count: 0,
-        bookmark_folder: nil
+        bookmark_folder: nil,
+        list_id: nil
       }
     }
 
@@ -912,6 +913,11 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
     status = StatusView.render("show.json", activity: activity)
 
     assert status.visibility == "list"
+    assert status.pleroma.list_id == nil
+
+    status = StatusView.render("show.json", activity: activity, for: user)
+
+    assert status.pleroma.list_id == list.id
   end
 
   test "has a field for parent visibility" do

From 92d5f0ac141e679af048ebcbec9cb91df68fd929 Mon Sep 17 00:00:00 2001
From: feld <feld@feld.me>
Date: Wed, 4 Sep 2024 02:22:25 +0000
Subject: [PATCH 074/212] Revert "Merge branch 'oauth-app-spam' into 'develop'"

This reverts merge request !4244
---
 changelog.d/oauth-app.fix                     |   1 -
 .../controllers/app_controller.ex             |   3 +-
 lib/pleroma/web/o_auth/app.ex                 |  24 ++--
 .../controllers/app_controller_test.exs       | 110 ------------------
 test/pleroma/web/o_auth/app_test.exs          |  15 +--
 5 files changed, 24 insertions(+), 129 deletions(-)
 delete mode 100644 changelog.d/oauth-app.fix

diff --git a/changelog.d/oauth-app.fix b/changelog.d/oauth-app.fix
deleted file mode 100644
index eb917462f..000000000
--- a/changelog.d/oauth-app.fix
+++ /dev/null
@@ -1 +0,0 @@
-Prevent OAuth App flow from creating duplicate entries
diff --git a/lib/pleroma/web/mastodon_api/controllers/app_controller.ex b/lib/pleroma/web/mastodon_api/controllers/app_controller.ex
index 4677ac40a..844673ae0 100644
--- a/lib/pleroma/web/mastodon_api/controllers/app_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/app_controller.ex
@@ -36,7 +36,8 @@ defmodule Pleroma.Web.MastodonAPI.AppController do
       |> Map.put(:scopes, scopes)
       |> Maps.put_if_present(:user_id, user_id)
 
-    with {:ok, app} <- App.get_or_make(app_attrs) do
+    with cs <- App.register_changeset(%App{}, app_attrs),
+         {:ok, app} <- Repo.insert(cs) do
       render(conn, "show.json", app: app)
     end
   end
diff --git a/lib/pleroma/web/o_auth/app.ex b/lib/pleroma/web/o_auth/app.ex
index 889850c73..d1bf6dd18 100644
--- a/lib/pleroma/web/o_auth/app.ex
+++ b/lib/pleroma/web/o_auth/app.ex
@@ -67,27 +67,35 @@ defmodule Pleroma.Web.OAuth.App do
     with %__MODULE__{} = app <- Repo.get(__MODULE__, id) do
       app
       |> changeset(params)
-      |> validate_required([:scopes])
       |> Repo.update()
     end
   end
 
   @doc """
-  Gets app by attrs or create new with attrs.
-  Updates the attrs if needed.
+  Gets app by attrs or create new  with attrs.
+  And updates the scopes if need.
   """
-  @spec get_or_make(map()) :: {:ok, t()} | {:error, Ecto.Changeset.t()}
-  def get_or_make(attrs) do
-    with %__MODULE__{} = app <- Repo.get_by(__MODULE__, client_name: attrs.client_name) do
-      __MODULE__.update(app.id, Map.take(attrs, [:scopes, :website]))
+  @spec get_or_make(map(), list(String.t())) :: {:ok, t()} | {:error, Ecto.Changeset.t()}
+  def get_or_make(attrs, scopes) do
+    with %__MODULE__{} = app <- Repo.get_by(__MODULE__, attrs) do
+      update_scopes(app, scopes)
     else
       _e ->
         %__MODULE__{}
-        |> register_changeset(attrs)
+        |> register_changeset(Map.put(attrs, :scopes, scopes))
         |> Repo.insert()
     end
   end
 
+  defp update_scopes(%__MODULE__{} = app, []), do: {:ok, app}
+  defp update_scopes(%__MODULE__{scopes: scopes} = app, scopes), do: {:ok, app}
+
+  defp update_scopes(%__MODULE__{} = app, scopes) do
+    app
+    |> change(%{scopes: scopes})
+    |> Repo.update()
+  end
+
   @spec search(map()) :: {:ok, [t()], non_neg_integer()}
   def search(params) do
     query = from(a in __MODULE__)
diff --git a/test/pleroma/web/mastodon_api/controllers/app_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/app_controller_test.exs
index df28f2010..bc9d4048c 100644
--- a/test/pleroma/web/mastodon_api/controllers/app_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/controllers/app_controller_test.exs
@@ -89,114 +89,4 @@ defmodule Pleroma.Web.MastodonAPI.AppControllerTest do
     assert expected == json_response_and_validate_schema(conn, 200)
     assert app.user_id == user.id
   end
-
-  test "creates an oauth app without a user", %{conn: conn} do
-    app_attrs = build(:oauth_app)
-
-    conn =
-      conn
-      |> put_req_header("content-type", "application/json")
-      |> post("/api/v1/apps", %{
-        client_name: app_attrs.client_name,
-        redirect_uris: app_attrs.redirect_uris
-      })
-
-    [app] = Repo.all(App)
-
-    expected = %{
-      "name" => app.client_name,
-      "website" => app.website,
-      "client_id" => app.client_id,
-      "client_secret" => app.client_secret,
-      "id" => app.id |> to_string(),
-      "redirect_uri" => app.redirect_uris,
-      "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
-    }
-
-    assert expected == json_response_and_validate_schema(conn, 200)
-  end
-
-  test "does not duplicate apps with the same client name", %{conn: conn} do
-    client_name = "BleromaSE"
-    redirect_uris = "https://bleroma.app/oauth-callback"
-
-    for _i <- 1..3 do
-      conn
-      |> put_req_header("content-type", "application/json")
-      |> post("/api/v1/apps", %{
-        client_name: client_name,
-        redirect_uris: redirect_uris
-      })
-      |> json_response_and_validate_schema(200)
-    end
-
-    apps = Repo.all(App)
-
-    assert length(apps) == 1
-    assert List.first(apps).client_name == client_name
-    assert List.first(apps).redirect_uris == redirect_uris
-  end
-
-  test "app scopes can be updated", %{conn: conn} do
-    client_name = "BleromaSE"
-    redirect_uris = "https://bleroma.app/oauth-callback"
-    website = "https://bleromase.com"
-    scopes = "read write"
-
-    conn
-    |> put_req_header("content-type", "application/json")
-    |> post("/api/v1/apps", %{
-      client_name: client_name,
-      redirect_uris: redirect_uris,
-      website: website,
-      scopes: scopes
-    })
-    |> json_response_and_validate_schema(200)
-
-    assert List.first(Repo.all(App)).scopes == String.split(scopes, " ")
-
-    updated_scopes = "read write push"
-
-    conn
-    |> put_req_header("content-type", "application/json")
-    |> post("/api/v1/apps", %{
-      client_name: client_name,
-      redirect_uris: redirect_uris,
-      website: website,
-      scopes: updated_scopes
-    })
-    |> json_response_and_validate_schema(200)
-
-    assert List.first(Repo.all(App)).scopes == String.split(updated_scopes, " ")
-  end
-
-  test "app website URL can be updated", %{conn: conn} do
-    client_name = "BleromaSE"
-    redirect_uris = "https://bleroma.app/oauth-callback"
-    website = "https://bleromase.com"
-
-    conn
-    |> put_req_header("content-type", "application/json")
-    |> post("/api/v1/apps", %{
-      client_name: client_name,
-      redirect_uris: redirect_uris,
-      website: website
-    })
-    |> json_response_and_validate_schema(200)
-
-    assert List.first(Repo.all(App)).website == website
-
-    updated_website = "https://bleromase2ultimateedition.com"
-
-    conn
-    |> put_req_header("content-type", "application/json")
-    |> post("/api/v1/apps", %{
-      client_name: client_name,
-      redirect_uris: redirect_uris,
-      website: updated_website
-    })
-    |> json_response_and_validate_schema(200)
-
-    assert List.first(Repo.all(App)).website == updated_website
-  end
 end
diff --git a/test/pleroma/web/o_auth/app_test.exs b/test/pleroma/web/o_auth/app_test.exs
index 423b660ea..96a67de6b 100644
--- a/test/pleroma/web/o_auth/app_test.exs
+++ b/test/pleroma/web/o_auth/app_test.exs
@@ -12,23 +12,20 @@ defmodule Pleroma.Web.OAuth.AppTest do
     test "gets exist app" do
       attrs = %{client_name: "Mastodon-Local", redirect_uris: "."}
       app = insert(:oauth_app, Map.merge(attrs, %{scopes: ["read", "write"]}))
-      {:ok, %App{} = exist_app} = App.get_or_make(attrs)
+      {:ok, %App{} = exist_app} = App.get_or_make(attrs, [])
       assert exist_app == app
     end
 
     test "make app" do
-      attrs = %{client_name: "Mastodon-Local", redirect_uris: ".", scopes: ["write"]}
-      {:ok, %App{} = app} = App.get_or_make(attrs)
+      attrs = %{client_name: "Mastodon-Local", redirect_uris: "."}
+      {:ok, %App{} = app} = App.get_or_make(attrs, ["write"])
       assert app.scopes == ["write"]
     end
 
     test "gets exist app and updates scopes" do
-      attrs = %{client_name: "Mastodon-Local", redirect_uris: ".", scopes: ["read", "write"]}
-      app = insert(:oauth_app, attrs)
-
-      {:ok, %App{} = exist_app} =
-        App.get_or_make(%{attrs | scopes: ["read", "write", "follow", "push"]})
-
+      attrs = %{client_name: "Mastodon-Local", redirect_uris: "."}
+      app = insert(:oauth_app, Map.merge(attrs, %{scopes: ["read", "write"]}))
+      {:ok, %App{} = exist_app} = App.get_or_make(attrs, ["read", "write", "follow", "push"])
       assert exist_app.id == app.id
       assert exist_app.scopes == ["read", "write", "follow", "push"]
     end

From 427da7a99a30ebc7a7deb54e7704b5d8dffea199 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Wed, 4 Sep 2024 09:19:07 -0400
Subject: [PATCH 075/212] Rate Limit the OAuth App spam

---
 changelog.d/oauth-app-spam.fix                             | 1 +
 config/config.exs                                          | 1 +
 lib/pleroma/web/mastodon_api/controllers/app_controller.ex | 2 ++
 3 files changed, 4 insertions(+)
 create mode 100644 changelog.d/oauth-app-spam.fix

diff --git a/changelog.d/oauth-app-spam.fix b/changelog.d/oauth-app-spam.fix
new file mode 100644
index 000000000..0e95c01d7
--- /dev/null
+++ b/changelog.d/oauth-app-spam.fix
@@ -0,0 +1 @@
+Add a rate limiter to the OAuth App creation endpoint
diff --git a/config/config.exs b/config/config.exs
index ad6b1cb94..a4fedff45 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -711,6 +711,7 @@ config :pleroma, :rate_limit,
   timeline: {500, 3},
   search: [{1000, 10}, {1000, 30}],
   app_account_creation: {1_800_000, 25},
+  oauth_app_creation: {900_000, 5},
   relations_actions: {10_000, 10},
   relation_id_action: {60_000, 2},
   statuses_actions: {10_000, 15},
diff --git a/lib/pleroma/web/mastodon_api/controllers/app_controller.ex b/lib/pleroma/web/mastodon_api/controllers/app_controller.ex
index 844673ae0..6cfeb712e 100644
--- a/lib/pleroma/web/mastodon_api/controllers/app_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/app_controller.ex
@@ -19,6 +19,8 @@ defmodule Pleroma.Web.MastodonAPI.AppController do
 
   action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
 
+  plug(Pleroma.Web.Plugs.RateLimiter, [name: :oauth_app_creation] when action == :create)
+
   plug(:skip_auth when action in [:create, :verify_credentials])
 
   plug(Pleroma.Web.ApiSpec.CastAndValidate)

From 7bd0750787859cb30382d90162d70380441abc05 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Wed, 4 Sep 2024 10:40:37 -0400
Subject: [PATCH 076/212] Ensure apps are assigned to users

---
 changelog.d/oauth-app-spam.fix                |  2 +-
 lib/pleroma/web/o_auth/app.ex                 | 10 +++++++++
 lib/pleroma/web/o_auth/o_auth_controller.ex   |  2 ++
 .../20240904142434_assign_app_user.exs        | 21 +++++++++++++++++++
 .../web/o_auth/o_auth_controller_test.exs     |  8 +++++++
 5 files changed, 42 insertions(+), 1 deletion(-)
 create mode 100644 priv/repo/migrations/20240904142434_assign_app_user.exs

diff --git a/changelog.d/oauth-app-spam.fix b/changelog.d/oauth-app-spam.fix
index 0e95c01d7..cdc2e816d 100644
--- a/changelog.d/oauth-app-spam.fix
+++ b/changelog.d/oauth-app-spam.fix
@@ -1 +1 @@
-Add a rate limiter to the OAuth App creation endpoint
+Add a rate limiter to the OAuth App creation endpoint and ensure registered apps are assigned to users.
diff --git a/lib/pleroma/web/o_auth/app.ex b/lib/pleroma/web/o_auth/app.ex
index d1bf6dd18..f0f54bb46 100644
--- a/lib/pleroma/web/o_auth/app.ex
+++ b/lib/pleroma/web/o_auth/app.ex
@@ -8,6 +8,7 @@ defmodule Pleroma.Web.OAuth.App do
   import Ecto.Query
   alias Pleroma.Repo
   alias Pleroma.User
+  alias Pleroma.Web.OAuth.Token
 
   @type t :: %__MODULE__{}
 
@@ -155,4 +156,13 @@ defmodule Pleroma.Web.OAuth.App do
         Map.put(acc, key, error)
     end)
   end
+
+  @spec maybe_update_owner(Token.t()) :: :ok
+  def maybe_update_owner(%Token{app_id: app_id, user_id: user_id}) when not is_nil(user_id) do
+    __MODULE__.update(app_id, %{user_id: user_id})
+
+    :ok
+  end
+
+  def maybe_update_owner(_), do: :ok
 end
diff --git a/lib/pleroma/web/o_auth/o_auth_controller.ex b/lib/pleroma/web/o_auth/o_auth_controller.ex
index 47b03215f..0b3de5481 100644
--- a/lib/pleroma/web/o_auth/o_auth_controller.ex
+++ b/lib/pleroma/web/o_auth/o_auth_controller.ex
@@ -318,6 +318,8 @@ defmodule Pleroma.Web.OAuth.OAuthController do
   def token_exchange(%Plug.Conn{} = conn, params), do: bad_request(conn, params)
 
   def after_token_exchange(%Plug.Conn{} = conn, %{token: token} = view_params) do
+    App.maybe_update_owner(token)
+
     conn
     |> AuthHelper.put_session_token(token.token)
     |> json(OAuthView.render("token.json", view_params))
diff --git a/priv/repo/migrations/20240904142434_assign_app_user.exs b/priv/repo/migrations/20240904142434_assign_app_user.exs
new file mode 100644
index 000000000..11bec529b
--- /dev/null
+++ b/priv/repo/migrations/20240904142434_assign_app_user.exs
@@ -0,0 +1,21 @@
+defmodule Pleroma.Repo.Migrations.AssignAppUser do
+  use Ecto.Migration
+
+  alias Pleroma.Repo
+  alias Pleroma.Web.OAuth.App
+  alias Pleroma.Web.OAuth.Token
+
+  def up do
+    Repo.all(Token)
+    |> Enum.group_by(fn x -> Map.get(x, :app_id) end)
+    |> Enum.each(fn {_app_id, tokens} ->
+      token =
+        Enum.filter(tokens, fn x -> not is_nil(x.user_id) end)
+        |> List.first()
+
+      App.maybe_update_owner(token)
+    end)
+  end
+
+  def down, do: :ok
+end
diff --git a/test/pleroma/web/o_auth/o_auth_controller_test.exs b/test/pleroma/web/o_auth/o_auth_controller_test.exs
index 83a08d9fc..260442771 100644
--- a/test/pleroma/web/o_auth/o_auth_controller_test.exs
+++ b/test/pleroma/web/o_auth/o_auth_controller_test.exs
@@ -12,6 +12,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
   alias Pleroma.MFA.TOTP
   alias Pleroma.Repo
   alias Pleroma.User
+  alias Pleroma.Web.OAuth.App
   alias Pleroma.Web.OAuth.Authorization
   alias Pleroma.Web.OAuth.OAuthController
   alias Pleroma.Web.OAuth.Token
@@ -770,6 +771,9 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
 
       {:ok, auth} = Authorization.create_authorization(app, user, ["write"])
 
+      # Verify app has no associated user yet
+      assert %Pleroma.Web.OAuth.App{user_id: nil} = Repo.get_by(App, %{id: app.id})
+
       conn =
         build_conn()
         |> post("/oauth/token", %{
@@ -786,6 +790,10 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
       assert token
       assert token.scopes == auth.scopes
       assert user.ap_id == ap_id
+
+      # Verify app has an associated user now
+      user_id = user.id
+      assert %Pleroma.Web.OAuth.App{user_id: ^user_id} = Repo.get_by(App, %{id: app.id})
     end
 
     test "issues a token for `password` grant_type with valid credentials, with full permissions by default" do

From a1951f3af7e1d5c4d53819962c3e68df5ba4475b Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Wed, 4 Sep 2024 10:59:58 -0400
Subject: [PATCH 077/212] Add Cron worker to clean up orphaned apps hourly

---
 config/config.exs                             |  3 ++-
 lib/pleroma/web/o_auth/app.ex                 |  6 ++++++
 .../workers/cron/app_cleanup_worker.ex        | 21 +++++++++++++++++++
 test/pleroma/web/o_auth/app_test.exs          | 12 +++++++++++
 4 files changed, 41 insertions(+), 1 deletion(-)
 create mode 100644 lib/pleroma/workers/cron/app_cleanup_worker.ex

diff --git a/config/config.exs b/config/config.exs
index a4fedff45..2bc28b256 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -597,7 +597,8 @@ config :pleroma, Oban,
   plugins: [{Oban.Plugins.Pruner, max_age: 900}],
   crontab: [
     {"0 0 * * 0", Pleroma.Workers.Cron.DigestEmailsWorker},
-    {"0 0 * * *", Pleroma.Workers.Cron.NewUsersDigestWorker}
+    {"0 0 * * *", Pleroma.Workers.Cron.NewUsersDigestWorker},
+    {"0 0 * * *", Pleroma.Workers.Cron.AppCleanupWorker}
   ]
 
 config :pleroma, Pleroma.Formatter,
diff --git a/lib/pleroma/web/o_auth/app.ex b/lib/pleroma/web/o_auth/app.ex
index f0f54bb46..6ae419d09 100644
--- a/lib/pleroma/web/o_auth/app.ex
+++ b/lib/pleroma/web/o_auth/app.ex
@@ -165,4 +165,10 @@ defmodule Pleroma.Web.OAuth.App do
   end
 
   def maybe_update_owner(_), do: :ok
+
+  @spec remove_orphans() :: :ok
+  def remove_orphans() do
+    from(a in __MODULE__, where: is_nil(a.user_id))
+    |> Repo.delete_all()
+  end
 end
diff --git a/lib/pleroma/workers/cron/app_cleanup_worker.ex b/lib/pleroma/workers/cron/app_cleanup_worker.ex
new file mode 100644
index 000000000..ee71cd7b6
--- /dev/null
+++ b/lib/pleroma/workers/cron/app_cleanup_worker.ex
@@ -0,0 +1,21 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Workers.Cron.AppCleanupWorker do
+  @moduledoc """
+  Cleans up registered apps that were never associated with a user.
+  """
+
+  use Oban.Worker, queue: "background"
+
+  alias Pleroma.Web.OAuth.App
+
+  @impl true
+  def perform(_job) do
+    App.remove_orphans()
+  end
+
+  @impl true
+  def timeout(_job), do: :timer.seconds(30)
+end
diff --git a/test/pleroma/web/o_auth/app_test.exs b/test/pleroma/web/o_auth/app_test.exs
index 96a67de6b..725ea3eb8 100644
--- a/test/pleroma/web/o_auth/app_test.exs
+++ b/test/pleroma/web/o_auth/app_test.exs
@@ -53,4 +53,16 @@ defmodule Pleroma.Web.OAuth.AppTest do
 
     assert Enum.sort(App.get_user_apps(user)) == Enum.sort(apps)
   end
+
+  test "removes orphaned apps" do
+    attrs = %{client_name: "Mastodon-Local", redirect_uris: "."}
+    {:ok, %App{} = app} = App.get_or_make(attrs, ["write"])
+    assert app.scopes == ["write"]
+
+    assert app == Pleroma.Repo.get_by(App, %{id: app.id})
+
+    App.remove_orphans()
+
+    assert nil == Pleroma.Repo.get_by(App, %{id: app.id})
+  end
 end

From 53744bf146f157ee1ecfc9ba4de9e5d65fa80784 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Wed, 4 Sep 2024 11:43:43 -0400
Subject: [PATCH 078/212] Limit the number of orphaned to delete at 100 every
 10 mins due to the cascading queries that have to check oauth_authorizations
 and oauth_tokens tables.

This should keep ahead of most app registration spam and not overwhelm lower powered servers.
---
 config/config.exs             |  2 +-
 lib/pleroma/web/o_auth/app.ex | 13 +++++++++----
 2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/config/config.exs b/config/config.exs
index 2bc28b256..80a3b8d57 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -598,7 +598,7 @@ config :pleroma, Oban,
   crontab: [
     {"0 0 * * 0", Pleroma.Workers.Cron.DigestEmailsWorker},
     {"0 0 * * *", Pleroma.Workers.Cron.NewUsersDigestWorker},
-    {"0 0 * * *", Pleroma.Workers.Cron.AppCleanupWorker}
+    {"*/10 * * * *", Pleroma.Workers.Cron.AppCleanupWorker}
   ]
 
 config :pleroma, Pleroma.Formatter,
diff --git a/lib/pleroma/web/o_auth/app.ex b/lib/pleroma/web/o_auth/app.ex
index 6ae419d09..032011433 100644
--- a/lib/pleroma/web/o_auth/app.ex
+++ b/lib/pleroma/web/o_auth/app.ex
@@ -166,9 +166,14 @@ defmodule Pleroma.Web.OAuth.App do
 
   def maybe_update_owner(_), do: :ok
 
-  @spec remove_orphans() :: :ok
-  def remove_orphans() do
-    from(a in __MODULE__, where: is_nil(a.user_id))
-    |> Repo.delete_all()
+  @spec remove_orphans(pos_integer()) :: :ok
+  def remove_orphans(limit \\ 100) do
+    Repo.transaction(fn ->
+      from(a in __MODULE__, where: is_nil(a.user_id), limit: ^limit)
+      |> Repo.all()
+      |> Enum.each(&Repo.delete(&1))
+    end)
+
+    :ok
   end
 end

From fb376ce0056cf977d3673c99bca4e77c564b4c47 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Thu, 5 Sep 2024 15:27:43 -0400
Subject: [PATCH 079/212] Test Account View does not indicate following if a
 FollowingRelationship is missing

---
 .../mastodon_api/views/account_view_test.exs  | 38 +++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/test/pleroma/web/mastodon_api/views/account_view_test.exs b/test/pleroma/web/mastodon_api/views/account_view_test.exs
index dca64853d..5d2f55c6d 100644
--- a/test/pleroma/web/mastodon_api/views/account_view_test.exs
+++ b/test/pleroma/web/mastodon_api/views/account_view_test.exs
@@ -456,6 +456,44 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
       test_relationship_rendering(user, other_user, expected)
     end
 
+    test "relationship does not indicate following if a FollowingRelationship is missing" do
+      user = insert(:user)
+      other_user = insert(:user, local: false)
+
+      # Create a follow relationship with the real Follow Activity and Accept it
+      assert {:ok, _, _, _} = CommonAPI.follow(other_user, user)
+      assert {:ok, _} = CommonAPI.accept_follow_request(user, other_user)
+
+      assert %{data: %{"state" => "accept"}} =
+               Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(user, other_user)
+
+      # Fetch the relationship and forcibly delete it to simulate a Follow Accept that did not complete processing
+      %{following_relationships: [relationship]} =
+        Pleroma.UserRelationship.view_relationships_option(user, [other_user])
+
+      assert {:ok, _} = Pleroma.Repo.delete(relationship)
+
+      assert %{following_relationships: [], user_relationships: []} ==
+               Pleroma.UserRelationship.view_relationships_option(user, [other_user])
+
+      expected =
+        Map.merge(
+          @blank_response,
+          %{
+            following: false,
+            followed_by: false,
+            muting: false,
+            muting_notifications: false,
+            subscribing: false,
+            notifying: false,
+            showing_reblogs: true,
+            id: to_string(other_user.id)
+          }
+        )
+
+      test_relationship_rendering(user, other_user, expected)
+    end
+
     test "represent a relationship for the blocking and blocked user" do
       user = insert(:user)
       other_user = insert(:user)

From 4d76692db36d6779fddacee3a7690739064eae0c Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Thu, 5 Sep 2024 11:43:48 -0400
Subject: [PATCH 080/212] Fix Following status bug

---
 changelog.d/following-state.fix               |  1 +
 .../web/mastodon_api/views/account_view.ex    | 19 +++++++++----------
 2 files changed, 10 insertions(+), 10 deletions(-)
 create mode 100644 changelog.d/following-state.fix

diff --git a/changelog.d/following-state.fix b/changelog.d/following-state.fix
new file mode 100644
index 000000000..314ea6210
--- /dev/null
+++ b/changelog.d/following-state.fix
@@ -0,0 +1 @@
+Resolved edge case where the API can report you are following a user but the relationship is not fully established.
diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex
index 6976ca6e5..298c73986 100644
--- a/lib/pleroma/web/mastodon_api/views/account_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/account_view.ex
@@ -92,14 +92,13 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
         User.get_follow_state(reading_user, target)
       end
 
-    followed_by =
-      if following_relationships do
-        case FollowingRelationship.find(following_relationships, target, reading_user) do
-          %{state: :follow_accept} -> true
-          _ -> false
-        end
-      else
-        User.following?(target, reading_user)
+    followed_by = FollowingRelationship.following?(target, reading_user)
+    following = FollowingRelationship.following?(reading_user, target)
+
+    requested =
+      cond do
+        following -> false
+        true -> match?(:follow_pending, follow_state)
       end
 
     subscribing =
@@ -114,7 +113,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
     # NOTE: adjust UserRelationship.view_relationships_option/2 on new relation-related flags
     %{
       id: to_string(target.id),
-      following: follow_state == :follow_accept,
+      following: following,
       followed_by: followed_by,
       blocking:
         UserRelationship.exists?(
@@ -150,7 +149,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
         ),
       subscribing: subscribing,
       notifying: subscribing,
-      requested: follow_state == :follow_pending,
+      requested: requested,
       domain_blocking: User.blocks_domain?(reading_user, target),
       showing_reblogs:
         not UserRelationship.exists?(

From 1797f5958a92f78dc79c5bf313755b16319c5d2d Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Thu, 5 Sep 2024 20:55:28 +0000
Subject: [PATCH 081/212] App orphans should only be removed if they are older
 than 15 mins

---
 lib/pleroma/web/o_auth/app.ex        |  7 ++++++-
 test/pleroma/web/o_auth/app_test.exs | 13 +++++++++----
 2 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/lib/pleroma/web/o_auth/app.ex b/lib/pleroma/web/o_auth/app.ex
index 032011433..7661c2566 100644
--- a/lib/pleroma/web/o_auth/app.ex
+++ b/lib/pleroma/web/o_auth/app.ex
@@ -168,8 +168,13 @@ defmodule Pleroma.Web.OAuth.App do
 
   @spec remove_orphans(pos_integer()) :: :ok
   def remove_orphans(limit \\ 100) do
+    fifteen_mins_ago = DateTime.add(DateTime.utc_now(), -900, :second)
+
     Repo.transaction(fn ->
-      from(a in __MODULE__, where: is_nil(a.user_id), limit: ^limit)
+      from(a in __MODULE__,
+        where: is_nil(a.user_id) and a.inserted_at < ^fifteen_mins_ago,
+        limit: ^limit
+      )
       |> Repo.all()
       |> Enum.each(&Repo.delete(&1))
     end)
diff --git a/test/pleroma/web/o_auth/app_test.exs b/test/pleroma/web/o_auth/app_test.exs
index 725ea3eb8..44219cf90 100644
--- a/test/pleroma/web/o_auth/app_test.exs
+++ b/test/pleroma/web/o_auth/app_test.exs
@@ -56,13 +56,18 @@ defmodule Pleroma.Web.OAuth.AppTest do
 
   test "removes orphaned apps" do
     attrs = %{client_name: "Mastodon-Local", redirect_uris: "."}
-    {:ok, %App{} = app} = App.get_or_make(attrs, ["write"])
-    assert app.scopes == ["write"]
+    {:ok, %App{} = old_app} = App.get_or_make(attrs, ["write"])
 
-    assert app == Pleroma.Repo.get_by(App, %{id: app.id})
+    attrs = %{client_name: "PleromaFE", redirect_uris: "."}
+    {:ok, %App{} = app} = App.get_or_make(attrs, ["write"])
+
+    # backdate the old app so it's within the threshold for being cleaned up
+    {:ok, _} =
+      "UPDATE apps SET inserted_at = now() - interval '1 hour' WHERE id = #{old_app.id}"
+      |> Pleroma.Repo.query()
 
     App.remove_orphans()
 
-    assert nil == Pleroma.Repo.get_by(App, %{id: app.id})
+    assert [app] == Pleroma.Repo.all(App)
   end
 end

From e51cd31a576715d8e7d991e4fce850edcf4c8a1e Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Thu, 5 Sep 2024 17:06:53 -0400
Subject: [PATCH 082/212] Bump credo to prevent it from crashing

---
 mix.lock | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mix.lock b/mix.lock
index 07c1122aa..865e09a4c 100644
--- a/mix.lock
+++ b/mix.lock
@@ -22,7 +22,7 @@
   "cowboy": {:hex, :cowboy, "2.12.0", "f276d521a1ff88b2b9b4c54d0e753da6c66dd7be6c9fca3d9418b561828a3731", [:make, :rebar3], [{:cowlib, "2.13.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "8a7abe6d183372ceb21caa2709bec928ab2b72e18a3911aa1771639bef82651e"},
   "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"},
   "cowlib": {:hex, :cowlib, "2.13.0", "db8f7505d8332d98ef50a3ef34b34c1afddec7506e4ee4dd4a3a266285d282ca", [:make, :rebar3], [], "hexpm", "e1e1284dc3fc030a64b1ad0d8382ae7e99da46c3246b815318a4b848873800a4"},
-  "credo": {:hex, :credo, "1.7.3", "05bb11eaf2f2b8db370ecaa6a6bda2ec49b2acd5e0418bc106b73b07128c0436", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "35ea675a094c934c22fb1dca3696f3c31f2728ae6ef5a53b5d648c11180a4535"},
+  "credo": {:hex, :credo, "1.7.7", "771445037228f763f9b2afd612b6aa2fd8e28432a95dbbc60d8e03ce71ba4446", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "8bc87496c9aaacdc3f90f01b7b0582467b69b4bd2441fe8aae3109d843cc2f2e"},
   "crontab": {:hex, :crontab, "1.1.8", "2ce0e74777dfcadb28a1debbea707e58b879e6aa0ffbf9c9bb540887bce43617", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"},
   "custom_base": {:hex, :custom_base, "0.2.1", "4a832a42ea0552299d81652aa0b1f775d462175293e99dfbe4d7dbaab785a706", [:mix], [], "hexpm", "8df019facc5ec9603e94f7270f1ac73ddf339f56ade76a721eaa57c1493ba463"},
   "db_connection": {:hex, :db_connection, "2.7.0", "b99faa9291bb09892c7da373bb82cba59aefa9b36300f6145c5f201c7adf48ec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dcf08f31b2701f857dfc787fbad78223d61a32204f217f15e881dd93e4bdd3ff"},

From 5f573b4095ade584a590b756c83f13f89336cd04 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Thu, 5 Sep 2024 17:11:02 -0400
Subject: [PATCH 083/212] Credo: comment line length

---
 test/pleroma/web/mastodon_api/views/account_view_test.exs | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/test/pleroma/web/mastodon_api/views/account_view_test.exs b/test/pleroma/web/mastodon_api/views/account_view_test.exs
index 5d2f55c6d..f88b90955 100644
--- a/test/pleroma/web/mastodon_api/views/account_view_test.exs
+++ b/test/pleroma/web/mastodon_api/views/account_view_test.exs
@@ -467,7 +467,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
       assert %{data: %{"state" => "accept"}} =
                Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(user, other_user)
 
-      # Fetch the relationship and forcibly delete it to simulate a Follow Accept that did not complete processing
+      # Fetch the relationship and forcibly delete it to simulate
+      # a Follow Accept that did not complete processing
       %{following_relationships: [relationship]} =
         Pleroma.UserRelationship.view_relationships_option(user, [other_user])
 

From a887188890a6b8c9e97c6cafe1776bb151e63843 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Fri, 6 Sep 2024 09:42:53 -0400
Subject: [PATCH 084/212] Oban: more unique job constraints

---
 changelog.d/oban-uniques.change              | 1 +
 lib/pleroma/workers/receiver_worker.ex       | 2 +-
 lib/pleroma/workers/remote_fetcher_worker.ex | 2 +-
 lib/pleroma/workers/rich_media_worker.ex     | 2 +-
 lib/pleroma/workers/user_refresh_worker.ex   | 2 +-
 lib/pleroma/workers/web_pusher_worker.ex     | 2 +-
 6 files changed, 6 insertions(+), 5 deletions(-)
 create mode 100644 changelog.d/oban-uniques.change

diff --git a/changelog.d/oban-uniques.change b/changelog.d/oban-uniques.change
new file mode 100644
index 000000000..d9deb4696
--- /dev/null
+++ b/changelog.d/oban-uniques.change
@@ -0,0 +1 @@
+Adjust more Oban workers to enforce unique job constraints.
diff --git a/lib/pleroma/workers/receiver_worker.ex b/lib/pleroma/workers/receiver_worker.ex
index 0373ec15f..11b672bef 100644
--- a/lib/pleroma/workers/receiver_worker.ex
+++ b/lib/pleroma/workers/receiver_worker.ex
@@ -7,7 +7,7 @@ defmodule Pleroma.Workers.ReceiverWorker do
   alias Pleroma.User
   alias Pleroma.Web.Federator
 
-  use Oban.Worker, queue: :federator_incoming, max_attempts: 5
+  use Oban.Worker, queue: :federator_incoming, max_attempts: 5, unique: [period: :infinity]
 
   @impl true
 
diff --git a/lib/pleroma/workers/remote_fetcher_worker.ex b/lib/pleroma/workers/remote_fetcher_worker.ex
index 9d3f1ec53..aa09362f5 100644
--- a/lib/pleroma/workers/remote_fetcher_worker.ex
+++ b/lib/pleroma/workers/remote_fetcher_worker.ex
@@ -5,7 +5,7 @@
 defmodule Pleroma.Workers.RemoteFetcherWorker do
   alias Pleroma.Object.Fetcher
 
-  use Oban.Worker, queue: :background
+  use Oban.Worker, queue: :background, unique: [period: :infinity]
 
   @impl true
   def perform(%Job{args: %{"op" => "fetch_remote", "id" => id} = args}) do
diff --git a/lib/pleroma/workers/rich_media_worker.ex b/lib/pleroma/workers/rich_media_worker.ex
index d5ba7b63e..e351ecd6e 100644
--- a/lib/pleroma/workers/rich_media_worker.ex
+++ b/lib/pleroma/workers/rich_media_worker.ex
@@ -7,7 +7,7 @@ defmodule Pleroma.Workers.RichMediaWorker do
   alias Pleroma.Web.RichMedia.Backfill
   alias Pleroma.Web.RichMedia.Card
 
-  use Oban.Worker, queue: :background, max_attempts: 3, unique: [period: 300]
+  use Oban.Worker, queue: :background, max_attempts: 3, unique: [period: :infinity]
 
   @impl true
   def perform(%Job{args: %{"op" => "expire", "url" => url} = _args}) do
diff --git a/lib/pleroma/workers/user_refresh_worker.ex b/lib/pleroma/workers/user_refresh_worker.ex
index 222a4a8f7..ee276774b 100644
--- a/lib/pleroma/workers/user_refresh_worker.ex
+++ b/lib/pleroma/workers/user_refresh_worker.ex
@@ -3,7 +3,7 @@
 # SPDX-License-Identifier: AGPL-3.0-only
 
 defmodule Pleroma.Workers.UserRefreshWorker do
-  use Oban.Worker, queue: :background, max_attempts: 1, unique: [period: 300]
+  use Oban.Worker, queue: :background, max_attempts: 1, unique: [period: :infinity]
 
   alias Pleroma.User
 
diff --git a/lib/pleroma/workers/web_pusher_worker.ex b/lib/pleroma/workers/web_pusher_worker.ex
index f4232d02a..879b26cc3 100644
--- a/lib/pleroma/workers/web_pusher_worker.ex
+++ b/lib/pleroma/workers/web_pusher_worker.ex
@@ -7,7 +7,7 @@ defmodule Pleroma.Workers.WebPusherWorker do
   alias Pleroma.Repo
   alias Pleroma.Web.Push.Impl
 
-  use Oban.Worker, queue: :web_push
+  use Oban.Worker, queue: :web_push, unique: [period: :infinity]
 
   @impl true
   def perform(%Job{args: %{"op" => "web_push", "notification_id" => notification_id}}) do

From fc3ea94a1c17e84033fa593c0ea987fbfa545447 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Fri, 6 Sep 2024 09:58:03 -0400
Subject: [PATCH 085/212] Dialyzer: the pattern can never match the type

---
 lib/pleroma/object/fetcher.ex | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/lib/pleroma/object/fetcher.ex b/lib/pleroma/object/fetcher.ex
index 9d9a201ca..ff7aa539f 100644
--- a/lib/pleroma/object/fetcher.ex
+++ b/lib/pleroma/object/fetcher.ex
@@ -58,8 +58,11 @@ defmodule Pleroma.Object.Fetcher do
     end
   end
 
+  @typep fetcher_errors ::
+           :error | :reject | :allowed_depth | :fetch | :containment | :transmogrifier
+
   # Note: will create a Create activity, which we need internally at the moment.
-  @spec fetch_object_from_id(String.t(), list()) :: {:ok, Object.t()} | {:error | :reject, any()}
+  @spec fetch_object_from_id(String.t(), list()) :: {:ok, Object.t()} | {fetcher_errors(), any()}
   def fetch_object_from_id(id, options \\ []) do
     with {_, nil} <- {:fetch_object, Object.get_cached_by_ap_id(id)},
          {_, true} <- {:allowed_depth, Federator.allowed_thread_distance?(options[:depth])},

From bc16f09d7b9c1a15c8c9be6d99092b9a8d867d18 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Fri, 6 Sep 2024 11:12:13 -0400
Subject: [PATCH 086/212] Dialyzer: the pattern can never match the type

The original error was for the chat controller:

lib/pleroma/web/pleroma_api/controllers/chat_controller.ex:104:pattern_match The pattern can never match the type {:error, :content_too_long | :forbidden | :no_content | :not_found} | {:user, nil}.

Improve typespecs for the Pipeline and apply them where it could be encountered
---
 lib/pleroma/object/fetcher.ex            |  3 +-
 lib/pleroma/web/activity_pub/pipeline.ex | 19 ++++++----
 lib/pleroma/web/common_api.ex            | 44 ++++++++++++++----------
 3 files changed, 39 insertions(+), 27 deletions(-)

diff --git a/lib/pleroma/object/fetcher.ex b/lib/pleroma/object/fetcher.ex
index ff7aa539f..69a5f3268 100644
--- a/lib/pleroma/object/fetcher.ex
+++ b/lib/pleroma/object/fetcher.ex
@@ -62,7 +62,8 @@ defmodule Pleroma.Object.Fetcher do
            :error | :reject | :allowed_depth | :fetch | :containment | :transmogrifier
 
   # Note: will create a Create activity, which we need internally at the moment.
-  @spec fetch_object_from_id(String.t(), list()) :: {:ok, Object.t()} | {fetcher_errors(), any()}
+  @spec fetch_object_from_id(String.t(), list()) ::
+          {:ok, Object.t()} | {fetcher_errors(), any()} | Pipeline.errors()
   def fetch_object_from_id(id, options \\ []) do
     with {_, nil} <- {:fetch_object, Object.get_cached_by_ap_id(id)},
          {_, true} <- {:allowed_depth, Federator.allowed_thread_distance?(options[:depth])},
diff --git a/lib/pleroma/web/activity_pub/pipeline.ex b/lib/pleroma/web/activity_pub/pipeline.ex
index 7f11a4d67..fc36935d5 100644
--- a/lib/pleroma/web/activity_pub/pipeline.ex
+++ b/lib/pleroma/web/activity_pub/pipeline.ex
@@ -22,22 +22,27 @@ defmodule Pleroma.Web.ActivityPub.Pipeline do
   defp activity_pub, do: Config.get([:pipeline, :activity_pub], ActivityPub)
   defp config, do: Config.get([:pipeline, :config], Config)
 
-  @spec common_pipeline(map(), keyword()) ::
-          {:ok, Activity.t() | Object.t(), keyword()} | {:error | :reject, any()}
+  @type results :: {:ok, Activity.t() | Object.t(), keyword()}
+  @type errors :: {:error | :reject, any()}
+
+  # The Repo.transaction will wrap the result in an {:ok, _}
+  # and only returns an {:error, _} if the error encountered was related
+  # to the SQL transaction
+  @spec common_pipeline(map(), keyword()) :: results() | errors()
   def common_pipeline(object, meta) do
     case Repo.transaction(fn -> do_common_pipeline(object, meta) end, Utils.query_timeout()) do
       {:ok, {:ok, activity, meta}} ->
         side_effects().handle_after_transaction(meta)
         {:ok, activity, meta}
 
-      {:ok, value} ->
-        value
+      {:ok, {:error, _} = error} ->
+        error
+
+      {:ok, {:reject, _} = error} ->
+        error
 
       {:error, e} ->
         {:error, e}
-
-      {:reject, e} ->
-        {:reject, e}
     end
   end
 
diff --git a/lib/pleroma/web/common_api.ex b/lib/pleroma/web/common_api.ex
index 921e414c3..412424dae 100644
--- a/lib/pleroma/web/common_api.ex
+++ b/lib/pleroma/web/common_api.ex
@@ -26,7 +26,7 @@ defmodule Pleroma.Web.CommonAPI do
   require Pleroma.Constants
   require Logger
 
-  @spec block(User.t(), User.t()) :: {:ok, Activity.t()} | {:error, any()}
+  @spec block(User.t(), User.t()) :: {:ok, Activity.t()} | Pipeline.errors()
   def block(blocked, blocker) do
     with {:ok, block_data, _} <- Builder.block(blocker, blocked),
          {:ok, block, _} <- Pipeline.common_pipeline(block_data, local: true) do
@@ -35,7 +35,7 @@ defmodule Pleroma.Web.CommonAPI do
   end
 
   @spec post_chat_message(User.t(), User.t(), String.t(), list()) ::
-          {:ok, Activity.t()} | {:error, any()}
+          {:ok, Activity.t()} | Pipeline.errors()
   def post_chat_message(%User{} = user, %User{} = recipient, content, opts \\ []) do
     with maybe_attachment <- opts[:media_id] && Object.get_by_id(opts[:media_id]),
          :ok <- validate_chat_attachment_attribution(maybe_attachment, user),
@@ -58,7 +58,7 @@ defmodule Pleroma.Web.CommonAPI do
             )} do
       {:ok, activity}
     else
-      {:common_pipeline, {:reject, _} = e} -> e
+      {:common_pipeline, e} -> e
       e -> e
     end
   end
@@ -99,7 +99,8 @@ defmodule Pleroma.Web.CommonAPI do
     end
   end
 
-  @spec unblock(User.t(), User.t()) :: {:ok, Activity.t()} | {:error, any()}
+  @spec unblock(User.t(), User.t()) ::
+          {:ok, Activity.t()} | {:ok, :no_activity} | Pipeline.errors() | {:error, :not_blocking}
   def unblock(blocked, blocker) do
     with {_, %Activity{} = block} <- {:fetch_block, Utils.fetch_latest_block(blocker, blocked)},
          {:ok, unblock_data, _} <- Builder.undo(blocker, block),
@@ -120,7 +121,9 @@ defmodule Pleroma.Web.CommonAPI do
   end
 
   @spec follow(User.t(), User.t()) ::
-          {:ok, User.t(), User.t(), Activity.t() | Object.t()} | {:error, :rejected}
+          {:ok, User.t(), User.t(), Activity.t() | Object.t()}
+          | {:error, :rejected}
+          | Pipeline.errors()
   def follow(followed, follower) do
     timeout = Pleroma.Config.get([:activitypub, :follow_handshake_timeout])
 
@@ -145,7 +148,7 @@ defmodule Pleroma.Web.CommonAPI do
     end
   end
 
-  @spec accept_follow_request(User.t(), User.t()) :: {:ok, User.t()} | {:error, any()}
+  @spec accept_follow_request(User.t(), User.t()) :: {:ok, User.t()} | Pipeline.errors()
   def accept_follow_request(follower, followed) do
     with %Activity{} = follow_activity <- Utils.fetch_latest_follow(follower, followed),
          {:ok, accept_data, _} <- Builder.accept(followed, follow_activity),
@@ -154,7 +157,7 @@ defmodule Pleroma.Web.CommonAPI do
     end
   end
 
-  @spec reject_follow_request(User.t(), User.t()) :: {:ok, User.t()} | {:error, any()} | nil
+  @spec reject_follow_request(User.t(), User.t()) :: {:ok, User.t()} | Pipeline.errors() | nil
   def reject_follow_request(follower, followed) do
     with %Activity{} = follow_activity <- Utils.fetch_latest_follow(follower, followed),
          {:ok, reject_data, _} <- Builder.reject(followed, follow_activity),
@@ -163,7 +166,8 @@ defmodule Pleroma.Web.CommonAPI do
     end
   end
 
-  @spec delete(String.t(), User.t()) :: {:ok, Activity.t()} | {:error, any()}
+  @spec delete(String.t(), User.t()) ::
+          {:ok, Activity.t()} | Pipeline.errors() | {:error, :not_found | String.t()}
   def delete(activity_id, user) do
     with {_, %Activity{data: %{"object" => _, "type" => "Create"}} = activity} <-
            {:find_activity, Activity.get_by_id(activity_id, filter: [])},
@@ -213,7 +217,7 @@ defmodule Pleroma.Web.CommonAPI do
     end
   end
 
-  @spec repeat(String.t(), User.t(), map()) :: {:ok, Activity.t()} | {:error, any()}
+  @spec repeat(String.t(), User.t(), map()) :: {:ok, Activity.t()} | {:error, :not_found}
   def repeat(id, user, params \\ %{}) do
     with %Activity{data: %{"type" => "Create"}} = activity <- Activity.get_by_id(id),
          object = %Object{} <- Object.normalize(activity, fetch: false),
@@ -231,7 +235,7 @@ defmodule Pleroma.Web.CommonAPI do
     end
   end
 
-  @spec unrepeat(String.t(), User.t()) :: {:ok, Activity.t()} | {:error, any()}
+  @spec unrepeat(String.t(), User.t()) :: {:ok, Activity.t()} | {:error, :not_found | String.t()}
   def unrepeat(id, user) do
     with {_, %Activity{data: %{"type" => "Create"}} = activity} <-
            {:find_activity, Activity.get_by_id(id)},
@@ -247,7 +251,8 @@ defmodule Pleroma.Web.CommonAPI do
     end
   end
 
-  @spec favorite(String.t(), User.t()) :: {:ok, Activity.t()} | {:error, any()}
+  @spec favorite(String.t(), User.t()) ::
+          {:ok, Activity.t()} | {:ok, :already_liked} | {:error, :not_found | String.t()}
   def favorite(id, %User{} = user) do
     case favorite_helper(user, id) do
       {:ok, _} = res ->
@@ -285,7 +290,8 @@ defmodule Pleroma.Web.CommonAPI do
     end
   end
 
-  @spec unfavorite(String.t(), User.t()) :: {:ok, Activity.t()} | {:error, any()}
+  @spec unfavorite(String.t(), User.t()) ::
+          {:ok, Activity.t()} | {:error, :not_found | String.t()}
   def unfavorite(id, user) do
     with {_, %Activity{data: %{"type" => "Create"}} = activity} <-
            {:find_activity, Activity.get_by_id(id)},
@@ -302,7 +308,7 @@ defmodule Pleroma.Web.CommonAPI do
   end
 
   @spec react_with_emoji(String.t(), User.t(), String.t()) ::
-          {:ok, Activity.t()} | {:error, any()}
+          {:ok, Activity.t()} | {:error, String.t()}
   def react_with_emoji(id, user, emoji) do
     with %Activity{} = activity <- Activity.get_by_id(id),
          object <- Object.normalize(activity, fetch: false),
@@ -316,7 +322,7 @@ defmodule Pleroma.Web.CommonAPI do
   end
 
   @spec unreact_with_emoji(String.t(), User.t(), String.t()) ::
-          {:ok, Activity.t()} | {:error, any()}
+          {:ok, Activity.t()} | {:error, String.t()}
   def unreact_with_emoji(id, user, emoji) do
     with %Activity{} = reaction_activity <- Utils.get_latest_reaction(id, user, emoji),
          {_, {:ok, _}} <- {:cancel_jobs, maybe_cancel_jobs(reaction_activity)},
@@ -329,7 +335,7 @@ defmodule Pleroma.Web.CommonAPI do
     end
   end
 
-  @spec vote(Object.t(), User.t(), list()) :: {:ok, list(), Object.t()} | {:error, any()}
+  @spec vote(Object.t(), User.t(), list()) :: {:ok, list(), Object.t()} | Pipeline.errors()
   def vote(%Object{data: %{"type" => "Question"}} = object, %User{} = user, choices) do
     with :ok <- validate_not_author(object, user),
          :ok <- validate_existing_votes(user, object),
@@ -461,7 +467,7 @@ defmodule Pleroma.Web.CommonAPI do
     end
   end
 
-  @spec update(Activity.t(), User.t(), map()) :: {:ok, Activity.t()} | {:error, any()}
+  @spec update(Activity.t(), User.t(), map()) :: {:ok, Activity.t()} | {:error, nil}
   def update(orig_activity, %User{} = user, changes) do
     with orig_object <- Object.normalize(orig_activity),
          {:ok, new_object} <- make_update_data(user, orig_object, changes),
@@ -497,7 +503,7 @@ defmodule Pleroma.Web.CommonAPI do
     end
   end
 
-  @spec pin(String.t(), User.t()) :: {:ok, Activity.t()} | {:error, term()}
+  @spec pin(String.t(), User.t()) :: {:ok, Activity.t()} | Pipeline.errors()
   def pin(id, %User{} = user) do
     with %Activity{} = activity <- create_activity_by_id(id),
          true <- activity_belongs_to_actor(activity, user.ap_id),
@@ -537,7 +543,7 @@ defmodule Pleroma.Web.CommonAPI do
     end
   end
 
-  @spec unpin(String.t(), User.t()) :: {:ok, Activity.t()} | {:error, term()}
+  @spec unpin(String.t(), User.t()) :: {:ok, Activity.t()} | Pipeline.errors()
   def unpin(id, user) do
     with %Activity{} = activity <- create_activity_by_id(id),
          {:ok, unpin_data, _} <- Builder.unpin(user, activity.object),
@@ -552,7 +558,7 @@ defmodule Pleroma.Web.CommonAPI do
     end
   end
 
-  @spec add_mute(Activity.t(), User.t(), map()) :: {:ok, Activity.t()} | {:error, any()}
+  @spec add_mute(Activity.t(), User.t(), map()) :: {:ok, Activity.t()} | {:error, String.t()}
   def add_mute(activity, user, params \\ %{}) do
     expires_in = Map.get(params, :expires_in, 0)
 

From 7eb579c1911f2eac175c2030f6bb80685b4ab4f8 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Fri, 6 Sep 2024 11:18:12 -0400
Subject: [PATCH 087/212] Dialyzer: invalid contract

---
 lib/pleroma/user/import.ex | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/pleroma/user/import.ex b/lib/pleroma/user/import.ex
index b79fa88eb..ab6bdb8d4 100644
--- a/lib/pleroma/user/import.ex
+++ b/lib/pleroma/user/import.ex
@@ -12,7 +12,7 @@ defmodule Pleroma.User.Import do
 
   require Logger
 
-  @spec perform(atom(), User.t(), list()) :: :ok | list() | {:error, any()}
+  @spec perform(atom(), User.t(), String.t()) :: :ok | {:error, any()}
   def perform(:mute_import, %User{} = user, actor) do
     with {:ok, %User{} = muted_user} <- User.get_or_fetch(actor),
          {_, false} <- {:existing_mute, User.mutes_user?(user, muted_user)},
@@ -49,7 +49,7 @@ defmodule Pleroma.User.Import do
 
   defp handle_error(op, user_id, error) do
     Logger.debug("#{op} failed for #{user_id} with: #{inspect(error)}")
-    error
+    {:error, error}
   end
 
   def blocks_import(%User{} = user, [_ | _] = actors) do

From 06d6febff960e5aafd44709d0a61311b45892a81 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Fri, 6 Sep 2024 11:19:24 -0400
Subject: [PATCH 088/212] Dialyzer: The pattern variable _e@1 can never match
 the type, because it is covered by previous clauses.

---
 lib/pleroma/user/backup.ex | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/lib/pleroma/user/backup.ex b/lib/pleroma/user/backup.ex
index 7feaa22bf..70cf5b2a1 100644
--- a/lib/pleroma/user/backup.ex
+++ b/lib/pleroma/user/backup.ex
@@ -92,9 +92,6 @@ defmodule Pleroma.User.Backup do
     else
       true ->
         {:error, "Backup is missing id. Please insert it into the Repo first."}
-
-      e ->
-        {:error, e}
     end
   end
 

From 1d0e3b1355c5a5883be1522f0f925c398c0e87a4 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Fri, 6 Sep 2024 11:24:37 -0400
Subject: [PATCH 089/212] Dialyzer: The pattern variable _ can never match the
 type, because it is covered by previous clauses.

---
 lib/pleroma/user/backup.ex | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/lib/pleroma/user/backup.ex b/lib/pleroma/user/backup.ex
index 70cf5b2a1..c5038c8f4 100644
--- a/lib/pleroma/user/backup.ex
+++ b/lib/pleroma/user/backup.ex
@@ -294,9 +294,6 @@ defmodule Pleroma.User.Backup do
               )
 
               acc
-
-            _ ->
-              acc
           end
         end)
 

From 06ce5e3b43b4a6809397bdb0eb192a82e7243e93 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Fri, 6 Sep 2024 11:27:07 -0400
Subject: [PATCH 090/212] Dialyzer: pattern_match The pattern can never match
 the type {:diff, false}.

---
 lib/pleroma/user/backup.ex | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/lib/pleroma/user/backup.ex b/lib/pleroma/user/backup.ex
index c5038c8f4..d77d49890 100644
--- a/lib/pleroma/user/backup.ex
+++ b/lib/pleroma/user/backup.ex
@@ -118,14 +118,13 @@ defmodule Pleroma.User.Backup do
   end
 
   defp permitted?(user) do
-    with {_, %__MODULE__{inserted_at: inserted_at}} <- {:last, get_last(user)},
-         days = Config.get([__MODULE__, :limit_days]),
-         diff = Timex.diff(NaiveDateTime.utc_now(), inserted_at, :days),
-         {_, true} <- {:diff, diff > days} do
-      true
+    with {_, %__MODULE__{inserted_at: inserted_at}} <- {:last, get_last(user)} do
+      days = Config.get([__MODULE__, :limit_days])
+      diff = Timex.diff(NaiveDateTime.utc_now(), inserted_at, :days)
+
+      diff > days
     else
       {:last, nil} -> true
-      {:diff, false} -> false
     end
   end
 

From 5b26c56624ad281987a18091a6ae245833d2fde1 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Fri, 6 Sep 2024 11:34:06 -0400
Subject: [PATCH 091/212] Changelog

---
 changelog.d/dialyzer.skip | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 changelog.d/dialyzer.skip

diff --git a/changelog.d/dialyzer.skip b/changelog.d/dialyzer.skip
new file mode 100644
index 000000000..e69de29bb

From 1afcfd4845fb71e111b7cbcf18858bb100863f8a Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Fri, 6 Sep 2024 11:51:16 -0400
Subject: [PATCH 092/212] Add tests for Mastodon mention hashtag class

---
 test/pleroma/html_test.exs | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/test/pleroma/html_test.exs b/test/pleroma/html_test.exs
index 1be161971..d17b07540 100644
--- a/test/pleroma/html_test.exs
+++ b/test/pleroma/html_test.exs
@@ -41,6 +41,10 @@ defmodule Pleroma.HTMLTest do
   <span class="h-card"><a class="u-url mention animate-spin">@<span>foo</span></a></span>
   """
 
+  @mention_hashtags_sample """
+  <a href="https://mastodon.example/tags/linux" class="mention hashtag" rel="tag">#<span>linux</span></a>
+  """
+
   describe "StripTags scrubber" do
     test "works as expected" do
       expected = """
@@ -126,6 +130,15 @@ defmodule Pleroma.HTMLTest do
                  Pleroma.HTML.Scrubber.TwitterText
                )
     end
+
+    test "does allow mention hashtags" do
+      expected = """
+      <a href="https://mastodon.example/tags/linux" class="mention hashtag" rel="tag">#<span>linux</span></a>
+      """
+
+      assert expected ==
+               HTML.filter_tags(@mention_hashtags_sample, Pleroma.HTML.Scrubber.Default)
+    end
   end
 
   describe "default scrubber" do
@@ -189,6 +202,15 @@ defmodule Pleroma.HTMLTest do
                  Pleroma.HTML.Scrubber.Default
                )
     end
+
+    test "does allow mention hashtags" do
+      expected = """
+      <a href="https://mastodon.example/tags/linux" class="mention hashtag" rel="tag">#<span>linux</span></a>
+      """
+
+      assert expected ==
+               HTML.filter_tags(@mention_hashtags_sample, Pleroma.HTML.Scrubber.Default)
+    end
   end
 
   describe "extract_first_external_url_from_object" do

From c9b28eaf9a484fa1f2c27d00855c997575369782 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= <git@mkljczk.pl>
Date: Sun, 8 Sep 2024 05:23:46 +0300
Subject: [PATCH 093/212] Argon2 password support

---
 lib/pleroma/web/plugs/authentication_plug.ex | 4 ++++
 mix.exs                                      | 1 +
 mix.lock                                     | 1 +
 3 files changed, 6 insertions(+)

diff --git a/lib/pleroma/web/plugs/authentication_plug.ex b/lib/pleroma/web/plugs/authentication_plug.ex
index f912a1542..3fc6e7b51 100644
--- a/lib/pleroma/web/plugs/authentication_plug.ex
+++ b/lib/pleroma/web/plugs/authentication_plug.ex
@@ -47,6 +47,10 @@ defmodule Pleroma.Web.Plugs.AuthenticationPlug do
     Pleroma.Password.Pbkdf2.verify_pass(password, password_hash)
   end
 
+  def checkpw(password, "$argon2" <> _ = password_hash) do
+    Argon2.verify_pass(password, password_hash)
+  end
+
   def checkpw(_password, _password_hash) do
     Logger.error("Password hash not recognized")
     false
diff --git a/mix.exs b/mix.exs
index df44934d7..0d49a6b45 100644
--- a/mix.exs
+++ b/mix.exs
@@ -203,6 +203,7 @@ defmodule Pleroma.Mixfile do
       {:websock_adapter, "~> 0.5.6"},
       {:oban_live_dashboard, "~> 0.1.1"},
       {:multipart, "~> 0.4.0", optional: true},
+      {:argon2_elixir, "~> 4.0"},
 
       ## dev & test
       {:phoenix_live_reload, "~> 1.3.3", only: :dev},
diff --git a/mix.lock b/mix.lock
index 865e09a4c..01f2eef98 100644
--- a/mix.lock
+++ b/mix.lock
@@ -1,5 +1,6 @@
 %{
   "accept": {:hex, :accept, "0.3.5", "b33b127abca7cc948bbe6caa4c263369abf1347cfa9d8e699c6d214660f10cd1", [:rebar3], [], "hexpm", "11b18c220bcc2eab63b5470c038ef10eb6783bcb1fcdb11aa4137defa5ac1bb8"},
+  "argon2_elixir": {:hex, :argon2_elixir, "4.0.0", "7f6cd2e4a93a37f61d58a367d82f830ad9527082ff3c820b8197a8a736648941", [:make, :mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "f9da27cf060c9ea61b1bd47837a28d7e48a8f6fa13a745e252556c14f9132c7f"},
   "bandit": {:hex, :bandit, "1.5.5", "df28f1c41f745401fe9e85a6882033f5f3442ab6d30c8a2948554062a4ab56e0", [:mix], [{:hpax, "~> 0.2.0", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.0", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "f21579a29ea4bc08440343b2b5f16f7cddf2fea5725d31b72cf973ec729079e1"},
   "base62": {:hex, :base62, "1.2.2", "85c6627eb609317b70f555294045895ffaaeb1758666ab9ef9ca38865b11e629", [:mix], [{:custom_base, "~> 0.2.1", [hex: :custom_base, repo: "hexpm", optional: false]}], "hexpm", "d41336bda8eaa5be197f1e4592400513ee60518e5b9f4dcf38f4b4dae6f377bb"},
   "bbcode_pleroma": {:hex, :bbcode_pleroma, "0.2.0", "d36f5bca6e2f62261c45be30fa9b92725c0655ad45c99025cb1c3e28e25803ef", [:mix], [{:nimble_parsec, "~> 0.5", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "19851074419a5fedb4ef49e1f01b30df504bb5dbb6d6adfc135238063bebd1c3"},

From 9de522ce5048bd72dd083a1661506b563be27cc1 Mon Sep 17 00:00:00 2001
From: Mint <mint@plagu.ee>
Date: Sun, 8 Sep 2024 05:32:40 +0300
Subject: [PATCH 094/212] Authentication: convert argon2 passwords, add tests

---
 lib/pleroma/web/plugs/authentication_plug.ex  |  5 ++++
 .../web/plugs/authentication_plug_test.exs    | 26 +++++++++++++++++++
 2 files changed, 31 insertions(+)

diff --git a/lib/pleroma/web/plugs/authentication_plug.ex b/lib/pleroma/web/plugs/authentication_plug.ex
index 3fc6e7b51..af7d7f45a 100644
--- a/lib/pleroma/web/plugs/authentication_plug.ex
+++ b/lib/pleroma/web/plugs/authentication_plug.ex
@@ -48,6 +48,7 @@ defmodule Pleroma.Web.Plugs.AuthenticationPlug do
   end
 
   def checkpw(password, "$argon2" <> _ = password_hash) do
+    # Handle argon2 passwords for Akkoma migration
     Argon2.verify_pass(password, password_hash)
   end
 
@@ -60,6 +61,10 @@ defmodule Pleroma.Web.Plugs.AuthenticationPlug do
     do_update_password(user, password)
   end
 
+  def maybe_update_password(%User{password_hash: "$argon2" <> _} = user, password) do
+    do_update_password(user, password)
+  end
+
   def maybe_update_password(user, _), do: {:ok, user}
 
   defp do_update_password(user, password) do
diff --git a/test/pleroma/web/plugs/authentication_plug_test.exs b/test/pleroma/web/plugs/authentication_plug_test.exs
index b8acd01c5..bdbf3de32 100644
--- a/test/pleroma/web/plugs/authentication_plug_test.exs
+++ b/test/pleroma/web/plugs/authentication_plug_test.exs
@@ -70,6 +70,24 @@ defmodule Pleroma.Web.Plugs.AuthenticationPlugTest do
     assert "$pbkdf2" <> _ = user.password_hash
   end
 
+  test "with an argon2 hash, it updates to a pkbdf2 hash", %{conn: conn} do
+    user = insert(:user, password_hash: Argon2.hash_pwd_salt("123"))
+    assert "$argon2" <> _ = user.password_hash
+
+    conn =
+      conn
+      |> assign(:auth_user, user)
+      |> assign(:auth_credentials, %{password: "123"})
+      |> AuthenticationPlug.call(%{})
+
+    assert conn.assigns.user.id == conn.assigns.auth_user.id
+    assert conn.assigns.token == nil
+    assert PlugHelper.plug_skipped?(conn, OAuthScopesPlug)
+
+    user = User.get_by_id(user.id)
+    assert "$pbkdf2" <> _ = user.password_hash
+  end
+
   describe "checkpw/2" do
     test "check pbkdf2 hash" do
       hash =
@@ -86,6 +104,14 @@ defmodule Pleroma.Web.Plugs.AuthenticationPlugTest do
       refute AuthenticationPlug.checkpw("password1", hash)
     end
 
+    test "check argon2 hash" do
+      hash =
+        "$argon2id$v=19$m=65536,t=8,p=2$zEMMsTuK5KkL5AFWbX7jyQ$VyaQD7PF6e9btz0oH1YiAkWwIGZ7WNDZP8l+a/O171g"
+
+      assert AuthenticationPlug.checkpw("password", hash)
+      refute AuthenticationPlug.checkpw("password1", hash)
+    end
+
     test "it returns false when hash invalid" do
       hash =
         "psBWV8gxkGOZWBz$PmfCycChoxeJ3GgGzwvhlgacb9mUoZ.KUXNCssekER4SJ7bOK53uXrHNb2e4i8yPFgSKyzaW9CcmrDXWIEMtD1"

From 7e91c3a306b8f050e6a88e888fd439b579c1f125 Mon Sep 17 00:00:00 2001
From: Mint <mint@plagu.ee>
Date: Sun, 8 Sep 2024 05:41:48 +0300
Subject: [PATCH 095/212] Changelog

---
 changelog.d/argon2-passwords.add | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 changelog.d/argon2-passwords.add

diff --git a/changelog.d/argon2-passwords.add b/changelog.d/argon2-passwords.add
new file mode 100644
index 000000000..36fd7faf2
--- /dev/null
+++ b/changelog.d/argon2-passwords.add
@@ -0,0 +1 @@
+Added support for argon2 passwords and their conversion for migration from Akkoma fork to upstream.

From 7def11d7c352f13ce0f12715649359344cbba9a6 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Wed, 11 Sep 2024 12:45:33 -0400
Subject: [PATCH 096/212] LDAP Auth: fix TLS certificate verification

Currently we only support STARTTLS and it was not verifying certificate and hostname correctly. We must pass a custom fqdn_fun/1 function so it knows what value to compare against.
---
 changelog.d/ldap-tls.fix                   |  1 +
 lib/pleroma/web/auth/ldap_authenticator.ex | 12 +++++++++++-
 mix.exs                                    |  1 +
 3 files changed, 13 insertions(+), 1 deletion(-)
 create mode 100644 changelog.d/ldap-tls.fix

diff --git a/changelog.d/ldap-tls.fix b/changelog.d/ldap-tls.fix
new file mode 100644
index 000000000..b15137d77
--- /dev/null
+++ b/changelog.d/ldap-tls.fix
@@ -0,0 +1 @@
+STARTTLS certificate and hostname verification for LDAP authentication
diff --git a/lib/pleroma/web/auth/ldap_authenticator.ex b/lib/pleroma/web/auth/ldap_authenticator.ex
index ea5620cf6..d31f34747 100644
--- a/lib/pleroma/web/auth/ldap_authenticator.ex
+++ b/lib/pleroma/web/auth/ldap_authenticator.ex
@@ -41,6 +41,7 @@ defmodule Pleroma.Web.Auth.LDAPAuthenticator do
     port = Keyword.get(ldap, :port, 389)
     ssl = Keyword.get(ldap, :ssl, false)
     sslopts = Keyword.get(ldap, :sslopts, [])
+    tlsopts = Keyword.get(ldap, :tlsopts, [])
 
     options =
       [{:port, port}, {:ssl, ssl}, {:timeout, @connection_timeout}] ++
@@ -54,7 +55,16 @@ defmodule Pleroma.Web.Auth.LDAPAuthenticator do
 
             case :eldap.start_tls(
                    connection,
-                   Keyword.get(ldap, :tlsopts, []),
+                   Keyword.merge(
+                     [
+                       verify: :verify_peer,
+                       cacerts: :certifi.cacerts(),
+                       customize_hostname_check: [
+                         fqdn_fun: fn _ -> to_charlist(host) end
+                       ]
+                     ],
+                     tlsopts
+                   ),
                    @connection_timeout
                  ) do
               :ok ->
diff --git a/mix.exs b/mix.exs
index 0d49a6b45..9a261547f 100644
--- a/mix.exs
+++ b/mix.exs
@@ -204,6 +204,7 @@ defmodule Pleroma.Mixfile do
       {:oban_live_dashboard, "~> 0.1.1"},
       {:multipart, "~> 0.4.0", optional: true},
       {:argon2_elixir, "~> 4.0"},
+      {:certifi, "~> 2.12"},
 
       ## dev & test
       {:phoenix_live_reload, "~> 1.3.3", only: :dev},

From affdcdb68daabb15f8fad2e7b6406606e8086e75 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= <git@mkljczk.pl>
Date: Thu, 12 Sep 2024 11:27:29 +0200
Subject: [PATCH 097/212] Manifest: declare /static/logo.svg as 512x512 to
 match one provided by pleroma-fe
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
---
 changelog.d/manifest-icon-size.skip | 0
 config/config.exs                   | 2 +-
 2 files changed, 1 insertion(+), 1 deletion(-)
 create mode 100644 changelog.d/manifest-icon-size.skip

diff --git a/changelog.d/manifest-icon-size.skip b/changelog.d/manifest-icon-size.skip
new file mode 100644
index 000000000..e69de29bb
diff --git a/config/config.exs b/config/config.exs
index 80a3b8d57..cd9a2539f 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -344,7 +344,7 @@ config :pleroma, :manifest,
   icons: [
     %{
       src: "/static/logo.svg",
-      sizes: "144x144",
+      sizes: "512x512",
       purpose: "any",
       type: "image/svg+xml"
     }

From 17b69c43d5ed6ba867f5fb1da15f6af9aa7c5d00 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= <git@mkljczk.pl>
Date: Thu, 12 Sep 2024 14:37:37 +0200
Subject: [PATCH 098/212] Add `group_key` to notifications
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
---
 changelog.d/notifications-group-key.add             |  1 +
 .../api_spec/operations/notification_operation.ex   |  5 +++++
 .../web/mastodon_api/views/notification_view.ex     |  1 +
 .../mastodon_api/views/notification_view_test.exs   | 13 +++++++++++++
 4 files changed, 20 insertions(+)
 create mode 100644 changelog.d/notifications-group-key.add

diff --git a/changelog.d/notifications-group-key.add b/changelog.d/notifications-group-key.add
new file mode 100644
index 000000000..386927f4a
--- /dev/null
+++ b/changelog.d/notifications-group-key.add
@@ -0,0 +1 @@
+Add `group_key` to notifications
\ No newline at end of file
diff --git a/lib/pleroma/web/api_spec/operations/notification_operation.ex b/lib/pleroma/web/api_spec/operations/notification_operation.ex
index 2dc0f66df..94d1f6b82 100644
--- a/lib/pleroma/web/api_spec/operations/notification_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/notification_operation.ex
@@ -158,6 +158,10 @@ defmodule Pleroma.Web.ApiSpec.NotificationOperation do
       type: :object,
       properties: %{
         id: %Schema{type: :string},
+        group_key: %Schema{
+          type: :string,
+          description: "Group key shared by similar notifications"
+        },
         type: notification_type(),
         created_at: %Schema{type: :string, format: :"date-time"},
         account: %Schema{
@@ -180,6 +184,7 @@ defmodule Pleroma.Web.ApiSpec.NotificationOperation do
       },
       example: %{
         "id" => "34975861",
+        "group-key" => "ungrouped-34975861",
         "type" => "mention",
         "created_at" => "2019-11-23T07:49:02.064Z",
         "account" => Account.schema().example,
diff --git a/lib/pleroma/web/mastodon_api/views/notification_view.ex b/lib/pleroma/web/mastodon_api/views/notification_view.ex
index 3f2478719..c277af98b 100644
--- a/lib/pleroma/web/mastodon_api/views/notification_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/notification_view.ex
@@ -95,6 +95,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
 
     response = %{
       id: to_string(notification.id),
+      group_key: "ungrouped-" <> to_string(notification.id),
       type: notification.type,
       created_at: CommonAPI.Utils.to_masto_date(notification.inserted_at),
       account: account,
diff --git a/test/pleroma/web/mastodon_api/views/notification_view_test.exs b/test/pleroma/web/mastodon_api/views/notification_view_test.exs
index 75ab375aa..b1f3523ac 100644
--- a/test/pleroma/web/mastodon_api/views/notification_view_test.exs
+++ b/test/pleroma/web/mastodon_api/views/notification_view_test.exs
@@ -56,6 +56,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
 
     expected = %{
       id: to_string(notification.id),
+      group_key: "ungrouped-#{to_string(notification.id)}",
       pleroma: %{is_seen: false, is_muted: false},
       type: "pleroma:chat_mention",
       account: AccountView.render("show.json", %{user: user, for: recipient}),
@@ -75,6 +76,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
 
     expected = %{
       id: to_string(notification.id),
+      group_key: "ungrouped-#{to_string(notification.id)}",
       pleroma: %{is_seen: false, is_muted: false},
       type: "mention",
       account:
@@ -99,6 +101,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
 
     expected = %{
       id: to_string(notification.id),
+      group_key: "ungrouped-#{to_string(notification.id)}",
       pleroma: %{is_seen: false, is_muted: false},
       type: "favourite",
       account: AccountView.render("show.json", %{user: another_user, for: user}),
@@ -119,6 +122,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
 
     expected = %{
       id: to_string(notification.id),
+      group_key: "ungrouped-#{to_string(notification.id)}",
       pleroma: %{is_seen: false, is_muted: false},
       type: "reblog",
       account: AccountView.render("show.json", %{user: another_user, for: user}),
@@ -137,6 +141,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
 
     expected = %{
       id: to_string(notification.id),
+      group_key: "ungrouped-#{to_string(notification.id)}",
       pleroma: %{is_seen: false, is_muted: false},
       type: "follow",
       account: AccountView.render("show.json", %{user: follower, for: followed}),
@@ -165,6 +170,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
 
     expected = %{
       id: to_string(notification.id),
+      group_key: "ungrouped-#{to_string(notification.id)}",
       pleroma: %{is_seen: false, is_muted: false},
       type: "move",
       account: AccountView.render("show.json", %{user: old_user, for: follower}),
@@ -190,6 +196,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
 
     expected = %{
       id: to_string(notification.id),
+      group_key: "ungrouped-#{to_string(notification.id)}",
       pleroma: %{is_seen: false, is_muted: false},
       type: "pleroma:emoji_reaction",
       emoji: "☕",
@@ -229,6 +236,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
 
     expected = %{
       id: to_string(notification.id),
+      group_key: "ungrouped-#{to_string(notification.id)}",
       pleroma: %{is_seen: false, is_muted: false},
       type: "pleroma:emoji_reaction",
       emoji: ":dinosaur:",
@@ -248,6 +256,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
 
     expected = %{
       id: to_string(notification.id),
+      group_key: "ungrouped-#{to_string(notification.id)}",
       pleroma: %{is_seen: false, is_muted: false},
       type: "poll",
       account:
@@ -274,6 +283,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
 
     expected = %{
       id: to_string(notification.id),
+      group_key: "ungrouped-#{to_string(notification.id)}",
       pleroma: %{is_seen: false, is_muted: false},
       type: "pleroma:report",
       account: AccountView.render("show.json", %{user: reporting_user, for: moderator_user}),
@@ -300,6 +310,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
 
     expected = %{
       id: to_string(notification.id),
+      group_key: "ungrouped-#{to_string(notification.id)}",
       pleroma: %{is_seen: false, is_muted: false},
       type: "update",
       account: AccountView.render("show.json", %{user: user, for: repeat_user}),
@@ -322,6 +333,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
 
     expected = %{
       id: to_string(notification.id),
+      group_key: "ungrouped-#{to_string(notification.id)}",
       pleroma: %{is_seen: true, is_muted: true},
       type: "favourite",
       account: AccountView.render("show.json", %{user: another_user, for: user}),
@@ -345,6 +357,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
 
     expected = %{
       id: to_string(notification.id),
+      group_key: "ungrouped-#{to_string(notification.id)}",
       pleroma: %{is_seen: false, is_muted: false},
       type: "status",
       account:

From e10db52e0a1c9cc24803a406998a9cfe75b7f9f2 Mon Sep 17 00:00:00 2001
From: Mint <mint@plagu.ee>
Date: Fri, 13 Sep 2024 02:58:59 +0300
Subject: [PATCH 099/212] Add dependencies for Swoosh's Mua mail adapter

---
 changelog.d/swoosh-mua.add | 1 +
 mix.exs                    | 4 +++-
 mix.lock                   | 4 +++-
 3 files changed, 7 insertions(+), 2 deletions(-)
 create mode 100644 changelog.d/swoosh-mua.add

diff --git a/changelog.d/swoosh-mua.add b/changelog.d/swoosh-mua.add
new file mode 100644
index 000000000..d4c4bbd08
--- /dev/null
+++ b/changelog.d/swoosh-mua.add
@@ -0,0 +1 @@
+Added dependencies for Swoosh's Mua mail adapter
diff --git a/mix.exs b/mix.exs
index 0d49a6b45..ceae5c26d 100644
--- a/mix.exs
+++ b/mix.exs
@@ -153,7 +153,7 @@ defmodule Pleroma.Mixfile do
       {:calendar, "~> 1.0"},
       {:cachex, "~> 3.2"},
       {:tesla, "~> 1.11"},
-      {:castore, "~> 0.1"},
+      {:castore, "~> 1.0"},
       {:cowlib, "~> 2.9", override: true},
       {:gun, "~> 2.0.0-rc.1", override: true},
       {:finch, "~> 0.15"},
@@ -169,6 +169,8 @@ defmodule Pleroma.Mixfile do
       {:swoosh, "~> 1.16.9"},
       {:phoenix_swoosh, "~> 1.1"},
       {:gen_smtp, "~> 0.13"},
+      {:mua, "~> 0.2.0"},
+      {:mail, "~> 0.3.0"},
       {:ex_syslogger, "~> 1.4"},
       {:floki, "~> 0.35"},
       {:timex, "~> 3.6"},
diff --git a/mix.lock b/mix.lock
index 01f2eef98..2cf44862b 100644
--- a/mix.lock
+++ b/mix.lock
@@ -11,7 +11,7 @@
   "cachex": {:hex, :cachex, "3.6.0", "14a1bfbeee060dd9bec25a5b6f4e4691e3670ebda28c8ba2884b12fe30b36bf8", [:mix], [{:eternal, "~> 1.2", [hex: :eternal, repo: "hexpm", optional: false]}, {:jumper, "~> 1.0", [hex: :jumper, repo: "hexpm", optional: false]}, {:sleeplocks, "~> 1.1", [hex: :sleeplocks, repo: "hexpm", optional: false]}, {:unsafe, "~> 1.0", [hex: :unsafe, repo: "hexpm", optional: false]}], "hexpm", "ebf24e373883bc8e0c8d894a63bbe102ae13d918f790121f5cfe6e485cc8e2e2"},
   "calendar": {:hex, :calendar, "1.0.0", "f52073a708528482ec33d0a171954ca610fe2bd28f1e871f247dc7f1565fa807", [:mix], [{:tzdata, "~> 0.5.20 or ~> 0.1.201603 or ~> 1.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "990e9581920c82912a5ee50e62ff5ef96da6b15949a2ee4734f935fdef0f0a6f"},
   "captcha": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/elixir-captcha.git", "6630c42aaaab124e697b4e513190c89d8b64e410", [ref: "6630c42aaaab124e697b4e513190c89d8b64e410"]},
-  "castore": {:hex, :castore, "0.1.22", "4127549e411bedd012ca3a308dede574f43819fe9394254ca55ab4895abfa1a2", [:mix], [], "hexpm", "c17576df47eb5aa1ee40cc4134316a99f5cad3e215d5c77b8dd3cfef12a22cac"},
+  "castore": {:hex, :castore, "1.0.8", "dedcf20ea746694647f883590b82d9e96014057aff1d44d03ec90f36a5c0dc6e", [:mix], [], "hexpm", "0b2b66d2ee742cb1d9cb8c8be3b43c3a70ee8651f37b75a8b982e036752983f1"},
   "cc_precompiler": {:hex, :cc_precompiler, "0.1.9", "e8d3364f310da6ce6463c3dd20cf90ae7bbecbf6c5203b98bf9b48035592649b", [:mix], [{:elixir_make, "~> 0.7", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "9dcab3d0f3038621f1601f13539e7a9ee99843862e66ad62827b0c42b2f58a54"},
   "certifi": {:hex, :certifi, "2.12.0", "2d1cca2ec95f59643862af91f001478c9863c2ac9cb6e2f89780bfd8de987329", [:rebar3], [], "hexpm", "ee68d85df22e554040cdb4be100f33873ac6051387baf6a8f6ce82272340ff1c"},
   "combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"},
@@ -72,6 +72,7 @@
   "jumper": {:hex, :jumper, "1.0.2", "68cdcd84472a00ac596b4e6459a41b3062d4427cbd4f1e8c8793c5b54f1406a7", [:mix], [], "hexpm", "9b7782409021e01ab3c08270e26f36eb62976a38c1aa64b2eaf6348422f165e1"},
   "linkify": {:hex, :linkify, "0.5.3", "5f8143d8f61f5ff08d3aeeff47ef6509492b4948d8f08007fbf66e4d2246a7f2", [:mix], [], "hexpm", "3ef35a1377d47c25506e07c1c005ea9d38d700699d92ee92825f024434258177"},
   "logger_backends": {:hex, :logger_backends, "1.0.0", "09c4fad6202e08cb0fbd37f328282f16539aca380f512523ce9472b28edc6bdf", [:mix], [], "hexpm", "1faceb3e7ec3ef66a8f5746c5afd020e63996df6fd4eb8cdb789e5665ae6c9ce"},
+  "mail": {:hex, :mail, "0.3.1", "cb0a14e4ed8904e4e5a08214e686ccf6f9099346885db17d8c309381f865cc5c", [:mix], [], "hexpm", "1db701e89865c1d5fa296b2b57b1cd587587cca8d8a1a22892b35ef5a8e352a6"},
   "majic": {:hex, :majic, "1.0.0", "37e50648db5f5c2ff0c9fb46454d034d11596c03683807b9fb3850676ffdaab3", [:make, :mix], [{:elixir_make, "~> 0.6.1", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "7905858f76650d49695f14ea55cd9aaaee0c6654fa391671d4cf305c275a0a9e"},
   "makeup": {:hex, :makeup, "1.0.5", "d5a830bc42c9800ce07dd97fa94669dfb93d3bf5fcf6ea7a0c67b2e0e4a7f26c", [:mix], [{:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cfa158c02d3f5c0c665d0af11512fed3fba0144cf1aadee0f2ce17747fba2ca9"},
   "makeup_elixir": {:hex, :makeup_elixir, "0.14.1", "4f0e96847c63c17841d42c08107405a005a2680eb9c7ccadfd757bd31dabccfb", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "f2438b1a80eaec9ede832b5c41cd4f373b38fd7aa33e3b22d9db79e640cbde11"},
@@ -85,6 +86,7 @@
   "mock": {:hex, :mock, "0.3.8", "7046a306b71db2488ef54395eeb74df0a7f335a7caca4a3d3875d1fc81c884dd", [:mix], [{:meck, "~> 0.9.2", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm", "7fa82364c97617d79bb7d15571193fc0c4fe5afd0c932cef09426b3ee6fe2022"},
   "mogrify": {:hex, :mogrify, "0.9.3", "238c782f00271dace01369ad35ae2e9dd020feee3443b9299ea5ea6bed559841", [:mix], [], "hexpm", "0189b1e1de27455f2b9ae8cf88239cefd23d38de9276eb5add7159aea51731e6"},
   "mox": {:hex, :mox, "1.1.0", "0f5e399649ce9ab7602f72e718305c0f9cdc351190f72844599545e4996af73c", [:mix], [], "hexpm", "d44474c50be02d5b72131070281a5d3895c0e7a95c780e90bc0cfe712f633a13"},
+  "mua": {:hex, :mua, "0.2.3", "46b29b7b2bb14105c0b7be9526f7c452df17a7841b30b69871c024a822ff551c", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "7fe861a87fcc06a980d3941bbcb2634e5f0f30fd6ad15ef6c0423ff9dc7e46de"},
   "multipart": {:hex, :multipart, "0.4.0", "634880a2148d4555d050963373d0e3bbb44a55b2badd87fa8623166172e9cda0", [:mix], [{:mime, "~> 1.2 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}], "hexpm", "3c5604bc2fb17b3137e5d2abdf5dacc2647e60c5cc6634b102cf1aef75a06f0a"},
   "nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"},
   "nimble_parsec": {:hex, :nimble_parsec, "0.6.0", "32111b3bf39137144abd7ba1cce0914533b2d16ef35e8abc5ec8be6122944263", [:mix], [], "hexpm", "27eac315a94909d4dc68bc07a4a83e06c8379237c5ea528a9acff4ca1c873c52"},

From 1a120d013019fc15b3f440f7db71d3eb328bc798 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= <git@mkljczk.pl>
Date: Sat, 14 Sep 2024 20:17:08 +0200
Subject: [PATCH 100/212] Federate avatar/header descriptions
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
---
 changelog.d/profile-image-descriptions.skip   |  0
 lib/pleroma/user.ex                           |  5 +++
 lib/pleroma/web/activity_pub/activity_pub.ex  |  9 ++++-
 .../web/activity_pub/views/user_view.ex       | 36 +++++++++++++++----
 .../web/mastodon_api/views/account_view.ex    |  8 ++---
 .../web/activity_pub/activity_pub_test.exs    | 35 ++++++++++++++++--
 .../web/activity_pub/views/user_view_test.exs | 17 +++++++++
 7 files changed, 94 insertions(+), 16 deletions(-)
 create mode 100644 changelog.d/profile-image-descriptions.skip

diff --git a/changelog.d/profile-image-descriptions.skip b/changelog.d/profile-image-descriptions.skip
new file mode 100644
index 000000000..e69de29bb
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index 517009253..7a36ece77 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -419,6 +419,11 @@ defmodule Pleroma.User do
     end
   end
 
+  def image_description(image, default \\ "")
+
+  def image_description(%{"name" => name}, _default), do: name
+  def image_description(_, default), do: default
+
   # Should probably be renamed or removed
   @spec ap_id(User.t()) :: String.t()
   def ap_id(%User{nickname: nickname}), do: "#{Endpoint.url()}/users/#{nickname}"
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index a2a94a0ff..df8795fe4 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -1542,16 +1542,23 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
 
   defp get_actor_url(_url), do: nil
 
-  defp normalize_image(%{"url" => url}) do
+  defp normalize_image(%{"url" => url} = data) do
     %{
       "type" => "Image",
       "url" => [%{"href" => url}]
     }
+    |> maybe_put_description(data)
   end
 
   defp normalize_image(urls) when is_list(urls), do: urls |> List.first() |> normalize_image()
   defp normalize_image(_), do: nil
 
+  defp maybe_put_description(map, %{"name" => description}) when is_binary(description) do
+    Map.put(map, "name", description)
+  end
+
+  defp maybe_put_description(map, _), do: map
+
   defp object_to_user_data(data, additional) do
     fields =
       data
diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex
index 937e4fd67..cd485ed64 100644
--- a/lib/pleroma/web/activity_pub/views/user_view.ex
+++ b/lib/pleroma/web/activity_pub/views/user_view.ex
@@ -129,8 +129,22 @@ defmodule Pleroma.Web.ActivityPub.UserView do
       "vcard:bday" => birthday,
       "webfinger" => "acct:#{User.full_nickname(user)}"
     }
-    |> Map.merge(maybe_make_image(&User.avatar_url/2, "icon", user))
-    |> Map.merge(maybe_make_image(&User.banner_url/2, "image", user))
+    |> Map.merge(
+      maybe_make_image(
+        &User.avatar_url/2,
+        User.image_description(user.avatar, nil),
+        "icon",
+        user
+      )
+    )
+    |> Map.merge(
+      maybe_make_image(
+        &User.banner_url/2,
+        User.image_description(user.banner, nil),
+        "image",
+        user
+      )
+    )
     |> Map.merge(Utils.make_json_ld_header())
   end
 
@@ -305,16 +319,24 @@ defmodule Pleroma.Web.ActivityPub.UserView do
     end
   end
 
-  defp maybe_make_image(func, key, user) do
+  defp maybe_make_image(func, description, key, user) do
     if image = func.(user, no_default: true) do
       %{
-        key => %{
-          "type" => "Image",
-          "url" => image
-        }
+        key =>
+          %{
+            "type" => "Image",
+            "url" => image
+          }
+          |> maybe_put_description(description)
       }
     else
       %{}
     end
   end
+
+  defp maybe_put_description(map, description) when is_binary(description) do
+    Map.put(map, "name", description)
+  end
+
+  defp maybe_put_description(map, _description), do: map
 end
diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex
index 7de6745d4..f6727d29d 100644
--- a/lib/pleroma/web/mastodon_api/views/account_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/account_view.ex
@@ -219,10 +219,10 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
 
     avatar = User.avatar_url(user) |> MediaProxy.url()
     avatar_static = User.avatar_url(user) |> MediaProxy.preview_url(static: true)
-    avatar_description = image_description(user.avatar)
+    avatar_description = User.image_description(user.avatar)
     header = User.banner_url(user) |> MediaProxy.url()
     header_static = User.banner_url(user) |> MediaProxy.preview_url(static: true)
-    header_description = image_description(user.banner)
+    header_description = User.image_description(user.banner)
 
     following_count =
       if !user.hide_follows_count or !user.hide_follows or self,
@@ -349,10 +349,6 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
 
   defp username_from_nickname(_), do: nil
 
-  defp image_description(%{"name" => name}), do: name
-
-  defp image_description(_), do: ""
-
   defp maybe_put_follow_requests_count(
          data,
          %User{id: user_id} = user,
diff --git a/test/pleroma/web/activity_pub/activity_pub_test.exs b/test/pleroma/web/activity_pub/activity_pub_test.exs
index b4f6fb68a..72222ae88 100644
--- a/test/pleroma/web/activity_pub/activity_pub_test.exs
+++ b/test/pleroma/web/activity_pub/activity_pub_test.exs
@@ -232,12 +232,14 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
 
       assert user.avatar == %{
                "type" => "Image",
-               "url" => [%{"href" => "https://jk.nipponalba.scot/images/profile.jpg"}]
+               "url" => [%{"href" => "https://jk.nipponalba.scot/images/profile.jpg"}],
+               "name" => "profile picture"
              }
 
       assert user.banner == %{
                "type" => "Image",
-               "url" => [%{"href" => "https://jk.nipponalba.scot/images/profile.jpg"}]
+               "url" => [%{"href" => "https://jk.nipponalba.scot/images/profile.jpg"}],
+               "name" => "profile picture"
              }
     end
 
@@ -432,6 +434,35 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
 
       assert user.birthday == ~D[2001-02-12]
     end
+
+    test "fetches avatar description" do
+      user_id = "https://example.com/users/marcin"
+
+      user_data =
+        "test/fixtures/users_mock/user.json"
+        |> File.read!()
+        |> String.replace("{{nickname}}", "marcin")
+        |> Jason.decode!()
+        |> Map.delete("featured")
+        |> Map.update("icon", %{}, fn image -> Map.put(image, "name", "image description") end)
+        |> Jason.encode!()
+
+      Tesla.Mock.mock(fn
+        %{
+          method: :get,
+          url: ^user_id
+        } ->
+          %Tesla.Env{
+            status: 200,
+            body: user_data,
+            headers: [{"content-type", "application/activity+json"}]
+          }
+      end)
+
+      {:ok, user} = ActivityPub.make_user_from_ap_id(user_id)
+
+      assert user.avatar["name"] == "image description"
+    end
   end
 
   test "it fetches the appropriate tag-restricted posts" do
diff --git a/test/pleroma/web/activity_pub/views/user_view_test.exs b/test/pleroma/web/activity_pub/views/user_view_test.exs
index 651e535ac..a32e72829 100644
--- a/test/pleroma/web/activity_pub/views/user_view_test.exs
+++ b/test/pleroma/web/activity_pub/views/user_view_test.exs
@@ -68,6 +68,23 @@ defmodule Pleroma.Web.ActivityPub.UserViewTest do
     result = UserView.render("user.json", %{user: user})
     assert result["icon"]["url"] == "https://someurl"
     assert result["image"]["url"] == "https://somebanner"
+
+    refute result["icon"]["name"]
+    refute result["image"]["name"]
+  end
+
+  test "Avatar has a description if the user set one" do
+    user =
+      insert(:user,
+        avatar: %{
+          "url" => [%{"href" => "https://someurl"}],
+          "name" => "a drawing of pleroma-tan using pleroma groups"
+        }
+      )
+
+    result = UserView.render("user.json", %{user: user})
+
+    assert result["icon"]["name"] == "a drawing of pleroma-tan using pleroma groups"
   end
 
   test "renders an invisible user with the invisible property set to true" do

From 5539fea3bb0d272b4cefc2b72755cb3cd285cc67 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Sat, 14 Sep 2024 20:03:26 -0400
Subject: [PATCH 101/212] LDAP: permit overriding the CA root

---
 changelog.d/ldap-ca.add                    |  1 +
 config/config.exs                          |  4 +++-
 docs/configuration/cheatsheet.md           |  1 +
 lib/pleroma/web/auth/ldap_authenticator.ex | 17 ++++++++++++++++-
 mix.exs                                    |  1 -
 5 files changed, 21 insertions(+), 3 deletions(-)
 create mode 100644 changelog.d/ldap-ca.add

diff --git a/changelog.d/ldap-ca.add b/changelog.d/ldap-ca.add
new file mode 100644
index 000000000..32ecbb5c0
--- /dev/null
+++ b/changelog.d/ldap-ca.add
@@ -0,0 +1 @@
+LDAP configuration now permits overriding the CA root certificate file for TLS validation.
diff --git a/config/config.exs b/config/config.exs
index 80a3b8d57..237928503 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -619,7 +619,9 @@ config :pleroma, :ldap,
   tls: System.get_env("LDAP_TLS") == "true",
   tlsopts: [],
   base: System.get_env("LDAP_BASE") || "dc=example,dc=com",
-  uid: System.get_env("LDAP_UID") || "cn"
+  uid: System.get_env("LDAP_UID") || "cn",
+  # defaults to CAStore's Mozilla roots
+  cacertfile: nil
 
 oauth_consumer_strategies =
   System.get_env("OAUTH_CONSUMER_STRATEGIES")
diff --git a/docs/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md
index 0b4e53b6f..4cbde696e 100644
--- a/docs/configuration/cheatsheet.md
+++ b/docs/configuration/cheatsheet.md
@@ -974,6 +974,7 @@ Pleroma account will be created with the same name as the LDAP user name.
 * `tlsopts`: additional TLS options
 * `base`: LDAP base, e.g. "dc=example,dc=com"
 * `uid`: LDAP attribute name to authenticate the user, e.g. when "cn", the filter will be "cn=username,base"
+* `cacertfile`: Path to alternate CA root certificates file
 
 Note, if your LDAP server is an Active Directory server the correct value is commonly `uid: "cn"`, but if you use an
 OpenLDAP server the value may be `uid: "uid"`.
diff --git a/lib/pleroma/web/auth/ldap_authenticator.ex b/lib/pleroma/web/auth/ldap_authenticator.ex
index d31f34747..7f2cd3d69 100644
--- a/lib/pleroma/web/auth/ldap_authenticator.ex
+++ b/lib/pleroma/web/auth/ldap_authenticator.ex
@@ -42,11 +42,14 @@ defmodule Pleroma.Web.Auth.LDAPAuthenticator do
     ssl = Keyword.get(ldap, :ssl, false)
     sslopts = Keyword.get(ldap, :sslopts, [])
     tlsopts = Keyword.get(ldap, :tlsopts, [])
+    cacertfile = Keyword.get(ldap, :cacertfile) || CAStore.file_path()
 
     options =
       [{:port, port}, {:ssl, ssl}, {:timeout, @connection_timeout}] ++
         if sslopts != [], do: [{:sslopts, sslopts}], else: []
 
+    cacerts = decode_certfile(cacertfile)
+
     case :eldap.open([to_charlist(host)], options) do
       {:ok, connection} ->
         try do
@@ -58,7 +61,7 @@ defmodule Pleroma.Web.Auth.LDAPAuthenticator do
                    Keyword.merge(
                      [
                        verify: :verify_peer,
-                       cacerts: :certifi.cacerts(),
+                       cacerts: cacerts,
                        customize_hostname_check: [
                          fqdn_fun: fn _ -> to_charlist(host) end
                        ]
@@ -147,4 +150,16 @@ defmodule Pleroma.Web.Auth.LDAPAuthenticator do
       error -> error
     end
   end
+
+  defp decode_certfile(file) do
+    with {:ok, data} <- File.read(file) do
+      data
+      |> :public_key.pem_decode()
+      |> Enum.map(fn {_, b, _} -> b end)
+    else
+      _ ->
+        Logger.error("Unable to read certfile: #{file}")
+        []
+    end
+  end
 end
diff --git a/mix.exs b/mix.exs
index 9a261547f..0d49a6b45 100644
--- a/mix.exs
+++ b/mix.exs
@@ -204,7 +204,6 @@ defmodule Pleroma.Mixfile do
       {:oban_live_dashboard, "~> 0.1.1"},
       {:multipart, "~> 0.4.0", optional: true},
       {:argon2_elixir, "~> 4.0"},
-      {:certifi, "~> 2.12"},
 
       ## dev & test
       {:phoenix_live_reload, "~> 1.3.3", only: :dev},

From af3bf8a4628c0b2981d69f624e3be298adc7dfe6 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Sun, 15 Sep 2024 13:56:16 -0400
Subject: [PATCH 102/212] Support implicit TLS connections

Update docs to clarify that the :ssl option is also for modern TLS, but the :tls option is only for STARTTLS

These options may benefit from being renamed but they match upstream terminology.
---
 changelog.d/ldaps.fix                      |  1 +
 docs/configuration/cheatsheet.md           |  4 +-
 lib/pleroma/web/auth/ldap_authenticator.ex | 50 ++++++++++++----------
 3 files changed, 31 insertions(+), 24 deletions(-)
 create mode 100644 changelog.d/ldaps.fix

diff --git a/changelog.d/ldaps.fix b/changelog.d/ldaps.fix
new file mode 100644
index 000000000..a1dc901ab
--- /dev/null
+++ b/changelog.d/ldaps.fix
@@ -0,0 +1 @@
+LDAPS connections (implicit TLS) are now supported.
diff --git a/docs/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md
index 4cbde696e..6a535e054 100644
--- a/docs/configuration/cheatsheet.md
+++ b/docs/configuration/cheatsheet.md
@@ -968,9 +968,9 @@ Pleroma account will be created with the same name as the LDAP user name.
 * `enabled`: enables LDAP authentication
 * `host`: LDAP server hostname
 * `port`: LDAP port, e.g. 389 or 636
-* `ssl`: true to use SSL, usually implies the port 636
+* `ssl`: true to use implicit SSL/TLS, usually port 636
 * `sslopts`: additional SSL options
-* `tls`: true to start TLS, usually implies the port 389
+* `tls`: true to use explicit TLS (STARTTLS), usually port 389
 * `tlsopts`: additional TLS options
 * `base`: LDAP base, e.g. "dc=example,dc=com"
 * `uid`: LDAP attribute name to authenticate the user, e.g. when "cn", the filter will be "cn=username,base"
diff --git a/lib/pleroma/web/auth/ldap_authenticator.ex b/lib/pleroma/web/auth/ldap_authenticator.ex
index 7f2cd3d69..18a4e81ee 100644
--- a/lib/pleroma/web/auth/ldap_authenticator.ex
+++ b/lib/pleroma/web/auth/ldap_authenticator.ex
@@ -40,34 +40,39 @@ defmodule Pleroma.Web.Auth.LDAPAuthenticator do
     host = Keyword.get(ldap, :host, "localhost")
     port = Keyword.get(ldap, :port, 389)
     ssl = Keyword.get(ldap, :ssl, false)
-    sslopts = Keyword.get(ldap, :sslopts, [])
-    tlsopts = Keyword.get(ldap, :tlsopts, [])
+    tls = Keyword.get(ldap, :tls, false)
     cacertfile = Keyword.get(ldap, :cacertfile) || CAStore.file_path()
 
-    options =
-      [{:port, port}, {:ssl, ssl}, {:timeout, @connection_timeout}] ++
-        if sslopts != [], do: [{:sslopts, sslopts}], else: []
+    default_secure_opts = [
+      verify: :verify_peer,
+      cacerts: decode_certfile(cacertfile),
+      customize_hostname_check: [
+        fqdn_fun: fn _ -> to_charlist(host) end
+      ]
+    ]
 
-    cacerts = decode_certfile(cacertfile)
+    sslopts = Keyword.merge(default_secure_opts, Keyword.get(ldap, :sslopts, []))
+    tlsopts = Keyword.merge(default_secure_opts, Keyword.get(ldap, :tlsopts, []))
+
+    # :sslopts can only be included in :eldap.open/2 when {ssl: true}
+    # or the connection will fail
+    options =
+      if ssl do
+        [{:port, port}, {:ssl, ssl}, {:sslopts, sslopts}, {:timeout, @connection_timeout}]
+      else
+        [{:port, port}, {:ssl, ssl}, {:timeout, @connection_timeout}]
+      end
 
     case :eldap.open([to_charlist(host)], options) do
       {:ok, connection} ->
-        try do
-          if Keyword.get(ldap, :tls, false) do
+        cond do
+          ssl ->
             :application.ensure_all_started(:ssl)
 
+          tls ->
             case :eldap.start_tls(
                    connection,
-                   Keyword.merge(
-                     [
-                       verify: :verify_peer,
-                       cacerts: cacerts,
-                       customize_hostname_check: [
-                         fqdn_fun: fn _ -> to_charlist(host) end
-                       ]
-                     ],
-                     tlsopts
-                   ),
+                   tlsopts,
                    @connection_timeout
                  ) do
               :ok ->
@@ -75,14 +80,15 @@ defmodule Pleroma.Web.Auth.LDAPAuthenticator do
 
               error ->
                 Logger.error("Could not start TLS: #{inspect(error)}")
+                :eldap.close(connection)
             end
-          end
 
-          bind_user(connection, ldap, name, password)
-        after
-          :eldap.close(connection)
+          true ->
+            :ok
         end
 
+        bind_user(connection, ldap, name, password)
+
       {:error, error} ->
         Logger.error("Could not open LDAP connection: #{inspect(error)}")
         {:error, {:ldap_connection_error, error}}

From 91d1d7260b7084f59ae42e7c4b46c7fb963fda96 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Sun, 15 Sep 2024 23:18:17 -0400
Subject: [PATCH 103/212] Retain the try do so an LDAP failure can fall back to
 local database.

This fixes tests but the automatic fallback may not be well documented behavior.
---
 lib/pleroma/web/auth/ldap_authenticator.ex | 42 ++++++++++++----------
 1 file changed, 23 insertions(+), 19 deletions(-)

diff --git a/lib/pleroma/web/auth/ldap_authenticator.ex b/lib/pleroma/web/auth/ldap_authenticator.ex
index 18a4e81ee..ad5bc9863 100644
--- a/lib/pleroma/web/auth/ldap_authenticator.ex
+++ b/lib/pleroma/web/auth/ldap_authenticator.ex
@@ -65,30 +65,34 @@ defmodule Pleroma.Web.Auth.LDAPAuthenticator do
 
     case :eldap.open([to_charlist(host)], options) do
       {:ok, connection} ->
-        cond do
-          ssl ->
-            :application.ensure_all_started(:ssl)
+        try do
+          cond do
+            ssl ->
+              :application.ensure_all_started(:ssl)
 
-          tls ->
-            case :eldap.start_tls(
-                   connection,
-                   tlsopts,
-                   @connection_timeout
-                 ) do
-              :ok ->
-                :ok
+            tls ->
+              case :eldap.start_tls(
+                     connection,
+                     tlsopts,
+                     @connection_timeout
+                   ) do
+                :ok ->
+                  :ok
 
-              error ->
-                Logger.error("Could not start TLS: #{inspect(error)}")
-                :eldap.close(connection)
-            end
+                error ->
+                  Logger.error("Could not start TLS: #{inspect(error)}")
+                  :eldap.close(connection)
+              end
 
-          true ->
-            :ok
+            true ->
+              :ok
+          end
+
+          bind_user(connection, ldap, name, password)
+        after
+          :eldap.close(connection)
         end
 
-        bind_user(connection, ldap, name, password)
-
       {:error, error} ->
         Logger.error("Could not open LDAP connection: #{inspect(error)}")
         {:error, {:ldap_connection_error, error}}

From e74e0089bf2943f925cbead14154f8b2fa207963 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= <git@mkljczk.pl>
Date: Mon, 16 Sep 2024 17:07:39 +0200
Subject: [PATCH 104/212] Repesct :restrict_unauthenticated for hashtag
 rss/atom feeds
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
---
 changelog.d/hashtag-feeds-restricted.add      |  1 +
 lib/pleroma/web/feed/tag_controller.ex        |  6 +-
 test/pleroma/web/feed/tag_controller_test.exs | 56 +++++++++++++++++++
 3 files changed, 61 insertions(+), 2 deletions(-)
 create mode 100644 changelog.d/hashtag-feeds-restricted.add

diff --git a/changelog.d/hashtag-feeds-restricted.add b/changelog.d/hashtag-feeds-restricted.add
new file mode 100644
index 000000000..accac9c9c
--- /dev/null
+++ b/changelog.d/hashtag-feeds-restricted.add
@@ -0,0 +1 @@
+Repesct :restrict_unauthenticated for hashtag rss/atom feeds
\ No newline at end of file
diff --git a/lib/pleroma/web/feed/tag_controller.ex b/lib/pleroma/web/feed/tag_controller.ex
index e60767327..02d639296 100644
--- a/lib/pleroma/web/feed/tag_controller.ex
+++ b/lib/pleroma/web/feed/tag_controller.ex
@@ -10,7 +10,7 @@ defmodule Pleroma.Web.Feed.TagController do
   alias Pleroma.Web.Feed.FeedView
 
   def feed(conn, params) do
-    if Config.get!([:instance, :public]) do
+    if not Config.restrict_unauthenticated_access?(:timelines, :local) do
       render_feed(conn, params)
     else
       render_error(conn, :not_found, "Not found")
@@ -18,10 +18,12 @@ defmodule Pleroma.Web.Feed.TagController do
   end
 
   defp render_feed(conn, %{"tag" => raw_tag} = params) do
+    local_only = Config.restrict_unauthenticated_access?(:timelines, :federated)
+
     {format, tag} = parse_tag(raw_tag)
 
     activities =
-      %{type: ["Create"], tag: tag}
+      %{type: ["Create"], tag: tag, local_only: local_only}
       |> Pleroma.Maps.put_if_present(:max_id, params["max_id"])
       |> ActivityPub.fetch_public_activities()
 
diff --git a/test/pleroma/web/feed/tag_controller_test.exs b/test/pleroma/web/feed/tag_controller_test.exs
index 7d196b228..662235f31 100644
--- a/test/pleroma/web/feed/tag_controller_test.exs
+++ b/test/pleroma/web/feed/tag_controller_test.exs
@@ -191,4 +191,60 @@ defmodule Pleroma.Web.Feed.TagControllerTest do
       |> response(404)
     end
   end
+
+  describe "restricted for unauthenticated" do
+    test "returns 404 when local timeline is disabled", %{conn: conn} do
+      clear_config([:restrict_unauthenticated, :timelines], %{local: true, federated: false})
+
+      conn
+      |> put_req_header("accept", "application/rss+xml")
+      |> get(tag_feed_path(conn, :feed, "pleromaart.rss"))
+      |> response(404)
+    end
+
+    test "returns local posts only when federated timeline is disabled", %{conn: conn} do
+      clear_config([:restrict_unauthenticated, :timelines], %{local: false, federated: true})
+
+      local_user = insert(:user)
+      remote_user = insert(:user, local: false)
+
+      local_note =
+        insert(:note,
+          user: local_user,
+          data: %{
+            "content" => "local post #PleromaArt",
+            "summary" => "",
+            "tag" => ["pleromaart"]
+          }
+        )
+
+      remote_note =
+        insert(:note,
+          user: remote_user,
+          data: %{
+            "content" => "remote post #PleromaArt",
+            "summary" => "",
+            "tag" => ["pleromaart"]
+          },
+          local: false
+        )
+
+      insert(:note_activity, user: local_user, note: local_note)
+      insert(:note_activity, user: remote_user, note: remote_note, local: false)
+
+      response =
+        conn
+        |> put_req_header("accept", "application/rss+xml")
+        |> get(tag_feed_path(conn, :feed, "pleromaart.rss"))
+        |> response(200)
+
+      xml = parse(response)
+
+      assert xpath(xml, ~x"//channel/title/text()") == ~c"#pleromaart"
+
+      assert xpath(xml, ~x"//channel/item/title/text()"l) == [
+               ~c"local post #PleromaArt"
+             ]
+    end
+  end
 end

From e59706c201bd71525c0a15008c3cb5dcdfb73289 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Mon, 16 Sep 2024 11:39:19 -0400
Subject: [PATCH 105/212] Reapply "Custom mix task to retry failed tests once
 in CI pipeline"

This reverts commit b281ad06de2de331450a5e319e3ba497071d4197.
---
 .gitlab-ci.yml                       |  2 +-
 changelog.d/fix-test-failures.skip   |  0
 lib/mix/tasks/pleroma/test_runner.ex | 25 +++++++++++++++++++++++++
 3 files changed, 26 insertions(+), 1 deletion(-)
 delete mode 100644 changelog.d/fix-test-failures.skip
 create mode 100644 lib/mix/tasks/pleroma/test_runner.ex

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 1e04dae76..76d1a4210 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -134,7 +134,7 @@ unit-testing-1.13.4-otp-25:
   script: &testing_script
     - mix ecto.create
     - mix ecto.migrate
-    - mix test --cover --preload-modules
+    - mix pleroma.test_runner --cover --preload-modules
   coverage: '/^Line total: ([^ ]*%)$/'
   artifacts:
     reports:
diff --git a/changelog.d/fix-test-failures.skip b/changelog.d/fix-test-failures.skip
deleted file mode 100644
index e69de29bb..000000000
diff --git a/lib/mix/tasks/pleroma/test_runner.ex b/lib/mix/tasks/pleroma/test_runner.ex
new file mode 100644
index 000000000..69fefb001
--- /dev/null
+++ b/lib/mix/tasks/pleroma/test_runner.ex
@@ -0,0 +1,25 @@
+defmodule Mix.Tasks.Pleroma.TestRunner do
+  @shortdoc "Retries tests once if they fail"
+
+  use Mix.Task
+
+  def run(args \\ []) do
+    case System.cmd("mix", ["test"] ++ args, into: IO.stream(:stdio, :line)) do
+      {_, 0} ->
+        :ok
+
+      _ ->
+        retry(args)
+    end
+  end
+
+  def retry(args) do
+    case System.cmd("mix", ["test", "--failed"] ++ args, into: IO.stream(:stdio, :line)) do
+      {_, 0} ->
+        :ok
+
+      _ ->
+        exit(1)
+    end
+  end
+end

From 9264b21907f5c6890694d6d611ade9b13433463a Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Mon, 16 Sep 2024 00:26:57 -0400
Subject: [PATCH 106/212] Pleroma.LDAP

This adds a GenServer which will keep an LDAP connection open and auto reconnect on failure with a 5 second wait between retries. Another benefit is this prevents parsing the Root CAs for every login attempt as we only need to do it once per connection.
---
 lib/pleroma/application.ex                 |   1 +
 lib/pleroma/ldap.ex                        | 233 +++++++++++++++++++++
 lib/pleroma/web/auth/ldap_authenticator.ex | 147 +------------
 3 files changed, 236 insertions(+), 145 deletions(-)
 create mode 100644 lib/pleroma/ldap.ex

diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex
index cb15dc1e9..3f199c002 100644
--- a/lib/pleroma/application.ex
+++ b/lib/pleroma/application.ex
@@ -94,6 +94,7 @@ defmodule Pleroma.Application do
     children =
       [
         Pleroma.PromEx,
+        Pleroma.LDAP,
         Pleroma.Repo,
         Config.TransferTask,
         Pleroma.Emoji,
diff --git a/lib/pleroma/ldap.ex b/lib/pleroma/ldap.ex
new file mode 100644
index 000000000..868932501
--- /dev/null
+++ b/lib/pleroma/ldap.ex
@@ -0,0 +1,233 @@
+defmodule Pleroma.LDAP do
+  use GenServer
+
+  require Logger
+
+  alias Pleroma.Config
+  alias Pleroma.User
+
+  import Pleroma.Web.Auth.Helpers, only: [fetch_user: 1]
+
+  @connection_timeout 10_000
+  @search_timeout 10_000
+
+  def start_link(_) do
+    GenServer.start_link(__MODULE__, [], name: __MODULE__)
+  end
+
+  @impl true
+  def init(state) do
+    case {Config.get(Pleroma.Web.Auth.Authenticator), Config.get([:ldap, :enabled])} do
+      {Pleroma.Web.Auth.LDAPAuthenticator, true} ->
+        {:ok, state, {:continue, :connect}}
+
+      {Pleroma.Web.Auth.LDAPAuthenticator, false} ->
+        Logger.error(
+          "LDAP Authenticator enabled but :pleroma, :ldap is not enabled. Auth will not work."
+        )
+
+        {:ok, state}
+
+      {_, true} ->
+        Logger.warning(
+          ":pleroma, :ldap is enabled but Pleroma.Web.Authenticator is not set to the LDAPAuthenticator. LDAP will not be used."
+        )
+
+        {:ok, state}
+    end
+  end
+
+  @impl true
+  def handle_continue(:connect, _state), do: do_handle_connect()
+
+  @impl true
+  def handle_info(:connect, _state), do: do_handle_connect()
+
+  def handle_info({:bind_after_reconnect, name, password, from}, state) do
+    result = bind_user(state[:connection], name, password)
+
+    GenServer.reply(from, result)
+
+    {:noreply, state}
+  end
+
+  defp do_handle_connect() do
+    state =
+      case connect() do
+        {:ok, connection} ->
+          :eldap.controlling_process(connection, self())
+          [connection: connection]
+
+        _ ->
+          Logger.error("Failed to connect to LDAP. Retrying in 5000ms")
+          Process.send_after(self(), :connect, 5_000)
+          []
+      end
+
+    {:noreply, state}
+  end
+
+  @impl true
+  def handle_call({:bind_user, name, password}, from, state) do
+    case bind_user(state[:connection], name, password) do
+      :needs_reconnect ->
+        Process.send(self(), {:bind_after_reconnect, name, password, from}, [])
+        {:noreply, state, {:continue, :connect}}
+
+      result ->
+        {:reply, result, state, :hibernate}
+    end
+  end
+
+  @impl true
+  def terminate(_, state) do
+    :eldap.close(state[:connection])
+
+    :ok
+  end
+
+  defp connect() do
+    ldap = Config.get(:ldap, [])
+    host = Keyword.get(ldap, :host, "localhost")
+    port = Keyword.get(ldap, :port, 389)
+    ssl = Keyword.get(ldap, :ssl, false)
+    tls = Keyword.get(ldap, :tls, false)
+    cacertfile = Keyword.get(ldap, :cacertfile) || CAStore.file_path()
+
+    default_secure_opts = [
+      verify: :verify_peer,
+      cacerts: decode_certfile(cacertfile),
+      customize_hostname_check: [
+        fqdn_fun: fn _ -> to_charlist(host) end
+      ]
+    ]
+
+    sslopts = Keyword.merge(default_secure_opts, Keyword.get(ldap, :sslopts, []))
+    tlsopts = Keyword.merge(default_secure_opts, Keyword.get(ldap, :tlsopts, []))
+
+    default_options = [{:port, port}, {:ssl, ssl}, {:timeout, @connection_timeout}]
+
+    # :sslopts can only be included in :eldap.open/2 when {ssl: true}
+    # or the connection will fail
+    options =
+      if ssl do
+        default_options ++ [{:sslopts, sslopts}]
+      else
+        default_options
+      end
+
+    case :eldap.open([to_charlist(host)], options) do
+      {:ok, connection} ->
+        try do
+          cond do
+            ssl ->
+              :application.ensure_all_started(:ssl)
+              {:ok, connection}
+
+            tls ->
+              case :eldap.start_tls(
+                     connection,
+                     tlsopts,
+                     @connection_timeout
+                   ) do
+                :ok ->
+                  {:ok, connection}
+
+                error ->
+                  Logger.error("Could not start TLS: #{inspect(error)}")
+                  :eldap.close(connection)
+              end
+
+            true ->
+              {:ok, :connection}
+          end
+        after
+          :ok
+        end
+
+      {:error, error} ->
+        Logger.error("Could not open LDAP connection: #{inspect(error)}")
+        {:error, {:ldap_connection_error, error}}
+    end
+  end
+
+  defp bind_user(connection, name, password) do
+    uid = Config.get([:ldap, :uid], "cn")
+    base = Config.get([:ldap, :base])
+
+    case :eldap.simple_bind(connection, "#{uid}=#{name},#{base}", password) do
+      :ok ->
+        case fetch_user(name) do
+          %User{} = user ->
+            user
+
+          _ ->
+            register_user(connection, base, uid, name)
+        end
+
+      # eldap does not inform us of socket closure
+      # until it is used
+      {:error, {:gen_tcp_error, :closed}} ->
+        :eldap.close(connection)
+        :needs_reconnect
+
+      error ->
+        Logger.error("Could not bind LDAP user #{name}: #{inspect(error)}")
+        {:error, {:ldap_bind_error, error}}
+    end
+  end
+
+  defp register_user(connection, base, uid, name) do
+    case :eldap.search(connection, [
+           {:base, to_charlist(base)},
+           {:filter, :eldap.equalityMatch(to_charlist(uid), to_charlist(name))},
+           {:scope, :eldap.wholeSubtree()},
+           {:timeout, @search_timeout}
+         ]) do
+      # The :eldap_search_result record structure changed in OTP 24.3 and added a controls field
+      # https://github.com/erlang/otp/pull/5538
+      {:ok, {:eldap_search_result, [{:eldap_entry, _object, attributes}], _referrals}} ->
+        try_register(name, attributes)
+
+      {:ok, {:eldap_search_result, [{:eldap_entry, _object, attributes}], _referrals, _controls}} ->
+        try_register(name, attributes)
+
+      error ->
+        Logger.error("Couldn't register user because LDAP search failed: #{inspect(error)}")
+        {:error, {:ldap_search_error, error}}
+    end
+  end
+
+  defp try_register(name, attributes) do
+    params = %{
+      name: name,
+      nickname: name,
+      password: nil
+    }
+
+    params =
+      case List.keyfind(attributes, ~c"mail", 0) do
+        {_, [mail]} -> Map.put_new(params, :email, :erlang.list_to_binary(mail))
+        _ -> params
+      end
+
+    changeset = User.register_changeset_ldap(%User{}, params)
+
+    case User.register(changeset) do
+      {:ok, user} -> user
+      error -> error
+    end
+  end
+
+  defp decode_certfile(file) do
+    with {:ok, data} <- File.read(file) do
+      data
+      |> :public_key.pem_decode()
+      |> Enum.map(fn {_, b, _} -> b end)
+    else
+      _ ->
+        Logger.error("Unable to read certfile: #{file}")
+        []
+    end
+  end
+end
diff --git a/lib/pleroma/web/auth/ldap_authenticator.ex b/lib/pleroma/web/auth/ldap_authenticator.ex
index ad5bc9863..c420c8bc3 100644
--- a/lib/pleroma/web/auth/ldap_authenticator.ex
+++ b/lib/pleroma/web/auth/ldap_authenticator.ex
@@ -5,16 +5,11 @@
 defmodule Pleroma.Web.Auth.LDAPAuthenticator do
   alias Pleroma.User
 
-  require Logger
-
-  import Pleroma.Web.Auth.Helpers, only: [fetch_credentials: 1, fetch_user: 1]
+  import Pleroma.Web.Auth.Helpers, only: [fetch_credentials: 1]
 
   @behaviour Pleroma.Web.Auth.Authenticator
   @base Pleroma.Web.Auth.PleromaAuthenticator
 
-  @connection_timeout 10_000
-  @search_timeout 10_000
-
   defdelegate get_registration(conn), to: @base
   defdelegate create_from_registration(conn, registration), to: @base
   defdelegate handle_error(conn, error), to: @base
@@ -24,7 +19,7 @@ defmodule Pleroma.Web.Auth.LDAPAuthenticator do
   def get_user(%Plug.Conn{} = conn) do
     with {:ldap, true} <- {:ldap, Pleroma.Config.get([:ldap, :enabled])},
          {:ok, {name, password}} <- fetch_credentials(conn),
-         %User{} = user <- ldap_user(name, password) do
+         %User{} = user <- GenServer.call(Pleroma.LDAP, {:bind_user, name, password}) do
       {:ok, user}
     else
       {:ldap, _} ->
@@ -34,142 +29,4 @@ defmodule Pleroma.Web.Auth.LDAPAuthenticator do
         error
     end
   end
-
-  defp ldap_user(name, password) do
-    ldap = Pleroma.Config.get(:ldap, [])
-    host = Keyword.get(ldap, :host, "localhost")
-    port = Keyword.get(ldap, :port, 389)
-    ssl = Keyword.get(ldap, :ssl, false)
-    tls = Keyword.get(ldap, :tls, false)
-    cacertfile = Keyword.get(ldap, :cacertfile) || CAStore.file_path()
-
-    default_secure_opts = [
-      verify: :verify_peer,
-      cacerts: decode_certfile(cacertfile),
-      customize_hostname_check: [
-        fqdn_fun: fn _ -> to_charlist(host) end
-      ]
-    ]
-
-    sslopts = Keyword.merge(default_secure_opts, Keyword.get(ldap, :sslopts, []))
-    tlsopts = Keyword.merge(default_secure_opts, Keyword.get(ldap, :tlsopts, []))
-
-    # :sslopts can only be included in :eldap.open/2 when {ssl: true}
-    # or the connection will fail
-    options =
-      if ssl do
-        [{:port, port}, {:ssl, ssl}, {:sslopts, sslopts}, {:timeout, @connection_timeout}]
-      else
-        [{:port, port}, {:ssl, ssl}, {:timeout, @connection_timeout}]
-      end
-
-    case :eldap.open([to_charlist(host)], options) do
-      {:ok, connection} ->
-        try do
-          cond do
-            ssl ->
-              :application.ensure_all_started(:ssl)
-
-            tls ->
-              case :eldap.start_tls(
-                     connection,
-                     tlsopts,
-                     @connection_timeout
-                   ) do
-                :ok ->
-                  :ok
-
-                error ->
-                  Logger.error("Could not start TLS: #{inspect(error)}")
-                  :eldap.close(connection)
-              end
-
-            true ->
-              :ok
-          end
-
-          bind_user(connection, ldap, name, password)
-        after
-          :eldap.close(connection)
-        end
-
-      {:error, error} ->
-        Logger.error("Could not open LDAP connection: #{inspect(error)}")
-        {:error, {:ldap_connection_error, error}}
-    end
-  end
-
-  defp bind_user(connection, ldap, name, password) do
-    uid = Keyword.get(ldap, :uid, "cn")
-    base = Keyword.get(ldap, :base)
-
-    case :eldap.simple_bind(connection, "#{uid}=#{name},#{base}", password) do
-      :ok ->
-        case fetch_user(name) do
-          %User{} = user ->
-            user
-
-          _ ->
-            register_user(connection, base, uid, name)
-        end
-
-      error ->
-        Logger.error("Could not bind LDAP user #{name}: #{inspect(error)}")
-        {:error, {:ldap_bind_error, error}}
-    end
-  end
-
-  defp register_user(connection, base, uid, name) do
-    case :eldap.search(connection, [
-           {:base, to_charlist(base)},
-           {:filter, :eldap.equalityMatch(to_charlist(uid), to_charlist(name))},
-           {:scope, :eldap.wholeSubtree()},
-           {:timeout, @search_timeout}
-         ]) do
-      # The :eldap_search_result record structure changed in OTP 24.3 and added a controls field
-      # https://github.com/erlang/otp/pull/5538
-      {:ok, {:eldap_search_result, [{:eldap_entry, _object, attributes}], _referrals}} ->
-        try_register(name, attributes)
-
-      {:ok, {:eldap_search_result, [{:eldap_entry, _object, attributes}], _referrals, _controls}} ->
-        try_register(name, attributes)
-
-      error ->
-        Logger.error("Couldn't register user because LDAP search failed: #{inspect(error)}")
-        {:error, {:ldap_search_error, error}}
-    end
-  end
-
-  defp try_register(name, attributes) do
-    params = %{
-      name: name,
-      nickname: name,
-      password: nil
-    }
-
-    params =
-      case List.keyfind(attributes, ~c"mail", 0) do
-        {_, [mail]} -> Map.put_new(params, :email, :erlang.list_to_binary(mail))
-        _ -> params
-      end
-
-    changeset = User.register_changeset_ldap(%User{}, params)
-
-    case User.register(changeset) do
-      {:ok, user} -> user
-      error -> error
-    end
-  end
-
-  defp decode_certfile(file) do
-    with {:ok, data} <- File.read(file) do
-      data
-      |> :public_key.pem_decode()
-      |> Enum.map(fn {_, b, _} -> b end)
-    else
-      _ ->
-        Logger.error("Unable to read certfile: #{file}")
-        []
-    end
-  end
 end

From ead287d623e83b8d9ffaa327b9edf96e046bfacd Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Mon, 16 Sep 2024 13:14:19 -0400
Subject: [PATCH 107/212] Credo

---
 lib/pleroma/ldap.ex | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/pleroma/ldap.ex b/lib/pleroma/ldap.ex
index 868932501..11544f0d9 100644
--- a/lib/pleroma/ldap.ex
+++ b/lib/pleroma/ldap.ex
@@ -51,7 +51,7 @@ defmodule Pleroma.LDAP do
     {:noreply, state}
   end
 
-  defp do_handle_connect() do
+  defp do_handle_connect do
     state =
       case connect() do
         {:ok, connection} ->
@@ -86,7 +86,7 @@ defmodule Pleroma.LDAP do
     :ok
   end
 
-  defp connect() do
+  defp connect do
     ldap = Config.get(:ldap, [])
     host = Keyword.get(ldap, :host, "localhost")
     port = Keyword.get(ldap, :port, 389)

From 7c04098dde0681f7ad299782bc09eaa9bc3a6bad Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Mon, 16 Sep 2024 16:15:53 -0400
Subject: [PATCH 108/212] Catchall for when LDAP is not enabled

---
 lib/pleroma/ldap.ex | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/lib/pleroma/ldap.ex b/lib/pleroma/ldap.ex
index 11544f0d9..ac819613e 100644
--- a/lib/pleroma/ldap.ex
+++ b/lib/pleroma/ldap.ex
@@ -34,6 +34,9 @@ defmodule Pleroma.LDAP do
         )
 
         {:ok, state}
+
+      _ ->
+        {:ok, state}
     end
   end
 

From 44b836c94c1059551fbc7564770001311d2d1e6a Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Mon, 16 Sep 2024 16:24:27 -0400
Subject: [PATCH 109/212] Fix tests

We do not need to mock and verify connections are closed as the new Pleroma.LDAP GenServer will handle managing the connection lifetime
---
 .../web/o_auth/ldap_authorization_test.exs    | 19 ++-----------------
 1 file changed, 2 insertions(+), 17 deletions(-)

diff --git a/test/pleroma/web/o_auth/ldap_authorization_test.exs b/test/pleroma/web/o_auth/ldap_authorization_test.exs
index 07ce2eed8..35b947fd0 100644
--- a/test/pleroma/web/o_auth/ldap_authorization_test.exs
+++ b/test/pleroma/web/o_auth/ldap_authorization_test.exs
@@ -28,11 +28,7 @@ defmodule Pleroma.Web.OAuth.LDAPAuthorizationTest do
       {:eldap, [],
        [
          open: fn [^host], [{:port, ^port}, {:ssl, false} | _] -> {:ok, self()} end,
-         simple_bind: fn _connection, _dn, ^password -> :ok end,
-         close: fn _connection ->
-           send(self(), :close_connection)
-           :ok
-         end
+         simple_bind: fn _connection, _dn, ^password -> :ok end
        ]}
     ] do
       conn =
@@ -50,7 +46,6 @@ defmodule Pleroma.Web.OAuth.LDAPAuthorizationTest do
       token = Repo.get_by(Token, token: token)
 
       assert token.user_id == user.id
-      assert_received :close_connection
     end
   end
 
@@ -72,10 +67,6 @@ defmodule Pleroma.Web.OAuth.LDAPAuthorizationTest do
          wholeSubtree: fn -> :ok end,
          search: fn _connection, _options ->
            {:ok, {:eldap_search_result, [{:eldap_entry, ~c"", []}], []}}
-         end,
-         close: fn _connection ->
-           send(self(), :close_connection)
-           :ok
          end
        ]}
     ] do
@@ -94,7 +85,6 @@ defmodule Pleroma.Web.OAuth.LDAPAuthorizationTest do
       token = Repo.get_by(Token, token: token) |> Repo.preload(:user)
 
       assert token.user.nickname == user.nickname
-      assert_received :close_connection
     end
   end
 
@@ -111,11 +101,7 @@ defmodule Pleroma.Web.OAuth.LDAPAuthorizationTest do
       {:eldap, [],
        [
          open: fn [^host], [{:port, ^port}, {:ssl, false} | _] -> {:ok, self()} end,
-         simple_bind: fn _connection, _dn, ^password -> {:error, :invalidCredentials} end,
-         close: fn _connection ->
-           send(self(), :close_connection)
-           :ok
-         end
+         simple_bind: fn _connection, _dn, ^password -> {:error, :invalidCredentials} end
        ]}
     ] do
       conn =
@@ -129,7 +115,6 @@ defmodule Pleroma.Web.OAuth.LDAPAuthorizationTest do
         })
 
       assert %{"error" => "Invalid credentials"} = json_response(conn, 400)
-      assert_received :close_connection
     end
   end
 end

From d82abf925ddbe8b98ba8191713115db50c38a0c0 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Mon, 16 Sep 2024 16:25:44 -0400
Subject: [PATCH 110/212] Ensure :cacertfile is configurable in ConfigDB

---
 config/description.exs | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/config/description.exs b/config/description.exs
index 15faecb38..ade47b7e0 100644
--- a/config/description.exs
+++ b/config/description.exs
@@ -2297,6 +2297,12 @@ config :pleroma, :config_description, [
         description:
           "LDAP attribute name to authenticate the user, e.g. when \"cn\", the filter will be \"cn=username,base\"",
         suggestions: ["cn"]
+      },
+      %{
+        key: :cacertfile,
+        label: "CACertfile",
+        type: :string,
+        description: "Path to CA certificate file"
       }
     ]
   },

From 65a7b387c35b4913b6109692a84bae80af8b9a96 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Mon, 16 Sep 2024 16:28:37 -0400
Subject: [PATCH 111/212] Require a reboot if LDAP configuration changes

---
 lib/pleroma/config/transfer_task.ex | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/lib/pleroma/config/transfer_task.ex b/lib/pleroma/config/transfer_task.ex
index ffc95f144..140dd7711 100644
--- a/lib/pleroma/config/transfer_task.ex
+++ b/lib/pleroma/config/transfer_task.ex
@@ -22,7 +22,8 @@ defmodule Pleroma.Config.TransferTask do
       {:pleroma, :markup},
       {:pleroma, :streamer},
       {:pleroma, :pools},
-      {:pleroma, :connections_pool}
+      {:pleroma, :connections_pool},
+      {:pleroma, :ldap}
     ]
 
   defp reboot_time_subkeys,

From 123093a1868b25f101dfc4b02895c22a0daf5733 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Tue, 17 Sep 2024 13:07:26 -0400
Subject: [PATCH 112/212] Ensure :ssl is started before we attempt to make the
 LDAP connection

---
 lib/pleroma/ldap.ex | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/lib/pleroma/ldap.ex b/lib/pleroma/ldap.ex
index ac819613e..042a4daa2 100644
--- a/lib/pleroma/ldap.ex
+++ b/lib/pleroma/ldap.ex
@@ -97,6 +97,8 @@ defmodule Pleroma.LDAP do
     tls = Keyword.get(ldap, :tls, false)
     cacertfile = Keyword.get(ldap, :cacertfile) || CAStore.file_path()
 
+    if ssl, do: Application.ensure_all_started(:ssl)
+
     default_secure_opts = [
       verify: :verify_peer,
       cacerts: decode_certfile(cacertfile),
@@ -123,10 +125,6 @@ defmodule Pleroma.LDAP do
       {:ok, connection} ->
         try do
           cond do
-            ssl ->
-              :application.ensure_all_started(:ssl)
-              {:ok, connection}
-
             tls ->
               case :eldap.start_tls(
                      connection,

From d0ee899ab94788e37e6ac3c43342017d1b27903a Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Tue, 17 Sep 2024 13:14:09 -0400
Subject: [PATCH 113/212] Only close connection if it is not nil

---
 lib/pleroma/ldap.ex | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/lib/pleroma/ldap.ex b/lib/pleroma/ldap.ex
index 042a4daa2..3df20fe09 100644
--- a/lib/pleroma/ldap.ex
+++ b/lib/pleroma/ldap.ex
@@ -84,7 +84,11 @@ defmodule Pleroma.LDAP do
 
   @impl true
   def terminate(_, state) do
-    :eldap.close(state[:connection])
+    connection = Keyword.get(state, :connection)
+
+    if not is_nil(connection) do
+      :eldap.close(connection)
+    end
 
     :ok
   end

From 164ffbcab822eda4c28f912082b6a7a3ec64a7e5 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Tue, 17 Sep 2024 13:17:40 -0400
Subject: [PATCH 114/212] Fix return value when not doing STARTTLS

---
 lib/pleroma/ldap.ex | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/pleroma/ldap.ex b/lib/pleroma/ldap.ex
index 3df20fe09..6be2188f4 100644
--- a/lib/pleroma/ldap.ex
+++ b/lib/pleroma/ldap.ex
@@ -144,7 +144,7 @@ defmodule Pleroma.LDAP do
               end
 
             true ->
-              {:ok, :connection}
+              {:ok, connection}
           end
         after
           :ok

From a1972d57e30f41e5173d61c0d0936685738c560d Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Tue, 17 Sep 2024 13:19:54 -0400
Subject: [PATCH 115/212] Link the eldap connection process

Ensure if LDAP GenServer crashes it gets cleaned up, and we should crash and restart if somehow the eldap connection process crashes unexpectedly as we can't seem to receive any DOWN messages from it, etc.
---
 lib/pleroma/ldap.ex | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/pleroma/ldap.ex b/lib/pleroma/ldap.ex
index 6be2188f4..0723cd094 100644
--- a/lib/pleroma/ldap.ex
+++ b/lib/pleroma/ldap.ex
@@ -59,6 +59,7 @@ defmodule Pleroma.LDAP do
       case connect() do
         {:ok, connection} ->
           :eldap.controlling_process(connection, self())
+          Process.link(connection)
           [connection: connection]
 
         _ ->

From 14a9663f1abe49b8f4f4f719fa2f4db3a5dd81b7 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Tue, 17 Sep 2024 13:28:42 -0400
Subject: [PATCH 116/212] Remove cacertfile as child of SSL and TLS options

We need to pass the cacerts (list of charlist encoded certs) not cacertfile, so our new cacertfile setting handles this for us.
---
 config/description.exs | 16 ++--------------
 1 file changed, 2 insertions(+), 14 deletions(-)

diff --git a/config/description.exs b/config/description.exs
index ade47b7e0..5062842f0 100644
--- a/config/description.exs
+++ b/config/description.exs
@@ -2241,14 +2241,8 @@ config :pleroma, :config_description, [
         label: "SSL options",
         type: :keyword,
         description: "Additional SSL options",
-        suggestions: [cacertfile: "path/to/file/with/PEM/cacerts", verify: :verify_peer],
+        suggestions: [verify: :verify_peer],
         children: [
-          %{
-            key: :cacertfile,
-            type: :string,
-            description: "Path to file with PEM encoded cacerts",
-            suggestions: ["path/to/file/with/PEM/cacerts"]
-          },
           %{
             key: :verify,
             type: :atom,
@@ -2268,14 +2262,8 @@ config :pleroma, :config_description, [
         label: "TLS options",
         type: :keyword,
         description: "Additional TLS options",
-        suggestions: [cacertfile: "path/to/file/with/PEM/cacerts", verify: :verify_peer],
+        suggestions: [verify: :verify_peer],
         children: [
-          %{
-            key: :cacertfile,
-            type: :string,
-            description: "Path to file with PEM encoded cacerts",
-            suggestions: ["path/to/file/with/PEM/cacerts"]
-          },
           %{
             key: :verify,
             type: :atom,

From 363b462c54c454e847072869db09f8f4d5da4426 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Tue, 17 Sep 2024 13:36:46 -0400
Subject: [PATCH 117/212] Make the email attribute configurable

While here, fix the System.get_env usage to use the normal fallback value method and improve the UID label description
---
 config/config.exs      | 11 ++++++-----
 config/description.exs |  9 ++++++++-
 lib/pleroma/ldap.ex    |  4 +++-
 3 files changed, 17 insertions(+), 7 deletions(-)

diff --git a/config/config.exs b/config/config.exs
index f53a083d0..47ddfac5a 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -612,16 +612,17 @@ config :pleroma, Pleroma.Formatter,
 
 config :pleroma, :ldap,
   enabled: System.get_env("LDAP_ENABLED") == "true",
-  host: System.get_env("LDAP_HOST") || "localhost",
-  port: String.to_integer(System.get_env("LDAP_PORT") || "389"),
+  host: System.get_env("LDAP_HOST", "localhost"),
+  port: String.to_integer(System.get_env("LDAP_PORT", "389")),
   ssl: System.get_env("LDAP_SSL") == "true",
   sslopts: [],
   tls: System.get_env("LDAP_TLS") == "true",
   tlsopts: [],
-  base: System.get_env("LDAP_BASE") || "dc=example,dc=com",
-  uid: System.get_env("LDAP_UID") || "cn",
+  base: System.get_env("LDAP_BASE", "dc=example,dc=com"),
+  uid: System.get_env("LDAP_UID", "cn"),
   # defaults to CAStore's Mozilla roots
-  cacertfile: nil
+  cacertfile: System.get_env("LDAP_CACERTFILE", nil),
+  mail: System.get_env("LDAP_MAIL", "mail")
 
 oauth_consumer_strategies =
   System.get_env("OAUTH_CONSUMER_STRATEGIES")
diff --git a/config/description.exs b/config/description.exs
index 5062842f0..e85ec0ff8 100644
--- a/config/description.exs
+++ b/config/description.exs
@@ -2280,7 +2280,7 @@ config :pleroma, :config_description, [
       },
       %{
         key: :uid,
-        label: "UID",
+        label: "UID Attribute",
         type: :string,
         description:
           "LDAP attribute name to authenticate the user, e.g. when \"cn\", the filter will be \"cn=username,base\"",
@@ -2291,6 +2291,13 @@ config :pleroma, :config_description, [
         label: "CACertfile",
         type: :string,
         description: "Path to CA certificate file"
+      },
+      %{
+        key: :mail,
+        label: "Mail Attribute",
+        type: :string,
+        description: "LDAP attribute name to use as the email address when automatically registering the user on first login",
+        suggestions: ["mail"]
       }
     ]
   },
diff --git a/lib/pleroma/ldap.ex b/lib/pleroma/ldap.ex
index 0723cd094..8e9c591b2 100644
--- a/lib/pleroma/ldap.ex
+++ b/lib/pleroma/ldap.ex
@@ -205,6 +205,8 @@ defmodule Pleroma.LDAP do
   end
 
   defp try_register(name, attributes) do
+    mail_attribute = Config.get([:ldap, :mail])
+
     params = %{
       name: name,
       nickname: name,
@@ -212,7 +214,7 @@ defmodule Pleroma.LDAP do
     }
 
     params =
-      case List.keyfind(attributes, ~c"mail", 0) do
+      case List.keyfind(attributes, to_charlist(mail_attribute), 0) do
         {_, [mail]} -> Map.put_new(params, :email, :erlang.list_to_binary(mail))
         _ -> params
       end

From 21bf229731f27426564140650397e51ba4bb4b93 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Tue, 17 Sep 2024 13:43:21 -0400
Subject: [PATCH 118/212] Reduce LDAP timeouts

10 seconds is way too long for any login attempt or search result. LDAP should always be fast.
---
 lib/pleroma/ldap.ex | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/pleroma/ldap.ex b/lib/pleroma/ldap.ex
index 8e9c591b2..33c9cff29 100644
--- a/lib/pleroma/ldap.ex
+++ b/lib/pleroma/ldap.ex
@@ -8,8 +8,8 @@ defmodule Pleroma.LDAP do
 
   import Pleroma.Web.Auth.Helpers, only: [fetch_user: 1]
 
-  @connection_timeout 10_000
-  @search_timeout 10_000
+  @connection_timeout 2_000
+  @search_timeout 2_000
 
   def start_link(_) do
     GenServer.start_link(__MODULE__, [], name: __MODULE__)

From 1d123832da6a2b8c67f34006b4ea05e0be86e366 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Tue, 17 Sep 2024 13:46:49 -0400
Subject: [PATCH 119/212] Formatting

---
 config/description.exs | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/config/description.exs b/config/description.exs
index e85ec0ff8..47f4771eb 100644
--- a/config/description.exs
+++ b/config/description.exs
@@ -2296,7 +2296,8 @@ config :pleroma, :config_description, [
         key: :mail,
         label: "Mail Attribute",
         type: :string,
-        description: "LDAP attribute name to use as the email address when automatically registering the user on first login",
+        description:
+          "LDAP attribute name to use as the email address when automatically registering the user on first login",
         suggestions: ["mail"]
       }
     ]

From ea63533cf28be8218a27806b1f6430f0c1ca4a01 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Tue, 17 Sep 2024 13:46:56 -0400
Subject: [PATCH 120/212] Change :connection to :handle to match upstream
 nomenclature

---
 lib/pleroma/ldap.ex | 40 ++++++++++++++++++++--------------------
 1 file changed, 20 insertions(+), 20 deletions(-)

diff --git a/lib/pleroma/ldap.ex b/lib/pleroma/ldap.ex
index 33c9cff29..b357b371a 100644
--- a/lib/pleroma/ldap.ex
+++ b/lib/pleroma/ldap.ex
@@ -47,7 +47,7 @@ defmodule Pleroma.LDAP do
   def handle_info(:connect, _state), do: do_handle_connect()
 
   def handle_info({:bind_after_reconnect, name, password, from}, state) do
-    result = bind_user(state[:connection], name, password)
+    result = bind_user(state[:handle], name, password)
 
     GenServer.reply(from, result)
 
@@ -57,10 +57,10 @@ defmodule Pleroma.LDAP do
   defp do_handle_connect do
     state =
       case connect() do
-        {:ok, connection} ->
-          :eldap.controlling_process(connection, self())
-          Process.link(connection)
-          [connection: connection]
+        {:ok, handle} ->
+          :eldap.controlling_process(handle, self())
+          Process.link(handle)
+          [handle: handle]
 
         _ ->
           Logger.error("Failed to connect to LDAP. Retrying in 5000ms")
@@ -73,7 +73,7 @@ defmodule Pleroma.LDAP do
 
   @impl true
   def handle_call({:bind_user, name, password}, from, state) do
-    case bind_user(state[:connection], name, password) do
+    case bind_user(state[:handle], name, password) do
       :needs_reconnect ->
         Process.send(self(), {:bind_after_reconnect, name, password, from}, [])
         {:noreply, state, {:continue, :connect}}
@@ -85,10 +85,10 @@ defmodule Pleroma.LDAP do
 
   @impl true
   def terminate(_, state) do
-    connection = Keyword.get(state, :connection)
+    handle = Keyword.get(state, :handle)
 
-    if not is_nil(connection) do
-      :eldap.close(connection)
+    if not is_nil(handle) do
+      :eldap.close(handle)
     end
 
     :ok
@@ -127,25 +127,25 @@ defmodule Pleroma.LDAP do
       end
 
     case :eldap.open([to_charlist(host)], options) do
-      {:ok, connection} ->
+      {:ok, handle} ->
         try do
           cond do
             tls ->
               case :eldap.start_tls(
-                     connection,
+                     handle,
                      tlsopts,
                      @connection_timeout
                    ) do
                 :ok ->
-                  {:ok, connection}
+                  {:ok, handle}
 
                 error ->
                   Logger.error("Could not start TLS: #{inspect(error)}")
-                  :eldap.close(connection)
+                  :eldap.close(handle)
               end
 
             true ->
-              {:ok, connection}
+              {:ok, handle}
           end
         after
           :ok
@@ -157,24 +157,24 @@ defmodule Pleroma.LDAP do
     end
   end
 
-  defp bind_user(connection, name, password) do
+  defp bind_user(handle, name, password) do
     uid = Config.get([:ldap, :uid], "cn")
     base = Config.get([:ldap, :base])
 
-    case :eldap.simple_bind(connection, "#{uid}=#{name},#{base}", password) do
+    case :eldap.simple_bind(handle, "#{uid}=#{name},#{base}", password) do
       :ok ->
         case fetch_user(name) do
           %User{} = user ->
             user
 
           _ ->
-            register_user(connection, base, uid, name)
+            register_user(handle, base, uid, name)
         end
 
       # eldap does not inform us of socket closure
       # until it is used
       {:error, {:gen_tcp_error, :closed}} ->
-        :eldap.close(connection)
+        :eldap.close(handle)
         :needs_reconnect
 
       error ->
@@ -183,8 +183,8 @@ defmodule Pleroma.LDAP do
     end
   end
 
-  defp register_user(connection, base, uid, name) do
-    case :eldap.search(connection, [
+  defp register_user(handle, base, uid, name) do
+    case :eldap.search(handle, [
            {:base, to_charlist(base)},
            {:filter, :eldap.equalityMatch(to_charlist(uid), to_charlist(name))},
            {:scope, :eldap.wholeSubtree()},

From 2b482e34ebf5aee49350d8198e6fade8820b3834 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Tue, 17 Sep 2024 13:54:57 -0400
Subject: [PATCH 121/212] Improve matching on bind errors

---
 lib/pleroma/ldap.ex | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/pleroma/ldap.ex b/lib/pleroma/ldap.ex
index b357b371a..cd84dee02 100644
--- a/lib/pleroma/ldap.ex
+++ b/lib/pleroma/ldap.ex
@@ -177,9 +177,9 @@ defmodule Pleroma.LDAP do
         :eldap.close(handle)
         :needs_reconnect
 
-      error ->
+      {:error, error} = e ->
         Logger.error("Could not bind LDAP user #{name}: #{inspect(error)}")
-        {:error, {:ldap_bind_error, error}}
+        e
     end
   end
 

From 35ddb1d2c8a53dcb54178522811242ef40a63211 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Tue, 17 Sep 2024 13:57:10 -0400
Subject: [PATCH 122/212] LDAP genserver changelog

---
 changelog.d/ldap-refactor.change | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 changelog.d/ldap-refactor.change

diff --git a/changelog.d/ldap-refactor.change b/changelog.d/ldap-refactor.change
new file mode 100644
index 000000000..1510eea6a
--- /dev/null
+++ b/changelog.d/ldap-refactor.change
@@ -0,0 +1 @@
+LDAP authentication has been refactored to operate as a GenServer process which will maintain an active connection to the LDAP server.

From 1de5208a9e90485be38ac0d00088f18c5b36390a Mon Sep 17 00:00:00 2001
From: Mint <mint@plagu.ee>
Date: Tue, 17 Sep 2024 21:48:37 +0300
Subject: [PATCH 123/212] Cheatsheet: add Mua mail adapter config

---
 docs/configuration/cheatsheet.md | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/docs/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md
index 0b4e53b6f..ba41fe84d 100644
--- a/docs/configuration/cheatsheet.md
+++ b/docs/configuration/cheatsheet.md
@@ -742,6 +742,21 @@ config :pleroma, Pleroma.Emails.Mailer,
   auth: :always
 ```
 
+An example for Mua adapter:
+
+```elixir
+config :pleroma, Pleroma.Emails.Mailer,
+  enabled: true,
+  adapter: Swoosh.Adapters.Mua,
+  relay: "mail.example.com",
+  port: 465,
+  auth: [
+    username: "YOUR_USERNAME@domain.tld",
+    password: "YOUR_SMTP_PASSWORD"
+  ],
+  protocol: :ssl
+```
+
 ### :email_notifications
 
 Email notifications settings.

From 73204c1bca740dbca5c780891fc720ac728c11a6 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Wed, 18 Sep 2024 11:16:16 -0400
Subject: [PATCH 124/212] LDAP: fix compile warning

Sometimes the compile will emit the following warning, so we'll just avoid it by making it call a function in the LDAP module which will never have this problem.

warning: :GenServer.call/2 is undefined (module :GenServer is not available or is yet to be defined)
---
 changelog.d/ldap-warning.skip              | 0
 lib/pleroma/ldap.ex                        | 4 ++++
 lib/pleroma/web/auth/ldap_authenticator.ex | 3 ++-
 3 files changed, 6 insertions(+), 1 deletion(-)
 create mode 100644 changelog.d/ldap-warning.skip

diff --git a/changelog.d/ldap-warning.skip b/changelog.d/ldap-warning.skip
new file mode 100644
index 000000000..e69de29bb
diff --git a/lib/pleroma/ldap.ex b/lib/pleroma/ldap.ex
index cd84dee02..46a2d0c17 100644
--- a/lib/pleroma/ldap.ex
+++ b/lib/pleroma/ldap.ex
@@ -94,6 +94,10 @@ defmodule Pleroma.LDAP do
     :ok
   end
 
+  def bind_user(name, password) do
+    GenServer.call(__MODULE__, {:bind_user, name, password})
+  end
+
   defp connect do
     ldap = Config.get(:ldap, [])
     host = Keyword.get(ldap, :host, "localhost")
diff --git a/lib/pleroma/web/auth/ldap_authenticator.ex b/lib/pleroma/web/auth/ldap_authenticator.ex
index c420c8bc3..7eb06183d 100644
--- a/lib/pleroma/web/auth/ldap_authenticator.ex
+++ b/lib/pleroma/web/auth/ldap_authenticator.ex
@@ -3,6 +3,7 @@
 # SPDX-License-Identifier: AGPL-3.0-only
 
 defmodule Pleroma.Web.Auth.LDAPAuthenticator do
+  alias Pleroma.LDAP
   alias Pleroma.User
 
   import Pleroma.Web.Auth.Helpers, only: [fetch_credentials: 1]
@@ -19,7 +20,7 @@ defmodule Pleroma.Web.Auth.LDAPAuthenticator do
   def get_user(%Plug.Conn{} = conn) do
     with {:ldap, true} <- {:ldap, Pleroma.Config.get([:ldap, :enabled])},
          {:ok, {name, password}} <- fetch_credentials(conn),
-         %User{} = user <- GenServer.call(Pleroma.LDAP, {:bind_user, name, password}) do
+         %User{} = user <- LDAP.bind_user(name, password) do
       {:ok, user}
     else
       {:ldap, _} ->

From ecd1b8393befe91175872af3db67a5c01f10eaf2 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Wed, 18 Sep 2024 12:07:52 -0400
Subject: [PATCH 125/212] Oban: update to 2.18.3

This release includes the fix which should prevent the scenario where Postgrex crashes can cause Oban to get into a state where it will stop processing jobs.
---
 changelog.d/oban-update.change | 1 +
 mix.lock                       | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)
 create mode 100644 changelog.d/oban-update.change

diff --git a/changelog.d/oban-update.change b/changelog.d/oban-update.change
new file mode 100644
index 000000000..48a54ed2d
--- /dev/null
+++ b/changelog.d/oban-update.change
@@ -0,0 +1 @@
+Oban updated to 2.18.3
diff --git a/mix.lock b/mix.lock
index 2cf44862b..421f99ec0 100644
--- a/mix.lock
+++ b/mix.lock
@@ -92,7 +92,7 @@
   "nimble_parsec": {:hex, :nimble_parsec, "0.6.0", "32111b3bf39137144abd7ba1cce0914533b2d16ef35e8abc5ec8be6122944263", [:mix], [], "hexpm", "27eac315a94909d4dc68bc07a4a83e06c8379237c5ea528a9acff4ca1c873c52"},
   "nimble_pool": {:hex, :nimble_pool, "0.2.6", "91f2f4c357da4c4a0a548286c84a3a28004f68f05609b4534526871a22053cde", [:mix], [], "hexpm", "1c715055095d3f2705c4e236c18b618420a35490da94149ff8b580a2144f653f"},
   "nodex": {:git, "https://git.pleroma.social/pleroma/nodex", "cb6730f943cfc6aad674c92161be23a8411f15d1", [ref: "cb6730f943cfc6aad674c92161be23a8411f15d1"]},
-  "oban": {:hex, :oban, "2.18.2", "583e78965ee15263ac968e38c983bad169ae55eadaa8e1e39912562badff93ba", [:mix], [{:ecto_sql, "~> 3.10", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:ecto_sqlite3, "~> 0.9", [hex: :ecto_sqlite3, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9dd25fd35883a91ed995e9fe516e479344d3a8623dfe2b8c3fc8e5be0228ec3a"},
+  "oban": {:hex, :oban, "2.18.3", "1608c04f8856c108555c379f2f56bc0759149d35fa9d3b825cb8a6769f8ae926", [:mix], [{:ecto_sql, "~> 3.10", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:ecto_sqlite3, "~> 0.9", [hex: :ecto_sqlite3, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "36ca6ca84ef6518f9c2c759ea88efd438a3c81d667ba23b02b062a0aa785475e"},
   "oban_live_dashboard": {:hex, :oban_live_dashboard, "0.1.1", "8aa4ceaf381c818f7d5c8185cc59942b8ac82ef0cf559881aacf8d3f8ac7bdd3", [:mix], [{:oban, "~> 2.15", [hex: :oban, repo: "hexpm", optional: false]}, {:phoenix_live_dashboard, "~> 0.7", [hex: :phoenix_live_dashboard, repo: "hexpm", optional: false]}], "hexpm", "16dc4ce9c9a95aa2e655e35ed4e675652994a8def61731a18af85e230e1caa63"},
   "octo_fetch": {:hex, :octo_fetch, "0.4.0", "074b5ecbc08be10b05b27e9db08bc20a3060142769436242702931c418695b19", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "cf8be6f40cd519d7000bb4e84adcf661c32e59369ca2827c4e20042eda7a7fc6"},
   "open_api_spex": {:hex, :open_api_spex, "3.18.2", "8c855e83bfe8bf81603d919d6e892541eafece3720f34d1700b58024dadde247", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 3.0 or ~> 4.0 or ~> 5.0", [hex: :poison, repo: "hexpm", optional: true]}, {:ymlr, "~> 2.0 or ~> 3.0 or ~> 4.0", [hex: :ymlr, repo: "hexpm", optional: true]}], "hexpm", "aa3e6dcfc0ad6a02596b2172662da21c9dd848dac145ea9e603f54e3d81b8d2b"},

From f00545d85bd601734cdbbc28454f33541dbf530d Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Wed, 18 Sep 2024 13:14:17 -0400
Subject: [PATCH 126/212] Elixir 1.14 and Erlang/OTP 23 is now the minimum
 supported release

---
 .gitlab-ci.yml                                 | 8 ++++----
 changelog.d/elixir.change                      | 1 +
 docs/installation/debian_based_jp.md           | 2 +-
 docs/installation/generic_dependencies.include | 4 ++--
 mix.exs                                        | 2 +-
 5 files changed, 9 insertions(+), 8 deletions(-)
 create mode 100644 changelog.d/elixir.change

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 76d1a4210..39947c75e 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,8 +1,8 @@
-image: git.pleroma.social:5050/pleroma/pleroma/ci-base:elixir-1.13.4-otp-25
+image: git.pleroma.social:5050/pleroma/pleroma/ci-base:elixir-1.14.5-otp-25
 
 variables: &global_variables
   # Only used for the release
-  ELIXIR_VER: 1.13.4
+  ELIXIR_VER: 1.14.5
   POSTGRES_DB: pleroma_test
   POSTGRES_USER: postgres
   POSTGRES_PASSWORD: postgres
@@ -71,7 +71,7 @@ check-changelog:
   tags:
     - amd64
 
-build-1.13.4-otp-25:
+build-1.14.5-otp-25:
   extends:
   - .build_changes_policy
   - .using-ci-base
@@ -119,7 +119,7 @@ benchmark:
     - mix ecto.migrate
     - mix pleroma.load_testing
 
-unit-testing-1.13.4-otp-25:
+unit-testing-1.14.5-otp-25:
   extends:
   - .build_changes_policy
   - .using-ci-base
diff --git a/changelog.d/elixir.change b/changelog.d/elixir.change
new file mode 100644
index 000000000..779c01562
--- /dev/null
+++ b/changelog.d/elixir.change
@@ -0,0 +1 @@
+Elixir 1.14 and Erlang/OTP 23 is now the minimum supported release
diff --git a/docs/installation/debian_based_jp.md b/docs/installation/debian_based_jp.md
index 5a0823a63..0817934ff 100644
--- a/docs/installation/debian_based_jp.md
+++ b/docs/installation/debian_based_jp.md
@@ -14,7 +14,7 @@ Note: This article is potentially outdated because at this time we may not have
 
 - PostgreSQL 11.0以上 (Ubuntu16.04では9.5しか提供されていないので,[](https://www.postgresql.org/download/linux/ubuntu/)こちらから新しいバージョンを入手してください)
 - `postgresql-contrib` 11.0以上 (同上)
-- Elixir 1.13 以上 ([Debianのリポジトリからインストールしないこと!!! ここからインストールすること!](https://elixir-lang.org/install.html#unix-and-unix-like)。または [asdf](https://github.com/asdf-vm/asdf) をpleromaユーザーでインストールしてください)
+- Elixir 1.14 以上 ([Debianのリポジトリからインストールしないこと!!! ここからインストールすること!](https://elixir-lang.org/install.html#unix-and-unix-like)。または [asdf](https://github.com/asdf-vm/asdf) をpleromaユーザーでインストールしてください)
 - `erlang-dev`
 - `erlang-nox`
 - `git`
diff --git a/docs/installation/generic_dependencies.include b/docs/installation/generic_dependencies.include
index bdb7f94d3..9f07f62c6 100644
--- a/docs/installation/generic_dependencies.include
+++ b/docs/installation/generic_dependencies.include
@@ -1,8 +1,8 @@
 ## Required dependencies
 
 * PostgreSQL >=11.0
-* Elixir >=1.13.0 <1.17
-* Erlang OTP >=22.2.0 (supported: <27)
+* Elixir >=1.14.0 <1.17
+* Erlang OTP >=23.0.0 (supported: <27)
 * git
 * file / libmagic
 * gcc or clang
diff --git a/mix.exs b/mix.exs
index ceae5c26d..89ec5e831 100644
--- a/mix.exs
+++ b/mix.exs
@@ -5,7 +5,7 @@ defmodule Pleroma.Mixfile do
     [
       app: :pleroma,
       version: version("2.7.0"),
-      elixir: "~> 1.13",
+      elixir: "~> 1.14",
       elixirc_paths: elixirc_paths(Mix.env()),
       compilers: Mix.compilers(),
       elixirc_options: [warnings_as_errors: warnings_as_errors(), prune_code_paths: false],

From 7e303600fb2914ab66fe54a8022ddc65ff93edf5 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Wed, 18 Sep 2024 17:15:55 +0000
Subject: [PATCH 127/212] Remove old elixir 1.12 build image generation script

---
 ci/elixir-1.12/Dockerfile        | 8 --------
 ci/elixir-1.12/build_and_push.sh | 1 -
 2 files changed, 9 deletions(-)
 delete mode 100644 ci/elixir-1.12/Dockerfile
 delete mode 100755 ci/elixir-1.12/build_and_push.sh

diff --git a/ci/elixir-1.12/Dockerfile b/ci/elixir-1.12/Dockerfile
deleted file mode 100644
index a2b566873..000000000
--- a/ci/elixir-1.12/Dockerfile
+++ /dev/null
@@ -1,8 +0,0 @@
-FROM elixir:1.12.3
-
-# Single RUN statement, otherwise intermediate images are created
-# https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#run
-RUN apt-get update &&\
-	apt-get install -y libmagic-dev cmake libimage-exiftool-perl ffmpeg &&\
-	mix local.hex --force &&\
-	mix local.rebar --force
diff --git a/ci/elixir-1.12/build_and_push.sh b/ci/elixir-1.12/build_and_push.sh
deleted file mode 100755
index 508262ed8..000000000
--- a/ci/elixir-1.12/build_and_push.sh
+++ /dev/null
@@ -1 +0,0 @@
-docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t git.pleroma.social:5050/pleroma/pleroma/ci-base:elixir-1.12 --push .

From 1bd28e7d592b429c5eee072db8d1f2ae77d76e29 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Wed, 18 Sep 2024 17:28:48 +0000
Subject: [PATCH 128/212] CI script to build and publish an image for Elixir
 1.14

---
 ci/{elixir-1.13.4-otp-25 => elixir-1.14.5-otp-25}/Dockerfile    | 2 +-
 .../build_and_push.sh                                           | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
 rename ci/{elixir-1.13.4-otp-25 => elixir-1.14.5-otp-25}/Dockerfile (91%)
 rename ci/{elixir-1.13.4-otp-25 => elixir-1.14.5-otp-25}/build_and_push.sh (52%)

diff --git a/ci/elixir-1.13.4-otp-25/Dockerfile b/ci/elixir-1.14.5-otp-25/Dockerfile
similarity index 91%
rename from ci/elixir-1.13.4-otp-25/Dockerfile
rename to ci/elixir-1.14.5-otp-25/Dockerfile
index 25a1639e8..3a35c84c3 100644
--- a/ci/elixir-1.13.4-otp-25/Dockerfile
+++ b/ci/elixir-1.14.5-otp-25/Dockerfile
@@ -1,4 +1,4 @@
-FROM elixir:1.13.4-otp-25
+FROM elixir:1.14.5-otp-25
 
 # Single RUN statement, otherwise intermediate images are created
 # https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#run
diff --git a/ci/elixir-1.13.4-otp-25/build_and_push.sh b/ci/elixir-1.14.5-otp-25/build_and_push.sh
similarity index 52%
rename from ci/elixir-1.13.4-otp-25/build_and_push.sh
rename to ci/elixir-1.14.5-otp-25/build_and_push.sh
index b8ca1d24d..912c47d0c 100755
--- a/ci/elixir-1.13.4-otp-25/build_and_push.sh
+++ b/ci/elixir-1.14.5-otp-25/build_and_push.sh
@@ -1 +1 @@
-docker buildx build --platform linux/amd64,linux/arm64 -t git.pleroma.social:5050/pleroma/pleroma/ci-base:elixir-1.13.4-otp-25 --push .
+docker buildx build --platform linux/amd64,linux/arm64 -t git.pleroma.social:5050/pleroma/pleroma/ci-base:elixir-1.14.5-otp-25 --push .

From 23e5eed4e0e61ea65bd895bee7d8a137fccf3307 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= <git@mkljczk.pl>
Date: Thu, 19 Sep 2024 10:57:50 +0200
Subject: [PATCH 129/212] Include session scopes in TokenView
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
---
 changelog.d/token-view-scopes.add                | 1 +
 lib/pleroma/web/twitter_api/views/token_view.ex  | 3 ++-
 test/pleroma/web/twitter_api/controller_test.exs | 2 +-
 3 files changed, 4 insertions(+), 2 deletions(-)
 create mode 100644 changelog.d/token-view-scopes.add

diff --git a/changelog.d/token-view-scopes.add b/changelog.d/token-view-scopes.add
new file mode 100644
index 000000000..e24fa38e6
--- /dev/null
+++ b/changelog.d/token-view-scopes.add
@@ -0,0 +1 @@
+Include session scopes in TokenView
\ No newline at end of file
diff --git a/lib/pleroma/web/twitter_api/views/token_view.ex b/lib/pleroma/web/twitter_api/views/token_view.ex
index 2e492c13f..36776ce3b 100644
--- a/lib/pleroma/web/twitter_api/views/token_view.ex
+++ b/lib/pleroma/web/twitter_api/views/token_view.ex
@@ -15,7 +15,8 @@ defmodule Pleroma.Web.TwitterAPI.TokenView do
     %{
       id: token_entry.id,
       valid_until: token_entry.valid_until,
-      app_name: token_entry.app.client_name
+      app_name: token_entry.app.client_name,
+      scopes: token_entry.scopes
     }
   end
 end
diff --git a/test/pleroma/web/twitter_api/controller_test.exs b/test/pleroma/web/twitter_api/controller_test.exs
index 495d371d2..0019b51af 100644
--- a/test/pleroma/web/twitter_api/controller_test.exs
+++ b/test/pleroma/web/twitter_api/controller_test.exs
@@ -69,7 +69,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
         |> hd()
         |> Map.keys()
 
-      assert keys -- ["id", "app_name", "valid_until"] == []
+      assert keys -- ["id", "app_name", "valid_until", "scopes"] == []
     end
 
     test "revoke token", %{token: token} do

From 03e14e759db47633cce320285d93d8c1f3bde65c Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier" <contact@hacktivis.me>
Date: Fri, 24 Mar 2023 09:08:39 +0100
Subject: [PATCH 130/212] MRF: Add filtering against AP id

---
 changelog.d/mrf-id_filter.add              | 1 +
 lib/pleroma/web/activity_pub/mrf.ex        | 8 ++++++++
 lib/pleroma/web/activity_pub/mrf/policy.ex | 3 ++-
 3 files changed, 11 insertions(+), 1 deletion(-)
 create mode 100644 changelog.d/mrf-id_filter.add

diff --git a/changelog.d/mrf-id_filter.add b/changelog.d/mrf-id_filter.add
new file mode 100644
index 000000000..f556f9bc4
--- /dev/null
+++ b/changelog.d/mrf-id_filter.add
@@ -0,0 +1 @@
+Add `id_filter` to MRF to filter URLs and their domain prior to fetching
\ No newline at end of file
diff --git a/lib/pleroma/web/activity_pub/mrf.ex b/lib/pleroma/web/activity_pub/mrf.ex
index bc418d908..51ab476b7 100644
--- a/lib/pleroma/web/activity_pub/mrf.ex
+++ b/lib/pleroma/web/activity_pub/mrf.ex
@@ -108,6 +108,14 @@ defmodule Pleroma.Web.ActivityPub.MRF do
 
   def filter(%{} = object), do: get_policies() |> filter(object)
 
+  def id_filter(policies, id) when is_binary(id) do
+    policies
+    |> Enum.filter(&function_exported?(&1, :id_filter, 1))
+    |> Enum.all?(& &1.id_filter(id))
+  end
+
+  def id_filter(id) when is_binary(id), do: get_policies() |> id_filter(id)
+
   @impl true
   def pipeline_filter(%{} = message, meta) do
     object = meta[:object_data]
diff --git a/lib/pleroma/web/activity_pub/mrf/policy.ex b/lib/pleroma/web/activity_pub/mrf/policy.ex
index 54ca4b735..08bcac08a 100644
--- a/lib/pleroma/web/activity_pub/mrf/policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/policy.ex
@@ -4,6 +4,7 @@
 
 defmodule Pleroma.Web.ActivityPub.MRF.Policy do
   @callback filter(Pleroma.Activity.t()) :: {:ok | :reject, Pleroma.Activity.t()}
+  @callback id_filter(String.t()) :: boolean()
   @callback describe() :: {:ok | :error, map()}
   @callback config_description() :: %{
               optional(:children) => [map()],
@@ -13,5 +14,5 @@ defmodule Pleroma.Web.ActivityPub.MRF.Policy do
               description: String.t()
             }
   @callback history_awareness() :: :auto | :manual
-  @optional_callbacks config_description: 0, history_awareness: 0
+  @optional_callbacks config_description: 0, history_awareness: 0, id_filter: 1
 end

From 3dd6f6585985a085c1c2f2243501323864dcac2d Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier" <contact@hacktivis.me>
Date: Fri, 24 Mar 2023 09:09:41 +0100
Subject: [PATCH 131/212] Object.Fetcher: Hook to MRF.id_filter

---
 lib/pleroma/object/fetcher.ex | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/lib/pleroma/object/fetcher.ex b/lib/pleroma/object/fetcher.ex
index 69a5f3268..c85a8b09f 100644
--- a/lib/pleroma/object/fetcher.ex
+++ b/lib/pleroma/object/fetcher.ex
@@ -145,6 +145,7 @@ defmodule Pleroma.Object.Fetcher do
     Logger.debug("Fetching object #{id} via AP")
 
     with {:scheme, true} <- {:scheme, String.starts_with?(id, "http")},
+         {_, true} <- {:mrf, MRF.id_filter(id)},
          {:ok, body} <- get_object(id),
          {:ok, data} <- safe_json_decode(body),
          :ok <- Containment.contain_origin_from_id(id, data) do
@@ -160,6 +161,9 @@ defmodule Pleroma.Object.Fetcher do
       {:error, e} ->
         {:error, e}
 
+      {:mrf, false} ->
+        {:error, {:reject, "Filtered by id"}}
+
       e ->
         {:error, e}
     end

From 30063c5914d229753f3bacab98c38736f2a447e6 Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier" <contact@hacktivis.me>
Date: Fri, 24 Mar 2023 09:09:58 +0100
Subject: [PATCH 132/212] MRF.DropPolicy: Add id_filter/1

---
 lib/pleroma/web/activity_pub/mrf/drop_policy.ex | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/lib/pleroma/web/activity_pub/mrf/drop_policy.ex b/lib/pleroma/web/activity_pub/mrf/drop_policy.ex
index e4fcc9935..cf07db7f3 100644
--- a/lib/pleroma/web/activity_pub/mrf/drop_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/drop_policy.ex
@@ -13,6 +13,12 @@ defmodule Pleroma.Web.ActivityPub.MRF.DropPolicy do
     {:reject, activity}
   end
 
+  @impl true
+  def id_filter(id) do
+    Logger.debug("REJECTING #{id}")
+    false
+  end
+
   @impl true
   def describe, do: {:ok, %{}}
 end

From 0fa13c55357ca83ae00b39626a0fa4be3a936640 Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier" <contact@hacktivis.me>
Date: Fri, 24 Mar 2023 09:16:25 +0100
Subject: [PATCH 133/212] MRF.SimplePolicy: Add id_filter/1

---
 lib/pleroma/web/activity_pub/mrf/simple_policy.ex | 12 ++++++++++++
 .../web/activity_pub/mrf/simple_policy_test.exs   | 15 +++++++++++++++
 2 files changed, 27 insertions(+)

diff --git a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex
index ae7f18bfe..a97e8db7b 100644
--- a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex
@@ -191,6 +191,18 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
     |> MRF.instance_list_from_tuples()
   end
 
+  @impl true
+  def id_filter(id) do
+    host_info = URI.parse(id)
+
+    with {:ok, _} <- check_accept(host_info, %{}),
+         {:ok, _} <- check_reject(host_info, %{}) do
+      true
+    else
+      _ -> false
+    end
+  end
+
   @impl true
   def filter(%{"type" => "Delete", "actor" => actor} = activity) do
     %{host: actor_host} = URI.parse(actor)
diff --git a/test/pleroma/web/activity_pub/mrf/simple_policy_test.exs b/test/pleroma/web/activity_pub/mrf/simple_policy_test.exs
index 1a51b7d30..f49a7b8ff 100644
--- a/test/pleroma/web/activity_pub/mrf/simple_policy_test.exs
+++ b/test/pleroma/web/activity_pub/mrf/simple_policy_test.exs
@@ -252,6 +252,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
       remote_message = build_remote_message()
 
       assert SimplePolicy.filter(remote_message) == {:ok, remote_message}
+      assert SimplePolicy.id_filter(remote_message["actor"])
     end
 
     test "activity has a matching host" do
@@ -260,6 +261,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
       remote_message = build_remote_message()
 
       assert {:reject, _} = SimplePolicy.filter(remote_message)
+      refute SimplePolicy.id_filter(remote_message["actor"])
     end
 
     test "activity matches with wildcard domain" do
@@ -268,6 +270,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
       remote_message = build_remote_message()
 
       assert {:reject, _} = SimplePolicy.filter(remote_message)
+      refute SimplePolicy.id_filter(remote_message["actor"])
     end
 
     test "actor has a matching host" do
@@ -276,6 +279,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
       remote_user = build_remote_user()
 
       assert {:reject, _} = SimplePolicy.filter(remote_user)
+      refute SimplePolicy.id_filter(remote_user["id"])
     end
 
     test "reject Announce when object would be rejected" do
@@ -288,6 +292,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
       }
 
       assert {:reject, _} = SimplePolicy.filter(announce)
+      # Note: Non-Applicable for id_filter/1
     end
 
     test "reject by URI object" do
@@ -300,6 +305,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
       }
 
       assert {:reject, _} = SimplePolicy.filter(announce)
+      # Note: Non-Applicable for id_filter/1
     end
   end
 
@@ -370,6 +376,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
 
       assert SimplePolicy.filter(local_message) == {:ok, local_message}
       assert SimplePolicy.filter(remote_message) == {:ok, remote_message}
+      assert SimplePolicy.id_filter(local_message["actor"])
+      assert SimplePolicy.id_filter(remote_message["actor"])
     end
 
     test "is not empty but activity doesn't have a matching host" do
@@ -380,6 +388,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
 
       assert SimplePolicy.filter(local_message) == {:ok, local_message}
       assert {:reject, _} = SimplePolicy.filter(remote_message)
+      assert SimplePolicy.id_filter(local_message["actor"])
+      refute SimplePolicy.id_filter(remote_message["actor"])
     end
 
     test "activity has a matching host" do
@@ -390,6 +400,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
 
       assert SimplePolicy.filter(local_message) == {:ok, local_message}
       assert SimplePolicy.filter(remote_message) == {:ok, remote_message}
+      assert SimplePolicy.id_filter(local_message["actor"])
+      assert SimplePolicy.id_filter(remote_message["actor"])
     end
 
     test "activity matches with wildcard domain" do
@@ -400,6 +412,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
 
       assert SimplePolicy.filter(local_message) == {:ok, local_message}
       assert SimplePolicy.filter(remote_message) == {:ok, remote_message}
+      assert SimplePolicy.id_filter(local_message["actor"])
+      assert SimplePolicy.id_filter(remote_message["actor"])
     end
 
     test "actor has a matching host" do
@@ -408,6 +422,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
       remote_user = build_remote_user()
 
       assert SimplePolicy.filter(remote_user) == {:ok, remote_user}
+      assert SimplePolicy.id_filter(remote_user["id"])
     end
   end
 

From a1e3fb506b309a529f0ce8ef231d853e7866be21 Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier" <contact@hacktivis.me>
Date: Sat, 21 Sep 2024 15:39:02 +0200
Subject: [PATCH 134/212] Dockerfile: Elixir 1.14

---
 Dockerfile                          | 7 ++++---
 changelog.d/elixir-1.14-docker.skip | 0
 2 files changed, 4 insertions(+), 3 deletions(-)
 create mode 100644 changelog.d/elixir-1.14-docker.skip

diff --git a/Dockerfile b/Dockerfile
index 72461305c..fff58154e 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,7 +1,8 @@
+# https://hub.docker.com/r/hexpm/elixir/tags
 ARG ELIXIR_IMG=hexpm/elixir
-ARG ELIXIR_VER=1.13.4
-ARG ERLANG_VER=24.3.4.15
-ARG ALPINE_VER=3.17.5
+ARG ELIXIR_VER=1.14.5
+ARG ERLANG_VER=25.3.2.14
+ARG ALPINE_VER=3.17.9
 
 FROM ${ELIXIR_IMG}:${ELIXIR_VER}-erlang-${ERLANG_VER}-alpine-${ALPINE_VER} as build
 
diff --git a/changelog.d/elixir-1.14-docker.skip b/changelog.d/elixir-1.14-docker.skip
new file mode 100644
index 000000000..e69de29bb

From 7dd3a4d86defff9c0960f7e39481215603ac85b9 Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier" <contact@hacktivis.me>
Date: Tue, 24 Sep 2024 05:54:25 +0200
Subject: [PATCH 135/212] push: make vapid_config fallback to empty array

    2024-09-24T03:53:27.770757+00:00 NightmareMoon pleroma: path=/notice/AmJcSqyeyij4W70K36 [error] Preloading for /notice/AmJcSqyeyij4W70K36 failed.
    ** (FunctionClauseError) no function clause matching in Keyword.get/3
        (elixir 1.15.8) lib/keyword.ex:388: Keyword.get(nil, :public_key, nil)
        (pleroma 2.7.0-3067-g9b76dbd4-dev-lanodan2) lib/pleroma/web/mastodon_api/views/instance_view.ex:262: Pleroma.Web.MastodonAPI.InstanceView.pleroma_configuration/1
        (pleroma 2.7.0-3067-g9b76dbd4-dev-lanodan2) lib/pleroma/web/mastodon_api/views/instance_view.ex:45: Pleroma.Web.MastodonAPI.InstanceView.render/2
        (pleroma 2.7.0-3067-g9b76dbd4-dev-lanodan2) lib/pleroma/web/preload/providers/instance.ex:28: Pleroma.Web.Preload.Providers.Instance.build_info_tag/1
        (pleroma 2.7.0-3067-g9b76dbd4-dev-lanodan2) lib/pleroma/web/preload/providers/instance.ex:21: Pleroma.Web.Preload.Providers.Instance.generate_terms/1
        (pleroma 2.7.0-3067-g9b76dbd4-dev-lanodan2) lib/pleroma/web/preload.ex:13: anonymous fn/3 in Pleroma.Web.Preload.build_tags/2
---
 changelog.d/vapid_keyword_fallback.fix | 1 +
 lib/pleroma/web/push.ex                | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)
 create mode 100644 changelog.d/vapid_keyword_fallback.fix

diff --git a/changelog.d/vapid_keyword_fallback.fix b/changelog.d/vapid_keyword_fallback.fix
new file mode 100644
index 000000000..aa48f8938
--- /dev/null
+++ b/changelog.d/vapid_keyword_fallback.fix
@@ -0,0 +1 @@
+Make vapid_config return empty array, fixing preloading for instances without push notifications configured
\ No newline at end of file
diff --git a/lib/pleroma/web/push.ex b/lib/pleroma/web/push.ex
index 6d777142e..77f77f88e 100644
--- a/lib/pleroma/web/push.ex
+++ b/lib/pleroma/web/push.ex
@@ -20,7 +20,7 @@ defmodule Pleroma.Web.Push do
   end
 
   def vapid_config do
-    Application.get_env(:web_push_encryption, :vapid_details, nil)
+    Application.get_env(:web_push_encryption, :vapid_details, [])
   end
 
   def enabled, do: match?([subject: _, public_key: _, private_key: _], vapid_config())

From 382426e0338d7918cd2db7c72ede446a2a8f7f4f Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Mon, 30 Sep 2024 12:41:06 -0400
Subject: [PATCH 136/212] Remove Object.get_by_id_and_maybe_refetch/2

This was only used for poll refreshing and is not a good approach to the problem.
---
 lib/pleroma/object.ex                         |  21 ---
 .../controllers/poll_controller.ex            |   2 +-
 test/pleroma/object_test.exs                  | 144 ------------------
 3 files changed, 1 insertion(+), 166 deletions(-)

diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex
index 748f18e6c..77dfda851 100644
--- a/lib/pleroma/object.ex
+++ b/lib/pleroma/object.ex
@@ -99,27 +99,6 @@ defmodule Pleroma.Object do
   def get_by_id(nil), do: nil
   def get_by_id(id), do: Repo.get(Object, id)
 
-  @spec get_by_id_and_maybe_refetch(integer(), list()) :: Object.t() | nil
-  def get_by_id_and_maybe_refetch(id, opts \\ []) do
-    with %Object{updated_at: updated_at} = object <- get_by_id(id) do
-      if opts[:interval] &&
-           NaiveDateTime.diff(NaiveDateTime.utc_now(), updated_at) > opts[:interval] do
-        case Fetcher.refetch_object(object) do
-          {:ok, %Object{} = object} ->
-            object
-
-          e ->
-            Logger.error("Couldn't refresh #{object.data["id"]}:\n#{inspect(e)}")
-            object
-        end
-      else
-        object
-      end
-    else
-      nil -> nil
-    end
-  end
-
   def get_by_ap_id(nil), do: nil
 
   def get_by_ap_id(ap_id) do
diff --git a/lib/pleroma/web/mastodon_api/controllers/poll_controller.ex b/lib/pleroma/web/mastodon_api/controllers/poll_controller.ex
index a2af8148c..303b995f6 100644
--- a/lib/pleroma/web/mastodon_api/controllers/poll_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/poll_controller.ex
@@ -30,7 +30,7 @@ defmodule Pleroma.Web.MastodonAPI.PollController do
 
   @doc "GET /api/v1/polls/:id"
   def show(%{assigns: %{user: user}, private: %{open_api_spex: %{params: %{id: id}}}} = conn, _) do
-    with %Object{} = object <- Object.get_by_id_and_maybe_refetch(id, interval: 60),
+    with %Object{} = object <- Object.get_by_id(id),
          %Activity{} = activity <- Activity.get_create_by_object_ap_id(object.data["id"]),
          true <- Visibility.visible_for_user?(activity, user) do
       try_render(conn, "show.json", %{object: object, for: user})
diff --git a/test/pleroma/object_test.exs b/test/pleroma/object_test.exs
index 48d4d86eb..b3c528e32 100644
--- a/test/pleroma/object_test.exs
+++ b/test/pleroma/object_test.exs
@@ -6,12 +6,10 @@ defmodule Pleroma.ObjectTest do
   use Pleroma.DataCase
   use Oban.Testing, repo: Pleroma.Repo
 
-  import ExUnit.CaptureLog
   import Mox
   import Pleroma.Factory
   import Tesla.Mock
 
-  alias Pleroma.Activity
   alias Pleroma.Hashtag
   alias Pleroma.Object
   alias Pleroma.Repo
@@ -282,148 +280,6 @@ defmodule Pleroma.ObjectTest do
     end
   end
 
-  describe "get_by_id_and_maybe_refetch" do
-    setup do
-      mock(fn
-        %{method: :get, url: "https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d"} ->
-          %Tesla.Env{
-            status: 200,
-            body: File.read!("test/fixtures/tesla_mock/poll_original.json"),
-            headers: HttpRequestMock.activitypub_object_headers()
-          }
-
-        env ->
-          apply(HttpRequestMock, :request, [env])
-      end)
-
-      mock_modified = fn resp ->
-        mock(fn
-          %{method: :get, url: "https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d"} ->
-            resp
-
-          env ->
-            apply(HttpRequestMock, :request, [env])
-        end)
-      end
-
-      on_exit(fn -> mock(fn env -> apply(HttpRequestMock, :request, [env]) end) end)
-
-      [mock_modified: mock_modified]
-    end
-
-    test "refetches if the time since the last refetch is greater than the interval", %{
-      mock_modified: mock_modified
-    } do
-      %Object{} =
-        object =
-        Object.normalize("https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d",
-          fetch: true
-        )
-
-      Object.set_cache(object)
-
-      assert Enum.at(object.data["oneOf"], 0)["replies"]["totalItems"] == 4
-      assert Enum.at(object.data["oneOf"], 1)["replies"]["totalItems"] == 0
-
-      mock_modified.(%Tesla.Env{
-        status: 200,
-        body: File.read!("test/fixtures/tesla_mock/poll_modified.json"),
-        headers: HttpRequestMock.activitypub_object_headers()
-      })
-
-      updated_object = Object.get_by_id_and_maybe_refetch(object.id, interval: -1)
-      object_in_cache = Object.get_cached_by_ap_id(object.data["id"])
-      assert updated_object == object_in_cache
-      assert Enum.at(updated_object.data["oneOf"], 0)["replies"]["totalItems"] == 8
-      assert Enum.at(updated_object.data["oneOf"], 1)["replies"]["totalItems"] == 3
-    end
-
-    test "returns the old object if refetch fails", %{mock_modified: mock_modified} do
-      %Object{} =
-        object =
-        Object.normalize("https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d",
-          fetch: true
-        )
-
-      Object.set_cache(object)
-
-      assert Enum.at(object.data["oneOf"], 0)["replies"]["totalItems"] == 4
-      assert Enum.at(object.data["oneOf"], 1)["replies"]["totalItems"] == 0
-
-      assert capture_log(fn ->
-               mock_modified.(%Tesla.Env{status: 404, body: ""})
-
-               updated_object = Object.get_by_id_and_maybe_refetch(object.id, interval: -1)
-               object_in_cache = Object.get_cached_by_ap_id(object.data["id"])
-               assert updated_object == object_in_cache
-               assert Enum.at(updated_object.data["oneOf"], 0)["replies"]["totalItems"] == 4
-               assert Enum.at(updated_object.data["oneOf"], 1)["replies"]["totalItems"] == 0
-             end) =~
-               "[error] Couldn't refresh https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d"
-    end
-
-    test "does not refetch if the time since the last refetch is greater than the interval", %{
-      mock_modified: mock_modified
-    } do
-      %Object{} =
-        object =
-        Object.normalize("https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d",
-          fetch: true
-        )
-
-      Object.set_cache(object)
-
-      assert Enum.at(object.data["oneOf"], 0)["replies"]["totalItems"] == 4
-      assert Enum.at(object.data["oneOf"], 1)["replies"]["totalItems"] == 0
-
-      mock_modified.(%Tesla.Env{
-        status: 200,
-        body: File.read!("test/fixtures/tesla_mock/poll_modified.json"),
-        headers: HttpRequestMock.activitypub_object_headers()
-      })
-
-      updated_object = Object.get_by_id_and_maybe_refetch(object.id, interval: 100)
-      object_in_cache = Object.get_cached_by_ap_id(object.data["id"])
-      assert updated_object == object_in_cache
-      assert Enum.at(updated_object.data["oneOf"], 0)["replies"]["totalItems"] == 4
-      assert Enum.at(updated_object.data["oneOf"], 1)["replies"]["totalItems"] == 0
-    end
-
-    test "preserves internal fields on refetch", %{mock_modified: mock_modified} do
-      %Object{} =
-        object =
-        Object.normalize("https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d",
-          fetch: true
-        )
-
-      Object.set_cache(object)
-
-      assert Enum.at(object.data["oneOf"], 0)["replies"]["totalItems"] == 4
-      assert Enum.at(object.data["oneOf"], 1)["replies"]["totalItems"] == 0
-
-      user = insert(:user)
-      activity = Activity.get_create_by_object_ap_id(object.data["id"])
-      {:ok, activity} = CommonAPI.favorite(activity.id, user)
-      object = Object.get_by_ap_id(activity.data["object"])
-
-      assert object.data["like_count"] == 1
-
-      mock_modified.(%Tesla.Env{
-        status: 200,
-        body: File.read!("test/fixtures/tesla_mock/poll_modified.json"),
-        headers: HttpRequestMock.activitypub_object_headers()
-      })
-
-      updated_object = Object.get_by_id_and_maybe_refetch(object.id, interval: -1)
-      object_in_cache = Object.get_cached_by_ap_id(object.data["id"])
-      assert updated_object == object_in_cache
-      assert Enum.at(updated_object.data["oneOf"], 0)["replies"]["totalItems"] == 8
-      assert Enum.at(updated_object.data["oneOf"], 1)["replies"]["totalItems"] == 3
-
-      assert updated_object.data["like_count"] == 1
-    end
-  end
-
   describe ":hashtags association" do
     test "Hashtag records are created with Object record and updated on its change" do
       user = insert(:user)

From 2380ae6dcc267d7d6ff81a55ae95eed718176563 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Mon, 30 Sep 2024 13:38:13 -0400
Subject: [PATCH 137/212] Validate an Oban job is inserted for poll refreshes

---
 .../web/mastodon_api/controllers/poll_controller_test.exs   | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/test/pleroma/web/mastodon_api/controllers/poll_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/poll_controller_test.exs
index 7912b1d5f..b2cceec51 100644
--- a/test/pleroma/web/mastodon_api/controllers/poll_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/controllers/poll_controller_test.exs
@@ -3,6 +3,7 @@
 # SPDX-License-Identifier: AGPL-3.0-only
 
 defmodule Pleroma.Web.MastodonAPI.PollControllerTest do
+  use Oban.Testing, repo: Pleroma.Repo
   use Pleroma.Web.ConnCase, async: true
 
   alias Pleroma.Object
@@ -27,6 +28,11 @@ defmodule Pleroma.Web.MastodonAPI.PollControllerTest do
       response = json_response_and_validate_schema(conn, 200)
       id = to_string(object.id)
       assert %{"id" => ^id, "expired" => false, "multiple" => false} = response
+
+      assert_enqueued(
+        worker: Pleroma.Workers.PollWorker,
+        args: %{"op" => "refresh", "activity_id" => activity.id}
+      )
     end
 
     test "does not expose polls for private statuses", %{conn: conn} do

From c077a14ce1343f5515fa11938df7d808f23a566c Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Mon, 30 Sep 2024 13:54:56 -0400
Subject: [PATCH 138/212] Add Oban job to handle poll refreshing and stream out
 the update

---
 .../controllers/poll_controller.ex            |  4 +++
 lib/pleroma/workers/poll_worker.ex            | 36 ++++++++++++++-----
 2 files changed, 32 insertions(+), 8 deletions(-)

diff --git a/lib/pleroma/web/mastodon_api/controllers/poll_controller.ex b/lib/pleroma/web/mastodon_api/controllers/poll_controller.ex
index 303b995f6..0d5a57518 100644
--- a/lib/pleroma/web/mastodon_api/controllers/poll_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/poll_controller.ex
@@ -9,6 +9,7 @@ defmodule Pleroma.Web.MastodonAPI.PollController do
 
   alias Pleroma.Activity
   alias Pleroma.Object
+  alias Pleroma.Workers.PollWorker
   alias Pleroma.Web.ActivityPub.Visibility
   alias Pleroma.Web.CommonAPI
   alias Pleroma.Web.Plugs.OAuthScopesPlug
@@ -33,6 +34,9 @@ defmodule Pleroma.Web.MastodonAPI.PollController do
     with %Object{} = object <- Object.get_by_id(id),
          %Activity{} = activity <- Activity.get_create_by_object_ap_id(object.data["id"]),
          true <- Visibility.visible_for_user?(activity, user) do
+      PollWorker.new(%{"op" => "refresh", "activity_id" => activity.id})
+      |> Oban.insert(unique: [period: 60])
+
       try_render(conn, "show.json", %{object: object, for: user})
     else
       error when is_nil(error) or error == false ->
diff --git a/lib/pleroma/workers/poll_worker.ex b/lib/pleroma/workers/poll_worker.ex
index d263aa1b9..0d2d67326 100644
--- a/lib/pleroma/workers/poll_worker.ex
+++ b/lib/pleroma/workers/poll_worker.ex
@@ -11,14 +11,34 @@ defmodule Pleroma.Workers.PollWorker do
   alias Pleroma.Activity
   alias Pleroma.Notification
   alias Pleroma.Object
+  alias Pleroma.Object.Fetcher
+
+  @stream_out_impl Pleroma.Config.get(
+                     [__MODULE__, :stream_out],
+                     Pleroma.Web.ActivityPub.ActivityPub
+                   )
 
   @impl true
   def perform(%Job{args: %{"op" => "poll_end", "activity_id" => activity_id}}) do
-    with %Activity{} = activity <- find_poll_activity(activity_id),
+    with {_, %Activity{} = activity} <- {:activity, Activity.get_by_id(activity_id)},
          {:ok, notifications} <- Notification.create_poll_notifications(activity) do
       Notification.stream(notifications)
     else
-      {:error, :poll_activity_not_found} = e -> {:cancel, e}
+      {:activity, nil} -> {:cancel, :poll_activity_not_found}
+      e -> {:error, e}
+    end
+  end
+
+  def perform(%Job{args: %{"op" => "refresh", "activity_id" => activity_id}}) do
+    with {_, %Activity{object: object}} <-
+           {:activity, Activity.get_by_id_with_object(activity_id)},
+         {_, {:ok, _object}} <- {:refetch, Fetcher.refetch_object(object)} do
+      stream_update(activity_id)
+
+      :ok
+    else
+      {:activity, nil} -> {:cancel, :poll_activity_not_found}
+      {:refetch, _} = e -> {:cancel, e}
       e -> {:error, e}
     end
   end
@@ -26,12 +46,6 @@ defmodule Pleroma.Workers.PollWorker do
   @impl true
   def timeout(_job), do: :timer.seconds(5)
 
-  defp find_poll_activity(activity_id) do
-    with nil <- Activity.get_by_id(activity_id) do
-      {:error, :poll_activity_not_found}
-    end
-  end
-
   def schedule_poll_end(%Activity{data: %{"type" => "Create"}, id: activity_id} = activity) do
     with %Object{data: %{"type" => "Question", "closed" => closed}} when is_binary(closed) <-
            Object.normalize(activity),
@@ -49,4 +63,10 @@ defmodule Pleroma.Workers.PollWorker do
   end
 
   def schedule_poll_end(activity), do: {:error, activity}
+
+  defp stream_update(activity_id) do
+    Activity.get_by_id(activity_id)
+    |> Activity.normalize()
+    |> @stream_out_impl.stream_out()
+  end
 end

From 4b3f604f9529c9ced23f747cb6f6d82fedfadab0 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Mon, 30 Sep 2024 14:02:41 -0400
Subject: [PATCH 139/212] Skip refetching poll results if the object's
 updated_at is newer than the poll closed timestamp

---
 lib/pleroma/workers/poll_worker.ex | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/lib/pleroma/workers/poll_worker.ex b/lib/pleroma/workers/poll_worker.ex
index 0d2d67326..a61c5eac1 100644
--- a/lib/pleroma/workers/poll_worker.ex
+++ b/lib/pleroma/workers/poll_worker.ex
@@ -32,6 +32,8 @@ defmodule Pleroma.Workers.PollWorker do
   def perform(%Job{args: %{"op" => "refresh", "activity_id" => activity_id}}) do
     with {_, %Activity{object: object}} <-
            {:activity, Activity.get_by_id_with_object(activity_id)},
+          {:ok, naive_closed} <- NaiveDateTime.from_iso8601(object.data["closed"]),
+          {_, :lt} <- {:closed_compare, NaiveDateTime.compare(object.updated_at, naive_closed)},
          {_, {:ok, _object}} <- {:refetch, Fetcher.refetch_object(object)} do
       stream_update(activity_id)
 
@@ -39,6 +41,7 @@ defmodule Pleroma.Workers.PollWorker do
     else
       {:activity, nil} -> {:cancel, :poll_activity_not_found}
       {:refetch, _} = e -> {:cancel, e}
+      {:closed_compare, _} -> {:cancel, :poll_finalized}
       e -> {:error, e}
     end
   end

From 47ce3a4a961bd7496f8105bc957dbf958b77d342 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Mon, 30 Sep 2024 14:17:35 -0400
Subject: [PATCH 140/212] Schedule a final poll refresh before streaming out
 the notifications

---
 lib/pleroma/workers/poll_worker.ex        | 8 ++++++--
 test/pleroma/workers/poll_worker_test.exs | 6 ++++++
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/lib/pleroma/workers/poll_worker.ex b/lib/pleroma/workers/poll_worker.ex
index a61c5eac1..574daa9ba 100644
--- a/lib/pleroma/workers/poll_worker.ex
+++ b/lib/pleroma/workers/poll_worker.ex
@@ -22,6 +22,10 @@ defmodule Pleroma.Workers.PollWorker do
   def perform(%Job{args: %{"op" => "poll_end", "activity_id" => activity_id}}) do
     with {_, %Activity{} = activity} <- {:activity, Activity.get_by_id(activity_id)},
          {:ok, notifications} <- Notification.create_poll_notifications(activity) do
+      # Schedule a final refresh
+      __MODULE__.new(%{"op" => "refresh", "activity_id" => activity_id})
+      |> Oban.insert()
+
       Notification.stream(notifications)
     else
       {:activity, nil} -> {:cancel, :poll_activity_not_found}
@@ -32,8 +36,8 @@ defmodule Pleroma.Workers.PollWorker do
   def perform(%Job{args: %{"op" => "refresh", "activity_id" => activity_id}}) do
     with {_, %Activity{object: object}} <-
            {:activity, Activity.get_by_id_with_object(activity_id)},
-          {:ok, naive_closed} <- NaiveDateTime.from_iso8601(object.data["closed"]),
-          {_, :lt} <- {:closed_compare, NaiveDateTime.compare(object.updated_at, naive_closed)},
+         {:ok, naive_closed} <- NaiveDateTime.from_iso8601(object.data["closed"]),
+         {_, :lt} <- {:closed_compare, NaiveDateTime.compare(object.updated_at, naive_closed)},
          {_, {:ok, _object}} <- {:refetch, Fetcher.refetch_object(object)} do
       stream_update(activity_id)
 
diff --git a/test/pleroma/workers/poll_worker_test.exs b/test/pleroma/workers/poll_worker_test.exs
index 749df8aff..e1c67f057 100644
--- a/test/pleroma/workers/poll_worker_test.exs
+++ b/test/pleroma/workers/poll_worker_test.exs
@@ -44,6 +44,12 @@ defmodule Pleroma.Workers.PollWorkerTest do
       # Ensure notifications were streamed out when job executes
       assert called(Pleroma.Web.Streamer.stream(["user", "user:notification"], :_))
       assert called(Pleroma.Web.Push.send(:_))
+
+      # Ensure we scheduled a final refresh of the poll
+      assert_enqueued(
+        worker: PollWorker,
+        args: %{"op" => "refresh", "activity_id" => activity.id}
+      )
     end
   end
 end

From a2e7db43aa3636569f4d770df980347a03c957fe Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Mon, 30 Sep 2024 14:23:04 -0400
Subject: [PATCH 141/212] Rename assignment for consistency

---
 lib/pleroma/workers/poll_worker.ex | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/pleroma/workers/poll_worker.ex b/lib/pleroma/workers/poll_worker.ex
index 574daa9ba..f70ab48a4 100644
--- a/lib/pleroma/workers/poll_worker.ex
+++ b/lib/pleroma/workers/poll_worker.ex
@@ -36,8 +36,8 @@ defmodule Pleroma.Workers.PollWorker do
   def perform(%Job{args: %{"op" => "refresh", "activity_id" => activity_id}}) do
     with {_, %Activity{object: object}} <-
            {:activity, Activity.get_by_id_with_object(activity_id)},
-         {:ok, naive_closed} <- NaiveDateTime.from_iso8601(object.data["closed"]),
-         {_, :lt} <- {:closed_compare, NaiveDateTime.compare(object.updated_at, naive_closed)},
+         {:ok, end_time} <- NaiveDateTime.from_iso8601(object.data["closed"]),
+         {_, :lt} <- {:closed_compare, NaiveDateTime.compare(object.updated_at, end_time)},
          {_, {:ok, _object}} <- {:refetch, Fetcher.refetch_object(object)} do
       stream_update(activity_id)
 

From 766edfe5b2b19f4819704540341b8fcc92f133bd Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Mon, 30 Sep 2024 14:32:28 -0400
Subject: [PATCH 142/212] Test Poll refresh jobs stream out updates after
 refetching the object

---
 test/pleroma/workers/poll_worker_test.exs | 29 +++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/test/pleroma/workers/poll_worker_test.exs b/test/pleroma/workers/poll_worker_test.exs
index e1c67f057..56a338bac 100644
--- a/test/pleroma/workers/poll_worker_test.exs
+++ b/test/pleroma/workers/poll_worker_test.exs
@@ -52,4 +52,33 @@ defmodule Pleroma.Workers.PollWorkerTest do
       )
     end
   end
+
+  test "poll refresh job" do
+    user = insert(:user, local: false)
+    question = insert(:question, user: user)
+    activity = insert(:question_activity, question: question)
+
+    PollWorker.new(%{"op" => "refresh", "activity_id" => activity.id})
+    |> Oban.insert()
+
+    expected_job_args = %{"activity_id" => activity.id, "op" => "refresh"}
+
+    assert_enqueued(args: expected_job_args)
+
+    with_mocks([
+      {
+        Pleroma.Web.Streamer,
+        [],
+        [
+          stream: fn _, _ -> nil end
+        ]
+      }
+    ]) do
+      [job] = all_enqueued(worker: PollWorker)
+      PollWorker.perform(job)
+
+      # Ensure updates are streamed out
+      assert called(Pleroma.Web.Streamer.stream(["user", "list", "public", "public:local"], :_))
+    end
+  end
 end

From b2340b5b776d243f6cf12971393783cc3b7c2dc2 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Mon, 30 Sep 2024 14:45:13 -0400
Subject: [PATCH 143/212] Permit backdating the poll closed timestamp

---
 test/support/factory.ex | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/test/support/factory.ex b/test/support/factory.ex
index 8f1c6faf9..732ea3143 100644
--- a/test/support/factory.ex
+++ b/test/support/factory.ex
@@ -241,6 +241,7 @@ defmodule Pleroma.Factory do
 
   def question_factory(attrs \\ %{}) do
     user = attrs[:user] || insert(:user)
+    closed = attrs[:closed] || DateTime.utc_now() |> DateTime.add(86_400) |> DateTime.to_iso8601()
 
     data = %{
       "id" => Pleroma.Web.ActivityPub.Utils.generate_object_id(),
@@ -251,7 +252,7 @@ defmodule Pleroma.Factory do
       "to" => ["https://www.w3.org/ns/activitystreams#Public"],
       "cc" => [user.follower_address],
       "context" => Pleroma.Web.ActivityPub.Utils.generate_context_id(),
-      "closed" => DateTime.utc_now() |> DateTime.add(86_400) |> DateTime.to_iso8601(),
+      "closed" => closed,
       "content" => "Which flavor of ice cream do you prefer?",
       "oneOf" => [
         %{

From a1b384f63c3587d0463109b74b0bbcc5c5ae82ee Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Mon, 30 Sep 2024 14:45:41 -0400
Subject: [PATCH 144/212] Test that a poll refresh is cancelled if updated_at
 on the object is newer than the poll closing time

---
 test/pleroma/workers/poll_worker_test.exs | 61 +++++++++++++++--------
 1 file changed, 40 insertions(+), 21 deletions(-)

diff --git a/test/pleroma/workers/poll_worker_test.exs b/test/pleroma/workers/poll_worker_test.exs
index 56a338bac..0fafcae11 100644
--- a/test/pleroma/workers/poll_worker_test.exs
+++ b/test/pleroma/workers/poll_worker_test.exs
@@ -53,32 +53,51 @@ defmodule Pleroma.Workers.PollWorkerTest do
     end
   end
 
-  test "poll refresh job" do
-    user = insert(:user, local: false)
-    question = insert(:question, user: user)
-    activity = insert(:question_activity, question: question)
+  describe "poll refresh" do
+    test "normal job" do
+      user = insert(:user, local: false)
+      question = insert(:question, user: user)
+      activity = insert(:question_activity, question: question)
 
-    PollWorker.new(%{"op" => "refresh", "activity_id" => activity.id})
-    |> Oban.insert()
+      PollWorker.new(%{"op" => "refresh", "activity_id" => activity.id})
+      |> Oban.insert()
 
-    expected_job_args = %{"activity_id" => activity.id, "op" => "refresh"}
+      expected_job_args = %{"activity_id" => activity.id, "op" => "refresh"}
 
-    assert_enqueued(args: expected_job_args)
+      assert_enqueued(args: expected_job_args)
+
+      with_mocks([
+        {
+          Pleroma.Web.Streamer,
+          [],
+          [
+            stream: fn _, _ -> nil end
+          ]
+        }
+      ]) do
+        [job] = all_enqueued(worker: PollWorker)
+        PollWorker.perform(job)
+
+        # Ensure updates are streamed out
+        assert called(Pleroma.Web.Streamer.stream(["user", "list", "public", "public:local"], :_))
+      end
+    end
+
+    test "when updated_at is after poll closing" do
+      poll_closed = DateTime.utc_now() |> DateTime.add(-86_400) |> DateTime.to_iso8601()
+      user = insert(:user, local: false)
+      question = insert(:question, user: user, closed: poll_closed)
+      activity = insert(:question_activity, question: question)
+
+      PollWorker.new(%{"op" => "refresh", "activity_id" => activity.id})
+      |> Oban.insert()
+
+      expected_job_args = %{"activity_id" => activity.id, "op" => "refresh"}
+
+      assert_enqueued(args: expected_job_args)
 
-    with_mocks([
-      {
-        Pleroma.Web.Streamer,
-        [],
-        [
-          stream: fn _, _ -> nil end
-        ]
-      }
-    ]) do
       [job] = all_enqueued(worker: PollWorker)
-      PollWorker.perform(job)
-
-      # Ensure updates are streamed out
-      assert called(Pleroma.Web.Streamer.stream(["user", "list", "public", "public:local"], :_))
+      assert {:cancel, :poll_finalized} = PollWorker.perform(job)
     end
   end
 end

From 2ab4049508148756076853bae26279b698740597 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Mon, 30 Sep 2024 14:47:30 -0400
Subject: [PATCH 145/212] Poll refreshing changelog

---
 changelog.d/poll-refresh.change | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 changelog.d/poll-refresh.change

diff --git a/changelog.d/poll-refresh.change b/changelog.d/poll-refresh.change
new file mode 100644
index 000000000..b755128a1
--- /dev/null
+++ b/changelog.d/poll-refresh.change
@@ -0,0 +1 @@
+Poll results refreshing is handled asynchronously and will not attempt to keep fetching updates to a closed poll.

From b735d9e6e19a1c64f43428e6342e3d172728c736 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Mon, 30 Sep 2024 14:55:38 -0400
Subject: [PATCH 146/212] Improve assertion

---
 test/pleroma/workers/poll_worker_test.exs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/pleroma/workers/poll_worker_test.exs b/test/pleroma/workers/poll_worker_test.exs
index 0fafcae11..c34647f1b 100644
--- a/test/pleroma/workers/poll_worker_test.exs
+++ b/test/pleroma/workers/poll_worker_test.exs
@@ -97,7 +97,7 @@ defmodule Pleroma.Workers.PollWorkerTest do
       assert_enqueued(args: expected_job_args)
 
       [job] = all_enqueued(worker: PollWorker)
-      assert {:cancel, :poll_finalized} = PollWorker.perform(job)
+      assert {:cancel, :poll_finalized} == PollWorker.perform(job)
     end
   end
 end

From 9ff57946e7d6fa7dabaf90457e11041ce46991c4 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Mon, 30 Sep 2024 15:25:13 -0400
Subject: [PATCH 147/212] Credo

---
 lib/pleroma/web/mastodon_api/controllers/poll_controller.ex | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/pleroma/web/mastodon_api/controllers/poll_controller.ex b/lib/pleroma/web/mastodon_api/controllers/poll_controller.ex
index 0d5a57518..f89bfa7f2 100644
--- a/lib/pleroma/web/mastodon_api/controllers/poll_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/poll_controller.ex
@@ -9,10 +9,10 @@ defmodule Pleroma.Web.MastodonAPI.PollController do
 
   alias Pleroma.Activity
   alias Pleroma.Object
-  alias Pleroma.Workers.PollWorker
   alias Pleroma.Web.ActivityPub.Visibility
   alias Pleroma.Web.CommonAPI
   alias Pleroma.Web.Plugs.OAuthScopesPlug
+  alias Pleroma.Workers.PollWorker
 
   action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
 

From 0a42a3f2eaf53fa87d934226874de5919320de26 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Wed, 2 Oct 2024 11:05:17 -0400
Subject: [PATCH 148/212] Do not attempt to schedule poll refresh jobs for
 local activities

---
 .../controllers/poll_controller.ex            |  6 ++++--
 .../controllers/poll_controller_test.exs      | 19 +++++++++++++++++++
 2 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/lib/pleroma/web/mastodon_api/controllers/poll_controller.ex b/lib/pleroma/web/mastodon_api/controllers/poll_controller.ex
index f89bfa7f2..495f89278 100644
--- a/lib/pleroma/web/mastodon_api/controllers/poll_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/poll_controller.ex
@@ -34,8 +34,10 @@ defmodule Pleroma.Web.MastodonAPI.PollController do
     with %Object{} = object <- Object.get_by_id(id),
          %Activity{} = activity <- Activity.get_create_by_object_ap_id(object.data["id"]),
          true <- Visibility.visible_for_user?(activity, user) do
-      PollWorker.new(%{"op" => "refresh", "activity_id" => activity.id})
-      |> Oban.insert(unique: [period: 60])
+      unless activity.local do
+        PollWorker.new(%{"op" => "refresh", "activity_id" => activity.id})
+        |> Oban.insert(unique: [period: 60])
+      end
 
       try_render(conn, "show.json", %{object: object, for: user})
     else
diff --git a/test/pleroma/web/mastodon_api/controllers/poll_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/poll_controller_test.exs
index b2cceec51..4b236678c 100644
--- a/test/pleroma/web/mastodon_api/controllers/poll_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/controllers/poll_controller_test.exs
@@ -29,6 +29,25 @@ defmodule Pleroma.Web.MastodonAPI.PollControllerTest do
       id = to_string(object.id)
       assert %{"id" => ^id, "expired" => false, "multiple" => false} = response
 
+      refute_enqueued(
+        worker: Pleroma.Workers.PollWorker,
+        args: %{"op" => "refresh", "activity_id" => activity.id}
+      )
+    end
+
+    test "does not create oban job to refresh poll if activity is local", %{conn: conn} do
+      user = insert(:user, local: false)
+      question = insert(:question, user: user)
+      activity = insert(:question_activity, question: question, local: false)
+
+      # Ensure this is not represented as a local activity
+      refute activity.local
+
+      object = Object.normalize(activity, fetch: false)
+
+      get(conn, "/api/v1/polls/#{object.id}")
+      |> json_response_and_validate_schema(200)
+
       assert_enqueued(
         worker: Pleroma.Workers.PollWorker,
         args: %{"op" => "refresh", "activity_id" => activity.id}

From 35bd1977335a2bf73207f22aecbaead6e3112a1c Mon Sep 17 00:00:00 2001
From: tusooa <tusooa@kazv.moe>
Date: Wed, 2 Oct 2024 18:39:14 -0400
Subject: [PATCH 149/212] Fix nonexisting user will not generate metadata for
 search engine opt-out

---
 changelog.d/se-opt-out.change                      | 1 +
 lib/pleroma/web/fallback/redirect_controller.ex    | 2 +-
 lib/pleroma/web/feed/user_controller.ex            | 4 ++--
 lib/pleroma/web/metadata/providers/feed.ex         | 3 +++
 lib/pleroma/web/metadata/providers/open_graph.ex   | 3 +++
 lib/pleroma/web/metadata/providers/rel_me.ex       | 3 +++
 lib/pleroma/web/metadata/providers/twitter_card.ex | 3 +++
 test/pleroma/web/fallback_test.exs                 | 2 +-
 test/pleroma/web/feed/user_controller_test.exs     | 9 +++++++++
 9 files changed, 26 insertions(+), 4 deletions(-)
 create mode 100644 changelog.d/se-opt-out.change

diff --git a/changelog.d/se-opt-out.change b/changelog.d/se-opt-out.change
new file mode 100644
index 000000000..dd694033f
--- /dev/null
+++ b/changelog.d/se-opt-out.change
@@ -0,0 +1 @@
+Fix nonexisting user will not generate metadata for search engine opt-out
diff --git a/lib/pleroma/web/fallback/redirect_controller.ex b/lib/pleroma/web/fallback/redirect_controller.ex
index 4a0885fab..6637848a9 100644
--- a/lib/pleroma/web/fallback/redirect_controller.ex
+++ b/lib/pleroma/web/fallback/redirect_controller.ex
@@ -46,7 +46,7 @@ defmodule Pleroma.Web.Fallback.RedirectController do
       redirector_with_meta(conn, %{user: user})
     else
       nil ->
-        redirector(conn, params)
+        redirector_with_meta(conn, Map.delete(params, "maybe_nickname_or_id"))
     end
   end
 
diff --git a/lib/pleroma/web/feed/user_controller.ex b/lib/pleroma/web/feed/user_controller.ex
index 6657c2b3e..304313068 100644
--- a/lib/pleroma/web/feed/user_controller.ex
+++ b/lib/pleroma/web/feed/user_controller.ex
@@ -15,11 +15,11 @@ defmodule Pleroma.Web.Feed.UserController do
 
   action_fallback(:errors)
 
-  def feed_redirect(%{assigns: %{format: "html"}} = conn, %{"nickname" => nickname}) do
+  def feed_redirect(%{assigns: %{format: "html"}} = conn, %{"nickname" => nickname} = params) do
     with {_, %User{} = user} <- {:fetch_user, User.get_cached_by_nickname_or_id(nickname)} do
       Pleroma.Web.Fallback.RedirectController.redirector_with_meta(conn, %{user: user})
     else
-      _ -> Pleroma.Web.Fallback.RedirectController.redirector(conn, nil)
+      _ -> Pleroma.Web.Fallback.RedirectController.redirector_with_meta(conn, params)
     end
   end
 
diff --git a/lib/pleroma/web/metadata/providers/feed.ex b/lib/pleroma/web/metadata/providers/feed.ex
index e97d6a54f..eb84b267f 100644
--- a/lib/pleroma/web/metadata/providers/feed.ex
+++ b/lib/pleroma/web/metadata/providers/feed.ex
@@ -20,4 +20,7 @@ defmodule Pleroma.Web.Metadata.Providers.Feed do
        ], []}
     ]
   end
+
+  @impl Provider
+  def build_tags(_), do: []
 end
diff --git a/lib/pleroma/web/metadata/providers/open_graph.ex b/lib/pleroma/web/metadata/providers/open_graph.ex
index 97d3865ed..fa5fbe553 100644
--- a/lib/pleroma/web/metadata/providers/open_graph.ex
+++ b/lib/pleroma/web/metadata/providers/open_graph.ex
@@ -67,6 +67,9 @@ defmodule Pleroma.Web.Metadata.Providers.OpenGraph do
     end
   end
 
+  @impl Provider
+  def build_tags(_), do: []
+
   defp build_attachments(%{data: %{"attachment" => attachments}}) do
     Enum.reduce(attachments, [], fn attachment, acc ->
       rendered_tags =
diff --git a/lib/pleroma/web/metadata/providers/rel_me.ex b/lib/pleroma/web/metadata/providers/rel_me.ex
index eabd8cb00..39aa71f06 100644
--- a/lib/pleroma/web/metadata/providers/rel_me.ex
+++ b/lib/pleroma/web/metadata/providers/rel_me.ex
@@ -20,6 +20,9 @@ defmodule Pleroma.Web.Metadata.Providers.RelMe do
     end)
   end
 
+  @impl Provider
+  def build_tags(_), do: []
+
   defp append_fields_tag(bio, fields) do
     fields
     |> Enum.reduce(bio, fn %{"value" => v}, res -> res <> v end)
diff --git a/lib/pleroma/web/metadata/providers/twitter_card.ex b/lib/pleroma/web/metadata/providers/twitter_card.ex
index 426022c65..7f50877c3 100644
--- a/lib/pleroma/web/metadata/providers/twitter_card.ex
+++ b/lib/pleroma/web/metadata/providers/twitter_card.ex
@@ -44,6 +44,9 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCard do
     end
   end
 
+  @impl Provider
+  def build_tags(_), do: []
+
   defp title_tag(user) do
     {:meta, [name: "twitter:title", content: Utils.user_name_string(user)], []}
   end
diff --git a/test/pleroma/web/fallback_test.exs b/test/pleroma/web/fallback_test.exs
index ed34d6490..9184cf8f1 100644
--- a/test/pleroma/web/fallback_test.exs
+++ b/test/pleroma/web/fallback_test.exs
@@ -32,7 +32,7 @@ defmodule Pleroma.Web.FallbackTest do
       resp = get(conn, "/foo")
 
       assert html_response(resp, 200) =~ "<title>a cool title</title>"
-      refute html_response(resp, 200) =~ "initial-results"
+      assert html_response(resp, 200) =~ "<meta content=\"noindex, noarchive\" name=\"robots\">"
     end
 
     test "GET /*path", %{conn: conn} do
diff --git a/test/pleroma/web/feed/user_controller_test.exs b/test/pleroma/web/feed/user_controller_test.exs
index 1c17d47b4..0a3aaff5c 100644
--- a/test/pleroma/web/feed/user_controller_test.exs
+++ b/test/pleroma/web/feed/user_controller_test.exs
@@ -147,6 +147,15 @@ defmodule Pleroma.Web.Feed.UserControllerTest do
       assert response(conn, 404)
     end
 
+    test "returns noindex meta for missing user", %{conn: conn} do
+      conn =
+        conn
+        |> put_req_header("accept", "text/html")
+        |> get("/users/nonexisting")
+
+      assert html_response(conn, 200) =~ "<meta content=\"noindex, noarchive\" name=\"robots\">"
+    end
+
     test "returns feed with public and unlisted activities", %{conn: conn} do
       user = insert(:user)
 

From ba2ae5e40bbe98d20be083d331222a9aea8b61de Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Thu, 3 Oct 2024 10:14:02 -0400
Subject: [PATCH 150/212] Check if a refresh is permitted by comparing
 timestamps before attempting to insert an Oban job

It's better to avoid inserting an Oban job that will just be rejected if it's not expensive to check.
---
 .../mastodon_api/controllers/poll_controller.ex | 17 ++++++++++++-----
 lib/pleroma/workers/poll_worker.ex              |  3 ---
 .../controllers/poll_controller_test.exs        |  5 ++++-
 3 files changed, 16 insertions(+), 9 deletions(-)

diff --git a/lib/pleroma/web/mastodon_api/controllers/poll_controller.ex b/lib/pleroma/web/mastodon_api/controllers/poll_controller.ex
index 495f89278..4b347a6a7 100644
--- a/lib/pleroma/web/mastodon_api/controllers/poll_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/poll_controller.ex
@@ -32,12 +32,10 @@ defmodule Pleroma.Web.MastodonAPI.PollController do
   @doc "GET /api/v1/polls/:id"
   def show(%{assigns: %{user: user}, private: %{open_api_spex: %{params: %{id: id}}}} = conn, _) do
     with %Object{} = object <- Object.get_by_id(id),
-         %Activity{} = activity <- Activity.get_create_by_object_ap_id(object.data["id"]),
+         %Activity{} = activity <-
+           Activity.get_create_by_object_ap_id_with_object(object.data["id"]),
          true <- Visibility.visible_for_user?(activity, user) do
-      unless activity.local do
-        PollWorker.new(%{"op" => "refresh", "activity_id" => activity.id})
-        |> Oban.insert(unique: [period: 60])
-      end
+      maybe_refresh_poll(activity)
 
       try_render(conn, "show.json", %{object: object, for: user})
     else
@@ -76,4 +74,13 @@ defmodule Pleroma.Web.MastodonAPI.PollController do
       end
     end)
   end
+
+  defp maybe_refresh_poll(%Activity{object: %Object{} = object} = activity) do
+    with false <- activity.local,
+         {:ok, end_time} <- NaiveDateTime.from_iso8601(object.data["closed"]),
+         {_, :lt} <- {:closed_compare, NaiveDateTime.compare(object.updated_at, end_time)} do
+      PollWorker.new(%{"op" => "refresh", "activity_id" => activity.id})
+      |> Oban.insert(unique: [period: 60])
+    end
+  end
 end
diff --git a/lib/pleroma/workers/poll_worker.ex b/lib/pleroma/workers/poll_worker.ex
index f70ab48a4..bb92634c9 100644
--- a/lib/pleroma/workers/poll_worker.ex
+++ b/lib/pleroma/workers/poll_worker.ex
@@ -36,8 +36,6 @@ defmodule Pleroma.Workers.PollWorker do
   def perform(%Job{args: %{"op" => "refresh", "activity_id" => activity_id}}) do
     with {_, %Activity{object: object}} <-
            {:activity, Activity.get_by_id_with_object(activity_id)},
-         {:ok, end_time} <- NaiveDateTime.from_iso8601(object.data["closed"]),
-         {_, :lt} <- {:closed_compare, NaiveDateTime.compare(object.updated_at, end_time)},
          {_, {:ok, _object}} <- {:refetch, Fetcher.refetch_object(object)} do
       stream_update(activity_id)
 
@@ -45,7 +43,6 @@ defmodule Pleroma.Workers.PollWorker do
     else
       {:activity, nil} -> {:cancel, :poll_activity_not_found}
       {:refetch, _} = e -> {:cancel, e}
-      {:closed_compare, _} -> {:cancel, :poll_finalized}
       e -> {:error, e}
     end
   end
diff --git a/test/pleroma/web/mastodon_api/controllers/poll_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/poll_controller_test.exs
index 4b236678c..51af87742 100644
--- a/test/pleroma/web/mastodon_api/controllers/poll_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/controllers/poll_controller_test.exs
@@ -29,13 +29,16 @@ defmodule Pleroma.Web.MastodonAPI.PollControllerTest do
       id = to_string(object.id)
       assert %{"id" => ^id, "expired" => false, "multiple" => false} = response
 
+      # Local activities should not generate an Oban job to refresh
+      assert activity.local
+
       refute_enqueued(
         worker: Pleroma.Workers.PollWorker,
         args: %{"op" => "refresh", "activity_id" => activity.id}
       )
     end
 
-    test "does not create oban job to refresh poll if activity is local", %{conn: conn} do
+    test "creates an oban job to refresh poll if activity is remote", %{conn: conn} do
       user = insert(:user, local: false)
       question = insert(:question, user: user)
       activity = insert(:question_activity, question: question, local: false)

From fa8de790dfbdb2cc7de212be4ecdd2823048ba8f Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Thu, 3 Oct 2024 10:19:10 -0400
Subject: [PATCH 151/212] Remove test superceded by logic change

We will not be inserting jobs that should be skipped due to updated_at
---
 test/pleroma/workers/poll_worker_test.exs | 61 ++++++++---------------
 1 file changed, 21 insertions(+), 40 deletions(-)

diff --git a/test/pleroma/workers/poll_worker_test.exs b/test/pleroma/workers/poll_worker_test.exs
index c34647f1b..70eb7c422 100644
--- a/test/pleroma/workers/poll_worker_test.exs
+++ b/test/pleroma/workers/poll_worker_test.exs
@@ -53,51 +53,32 @@ defmodule Pleroma.Workers.PollWorkerTest do
     end
   end
 
-  describe "poll refresh" do
-    test "normal job" do
-      user = insert(:user, local: false)
-      question = insert(:question, user: user)
-      activity = insert(:question_activity, question: question)
+  test "poll refresh" do
+    user = insert(:user, local: false)
+    question = insert(:question, user: user)
+    activity = insert(:question_activity, question: question)
 
-      PollWorker.new(%{"op" => "refresh", "activity_id" => activity.id})
-      |> Oban.insert()
+    PollWorker.new(%{"op" => "refresh", "activity_id" => activity.id})
+    |> Oban.insert()
 
-      expected_job_args = %{"activity_id" => activity.id, "op" => "refresh"}
+    expected_job_args = %{"activity_id" => activity.id, "op" => "refresh"}
 
-      assert_enqueued(args: expected_job_args)
-
-      with_mocks([
-        {
-          Pleroma.Web.Streamer,
-          [],
-          [
-            stream: fn _, _ -> nil end
-          ]
-        }
-      ]) do
-        [job] = all_enqueued(worker: PollWorker)
-        PollWorker.perform(job)
-
-        # Ensure updates are streamed out
-        assert called(Pleroma.Web.Streamer.stream(["user", "list", "public", "public:local"], :_))
-      end
-    end
-
-    test "when updated_at is after poll closing" do
-      poll_closed = DateTime.utc_now() |> DateTime.add(-86_400) |> DateTime.to_iso8601()
-      user = insert(:user, local: false)
-      question = insert(:question, user: user, closed: poll_closed)
-      activity = insert(:question_activity, question: question)
-
-      PollWorker.new(%{"op" => "refresh", "activity_id" => activity.id})
-      |> Oban.insert()
-
-      expected_job_args = %{"activity_id" => activity.id, "op" => "refresh"}
-
-      assert_enqueued(args: expected_job_args)
+    assert_enqueued(args: expected_job_args)
 
+    with_mocks([
+      {
+        Pleroma.Web.Streamer,
+        [],
+        [
+          stream: fn _, _ -> nil end
+        ]
+      }
+    ]) do
       [job] = all_enqueued(worker: PollWorker)
-      assert {:cancel, :poll_finalized} == PollWorker.perform(job)
+      PollWorker.perform(job)
+
+      # Ensure updates are streamed out
+      assert called(Pleroma.Web.Streamer.stream(["user", "list", "public", "public:local"], :_))
     end
   end
 end

From b854e3836fd22a2589a6a6b97478998675d72048 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Thu, 3 Oct 2024 10:30:32 -0400
Subject: [PATCH 152/212] Remove pattern that can never match

---
 lib/pleroma/workers/poll_worker.ex | 1 -
 1 file changed, 1 deletion(-)

diff --git a/lib/pleroma/workers/poll_worker.ex b/lib/pleroma/workers/poll_worker.ex
index bb92634c9..7d69bea54 100644
--- a/lib/pleroma/workers/poll_worker.ex
+++ b/lib/pleroma/workers/poll_worker.ex
@@ -43,7 +43,6 @@ defmodule Pleroma.Workers.PollWorker do
     else
       {:activity, nil} -> {:cancel, :poll_activity_not_found}
       {:refetch, _} = e -> {:cancel, e}
-      e -> {:error, e}
     end
   end
 

From a3038aa6a2189ced1e5c394a4e6e8be76f2644d0 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Thu, 3 Oct 2024 11:01:33 -0400
Subject: [PATCH 153/212] Increase poll refresh interval to 120 seconds

---
 lib/pleroma/web/mastodon_api/controllers/poll_controller.ex | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/lib/pleroma/web/mastodon_api/controllers/poll_controller.ex b/lib/pleroma/web/mastodon_api/controllers/poll_controller.ex
index 4b347a6a7..6526457df 100644
--- a/lib/pleroma/web/mastodon_api/controllers/poll_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/poll_controller.ex
@@ -28,6 +28,7 @@ defmodule Pleroma.Web.MastodonAPI.PollController do
   defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PollOperation
 
   @cachex Pleroma.Config.get([:cachex, :provider], Cachex)
+  @poll_refresh_interval 120
 
   @doc "GET /api/v1/polls/:id"
   def show(%{assigns: %{user: user}, private: %{open_api_spex: %{params: %{id: id}}}} = conn, _) do
@@ -80,7 +81,7 @@ defmodule Pleroma.Web.MastodonAPI.PollController do
          {:ok, end_time} <- NaiveDateTime.from_iso8601(object.data["closed"]),
          {_, :lt} <- {:closed_compare, NaiveDateTime.compare(object.updated_at, end_time)} do
       PollWorker.new(%{"op" => "refresh", "activity_id" => activity.id})
-      |> Oban.insert(unique: [period: 60])
+      |> Oban.insert(unique: [period: @poll_refresh_interval])
     end
   end
 end

From 4533f171ab5b73e5fc332c8f65fcf1e39e4d6003 Mon Sep 17 00:00:00 2001
From: Alex Gleason <alex@alexgleason.me>
Date: Sat, 5 Nov 2022 13:56:56 -0500
Subject: [PATCH 154/212] Add RemoteReportPolicy to reject reports without
 enough information

---
 config/config.exs                             |  4 +
 .../activity_pub/mrf/remote_report_policy.ex  | 80 +++++++++++++++++
 .../mrf/remote_report_policy_test.exs         | 85 +++++++++++++++++++
 3 files changed, 169 insertions(+)
 create mode 100644 lib/pleroma/web/activity_pub/mrf/remote_report_policy.ex
 create mode 100644 test/pleroma/web/activity_pub/mrf/remote_report_policy_test.exs

diff --git a/config/config.exs b/config/config.exs
index 47ddfac5a..203a61c75 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -434,6 +434,10 @@ config :pleroma, :mrf_follow_bot, follower_nickname: nil
 
 config :pleroma, :mrf_inline_quote, template: "<bdi>RT:</bdi> {url}"
 
+config :pleroma, :mrf_remote_report,
+  reject_anonymous: true,
+  reject_empty_message: true
+
 config :pleroma, :mrf_force_mention,
   mention_parent: true,
   mention_quoted: true
diff --git a/lib/pleroma/web/activity_pub/mrf/remote_report_policy.ex b/lib/pleroma/web/activity_pub/mrf/remote_report_policy.ex
new file mode 100644
index 000000000..3cf47e3ed
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/mrf/remote_report_policy.ex
@@ -0,0 +1,80 @@
+defmodule Pleroma.Web.ActivityPub.MRF.RemoteReportPolicy do
+  @moduledoc "Drop remote reports if they don't contain enough information."
+  @behaviour Pleroma.Web.ActivityPub.MRF.Policy
+
+  alias Pleroma.Config
+
+  @impl true
+  def filter(%{"type" => "Flag"} = object) do
+    with {_, false} <- {:local, local?(object)},
+         {:ok, _} <- maybe_reject_anonymous(object),
+         {:ok, _} <- maybe_reject_empty_message(object) do
+      {:ok, object}
+    else
+      {:local, true} -> {:ok, object}
+      {:reject, message} -> {:reject, message}
+      error -> {:reject, error}
+    end
+  end
+
+  def filter(object), do: {:ok, object}
+
+  defp maybe_reject_anonymous(%{"actor" => actor} = object) do
+    with true <- Config.get([:mrf_remote_report, :reject_anonymous]),
+         %URI{path: "/actor"} <- URI.parse(actor) do
+      {:reject, "[RemoteReportPolicy] Anonymous: #{actor}"}
+    else
+      _ -> {:ok, object}
+    end
+  end
+
+  defp maybe_reject_empty_message(%{"content" => content} = object)
+       when is_binary(content) and content != "" do
+    {:ok, object}
+  end
+
+  defp maybe_reject_empty_message(object) do
+    if Config.get([:mrf_remote_report, :reject_empty_message]) do
+      {:reject, ["RemoteReportPolicy] No content"]}
+    else
+      {:ok, object}
+    end
+  end
+
+  defp local?(%{"actor" => actor}) do
+    String.starts_with?(actor, Pleroma.Web.Endpoint.url())
+  end
+
+  @impl true
+  def describe do
+    mrf_remote_report =
+      Config.get(:mrf_remote_report)
+      |> Enum.into(%{})
+
+    {:ok, %{mrf_remote_report: mrf_remote_report}}
+  end
+
+  @impl true
+  def config_description do
+    %{
+      key: :mrf_remote_report,
+      related_policy: "Pleroma.Web.ActivityPub.MRF.RemoteReportPolicy",
+      label: "MRF Remote Report",
+      description: "Drop remote reports if they don't contain enough information.",
+      children: [
+        %{
+          key: :reject_anonymous,
+          type: :boolean,
+          description: "Reject anonymous remote reports?",
+          suggestions: [true]
+        },
+        %{
+          key: :reject_empty_message,
+          type: :boolean,
+          description: "Reject remote reports with no message?",
+          suggestions: [true]
+        }
+      ]
+    }
+  end
+end
diff --git a/test/pleroma/web/activity_pub/mrf/remote_report_policy_test.exs b/test/pleroma/web/activity_pub/mrf/remote_report_policy_test.exs
new file mode 100644
index 000000000..55fa0f2f2
--- /dev/null
+++ b/test/pleroma/web/activity_pub/mrf/remote_report_policy_test.exs
@@ -0,0 +1,85 @@
+defmodule Pleroma.Web.ActivityPub.MRF.RemoteReportPolicyTest do
+  use Pleroma.DataCase, async: true
+
+  alias Pleroma.Web.ActivityPub.MRF.RemoteReportPolicy
+
+  test "doesn't impact local report" do
+    clear_config([:mrf_remote_report, :reject_anonymous], true)
+    clear_config([:mrf_remote_report, :reject_empty_message], true)
+
+    activity = %{
+      "type" => "Flag",
+      "actor" => "http://localhost:4001/actor"
+    }
+
+    assert {:ok, _} = RemoteReportPolicy.filter(activity)
+  end
+
+  test "rejects anonymous report if `reject_anonymous: true`" do
+    clear_config([:mrf_remote_report, :reject_anonymous], true)
+
+    activity = %{
+      "type" => "Flag",
+      "actor" => "https://mastodon.social/actor"
+    }
+
+    assert {:reject, _} = RemoteReportPolicy.filter(activity)
+  end
+
+  test "preserves anonymous report if `reject_anonymous: false`" do
+    clear_config([:mrf_remote_report, :reject_anonymous], false)
+
+    activity = %{
+      "type" => "Flag",
+      "actor" => "https://mastodon.social/actor"
+    }
+
+    assert {:ok, _} = RemoteReportPolicy.filter(activity)
+  end
+
+  test "rejects empty message report if `reject_empty_message: true`" do
+    clear_config([:mrf_remote_report, :reject_empty_message], true)
+
+    activity = %{
+      "type" => "Flag",
+      "actor" => "https://mastodon.social/users/Gargron"
+    }
+
+    assert {:reject, _} = RemoteReportPolicy.filter(activity)
+  end
+
+  test "rejects empty message report (\"\") if `reject_empty_message: true`" do
+    clear_config([:mrf_remote_report, :reject_empty_message], true)
+
+    activity = %{
+      "type" => "Flag",
+      "actor" => "https://mastodon.social/users/Gargron",
+      "content" => ""
+    }
+
+    assert {:reject, _} = RemoteReportPolicy.filter(activity)
+  end
+
+  test "preserves empty message report if `reject_empty_message: false`" do
+    clear_config([:mrf_remote_report, :reject_empty_message], false)
+
+    activity = %{
+      "type" => "Flag",
+      "actor" => "https://mastodon.social/users/Gargron"
+    }
+
+    assert {:ok, _} = RemoteReportPolicy.filter(activity)
+  end
+
+  test "preserves anonymous, empty message report with all settings disabled" do
+    clear_config([:mrf_remote_report, :reject_empty_message], false)
+    clear_config([:mrf_remote_report, :reject_empty_message], false)
+
+    activity = %{
+      "type" => "Flag",
+      "actor" => "https://mastodon.social/actor"
+    }
+
+    assert {:ok, _} = RemoteReportPolicy.filter(activity)
+  end
+end

From b7c91876d2cc027a5a7f8a79ba256f13af623997 Mon Sep 17 00:00:00 2001
From: Alex Gleason <alex@alexgleason.me>
Date: Sat, 5 Nov 2022 14:07:37 -0500
Subject: [PATCH 155/212] RemoteReportPolicy: add `:reject_all` option, fix
 tests

---
 config/config.exs                             |  1 +
 .../activity_pub/mrf/remote_report_policy.ex  | 15 +++++++++++
 .../mrf/remote_report_policy_test.exs         | 25 ++++++++++++++++++-
 3 files changed, 40 insertions(+), 1 deletion(-)

diff --git a/config/config.exs b/config/config.exs
index 203a61c75..07e98011d 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -435,6 +435,7 @@ config :pleroma, :mrf_follow_bot, follower_nickname: nil
 config :pleroma, :mrf_inline_quote, template: "<bdi>RT:</bdi> {url}"
 
 config :pleroma, :mrf_remote_report,
+  reject_all: false,
   reject_anonymous: true,
   reject_empty_message: true
 
diff --git a/lib/pleroma/web/activity_pub/mrf/remote_report_policy.ex b/lib/pleroma/web/activity_pub/mrf/remote_report_policy.ex
index 3cf47e3ed..0bd83d8f0 100644
--- a/lib/pleroma/web/activity_pub/mrf/remote_report_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/remote_report_policy.ex
@@ -7,6 +7,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.RemoteReportPolicy do
   @impl true
   def filter(%{"type" => "Flag"} = object) do
     with {_, false} <- {:local, local?(object)},
+         {:ok, _} <- maybe_reject_all(object),
          {:ok, _} <- maybe_reject_anonymous(object),
          {:ok, _} <- maybe_reject_empty_message(object) do
       {:ok, object}
@@ -19,6 +20,14 @@ defmodule Pleroma.Web.ActivityPub.MRF.RemoteReportPolicy do
 
   def filter(object), do: {:ok, object}
 
+  defp maybe_reject_all(object) do
+    if Config.get([:mrf_remote_report, :reject_all]) do
+      {:reject, "[RemoteReportPolicy] Remote report"}
+    else
+      {:ok, object}
+    end
+  end
+
   defp maybe_reject_anonymous(%{"actor" => actor} = object) do
     with true <- Config.get([:mrf_remote_report, :reject_anonymous]),
          %URI{path: "/actor"} <- URI.parse(actor) do
@@ -62,6 +71,12 @@ defmodule Pleroma.Web.ActivityPub.MRF.RemoteReportPolicy do
       label: "MRF Remote Report",
       description: "Drop remote reports if they don't contain enough information.",
       children: [
+        %{
+          key: :reject_all,
+          type: :boolean,
+          description: "Reject all remote reports? (this option takes precedence)",
+          suggestions: [false]
+        },
         %{
           key: :reject_anonymous,
           type: :boolean,
diff --git a/test/pleroma/web/activity_pub/mrf/remote_report_policy_test.exs b/test/pleroma/web/activity_pub/mrf/remote_report_policy_test.exs
index 55fa0f2f2..43258a7f6 100644
--- a/test/pleroma/web/activity_pub/mrf/remote_report_policy_test.exs
+++ b/test/pleroma/web/activity_pub/mrf/remote_report_policy_test.exs
@@ -3,6 +3,10 @@ defmodule Pleroma.Web.ActivityPub.MRF.RemoteReportPolicyTest do
 
   alias Pleroma.Web.ActivityPub.MRF.RemoteReportPolicy
 
+  setup do
+    clear_config([:mrf_remote_report, :reject_all], false)
+  end
+
   test "doesn't impact local report" do
     clear_config([:mrf_remote_report, :reject_anonymous], true)
     clear_config([:mrf_remote_report, :reject_empty_message], true)
@@ -17,6 +21,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.RemoteReportPolicyTest do
 
   test "rejects anonymous report if `reject_anonymous: true`" do
     clear_config([:mrf_remote_report, :reject_anonymous], true)
+    clear_config([:mrf_remote_report, :reject_empty_message], true)
 
     activity = %{
       "type" => "Flag",
@@ -28,6 +33,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.RemoteReportPolicyTest do
 
   test "preserves anonymous report if `reject_anonymous: false`" do
     clear_config([:mrf_remote_report, :reject_anonymous], false)
+    clear_config([:mrf_remote_report, :reject_empty_message], false)
 
     activity = %{
       "type" => "Flag",
@@ -38,6 +44,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.RemoteReportPolicyTest do
   end
 
   test "rejects empty message report if `reject_empty_message: true`" do
+    clear_config([:mrf_remote_report, :reject_anonymous], false)
     clear_config([:mrf_remote_report, :reject_empty_message], true)
 
     activity = %{
@@ -49,6 +56,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.RemoteReportPolicyTest do
   end
 
   test "rejects empty message report (\"\") if `reject_empty_message: true`" do
+    clear_config([:mrf_remote_report, :reject_anonymous], false)
     clear_config([:mrf_remote_report, :reject_empty_message], true)
 
     activity = %{
@@ -61,6 +69,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.RemoteReportPolicyTest do
   end
 
   test "preserves empty message report if `reject_empty_message: false`" do
+    clear_config([:mrf_remote_report, :reject_anonymous], false)
     clear_config([:mrf_remote_report, :reject_empty_message], false)
 
     activity = %{
@@ -72,7 +81,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.RemoteReportPolicyTest do
   end
 
   test "preserves anonymous, empty message report with all settings disabled" do
-    clear_config([:mrf_remote_report, :reject_empty_message], false)
+    clear_config([:mrf_remote_report, :reject_anonymous], false)
     clear_config([:mrf_remote_report, :reject_empty_message], false)
 
     activity = %{
@@ -82,4 +91,18 @@ defmodule Pleroma.Web.ActivityPub.MRF.RemoteReportPolicyTest do
 
     assert {:ok, _} = RemoteReportPolicy.filter(activity)
   end
+
+  test "reject remote report if `reject_all: true`" do
+    clear_config([:mrf_remote_report, :reject_all], true)
+    clear_config([:mrf_remote_report, :reject_anonymous], false)
+    clear_config([:mrf_remote_report, :reject_empty_message], false)
+
+    activity = %{
+      "type" => "Flag",
+      "actor" => "https://mastodon.social/users/Gargron",
+      "content" => "Transphobia"
+    }
+
+    assert {:reject, _} = RemoteReportPolicy.filter(activity)
+  end
 end

From fd83b86b99ee6642fa0a765a55c0f0e35f272151 Mon Sep 17 00:00:00 2001
From: Mint <mint@plagu.ee>
Date: Tue, 12 Mar 2024 22:45:15 +0300
Subject: [PATCH 156/212] RemoteReportPolicy: add `reject_third_party` option

---
 .../activity_pub/mrf/remote_report_policy.ex  | 22 +++++++++
 .../mrf/remote_report_policy_test.exs         | 48 ++++++++++++++++---
 2 files changed, 63 insertions(+), 7 deletions(-)

diff --git a/lib/pleroma/web/activity_pub/mrf/remote_report_policy.ex b/lib/pleroma/web/activity_pub/mrf/remote_report_policy.ex
index 0bd83d8f0..964c59cbf 100644
--- a/lib/pleroma/web/activity_pub/mrf/remote_report_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/remote_report_policy.ex
@@ -9,6 +9,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.RemoteReportPolicy do
     with {_, false} <- {:local, local?(object)},
          {:ok, _} <- maybe_reject_all(object),
          {:ok, _} <- maybe_reject_anonymous(object),
+         {:ok, _} <- maybe_reject_third_party(object),
          {:ok, _} <- maybe_reject_empty_message(object) do
       {:ok, object}
     else
@@ -37,6 +38,21 @@ defmodule Pleroma.Web.ActivityPub.MRF.RemoteReportPolicy do
     end
   end
 
+  defp maybe_reject_third_party(%{"object" => objects} = object) do
+    {_, to} = case objects do
+      [head | tail] when is_binary(head) -> {tail, head}
+      s when is_binary(s) -> {[], s}
+      _ -> {[], ""}
+    end
+
+    with true <- Config.get([:mrf_remote_report, :reject_third_party]),
+         String.starts_with?(to, Pleroma.Web.Endpoint.url()) do
+      {:reject, "[RemoteReportPolicy] Third-party: #{to}"}
+    else
+      _ -> {:ok, object}
+    end
+  end
+
   defp maybe_reject_empty_message(%{"content" => content} = object)
        when is_binary(content) and content != "" do
     {:ok, object}
@@ -83,6 +99,12 @@ defmodule Pleroma.Web.ActivityPub.MRF.RemoteReportPolicy do
           description: "Reject anonymous remote reports?",
           suggestions: [true]
         },
+        %{
+          key: :reject_third_party,
+          type: :boolean,
+          description: "Reject reports on users from third-party instances?",
+          suggestions: [true]
+        },
         %{
           key: :reject_empty_message,
           type: :boolean,
diff --git a/test/pleroma/web/activity_pub/mrf/remote_report_policy_test.exs b/test/pleroma/web/activity_pub/mrf/remote_report_policy_test.exs
index 43258a7f6..dd56a1e9b 100644
--- a/test/pleroma/web/activity_pub/mrf/remote_report_policy_test.exs
+++ b/test/pleroma/web/activity_pub/mrf/remote_report_policy_test.exs
@@ -13,7 +13,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.RemoteReportPolicyTest do
 
     activity = %{
       "type" => "Flag",
-      "actor" => "http://localhost:4001/actor"
+      "actor" => "http://localhost:4001/actor",
+      "object" => ["https://mastodon.online/users/Gargron"]
     }
 
     assert {:ok, _} = RemoteReportPolicy.filter(activity)
@@ -25,7 +26,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.RemoteReportPolicyTest do
 
     activity = %{
       "type" => "Flag",
-      "actor" => "https://mastodon.social/actor"
+      "actor" => "https://mastodon.social/actor",
+      "object" => ["https://mastodon.online/users/Gargron"]
     }
 
     assert {:reject, _} = RemoteReportPolicy.filter(activity)
@@ -37,7 +39,34 @@ defmodule Pleroma.Web.ActivityPub.MRF.RemoteReportPolicyTest do
 
     activity = %{
       "type" => "Flag",
-      "actor" => "https://mastodon.social/actor"
+      "actor" => "https://mastodon.social/actor",
+      "object" => ["https://mastodon.online/users/Gargron"]
+    }
+
+    assert {:ok, _} = RemoteReportPolicy.filter(activity)
+  end
+
+  test "rejects report on third-party if `reject_third_party: true`" do
+    clear_config([:mrf_remote_report, :reject_third_party], true)
+    clear_config([:mrf_remote_report, :reject_empty_message], false)
+
+    activity = %{
+      "type" => "Flag",
+      "actor" => "https://mastodon.social/users/Gargron",
+      "object" => ["https://mastodon.online/users/Gargron"]
+    }
+
+    assert {:reject, _} = RemoteReportPolicy.filter(activity)
+  end
+
+  test "preserves report on third party if `reject_third_party: false`" do
+    clear_config([:mrf_remote_report, :reject_third_party], false)
+    clear_config([:mrf_remote_report, :reject_empty_message], false)
+
+    activity = %{
+      "type" => "Flag",
+      "actor" => "https://mastodon.social/users/Gargron",
+      "object" => ["https://mastodon.online/users/Gargron"]
     }
 
     assert {:ok, _} = RemoteReportPolicy.filter(activity)
@@ -49,7 +78,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.RemoteReportPolicyTest do
 
     activity = %{
       "type" => "Flag",
-      "actor" => "https://mastodon.social/users/Gargron"
+      "actor" => "https://mastodon.social/users/Gargron",
+      "object" => ["https://mastodon.online/users/Gargron"]
     }
 
     assert {:reject, _} = RemoteReportPolicy.filter(activity)
@@ -62,6 +92,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.RemoteReportPolicyTest do
     activity = %{
       "type" => "Flag",
       "actor" => "https://mastodon.social/users/Gargron",
+      "object" => ["https://mastodon.online/users/Gargron"],
       "content" => ""
     }
 
@@ -74,7 +105,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.RemoteReportPolicyTest do
 
     activity = %{
       "type" => "Flag",
-      "actor" => "https://mastodon.social/users/Gargron"
+      "actor" => "https://mastodon.social/users/Gargron",
+      "object" => ["https://mastodon.online/users/Gargron"]
     }
 
     assert {:ok, _} = RemoteReportPolicy.filter(activity)
@@ -86,7 +118,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.RemoteReportPolicyTest do
 
     activity = %{
       "type" => "Flag",
-      "actor" => "https://mastodon.social/actor"
+      "actor" => "https://mastodon.social/actor",
+      "object" => ["https://mastodon.online/users/Gargron"]
     }
 
     assert {:ok, _} = RemoteReportPolicy.filter(activity)
@@ -100,7 +133,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.RemoteReportPolicyTest do
     activity = %{
       "type" => "Flag",
       "actor" => "https://mastodon.social/users/Gargron",
-      "content" => "Transphobia"
+      "content" => "Transphobia",
+      "object" => ["https://mastodon.online/users/Gargron"]
     }
 
     assert {:reject, _} = RemoteReportPolicy.filter(activity)

From 55612cb8ee4908a2fbb200ff581bb07c7e43410a Mon Sep 17 00:00:00 2001
From: Alex Gleason <alex@alexgleason.me>
Date: Tue, 12 Mar 2024 15:52:33 -0500
Subject: [PATCH 157/212] mix format

---
 .../web/activity_pub/mrf/remote_report_policy.ex      | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/lib/pleroma/web/activity_pub/mrf/remote_report_policy.ex b/lib/pleroma/web/activity_pub/mrf/remote_report_policy.ex
index 964c59cbf..d33028931 100644
--- a/lib/pleroma/web/activity_pub/mrf/remote_report_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/remote_report_policy.ex
@@ -39,11 +39,12 @@ defmodule Pleroma.Web.ActivityPub.MRF.RemoteReportPolicy do
   end
 
   defp maybe_reject_third_party(%{"object" => objects} = object) do
-    {_, to} = case objects do
-      [head | tail] when is_binary(head) -> {tail, head}
-      s when is_binary(s) -> {[], s}
-      _ -> {[], ""}
-    end
+    {_, to} =
+      case objects do
+        [head | tail] when is_binary(head) -> {tail, head}
+        s when is_binary(s) -> {[], s}
+        _ -> {[], ""}
+      end
 
     with true <- Config.get([:mrf_remote_report, :reject_third_party]),
          String.starts_with?(to, Pleroma.Web.Endpoint.url()) do

From 48af6850fc2903d6f8c7cbf43b7db6b769c37a2a Mon Sep 17 00:00:00 2001
From: Mint <mint@plagu.ee>
Date: Fri, 12 Apr 2024 23:04:37 +0300
Subject: [PATCH 158/212] RemoteReportPolicy: Fix third-party report detection

---
 .../web/activity_pub/mrf/remote_report_policy.ex  |  2 +-
 .../mrf/remote_report_policy_test.exs             | 15 ++++++++++++++-
 2 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/lib/pleroma/web/activity_pub/mrf/remote_report_policy.ex b/lib/pleroma/web/activity_pub/mrf/remote_report_policy.ex
index d33028931..fa0610bf1 100644
--- a/lib/pleroma/web/activity_pub/mrf/remote_report_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/remote_report_policy.ex
@@ -47,7 +47,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.RemoteReportPolicy do
       end
 
     with true <- Config.get([:mrf_remote_report, :reject_third_party]),
-         String.starts_with?(to, Pleroma.Web.Endpoint.url()) do
+         false <- String.starts_with?(to, Pleroma.Web.Endpoint.url()) do
       {:reject, "[RemoteReportPolicy] Third-party: #{to}"}
     else
       _ -> {:ok, object}
diff --git a/test/pleroma/web/activity_pub/mrf/remote_report_policy_test.exs b/test/pleroma/web/activity_pub/mrf/remote_report_policy_test.exs
index dd56a1e9b..8d2a6b4fa 100644
--- a/test/pleroma/web/activity_pub/mrf/remote_report_policy_test.exs
+++ b/test/pleroma/web/activity_pub/mrf/remote_report_policy_test.exs
@@ -46,7 +46,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.RemoteReportPolicyTest do
     assert {:ok, _} = RemoteReportPolicy.filter(activity)
   end
 
-  test "rejects report on third-party if `reject_third_party: true`" do
+  test "rejects report on third party if `reject_third_party: true`" do
     clear_config([:mrf_remote_report, :reject_third_party], true)
     clear_config([:mrf_remote_report, :reject_empty_message], false)
 
@@ -59,6 +59,19 @@ defmodule Pleroma.Web.ActivityPub.MRF.RemoteReportPolicyTest do
     assert {:reject, _} = RemoteReportPolicy.filter(activity)
   end
 
+  test "preserves report on first party if `reject_third_party: true`" do
+    clear_config([:mrf_remote_report, :reject_third_party], true)
+    clear_config([:mrf_remote_report, :reject_empty_message], false)
+
+    activity = %{
+      "type" => "Flag",
+      "actor" => "https://mastodon.social/users/Gargron",
+      "object" => ["http://localhost:4001/actor"]
+    }
+
+    assert {:ok, _} = RemoteReportPolicy.filter(activity)
+  end
+
   test "preserves report on third party if `reject_third_party: false`" do
     clear_config([:mrf_remote_report, :reject_third_party], false)
     clear_config([:mrf_remote_report, :reject_empty_message], false)

From eb971aa022f524f364daf24d6e6d617bfc5ca036 Mon Sep 17 00:00:00 2001
From: Mint <mint@plagu.ee>
Date: Thu, 3 Oct 2024 20:02:58 +0300
Subject: [PATCH 159/212] Changelog

---
 changelog.d/remote-report-policy.add | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 changelog.d/remote-report-policy.add

diff --git a/changelog.d/remote-report-policy.add b/changelog.d/remote-report-policy.add
new file mode 100644
index 000000000..1cf25b1a8
--- /dev/null
+++ b/changelog.d/remote-report-policy.add
@@ -0,0 +1 @@
+Added RemoteReportPolicy from Rebased for handling bogus federated reports

From 0c41d986de973bfae82794b6fe499f8261a2f6e9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= <git@mkljczk.pl>
Date: Sun, 6 Oct 2024 17:00:39 +0200
Subject: [PATCH 160/212] Metadata: Do not include .atom feed links for remote
 accounts
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
---
 changelog.d/atom-tag.change                       | 1 +
 lib/pleroma/web/metadata/providers/feed.ex        | 4 +++-
 test/pleroma/web/metadata/providers/feed_test.exs | 6 ++++++
 3 files changed, 10 insertions(+), 1 deletion(-)
 create mode 100644 changelog.d/atom-tag.change

diff --git a/changelog.d/atom-tag.change b/changelog.d/atom-tag.change
new file mode 100644
index 000000000..1b3590dea
--- /dev/null
+++ b/changelog.d/atom-tag.change
@@ -0,0 +1 @@
+Metadata: Do not include .atom feed links for remote accounts
diff --git a/lib/pleroma/web/metadata/providers/feed.ex b/lib/pleroma/web/metadata/providers/feed.ex
index e97d6a54f..3811f96f6 100644
--- a/lib/pleroma/web/metadata/providers/feed.ex
+++ b/lib/pleroma/web/metadata/providers/feed.ex
@@ -10,7 +10,7 @@ defmodule Pleroma.Web.Metadata.Providers.Feed do
   @behaviour Provider
 
   @impl Provider
-  def build_tags(%{user: user}) do
+  def build_tags(%{user: %{local: true} = user}) do
     [
       {:link,
        [
@@ -20,4 +20,6 @@ defmodule Pleroma.Web.Metadata.Providers.Feed do
        ], []}
     ]
   end
+
+  def build_tags(_), do: []
 end
diff --git a/test/pleroma/web/metadata/providers/feed_test.exs b/test/pleroma/web/metadata/providers/feed_test.exs
index e593453da..40d9d0909 100644
--- a/test/pleroma/web/metadata/providers/feed_test.exs
+++ b/test/pleroma/web/metadata/providers/feed_test.exs
@@ -15,4 +15,10 @@ defmodule Pleroma.Web.Metadata.Providers.FeedTest do
               [rel: "alternate", type: "application/atom+xml", href: "/users/lain/feed.atom"], []}
            ]
   end
+
+  test "it doesn't render a link to remote user's feed" do
+    user = insert(:user, nickname: "lain@lain.com", local: false)
+
+    assert Feed.build_tags(%{user: user}) == []
+  end
 end

From f758b6e37c80f5adeba74009e1cc72a420937a30 Mon Sep 17 00:00:00 2001
From: tusooa <tusooa@kazv.moe>
Date: Tue, 8 Oct 2024 23:09:59 -0400
Subject: [PATCH 161/212] Fix incoming Blocks being rejected

---
 changelog.d/incoming-blocks.fix               |  1 +
 lib/pleroma/constants.ex                      |  5 +++++
 .../web/activity_pub/object_validator.ex      | 12 +++++++++++
 .../activity_pub_controller_test.exs          | 21 +++++++++++++++++++
 4 files changed, 39 insertions(+)
 create mode 100644 changelog.d/incoming-blocks.fix

diff --git a/changelog.d/incoming-blocks.fix b/changelog.d/incoming-blocks.fix
new file mode 100644
index 000000000..3228d7318
--- /dev/null
+++ b/changelog.d/incoming-blocks.fix
@@ -0,0 +1 @@
+Fix incoming Block activities being rejected
diff --git a/lib/pleroma/constants.ex b/lib/pleroma/constants.ex
index 5268ebe7a..2828c79a9 100644
--- a/lib/pleroma/constants.ex
+++ b/lib/pleroma/constants.ex
@@ -87,6 +87,7 @@ defmodule Pleroma.Constants do
 
   const(activity_types,
     do: [
+      "Block",
       "Create",
       "Update",
       "Delete",
@@ -115,6 +116,10 @@ defmodule Pleroma.Constants do
     ]
   )
 
+  const(object_types,
+    do: ~w[Event Question Answer Audio Video Image Article Note Page ChatMessage]
+  )
+
   # basic regex, just there to weed out potential mistakes
   # https://datatracker.ietf.org/doc/html/rfc2045#section-5.1
   const(mime_regex,
diff --git a/lib/pleroma/web/activity_pub/object_validator.ex b/lib/pleroma/web/activity_pub/object_validator.ex
index b3043b93a..35774d410 100644
--- a/lib/pleroma/web/activity_pub/object_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validator.ex
@@ -11,6 +11,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
 
   @behaviour Pleroma.Web.ActivityPub.ObjectValidator.Validating
 
+  import Pleroma.Constants, only: [activity_types: 0, object_types: 0]
+
   alias Pleroma.Activity
   alias Pleroma.EctoType.ActivityPub.ObjectValidators
   alias Pleroma.Object
@@ -38,6 +40,16 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
   @impl true
   def validate(object, meta)
 
+  # This overload works together with the InboxGuardPlug
+  # and ensures that we are not accepting any activity type
+  # that cannot pass InboxGuardPlug.
+  # If we want to support any more activity types, make sure to
+  # add it in Pleroma.Constants's activity_types or object_types,
+  # and, if applicable, allowed_activity_types_from_strangers.
+  def validate(%{"type" => type}, _meta)
+      when type not in activity_types() and type not in object_types(),
+      do: {:error, :not_allowed_object_type}
+
   def validate(%{"type" => "Block"} = block_activity, meta) do
     with {:ok, block_activity} <-
            block_activity
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 3bd589f49..d4175b56f 100644
--- a/test/pleroma/web/activity_pub/activity_pub_controller_test.exs
+++ b/test/pleroma/web/activity_pub/activity_pub_controller_test.exs
@@ -1320,6 +1320,27 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
         html_body: ~r/#{note.data["object"]}/i
       )
     end
+
+    test "it accepts an incoming Block", %{conn: conn, data: data} do
+      user = insert(:user)
+
+      data =
+        data
+        |> Map.put("type", "Block")
+        |> Map.put("to", [user.ap_id])
+        |> Map.put("cc", [])
+        |> Map.put("object", user.ap_id)
+
+      conn =
+        conn
+        |> assign(:valid_signature, true)
+        |> put_req_header("content-type", "application/activity+json")
+        |> post("/users/#{user.nickname}/inbox", data)
+
+      assert "ok" == json_response(conn, 200)
+      ObanHelpers.perform(all_enqueued(worker: ReceiverWorker))
+      assert Activity.get_by_ap_id(data["id"])
+    end
   end
 
   describe "GET /users/:nickname/outbox" do

From 37b1192b7bf7aa98fef0ca6c06d5b53719cb2e7b Mon Sep 17 00:00:00 2001
From: fzorb fzorbius <fzorb@catin.space>
Date: Wed, 9 Oct 2024 18:33:22 +0000
Subject: [PATCH 162/212] Should probably also include vips in the
 media/graphics packages section, as you need it to compile some library

---
 docs/installation/freebsd_en.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/installation/freebsd_en.md b/docs/installation/freebsd_en.md
index 02513daf2..920bc7d35 100644
--- a/docs/installation/freebsd_en.md
+++ b/docs/installation/freebsd_en.md
@@ -31,7 +31,7 @@ Setup the required services to automatically start at boot, using `sysrc(8)`.
 ### Install media / graphics packages (optional, see [`docs/installation/optional/media_graphics_packages.md`](../installation/optional/media_graphics_packages.md))
 
 ```shell
-# pkg install imagemagick ffmpeg p5-Image-ExifTool
+# pkg install imagemagick ffmpeg p5-Image-ExifTool vips
 ```
 
 ## Configuring Pleroma

From 03a6e33b81281256f2e9b6ffb75910fdd1a7894f Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Wed, 9 Oct 2024 16:25:58 -0400
Subject: [PATCH 163/212] Skip the final refresh job if the activity is local

---
 lib/pleroma/workers/poll_worker.ex | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/lib/pleroma/workers/poll_worker.ex b/lib/pleroma/workers/poll_worker.ex
index 7d69bea54..a9afe9d63 100644
--- a/lib/pleroma/workers/poll_worker.ex
+++ b/lib/pleroma/workers/poll_worker.ex
@@ -22,9 +22,11 @@ defmodule Pleroma.Workers.PollWorker do
   def perform(%Job{args: %{"op" => "poll_end", "activity_id" => activity_id}}) do
     with {_, %Activity{} = activity} <- {:activity, Activity.get_by_id(activity_id)},
          {:ok, notifications} <- Notification.create_poll_notifications(activity) do
-      # Schedule a final refresh
-      __MODULE__.new(%{"op" => "refresh", "activity_id" => activity_id})
-      |> Oban.insert()
+      unless activity.local do
+        # Schedule a final refresh
+        __MODULE__.new(%{"op" => "refresh", "activity_id" => activity_id})
+        |> Oban.insert()
+      end
 
       Notification.stream(notifications)
     else

From 5b04c2bf131f70120c407f5b4c242e3d245151f8 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Wed, 9 Oct 2024 20:15:00 -0400
Subject: [PATCH 164/212] Test the final refresh behavior of a PollWorker
 poll_end job

---
 test/pleroma/workers/poll_worker_test.exs | 32 ++++++++++++++++++++---
 test/support/factory.ex                   |  3 ++-
 2 files changed, 30 insertions(+), 5 deletions(-)

diff --git a/test/pleroma/workers/poll_worker_test.exs b/test/pleroma/workers/poll_worker_test.exs
index 70eb7c422..a7cbbdb83 100644
--- a/test/pleroma/workers/poll_worker_test.exs
+++ b/test/pleroma/workers/poll_worker_test.exs
@@ -11,10 +11,10 @@ defmodule Pleroma.Workers.PollWorkerTest do
 
   alias Pleroma.Workers.PollWorker
 
-  test "poll notification job" do
+  test "local poll ending notification job" do
     user = insert(:user)
     question = insert(:question, user: user)
-    activity = insert(:question_activity, question: question)
+    activity = insert(:question_activity, question: question, user: user)
 
     PollWorker.schedule_poll_end(activity)
 
@@ -45,14 +45,38 @@ defmodule Pleroma.Workers.PollWorkerTest do
       assert called(Pleroma.Web.Streamer.stream(["user", "user:notification"], :_))
       assert called(Pleroma.Web.Push.send(:_))
 
-      # Ensure we scheduled a final refresh of the poll
-      assert_enqueued(
+      # Skip refreshing polls for local activities
+      assert activity.local
+
+      refute_enqueued(
         worker: PollWorker,
         args: %{"op" => "refresh", "activity_id" => activity.id}
       )
     end
   end
 
+  test "remote poll ending notification job schedules refresh" do
+    user = insert(:user, local: false)
+    question = insert(:question, user: user)
+    activity = insert(:question_activity, question: question, user: user)
+
+    PollWorker.schedule_poll_end(activity)
+
+    expected_job_args = %{"activity_id" => activity.id, "op" => "poll_end"}
+
+    assert_enqueued(args: expected_job_args)
+
+    [job] = all_enqueued(worker: PollWorker)
+    PollWorker.perform(job)
+
+    refute activity.local
+
+    assert_enqueued(
+      worker: PollWorker,
+      args: %{"op" => "refresh", "activity_id" => activity.id}
+    )
+  end
+
   test "poll refresh" do
     user = insert(:user, local: false)
     question = insert(:question, user: user)
diff --git a/test/support/factory.ex b/test/support/factory.ex
index 732ea3143..91e5805c8 100644
--- a/test/support/factory.ex
+++ b/test/support/factory.ex
@@ -510,7 +510,8 @@ defmodule Pleroma.Factory do
     %Pleroma.Activity{
       data: data,
       actor: data["actor"],
-      recipients: data["to"]
+      recipients: data["to"],
+      local: user.local
     }
     |> Map.merge(attrs)
   end

From 23f78c75738aac49a79de2834490048cde817669 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Fri, 11 Oct 2024 14:27:11 -0400
Subject: [PATCH 165/212] Refactor password changes to go through
 Pleroma.Web.Auth so they can be supported by the different auth backends

---
 lib/pleroma/web/auth/authenticator.ex         |  5 ++++
 lib/pleroma/web/auth/pleroma_authenticator.ex | 20 +++++++++++++
 lib/pleroma/web/auth/wrapper_authenticator.ex |  4 +++
 .../controllers/util_controller.ex            | 29 ++++++++++---------
 4 files changed, 45 insertions(+), 13 deletions(-)

diff --git a/lib/pleroma/web/auth/authenticator.ex b/lib/pleroma/web/auth/authenticator.ex
index 01bf1575c..95be892cd 100644
--- a/lib/pleroma/web/auth/authenticator.ex
+++ b/lib/pleroma/web/auth/authenticator.ex
@@ -10,4 +10,9 @@ defmodule Pleroma.Web.Auth.Authenticator do
   @callback handle_error(Plug.Conn.t(), any()) :: any()
   @callback auth_template() :: String.t() | nil
   @callback oauth_consumer_template() :: String.t() | nil
+
+  @callback change_password(Pleroma.User.t(), String.t(), String.t(), String.t()) ::
+              {:ok, Pleroma.User.t()} | {:error, term()}
+
+  @optional_callbacks change_password: 4
 end
diff --git a/lib/pleroma/web/auth/pleroma_authenticator.ex b/lib/pleroma/web/auth/pleroma_authenticator.ex
index 09a58eb66..0da3f19fc 100644
--- a/lib/pleroma/web/auth/pleroma_authenticator.ex
+++ b/lib/pleroma/web/auth/pleroma_authenticator.ex
@@ -6,6 +6,7 @@ defmodule Pleroma.Web.Auth.PleromaAuthenticator do
   alias Pleroma.Registration
   alias Pleroma.Repo
   alias Pleroma.User
+  alias Pleroma.Web.CommonAPI
   alias Pleroma.Web.Plugs.AuthenticationPlug
 
   import Pleroma.Web.Auth.Helpers, only: [fetch_credentials: 1, fetch_user: 1]
@@ -101,4 +102,23 @@ defmodule Pleroma.Web.Auth.PleromaAuthenticator do
   def auth_template, do: nil
 
   def oauth_consumer_template, do: nil
+
+  @doc "Changes Pleroma.User password in the database"
+  def change_password(user, password, new_password, new_password) do
+    case CommonAPI.Utils.confirm_current_password(user, password) do
+      {:ok, user} ->
+        with {:ok, _user} <-
+               User.reset_password(user, %{
+                 password: new_password,
+                 password_confirmation: new_password
+               }) do
+          {:ok, user}
+        end
+
+      error ->
+        error
+    end
+  end
+
+  def change_password(_, _, _, _), do: {:error, :password_confirmation}
 end
diff --git a/lib/pleroma/web/auth/wrapper_authenticator.ex b/lib/pleroma/web/auth/wrapper_authenticator.ex
index a077cfa41..97b901036 100644
--- a/lib/pleroma/web/auth/wrapper_authenticator.ex
+++ b/lib/pleroma/web/auth/wrapper_authenticator.ex
@@ -39,4 +39,8 @@ defmodule Pleroma.Web.Auth.WrapperAuthenticator do
     implementation().oauth_consumer_template() ||
       Pleroma.Config.get([:auth, :oauth_consumer_template], "consumer.html")
   end
+
+  @impl true
+  def change_password(user, password, new_password, new_password_confirmation),
+    do: implementation().change_password(user, password, new_password, new_password_confirmation)
 end
diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
index 6805233df..aeafa195d 100644
--- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex
+++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
@@ -13,6 +13,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
   alias Pleroma.Healthcheck
   alias Pleroma.User
   alias Pleroma.Web.ActivityPub.ActivityPub
+  alias Pleroma.Web.Auth.WrapperAuthenticator, as: Authenticator
   alias Pleroma.Web.CommonAPI
   alias Pleroma.Web.Plugs.OAuthScopesPlug
   alias Pleroma.Web.WebFinger
@@ -195,19 +196,21 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
         %{assigns: %{user: user}, private: %{open_api_spex: %{body_params: body_params}}} = conn,
         _
       ) do
-    case CommonAPI.Utils.confirm_current_password(user, body_params.password) do
-      {:ok, user} ->
-        with {:ok, _user} <-
-               User.reset_password(user, %{
-                 password: body_params.new_password,
-                 password_confirmation: body_params.new_password_confirmation
-               }) do
-          json(conn, %{status: "success"})
-        else
-          {:error, changeset} ->
-            {_, {error, _}} = Enum.at(changeset.errors, 0)
-            json(conn, %{error: "New password #{error}."})
-        end
+    with {:ok, %User{}} <-
+           Authenticator.change_password(
+             user,
+             body_params.password,
+             body_params.new_password,
+             body_params.new_password_confirmation
+           ) do
+      json(conn, %{status: "success"})
+    else
+      {:error, %Ecto.Changeset{} = changeset} ->
+        {_, {error, _}} = Enum.at(changeset.errors, 0)
+        json(conn, %{error: "New password #{error}."})
+
+      {:error, :password_confirmation} ->
+        json(conn, %{error: "New password does not match confirmation."})
 
       {:error, msg} ->
         json(conn, %{error: msg})

From 67cc38b5ac0cb009a38de3b182f34bbcb97467da Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Fri, 11 Oct 2024 15:39:38 -0400
Subject: [PATCH 166/212] Support password changes for LDAP auth backend

---
 lib/pleroma/ldap.ex                        | 30 +++++++++++++++++++---
 lib/pleroma/web/auth/ldap_authenticator.ex |  9 +++++++
 2 files changed, 35 insertions(+), 4 deletions(-)

diff --git a/lib/pleroma/ldap.ex b/lib/pleroma/ldap.ex
index 46a2d0c17..9c1263fcf 100644
--- a/lib/pleroma/ldap.ex
+++ b/lib/pleroma/ldap.ex
@@ -83,6 +83,12 @@ defmodule Pleroma.LDAP do
     end
   end
 
+  def handle_call({:change_password, name, password, new_password}, _from, state) do
+    result = change_password(state[:handle], name, password, new_password)
+
+    {:reply, result, state, :hibernate}
+  end
+
   @impl true
   def terminate(_, state) do
     handle = Keyword.get(state, :handle)
@@ -162,17 +168,16 @@ defmodule Pleroma.LDAP do
   end
 
   defp bind_user(handle, name, password) do
-    uid = Config.get([:ldap, :uid], "cn")
-    base = Config.get([:ldap, :base])
+    dn = make_dn(name)
 
-    case :eldap.simple_bind(handle, "#{uid}=#{name},#{base}", password) do
+    case :eldap.simple_bind(handle, dn, password) do
       :ok ->
         case fetch_user(name) do
           %User{} = user ->
             user
 
           _ ->
-            register_user(handle, base, uid, name)
+            register_user(handle, ldap_base(), ldap_uid(), name)
         end
 
       # eldap does not inform us of socket closure
@@ -231,6 +236,14 @@ defmodule Pleroma.LDAP do
     end
   end
 
+  defp change_password(handle, name, password, new_password) do
+    dn = make_dn(name)
+
+    with :ok <- :eldap.simple_bind(handle, dn, password) do
+      :eldap.modify_password(handle, dn, to_charlist(new_password), to_charlist(password))
+    end
+  end
+
   defp decode_certfile(file) do
     with {:ok, data} <- File.read(file) do
       data
@@ -242,4 +255,13 @@ defmodule Pleroma.LDAP do
         []
     end
   end
+
+  defp ldap_uid, do: to_charlist(Config.get([:ldap, :uid], "cn"))
+  defp ldap_base, do: to_charlist(Config.get([:ldap, :base]))
+
+  defp make_dn(name) do
+    uid = ldap_uid()
+    base = ldap_base()
+    ~c"#{uid}=#{name},#{base}"
+  end
 end
diff --git a/lib/pleroma/web/auth/ldap_authenticator.ex b/lib/pleroma/web/auth/ldap_authenticator.ex
index 7eb06183d..9bdf8447d 100644
--- a/lib/pleroma/web/auth/ldap_authenticator.ex
+++ b/lib/pleroma/web/auth/ldap_authenticator.ex
@@ -30,4 +30,13 @@ defmodule Pleroma.Web.Auth.LDAPAuthenticator do
         error
     end
   end
+
+  def change_password(user, password, new_password, new_password) do
+    case GenServer.call(LDAP, {:change_password, user.nickname, password, new_password}) do
+      :ok -> {:ok, user}
+      e -> e
+    end
+  end
+
+  def change_password(_, _, _, _), do: {:error, :password_confirmation}
 end

From ff039f953043d2c15f1eb44f794a77865ab5a775 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Fri, 11 Oct 2024 15:41:08 -0400
Subject: [PATCH 167/212] Add example OpenLDAP ldif to enable users to change
 their own passwords

---
 installation/openldap/pw_self_service.ldif | 7 +++++++
 1 file changed, 7 insertions(+)
 create mode 100644 installation/openldap/pw_self_service.ldif

diff --git a/installation/openldap/pw_self_service.ldif b/installation/openldap/pw_self_service.ldif
new file mode 100644
index 000000000..463dabbfb
--- /dev/null
+++ b/installation/openldap/pw_self_service.ldif
@@ -0,0 +1,7 @@
+dn: olcDatabase={1}mdb,cn=config
+changetype: modify
+add: olcAccess
+olcAccess: {1}to attrs=userPassword
+  by self write
+  by anonymous auth
+  by * none

From 6bc70b8b2a7c6942bfda01bfcc301a198cf3238b Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Fri, 11 Oct 2024 15:45:09 -0400
Subject: [PATCH 168/212] Add change_password/3 to LDAP module

---
 lib/pleroma/ldap.ex                        | 4 ++++
 lib/pleroma/web/auth/ldap_authenticator.ex | 2 +-
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/lib/pleroma/ldap.ex b/lib/pleroma/ldap.ex
index 9c1263fcf..2bc894bd8 100644
--- a/lib/pleroma/ldap.ex
+++ b/lib/pleroma/ldap.ex
@@ -104,6 +104,10 @@ defmodule Pleroma.LDAP do
     GenServer.call(__MODULE__, {:bind_user, name, password})
   end
 
+  def change_password(name, password, new_password) do
+    GenServer.call(__MODULE__, {:change_password, name, password, new_password})
+  end
+
   defp connect do
     ldap = Config.get(:ldap, [])
     host = Keyword.get(ldap, :host, "localhost")
diff --git a/lib/pleroma/web/auth/ldap_authenticator.ex b/lib/pleroma/web/auth/ldap_authenticator.ex
index 9bdf8447d..ec6601fb9 100644
--- a/lib/pleroma/web/auth/ldap_authenticator.ex
+++ b/lib/pleroma/web/auth/ldap_authenticator.ex
@@ -32,7 +32,7 @@ defmodule Pleroma.Web.Auth.LDAPAuthenticator do
   end
 
   def change_password(user, password, new_password, new_password) do
-    case GenServer.call(LDAP, {:change_password, user.nickname, password, new_password}) do
+    case LDAP.change_password(user.nickname, password, new_password) do
       :ok -> {:ok, user}
       e -> e
     end

From 1da057e6a4e4f8f7ddeb0ba286a3b996c1ba7710 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Fri, 11 Oct 2024 15:51:56 -0400
Subject: [PATCH 169/212] Reorganize the LDAP module

---
 lib/pleroma/ldap.ex | 50 ++++++++++++++++++++++-----------------------
 1 file changed, 25 insertions(+), 25 deletions(-)

diff --git a/lib/pleroma/ldap.ex b/lib/pleroma/ldap.ex
index 2bc894bd8..b591c2918 100644
--- a/lib/pleroma/ldap.ex
+++ b/lib/pleroma/ldap.ex
@@ -15,6 +15,14 @@ defmodule Pleroma.LDAP do
     GenServer.start_link(__MODULE__, [], name: __MODULE__)
   end
 
+  def bind_user(name, password) do
+    GenServer.call(__MODULE__, {:bind_user, name, password})
+  end
+
+  def change_password(name, password, new_password) do
+    GenServer.call(__MODULE__, {:change_password, name, password, new_password})
+  end
+
   @impl true
   def init(state) do
     case {Config.get(Pleroma.Web.Auth.Authenticator), Config.get([:ldap, :enabled])} do
@@ -47,33 +55,16 @@ defmodule Pleroma.LDAP do
   def handle_info(:connect, _state), do: do_handle_connect()
 
   def handle_info({:bind_after_reconnect, name, password, from}, state) do
-    result = bind_user(state[:handle], name, password)
+    result = do_bind_user(state[:handle], name, password)
 
     GenServer.reply(from, result)
 
     {:noreply, state}
   end
 
-  defp do_handle_connect do
-    state =
-      case connect() do
-        {:ok, handle} ->
-          :eldap.controlling_process(handle, self())
-          Process.link(handle)
-          [handle: handle]
-
-        _ ->
-          Logger.error("Failed to connect to LDAP. Retrying in 5000ms")
-          Process.send_after(self(), :connect, 5_000)
-          []
-      end
-
-    {:noreply, state}
-  end
-
   @impl true
   def handle_call({:bind_user, name, password}, from, state) do
-    case bind_user(state[:handle], name, password) do
+    case do_bind_user(state[:handle], name, password) do
       :needs_reconnect ->
         Process.send(self(), {:bind_after_reconnect, name, password, from}, [])
         {:noreply, state, {:continue, :connect}}
@@ -100,12 +91,21 @@ defmodule Pleroma.LDAP do
     :ok
   end
 
-  def bind_user(name, password) do
-    GenServer.call(__MODULE__, {:bind_user, name, password})
-  end
+  defp do_handle_connect do
+    state =
+      case connect() do
+        {:ok, handle} ->
+          :eldap.controlling_process(handle, self())
+          Process.link(handle)
+          [handle: handle]
 
-  def change_password(name, password, new_password) do
-    GenServer.call(__MODULE__, {:change_password, name, password, new_password})
+        _ ->
+          Logger.error("Failed to connect to LDAP. Retrying in 5000ms")
+          Process.send_after(self(), :connect, 5_000)
+          []
+      end
+
+    {:noreply, state}
   end
 
   defp connect do
@@ -171,7 +171,7 @@ defmodule Pleroma.LDAP do
     end
   end
 
-  defp bind_user(handle, name, password) do
+  defp do_bind_user(handle, name, password) do
     dn = make_dn(name)
 
     case :eldap.simple_bind(handle, dn, password) do

From b6a951cfb5e277aa265436674055a4d0b993c5b9 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Fri, 11 Oct 2024 16:20:38 -0400
Subject: [PATCH 170/212] LDAP password changing changelog

---
 changelog.d/ldap-password-change.add | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 changelog.d/ldap-password-change.add

diff --git a/changelog.d/ldap-password-change.add b/changelog.d/ldap-password-change.add
new file mode 100644
index 000000000..7ca555ee4
--- /dev/null
+++ b/changelog.d/ldap-password-change.add
@@ -0,0 +1 @@
+LDAP now supports users changing their passwords

From 60ec42cb9c5f362e01ca2fb506ac153e00d5caa1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= <git@mkljczk.pl>
Date: Sat, 12 Oct 2024 23:45:18 +0200
Subject: [PATCH 171/212] Add metadata provider for ActivityPub alternate links
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
---
 changelog.d/activity-pub-metadata.add         |  1 +
 lib/pleroma/web/metadata.ex                   |  1 +
 .../web/metadata/providers/activity_pub.ex    | 19 +++++++++++
 .../metadata/providers/activity_pub_test.exs  | 34 +++++++++++++++++++
 4 files changed, 55 insertions(+)
 create mode 100644 changelog.d/activity-pub-metadata.add
 create mode 100644 lib/pleroma/web/metadata/providers/activity_pub.ex
 create mode 100644 test/pleroma/web/metadata/providers/activity_pub_test.exs

diff --git a/changelog.d/activity-pub-metadata.add b/changelog.d/activity-pub-metadata.add
new file mode 100644
index 000000000..2ad3d7b2d
--- /dev/null
+++ b/changelog.d/activity-pub-metadata.add
@@ -0,0 +1 @@
+Add metadata provider for ActivityPub alternate links
diff --git a/lib/pleroma/web/metadata.ex b/lib/pleroma/web/metadata.ex
index 59d018730..4ee7c41ec 100644
--- a/lib/pleroma/web/metadata.ex
+++ b/lib/pleroma/web/metadata.ex
@@ -7,6 +7,7 @@ defmodule Pleroma.Web.Metadata do
 
   def build_tags(params) do
     providers = [
+      Pleroma.Web.Metadata.Providers.ActivityPub,
       Pleroma.Web.Metadata.Providers.RelMe,
       Pleroma.Web.Metadata.Providers.RestrictIndexing
       | activated_providers()
diff --git a/lib/pleroma/web/metadata/providers/activity_pub.ex b/lib/pleroma/web/metadata/providers/activity_pub.ex
new file mode 100644
index 000000000..1759a5a0d
--- /dev/null
+++ b/lib/pleroma/web/metadata/providers/activity_pub.ex
@@ -0,0 +1,19 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2024 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.Metadata.Providers.ActivityPub do
+  alias Pleroma.Web.Metadata.Providers.Provider
+
+  @behaviour Provider
+
+  @impl Provider
+  def build_tags(%{object: %{data: %{"id" => object_id}}}) do
+    [{:link, [rel: "alternate", type: "application/activity+json", href: object_id], []}]
+  end
+
+  @impl Provider
+  def build_tags(%{user: user}) do
+    [{:link, [rel: "alternate", type: "application/activity+json", href: user.ap_id], []}]
+  end
+end
diff --git a/test/pleroma/web/metadata/providers/activity_pub_test.exs b/test/pleroma/web/metadata/providers/activity_pub_test.exs
new file mode 100644
index 000000000..c379ec092
--- /dev/null
+++ b/test/pleroma/web/metadata/providers/activity_pub_test.exs
@@ -0,0 +1,34 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2024 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.Metadata.Providers.ActivityPubTest do
+  use Pleroma.DataCase
+  import Pleroma.Factory
+
+  alias Pleroma.Web.CommonAPI
+  alias Pleroma.Web.Metadata.Providers.ActivityPub
+
+  setup do: clear_config([Pleroma.Web.Metadata, :unfurl_nsfw])
+
+  test "it renders a link for user info" do
+    user = insert(:user)
+    res = ActivityPub.build_tags(%{user: user})
+
+    assert res == [
+             {:link, [rel: "alternate", type: "application/activity+json", href: user.ap_id], []}
+           ]
+  end
+
+  test "it renders a link for a post" do
+    user = insert(:user)
+    {:ok, %{id: activity_id, object: object}} = CommonAPI.post(user, %{status: "hi"})
+
+    result = ActivityPub.build_tags(%{object: object, user: user, activity_id: activity_id})
+
+    assert [
+             {:link,
+              [rel: "alternate", type: "application/activity+json", href: object.data["id"]], []}
+           ] == result
+  end
+end

From f048637b41a81c527b6f3c0f5e90db91971f3842 Mon Sep 17 00:00:00 2001
From: Mark Jaroski <pleorama@rationa.li>
Date: Mon, 21 Oct 2024 00:10:27 +0000
Subject: [PATCH 172/212] Some tidying and grammer improvements for these
 installation docs, based on my experience installing Pleroma on Ubuntu 24.04
 a few minutes ago.

---
 changelog.d/debian-install-improve.skip |  1 +
 docs/installation/debian_based_en.md    | 10 ++++++++--
 2 files changed, 9 insertions(+), 2 deletions(-)
 create mode 100644 changelog.d/debian-install-improve.skip

diff --git a/changelog.d/debian-install-improve.skip b/changelog.d/debian-install-improve.skip
new file mode 100644
index 000000000..6068a3066
--- /dev/null
+++ b/changelog.d/debian-install-improve.skip
@@ -0,0 +1 @@
+Fixed a formatting issue that had a required commend embedded in a textblock, and change the language to make it a bit more idiomatic.
\ No newline at end of file
diff --git a/docs/installation/debian_based_en.md b/docs/installation/debian_based_en.md
index b61e4addd..21cfe2bff 100644
--- a/docs/installation/debian_based_en.md
+++ b/docs/installation/debian_based_en.md
@@ -69,12 +69,18 @@ cd /opt/pleroma
 sudo -Hu pleroma mix deps.get
 ```
 
-* Generate the configuration: `sudo -Hu pleroma MIX_ENV=prod mix pleroma.instance gen`
+* Generate the configuration: 
+
+```shell
+sudo -Hu pleroma MIX_ENV=prod mix pleroma.instance gen`
+```
+
+* During this process:
   * Answer with `yes` if it asks you to install `rebar3`.
   * This may take some time, because parts of pleroma get compiled first.
   * After that it will ask you a few questions about your instance and generates a configuration file in `config/generated_config.exs`.
 
-* Check the configuration and if all looks right, rename it, so Pleroma will load it (`prod.secret.exs` for productive instance, `dev.secret.exs` for development instances):
+* Check the configuration and if all looks right, rename it, so Pleroma will load it (`prod.secret.exs` for production instances, `dev.secret.exs` for development instances):
 
 ```shell
 sudo -Hu pleroma mv config/{generated_config.exs,prod.secret.exs}

From e1296737a69703535a3688f2dd205821f0e9d073 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Sun, 22 Sep 2024 15:19:05 -0400
Subject: [PATCH 173/212] Disable busywaits in releases

---
 changelog.d/release-tuning.change | 1 +
 rel/vm.args.eex                   | 5 +++++
 2 files changed, 6 insertions(+)
 create mode 100644 changelog.d/release-tuning.change

diff --git a/changelog.d/release-tuning.change b/changelog.d/release-tuning.change
new file mode 100644
index 000000000..bf9abc3ad
--- /dev/null
+++ b/changelog.d/release-tuning.change
@@ -0,0 +1 @@
+Tuning for release builds to lower CPU usage.
diff --git a/rel/vm.args.eex b/rel/vm.args.eex
index 71e803264..8e38fee4b 100644
--- a/rel/vm.args.eex
+++ b/rel/vm.args.eex
@@ -9,3 +9,8 @@
 
 ## Tweak GC to run more often
 ##-env ERL_FULLSWEEP_AFTER 10
+
+# Disable wasteful busywait.
++sbwt none
++sbwtdcpu none
++sbwtdio none

From dc6362f71df2edc126cbebbb7f346ff4768c8451 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Fri, 25 Oct 2024 11:38:20 -0400
Subject: [PATCH 174/212] Changelog

---
 changelog.d/freebsd-docs.skip | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 changelog.d/freebsd-docs.skip

diff --git a/changelog.d/freebsd-docs.skip b/changelog.d/freebsd-docs.skip
new file mode 100644
index 000000000..e69de29bb

From 63c6dacfcecd792cacbb8f735f52aa4912f23c9c Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Fri, 25 Oct 2024 11:38:20 -0400
Subject: [PATCH 175/212] Changelog

---
 changelog.d/docs-vips.skip | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 changelog.d/docs-vips.skip

diff --git a/changelog.d/docs-vips.skip b/changelog.d/docs-vips.skip
new file mode 100644
index 000000000..e69de29bb

From 00b6a586acfbd60883fc1197fb5d5ed459606c9e Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Fri, 25 Oct 2024 11:56:55 -0400
Subject: [PATCH 176/212] OpenBSD needs libvips

Confirmed package exists by testing an OpenBSD 7.6 arm64 VM
---
 docs/installation/openbsd_en.md | 2 +-
 docs/installation/openbsd_fi.md | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/docs/installation/openbsd_en.md b/docs/installation/openbsd_en.md
index e58e144d2..78bbf399f 100644
--- a/docs/installation/openbsd_en.md
+++ b/docs/installation/openbsd_en.md
@@ -12,7 +12,7 @@ For any additional information regarding commands and configuration files mentio
 To install them, run the following command (with doas or as root):
 
 ```
-pkg_add elixir gmake git postgresql-server postgresql-contrib cmake ffmpeg ImageMagick
+pkg_add elixir gmake git postgresql-server postgresql-contrib cmake ffmpeg ImageMagick libvips
 ```
 
 Pleroma requires a reverse proxy, OpenBSD has relayd in base (and is used in this guide) and packages/ports are available for nginx (www/nginx) and apache (www/apache-httpd). Independently of the reverse proxy, [acme-client(1)](https://man.openbsd.org/acme-client) can be used to get a certificate from Let's Encrypt.
diff --git a/docs/installation/openbsd_fi.md b/docs/installation/openbsd_fi.md
index 73aca3a6f..d7c94d8a0 100644
--- a/docs/installation/openbsd_fi.md
+++ b/docs/installation/openbsd_fi.md
@@ -18,7 +18,7 @@ Matrix-kanava #pleroma:libera.chat ovat hyviä paikkoja löytää apua
 
 Asenna tarvittava ohjelmisto:
 
-`# pkg_add git elixir gmake postgresql-server-10.3 postgresql-contrib-10.3 cmake ffmpeg ImageMagick`
+`# pkg_add git elixir gmake postgresql-server-10.3 postgresql-contrib-10.3 cmake ffmpeg ImageMagick libvips`
 
 #### Optional software
 

From 7d5ef8173735015c473fbc292a7f4b23d3e504a1 Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Sun, 27 Oct 2024 21:52:42 -0400
Subject: [PATCH 177/212] Fix /api/v2/media returning the wrong status code for
 media processed synchronously

The API should return a 202 only if data cannot be returned yet and a followup GET /api/v1/media/:id should be called to retrieve it. This is something Mastodon does when it needs to transcode large media files. It does not apply to Pleroma and causes apps to waste an API call when posting a status which causes apps to appear to hang on higher latency environments, such as on mobile networks.

https://docs.joinmastodon.org/methods/media/#v2
---
 changelog.d/mediav2_status.fix                                | 1 +
 lib/pleroma/web/api_spec/operations/media_operation.ex        | 2 +-
 lib/pleroma/web/mastodon_api/controllers/media_controller.ex  | 4 +---
 .../web/mastodon_api/controllers/media_controller_test.exs    | 4 ++--
 4 files changed, 5 insertions(+), 6 deletions(-)
 create mode 100644 changelog.d/mediav2_status.fix

diff --git a/changelog.d/mediav2_status.fix b/changelog.d/mediav2_status.fix
new file mode 100644
index 000000000..28e93e030
--- /dev/null
+++ b/changelog.d/mediav2_status.fix
@@ -0,0 +1 @@
+Fix /api/v2/media returning the wrong status code (202) for media processed synchronously
diff --git a/lib/pleroma/web/api_spec/operations/media_operation.ex b/lib/pleroma/web/api_spec/operations/media_operation.ex
index e6df21246..588b42e06 100644
--- a/lib/pleroma/web/api_spec/operations/media_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/media_operation.ex
@@ -121,7 +121,7 @@ defmodule Pleroma.Web.ApiSpec.MediaOperation do
       security: [%{"oAuth" => ["write:media"]}],
       requestBody: Helpers.request_body("Parameters", create_request()),
       responses: %{
-        202 => Operation.response("Media", "application/json", Attachment),
+        200 => Operation.response("Media", "application/json", Attachment),
         400 => Operation.response("Media", "application/json", ApiError),
         422 => Operation.response("Media", "application/json", ApiError),
         500 => Operation.response("Media", "application/json", ApiError)
diff --git a/lib/pleroma/web/mastodon_api/controllers/media_controller.ex b/lib/pleroma/web/mastodon_api/controllers/media_controller.ex
index 056bad844..41056d389 100644
--- a/lib/pleroma/web/mastodon_api/controllers/media_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/media_controller.ex
@@ -53,9 +53,7 @@ defmodule Pleroma.Web.MastodonAPI.MediaController do
            ) do
       attachment_data = Map.put(object.data, "id", object.id)
 
-      conn
-      |> put_status(202)
-      |> render("attachment.json", %{attachment: attachment_data})
+      render(conn, "attachment.json", %{attachment: attachment_data})
     end
   end
 
diff --git a/test/pleroma/web/mastodon_api/controllers/media_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/media_controller_test.exs
index 4adbaa640..3f696d94d 100644
--- a/test/pleroma/web/mastodon_api/controllers/media_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/controllers/media_controller_test.exs
@@ -56,7 +56,7 @@ defmodule Pleroma.Web.MastodonAPI.MediaControllerTest do
         conn
         |> put_req_header("content-type", "multipart/form-data")
         |> post("/api/v2/media", %{"file" => image, "description" => desc})
-        |> json_response_and_validate_schema(202)
+        |> json_response_and_validate_schema(200)
 
       assert media_id = response["id"]
 
@@ -111,7 +111,7 @@ defmodule Pleroma.Web.MastodonAPI.MediaControllerTest do
                  "file" => large_binary,
                  "description" => desc
                })
-               |> json_response_and_validate_schema(202)
+               |> json_response_and_validate_schema(200)
 
       assert media_id = response["id"]
 

From d2de251c4d018c7d517d399d7d5e0e20d853972f Mon Sep 17 00:00:00 2001
From: Mark Felder <feld@feld.me>
Date: Tue, 29 Oct 2024 16:00:18 -0400
Subject: [PATCH 178/212] Pleroma.Upload.Filter.Dedupe: sharding directory
 structure

Dedupe now uses a three-level sharding directory structure to improve performance when many files are uploaded and stored on a filesystem instead of an object store. (note: Minio still affected as it still uses a traditional filesystem)

This does not help if you already have hundreds of thousands of files uploaded. The media URLs are permanently part of the activity so the files cannot be relocated. A motivated user could write a tool to move the files and perhaps write an Nginx or equivalent redirect to make the files still accessible, but that is beyond the scope of this change.
---
 changelog.d/dedupe-sharding.change         |  1 +
 lib/pleroma/upload/filter/dedupe.ex        | 10 +++++++++-
 test/pleroma/object_test.exs               |  8 ++++----
 test/pleroma/upload/filter/dedupe_test.exs |  4 +++-
 test/pleroma/upload_test.exs               |  6 ++++--
 5 files changed, 21 insertions(+), 8 deletions(-)
 create mode 100644 changelog.d/dedupe-sharding.change

diff --git a/changelog.d/dedupe-sharding.change b/changelog.d/dedupe-sharding.change
new file mode 100644
index 000000000..2e140d8a2
--- /dev/null
+++ b/changelog.d/dedupe-sharding.change
@@ -0,0 +1 @@
+Dedupe upload filter now uses a three-level sharding directory structure
diff --git a/lib/pleroma/upload/filter/dedupe.ex b/lib/pleroma/upload/filter/dedupe.ex
index ef793d390..7b278d299 100644
--- a/lib/pleroma/upload/filter/dedupe.ex
+++ b/lib/pleroma/upload/filter/dedupe.ex
@@ -17,8 +17,16 @@ defmodule Pleroma.Upload.Filter.Dedupe do
       |> Base.encode16(case: :lower)
 
     filename = shasum <> "." <> extension
-    {:ok, :filtered, %Upload{upload | id: shasum, path: filename}}
+
+    {:ok, :filtered, %Upload{upload | id: shasum, path: shard_path(filename)}}
   end
 
   def filter(_), do: {:ok, :noop}
+
+  @spec shard_path(String.t()) :: String.t()
+  def shard_path(
+        <<a::binary-size(2), b::binary-size(2), c::binary-size(2), _::binary>> = filename
+      ) do
+    Path.join([a, b, c, filename])
+  end
 end
diff --git a/test/pleroma/object_test.exs b/test/pleroma/object_test.exs
index b3c528e32..ed5c2b6c8 100644
--- a/test/pleroma/object_test.exs
+++ b/test/pleroma/object_test.exs
@@ -174,8 +174,9 @@ defmodule Pleroma.ObjectTest do
 
       filename = Path.basename(href)
 
-      assert {:ok, files} = File.ls(uploads_dir)
-      assert filename in files
+      expected_path = Path.join([uploads_dir, Pleroma.Upload.Filter.Dedupe.shard_path(filename)])
+
+      assert File.exists?(expected_path)
 
       Object.delete(note)
 
@@ -183,8 +184,7 @@ defmodule Pleroma.ObjectTest do
 
       assert Object.get_by_id(note.id).data["deleted"]
       assert Object.get_by_id(attachment.id) == nil
-      assert {:ok, files} = File.ls(uploads_dir)
-      refute filename in files
+      refute File.exists?(expected_path)
     end
 
     test "with objects that have legacy data.url attribute" do
diff --git a/test/pleroma/upload/filter/dedupe_test.exs b/test/pleroma/upload/filter/dedupe_test.exs
index 29c181509..cd5ce121b 100644
--- a/test/pleroma/upload/filter/dedupe_test.exs
+++ b/test/pleroma/upload/filter/dedupe_test.exs
@@ -23,10 +23,12 @@ defmodule Pleroma.Upload.Filter.DedupeTest do
       tempfile: Path.absname("test/fixtures/image_tmp.jpg")
     }
 
+    expected_path = Dedupe.shard_path(@shasum <> ".jpg")
+
     assert {
              :ok,
              :filtered,
-             %Pleroma.Upload{id: @shasum, path: @shasum <> ".jpg"}
+             %Pleroma.Upload{id: @shasum, path: ^expected_path}
            } = Dedupe.filter(upload)
   end
 end
diff --git a/test/pleroma/upload_test.exs b/test/pleroma/upload_test.exs
index facb634c3..5fd62fa43 100644
--- a/test/pleroma/upload_test.exs
+++ b/test/pleroma/upload_test.exs
@@ -149,6 +149,9 @@ defmodule Pleroma.UploadTest do
 
     test "copies the file to the configured folder with deduping" do
       File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
+      expected_filename = "e30397b58d226d6583ab5b8b3c5defb0c682bda5c31ef07a9f57c1c4986e3781.jpg"
+
+      expected_path = Pleroma.Upload.Filter.Dedupe.shard_path(expected_filename)
 
       file = %Plug.Upload{
         content_type: "image/jpeg",
@@ -159,8 +162,7 @@ defmodule Pleroma.UploadTest do
       {:ok, data} = Upload.store(file, filters: [Pleroma.Upload.Filter.Dedupe])
 
       assert List.first(data["url"])["href"] ==
-               Pleroma.Upload.base_url() <>
-                 "e30397b58d226d6583ab5b8b3c5defb0c682bda5c31ef07a9f57c1c4986e3781.jpg"
+               Path.join([Pleroma.Upload.base_url(), expected_path])
     end
 
     test "copies the file to the configured folder without deduping" do

From 8d2410948f3310596491fcd21e4726297b89c3ba Mon Sep 17 00:00:00 2001
From: Lain Soykaf <lain@lain.com>
Date: Thu, 31 Oct 2024 18:22:21 +0400
Subject: [PATCH 179/212] Mix: Update version

---
 mix.exs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mix.exs b/mix.exs
index 89ec5e831..95fcb7491 100644
--- a/mix.exs
+++ b/mix.exs
@@ -4,7 +4,7 @@ defmodule Pleroma.Mixfile do
   def project do
     [
       app: :pleroma,
-      version: version("2.7.0"),
+      version: version("2.8.0"),
       elixir: "~> 1.14",
       elixirc_paths: elixirc_paths(Mix.env()),
       compilers: Mix.compilers(),

From ebea518c8c9dea17ff18c8fa8192a7957adcfadb Mon Sep 17 00:00:00 2001
From: Lain Soykaf <lain@lain.com>
Date: Tue, 12 Nov 2024 12:43:16 +0400
Subject: [PATCH 180/212] B DedupeTest: Add explicit test for the sharding
 structure

---
 test/pleroma/upload/filter/dedupe_test.exs | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/test/pleroma/upload/filter/dedupe_test.exs b/test/pleroma/upload/filter/dedupe_test.exs
index cd5ce121b..4dc28b998 100644
--- a/test/pleroma/upload/filter/dedupe_test.exs
+++ b/test/pleroma/upload/filter/dedupe_test.exs
@@ -10,6 +10,10 @@ defmodule Pleroma.Upload.Filter.DedupeTest do
 
   @shasum "e30397b58d226d6583ab5b8b3c5defb0c682bda5c31ef07a9f57c1c4986e3781"
 
+  test "generates a shard path for a shasum" do
+    assert "e3/03/97/" <> _path = Dedupe.shard_path(@shasum)
+  end
+
   test "adds shasum" do
     File.cp!(
       "test/fixtures/image.jpg",

From 1e9edccab8d2546427f4e02666955740f6e74a60 Mon Sep 17 00:00:00 2001
From: Codimp <contact@lithio.fr>
Date: Sat, 12 Oct 2024 20:46:07 +0000
Subject: [PATCH 181/212] Translated using Weblate (French)

Currently translated at 5.4% (53 of 974 strings)

Translation: Pleroma/Pleroma Backend (domain config_descriptions)
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-backend-domain-config_descriptions/fr/
---
 .../fr/LC_MESSAGES/config_descriptions.po     | 128 ++++++++++++------
 1 file changed, 85 insertions(+), 43 deletions(-)

diff --git a/priv/gettext/fr/LC_MESSAGES/config_descriptions.po b/priv/gettext/fr/LC_MESSAGES/config_descriptions.po
index e43db68aa..c24ab6751 100644
--- a/priv/gettext/fr/LC_MESSAGES/config_descriptions.po
+++ b/priv/gettext/fr/LC_MESSAGES/config_descriptions.po
@@ -3,14 +3,16 @@ msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2022-07-22 02:09+0300\n"
-"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
-"Last-Translator: Automatically generated\n"
-"Language-Team: none\n"
+"PO-Revision-Date: 2024-10-13 21:03+0000\n"
+"Last-Translator: Codimp <contact@lithio.fr>\n"
+"Language-Team: French <https://translate.pleroma.social/projects/pleroma/"
+"pleroma-backend-domain-config_descriptions/fr/>\n"
 "Language: fr\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: Translate Toolkit 3.7.2\n"
+"Plural-Forms: nplurals=2; plural=n > 1;\n"
+"X-Generator: Weblate 4.13.1\n"
 
 ## This file is a PO Template file.
 ##
@@ -21,7 +23,6 @@ msgstr ""
 ## Run "mix gettext.extract" to bring this file up to
 ## date. Leave "msgstr"s empty as changing them here has no
 ## effect: edit them in PO (.po) files instead.
-
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :esshd"
@@ -32,25 +33,30 @@ msgstr ""
 #, elixir-autogen, elixir-format
 msgctxt "config description at :logger"
 msgid "Logger-related settings"
-msgstr ""
+msgstr "Paramètres liés à la journalisation"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :mime"
 msgid "Mime Types settings"
-msgstr ""
+msgstr "Paramètres des types Mime"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma"
 msgid "Allows setting a token that can be used to authenticate requests with admin privileges without a normal user account token. Append the `admin_token` parameter to requests to utilize it. (Please reconsider using HTTP Basic Auth or OAuth-based authentication if possible)"
 msgstr ""
+"Permet de configurer un jeton qui peut être utilisé pour authentifier les "
+"requêtes avec des privilèges administrateurs sans utiliser un jeton de "
+"compte utilisateur standard. Pour l'utiliser, ajoutez le paramètre "
+"`admin_token`aux requêtes. (Vous devriez utiliser l'authentification HTTP "
+"Basic ou OAuth à la place si vous le pouvez)"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma"
 msgid "Authenticator"
-msgstr ""
+msgstr "Authentifieur"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -62,7 +68,7 @@ msgstr ""
 #, elixir-autogen, elixir-format
 msgctxt "config label at :cors_plug"
 msgid "CORS plug config"
-msgstr ""
+msgstr "Configuration du plug CORS"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -74,25 +80,25 @@ msgstr ""
 #, elixir-autogen, elixir-format
 msgctxt "config label at :logger"
 msgid "Logger"
-msgstr ""
+msgstr "Journaliseur"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config label at :mime"
 msgid "Mime Types"
-msgstr ""
+msgstr "Types Mime"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma"
 msgid "Pleroma Admin Token"
-msgstr ""
+msgstr "Jeton Administrateur Pleroma"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config label at :pleroma"
 msgid "Pleroma Authenticator"
-msgstr ""
+msgstr "Authentifieur Pleroma"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -104,103 +110,111 @@ msgstr ""
 #, elixir-autogen, elixir-format
 msgctxt "config description at :logger-:console"
 msgid "Console logger settings"
-msgstr ""
+msgstr "Paramètres de journalisation de la console"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :logger-:ex_syslogger"
 msgid "ExSyslogger-related settings"
-msgstr ""
+msgstr "Paramètres liés à ExSyslogger"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:activitypub"
 msgid "ActivityPub-related settings"
-msgstr ""
+msgstr "Paramètres liés à ActivityPub"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:assets"
 msgid "This section configures assets to be used with various frontends. Currently the only option relates to mascots on the mastodon frontend"
 msgstr ""
+"Cette section configure les annexes (assets) à utiliser avec divers "
+"frontaux. La seule option est actuellement liée au mascottes du frontal "
+"mastodon"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:auth"
 msgid "Authentication / authorization settings"
-msgstr ""
+msgstr "Paramètres d'authentification/autorisations"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:connections_pool"
 msgid "Advanced settings for `Gun` connections pool"
-msgstr ""
+msgstr "Paramètres avancés pour le bac (pool) de connexions `Gun`"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:email_notifications"
 msgid "Email notifications settings"
-msgstr ""
+msgstr "Paramètres de notification par email"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:features"
 msgid "Customizable features"
-msgstr ""
+msgstr "Fonctionnalités personnalisables"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:feed"
 msgid "Configure feed rendering"
-msgstr ""
+msgstr "Configurer le rendu des flux"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:frontend_configurations"
 msgid "This form can be used to configure a keyword list that keeps the configuration data for any kind of frontend. By default, settings for pleroma_fe are configured. If you want to add your own configuration your settings all fields must be complete."
 msgstr ""
+"Ce formulaire peut être utilisé pour configurer une liste de clés (keyword) "
+"qui contiennent les données de configuration pour tout types de frontaux. "
+"Par défaut, les paramètres pour pleroma_fe sont configurés. Si vous voulez "
+"ajouter vos propres paramètres de configurations, tout les champs doivent "
+"être remplis."
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:frontends"
 msgid "Installed frontends management"
-msgstr ""
+msgstr "Gestion des frontaux installés"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:gopher"
 msgid "Gopher settings"
-msgstr ""
+msgstr "Paramètres Gopher"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:hackney_pools"
 msgid "Advanced settings for `Hackney` connections pools"
-msgstr ""
+msgstr "Paramètres avancés pour les bacs (pool) de connexions `Hackney`"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:http"
 msgid "HTTP settings"
-msgstr ""
+msgstr "Paramètres HTTP"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:http_security"
 msgid "HTTP security settings"
-msgstr ""
+msgstr "Paramètres de sécurité HTTP"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:instance"
 msgid "Instance-related settings"
-msgstr ""
+msgstr "Paramètres liés à l'instance"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:instances_favicons"
 msgid "Control favicons for instances"
-msgstr ""
+msgstr "Gère les favicons des instances"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -212,151 +226,177 @@ msgstr ""
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:majic_pool"
 msgid "Majic/libmagic configuration"
-msgstr ""
+msgstr "Configuration de majic/libmagic"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:manifest"
 msgid "This section describe PWA manifest instance-specific values. Currently this option relate only for MastoFE."
 msgstr ""
+"Cette section décrit les valeurs spécifique à l'instance du manifeste PWA. "
+"Actuellement, cette option ne concerne que MastoFE."
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:media_preview_proxy"
 msgid "Media preview proxy"
-msgstr ""
+msgstr "Proxy de prévisualisation média"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:media_proxy"
 msgid "Media proxy"
-msgstr ""
+msgstr "Proxy média"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:modules"
 msgid "Custom Runtime Modules"
-msgstr ""
+msgstr "Modules Runtime Personalisés"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:mrf"
 msgid "General MRF settings"
-msgstr ""
+msgstr "Paramètres généraux MRF"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:mrf_activity_expiration"
 msgid "Adds automatic expiration to all local activities"
-msgstr ""
+msgstr "Ajoute une expiration automatique à toutes les activités locales"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:mrf_follow_bot"
 msgid "Automatically follows newly discovered accounts."
-msgstr ""
+msgstr "Suivre automatiquement les comptes venant d'être découverts."
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:mrf_hashtag"
 msgid "Reject, TWKN-remove or Set-Sensitive messsages with specific hashtags (without the leading #)\n\nNote: This MRF Policy is always enabled, if you want to disable it you have to set empty lists.\n"
 msgstr ""
+"Rejeter, Enlever de TWKN ou marquer comme contenu sensible les messages avec "
+"des mots-croisillons (sans mettre le # du début)\n"
+"\n"
+"Note: cette politique MRF est toujours activée. Si vous voulez la "
+"désactiver, vous devez configurer des listes vides.\n"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:mrf_hellthread"
 msgid "Block messages with excessive user mentions"
-msgstr ""
+msgstr "Bloquer les messages avec un nombre excessif de mentions"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:mrf_keyword"
 msgid "Reject or Word-Replace messages matching a keyword or [Regex](https://hexdocs.pm/elixir/Regex.html)."
 msgstr ""
+"Rejeter ou remplacer les mots des messages qui correspondent à un mot clef "
+"ou à une [expression rationnelle (Regex)](https://hexdocs.pm/elixir/Regex."
+"html)."
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:mrf_mention"
 msgid "Block messages which mention a specific user"
-msgstr ""
+msgstr "Bloquer les messages mentionnant un utilisateur particulier"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:mrf_normalize_markup"
 msgid "MRF NormalizeMarkup settings. Scrub configured hypertext markup."
 msgstr ""
+"Paramètres de normalisation MRF. Balaie les balises hypertextes configurées."
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:mrf_object_age"
 msgid "Rejects or delists posts based on their timestamp deviance from your server's clock."
 msgstr ""
+"Rejette ou retire des listes les messages selon l'écart entre leur heure et "
+"l'horloge de votre serveur."
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:mrf_rejectnonpublic"
 msgid "RejectNonPublic drops posts with non-public visibility settings."
 msgstr ""
+"RejectNonPublic enlève les messages avec des paramètres de visibilité non-"
+"publics."
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:mrf_simple"
 msgid "Simple ingress policies"
-msgstr ""
+msgstr "Politiques simples pour entrants"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:mrf_steal_emoji"
 msgid "Steals emojis from selected instances when it sees them."
-msgstr ""
+msgstr "Vole les emojis des instances sélectionnées quand il les voit."
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:mrf_subchain"
 msgid "This policy processes messages through an alternate pipeline when a given message matches certain criteria. All criteria are configured as a map of regular expressions to lists of policy modules."
 msgstr ""
+"Cette politique traite les messages à travers un tuyau séparé lorsqu'un "
+"message donné correspond à certain critères. Chaque critère est configuré "
+"comme une correspondance entre une expression rationnelle et une liste de "
+"modules de politiques."
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:mrf_vocabulary"
 msgid "Filter messages which belong to certain activity vocabularies"
 msgstr ""
+"Filtrer les messages qui correspondent à certain vocabulaires d'activités"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:oauth2"
 msgid "Configure OAuth 2 provider capabilities"
-msgstr ""
+msgstr "Configurer les capacités du fournisseur OAuth 2"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:pools"
 msgid "Advanced settings for `Gun` workers pools"
-msgstr ""
+msgstr "Paramètres avancés pour les bacs (pools) de travailleurs `Gun`"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:populate_hashtags_table"
 msgid "`populate_hashtags_table` background migration settings"
-msgstr ""
+msgstr "Paramètres de migration en arrière-plan `populate_hashtags_table`"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:rate_limit"
 msgid "Rate limit settings. This is an advanced feature enabled only for :authentication by default."
 msgstr ""
+"Paramètres de limites par secondes. C'est une fonctionnalité avancée qui, "
+"par défaut, n'est activée que pour :authentication."
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:restrict_unauthenticated"
 msgid "Disallow viewing timelines, user profiles and statuses for unauthenticated users."
 msgstr ""
+"Empêche de regarder les flux, les profils utilisateurs et les status pour "
+"les utilisateurs non-authentifiés."
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:rich_media"
 msgid "If enabled the instance will parse metadata from attached links to generate link previews"
 msgstr ""
+"Si activé, l'instance interprétera les métadonnées des liens joins pour "
+"générer les prévisualisations de liens"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -369,6 +409,8 @@ msgstr ""
 msgctxt "config description at :pleroma-:static_fe"
 msgid "Render profiles and posts using server-generated HTML that is viewable without using JavaScript"
 msgstr ""
+"Rendre les profils et les status en utilisant du HTML généré par le serveur "
+"qui ne nécessitera pas de JavaScript"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format
@@ -380,7 +422,7 @@ msgstr ""
 #, elixir-autogen, elixir-format
 msgctxt "config description at :pleroma-:uri_schemes"
 msgid "URI schemes related settings"
-msgstr ""
+msgstr "Paramètres liés au schémas d'URI"
 
 #: lib/pleroma/docs/translator.ex:5
 #, elixir-autogen, elixir-format

From 5b3e4cf49bfc80579c6349dd9f81001142a7d3d0 Mon Sep 17 00:00:00 2001
From: Lain Soykaf <lain@lain.com>
Date: Tue, 12 Nov 2024 14:22:02 +0400
Subject: [PATCH 182/212] B Providers/ActivityPub: Ensure that nothing explodes
 on unexpected input.

---
 lib/pleroma/web/metadata/providers/activity_pub.ex        | 3 +++
 test/pleroma/web/metadata/providers/activity_pub_test.exs | 6 ++++++
 2 files changed, 9 insertions(+)

diff --git a/lib/pleroma/web/metadata/providers/activity_pub.ex b/lib/pleroma/web/metadata/providers/activity_pub.ex
index 1759a5a0d..bd9f92332 100644
--- a/lib/pleroma/web/metadata/providers/activity_pub.ex
+++ b/lib/pleroma/web/metadata/providers/activity_pub.ex
@@ -16,4 +16,7 @@ defmodule Pleroma.Web.Metadata.Providers.ActivityPub do
   def build_tags(%{user: user}) do
     [{:link, [rel: "alternate", type: "application/activity+json", href: user.ap_id], []}]
   end
+
+  @impl Provider
+  def build_tags(_), do: []
 end
diff --git a/test/pleroma/web/metadata/providers/activity_pub_test.exs b/test/pleroma/web/metadata/providers/activity_pub_test.exs
index c379ec092..c5cf78a60 100644
--- a/test/pleroma/web/metadata/providers/activity_pub_test.exs
+++ b/test/pleroma/web/metadata/providers/activity_pub_test.exs
@@ -31,4 +31,10 @@ defmodule Pleroma.Web.Metadata.Providers.ActivityPubTest do
               [rel: "alternate", type: "application/activity+json", href: object.data["id"]], []}
            ] == result
   end
+
+  test "it returns an empty array for anything else" do
+    result = ActivityPub.build_tags(%{})
+
+    assert result == []
+  end
 end

From 29b048d351fb9867f11892315bed49adfbb282fb Mon Sep 17 00:00:00 2001
From: Lain Soykaf <lain@lain.com>
Date: Tue, 12 Nov 2024 14:35:02 +0400
Subject: [PATCH 183/212] B TwitterAPI/ControllerTest: Actually test the keys

---
 test/pleroma/web/twitter_api/controller_test.exs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/pleroma/web/twitter_api/controller_test.exs b/test/pleroma/web/twitter_api/controller_test.exs
index 0019b51af..494be9ec7 100644
--- a/test/pleroma/web/twitter_api/controller_test.exs
+++ b/test/pleroma/web/twitter_api/controller_test.exs
@@ -69,7 +69,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
         |> hd()
         |> Map.keys()
 
-      assert keys -- ["id", "app_name", "valid_until", "scopes"] == []
+      assert Enum.sort(keys) == Enum.sort(["id", "app_name", "valid_until", "scopes"])
     end
 
     test "revoke token", %{token: token} do

From 0c3b71e1cc9a60941e434f4fad8d6968c1f00b48 Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier" <contact@hacktivis.me>
Date: Wed, 13 Nov 2024 04:24:05 +0100
Subject: [PATCH 184/212] mix.lock: bump fast_html to 2.3.0

---
 changelog.d/bump-lexbor.change | 1 +
 mix.lock                       | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)
 create mode 100644 changelog.d/bump-lexbor.change

diff --git a/changelog.d/bump-lexbor.change b/changelog.d/bump-lexbor.change
new file mode 100644
index 000000000..2c7061a81
--- /dev/null
+++ b/changelog.d/bump-lexbor.change
@@ -0,0 +1 @@
+- Bumped `fast_html` to v2.3.0, which notably allows to use system-installed lexbor with passing `WITH_SYSTEM_LEXBOR=1` environment variable at build-time
\ No newline at end of file
diff --git a/mix.lock b/mix.lock
index 421f99ec0..a98867142 100644
--- a/mix.lock
+++ b/mix.lock
@@ -50,7 +50,7 @@
   "ex_syslogger": {:hex, :ex_syslogger, "1.5.2", "72b6aa2d47a236e999171f2e1ec18698740f40af0bd02c8c650bf5f1fd1bac79", [:mix], [{:poison, ">= 1.5.0", [hex: :poison, repo: "hexpm", optional: true]}, {:syslog, "~> 1.1.0", [hex: :syslog, repo: "hexpm", optional: false]}], "hexpm", "ab9fab4136dbc62651ec6f16fa4842f10cf02ab4433fa3d0976c01be99398399"},
   "exile": {:hex, :exile, "0.10.0", "b69e2d27a9af670b0f0a0898addca0eda78f6f5ba95ccfbc9bc6ccdd04925436", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "c62ee8fee565b5ac4a898d0dcd58d2b04fb5eec1655af1ddcc9eb582c6732c33"},
   "expo": {:hex, :expo, "0.5.1", "249e826a897cac48f591deba863b26c16682b43711dd15ee86b92f25eafd96d9", [:mix], [], "hexpm", "68a4233b0658a3d12ee00d27d37d856b1ba48607e7ce20fd376958d0ba6ce92b"},
-  "fast_html": {:hex, :fast_html, "2.2.0", "6c5ef1be087a4ed613b0379c13f815c4d11742b36b67bb52cee7859847c84520", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}], "hexpm", "064c4f23b4a6168f9187dac8984b056f2c531bb0787f559fd6a8b34b38aefbae"},
+  "fast_html": {:hex, :fast_html, "2.3.0", "08c1d8ead840dd3060ba02c761bed9f37f456a1ddfe30bcdcfee8f651cec06a6", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}], "hexpm", "f18e3c7668f82d3ae0b15f48d48feeb257e28aa5ab1b0dbf781c7312e5da029d"},
   "fast_sanitize": {:hex, :fast_sanitize, "0.2.3", "67b93dfb34e302bef49fec3aaab74951e0f0602fd9fa99085987af05bd91c7a5", [:mix], [{:fast_html, "~> 2.0", [hex: :fast_html, repo: "hexpm", optional: false]}, {:plug, "~> 1.8", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "e8ad286d10d0386e15d67d0ee125245ebcfbc7d7290b08712ba9013c8c5e56e2"},
   "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"},
   "finch": {:hex, :finch, "0.18.0", "944ac7d34d0bd2ac8998f79f7a811b21d87d911e77a786bc5810adb75632ada4", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6 or ~> 1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "69f5045b042e531e53edc2574f15e25e735b522c37e2ddb766e15b979e03aa65"},

From c9f9ec04c8b7c24b47acb3f5a00f596b699c2c82 Mon Sep 17 00:00:00 2001
From: Mint <mint@plagu.ee>
Date: Thu, 21 Nov 2024 02:13:10 +0300
Subject: [PATCH 185/212] Meilisearch: use PUT method for indexing Mix task

See https://github.com/meilisearch/meilisearch/issues/2619
---
 lib/mix/tasks/pleroma/search/meilisearch.ex | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/mix/tasks/pleroma/search/meilisearch.ex b/lib/mix/tasks/pleroma/search/meilisearch.ex
index 8379a0c25..389b8a564 100644
--- a/lib/mix/tasks/pleroma/search/meilisearch.ex
+++ b/lib/mix/tasks/pleroma/search/meilisearch.ex
@@ -28,7 +28,7 @@ defmodule Mix.Tasks.Pleroma.Search.Meilisearch do
     end
 
     {:ok, _} =
-      meili_post(
+      meili_put(
         "/indexes/objects/settings/ranking-rules",
         [
           "published:desc",
@@ -42,7 +42,7 @@ defmodule Mix.Tasks.Pleroma.Search.Meilisearch do
       )
 
     {:ok, _} =
-      meili_post(
+      meili_put(
         "/indexes/objects/settings/searchable-attributes",
         [
           "content"

From d65f768b59649de5ed5e76d7dd8248c76fd81a9f Mon Sep 17 00:00:00 2001
From: Mint <mint@plagu.ee>
Date: Thu, 21 Nov 2024 02:14:55 +0300
Subject: [PATCH 186/212] Meilisearch: stop attempting to index posts with nil
 date

---
 lib/pleroma/search/meilisearch.ex | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/pleroma/search/meilisearch.ex b/lib/pleroma/search/meilisearch.ex
index 9bba5b30f..cafae8099 100644
--- a/lib/pleroma/search/meilisearch.ex
+++ b/lib/pleroma/search/meilisearch.ex
@@ -122,6 +122,7 @@ defmodule Pleroma.Search.Meilisearch do
     # Only index public or unlisted Notes
     if not is_nil(object) and object.data["type"] == "Note" and
          not is_nil(object.data["content"]) and
+         not is_nil(object.data["published"]) and
          (Pleroma.Constants.as_public() in object.data["to"] or
             Pleroma.Constants.as_public() in object.data["cc"]) and
          object.data["content"] not in ["", "."] do

From 3a82a51a6e8b25c2e58e75329e12a090ad977519 Mon Sep 17 00:00:00 2001
From: Mint <mint@plagu.ee>
Date: Thu, 21 Nov 2024 02:16:36 +0300
Subject: [PATCH 187/212] Docs: fix OTP mix task command for Meilisearch

---
 docs/configuration/search.md | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/docs/configuration/search.md b/docs/configuration/search.md
index d34f84d4f..de1a72203 100644
--- a/docs/configuration/search.md
+++ b/docs/configuration/search.md
@@ -73,7 +73,7 @@ you have to get the _private key_, which is actually used for authentication.
 
 === "OTP"
     ```sh
-    ./bin/pleroma_ctl search.meilisearch show-keys <your master key here>
+    ./bin/pleroma_ctl meilisearch show-keys <your master key here>
     ```
 
 === "From Source"
@@ -103,7 +103,7 @@ To start the initial indexing, run the `index` command:
 
 === "OTP"
     ```sh
-    ./bin/pleroma_ctl search.meilisearch index
+    ./bin/pleroma_ctl meilisearch index
     ```
 
 === "From Source"
@@ -118,7 +118,7 @@ of indexing and how many posts have actually been indexed, use the `stats` comma
 
 === "OTP"
     ```sh
-    ./bin/pleroma_ctl search.meilisearch stats
+    ./bin/pleroma_ctl meilisearch stats
     ```
 
 === "From Source"
@@ -133,7 +133,7 @@ use the `clear` command:
 
 === "OTP"
     ```sh
-    ./bin/pleroma_ctl search.meilisearch clear
+    ./bin/pleroma_ctl meilisearch clear
     ```
 
 === "From Source"

From af7de4c17a0f146a3048d5b2742a292e69bbbb70 Mon Sep 17 00:00:00 2001
From: Mint <mint@plagu.ee>
Date: Thu, 21 Nov 2024 02:17:53 +0300
Subject: [PATCH 188/212] Changelog

---
 changelog.d/meilisearch-misc-fixes.fix | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 changelog.d/meilisearch-misc-fixes.fix

diff --git a/changelog.d/meilisearch-misc-fixes.fix b/changelog.d/meilisearch-misc-fixes.fix
new file mode 100644
index 000000000..0f127d3a8
--- /dev/null
+++ b/changelog.d/meilisearch-misc-fixes.fix
@@ -0,0 +1 @@
+Miscellaneous fixes for Meilisearch support

From da7132caba49777c25413efc8adc90d27576b07f Mon Sep 17 00:00:00 2001
From: Mint <mint@plagu.ee>
Date: Thu, 21 Nov 2024 02:40:27 +0300
Subject: [PATCH 189/212] Remove unused import

---
 lib/mix/tasks/pleroma/search/meilisearch.ex | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/mix/tasks/pleroma/search/meilisearch.ex b/lib/mix/tasks/pleroma/search/meilisearch.ex
index 389b8a564..edce9e871 100644
--- a/lib/mix/tasks/pleroma/search/meilisearch.ex
+++ b/lib/mix/tasks/pleroma/search/meilisearch.ex
@@ -9,7 +9,7 @@ defmodule Mix.Tasks.Pleroma.Search.Meilisearch do
   import Ecto.Query
 
   import Pleroma.Search.Meilisearch,
-    only: [meili_post: 2, meili_put: 2, meili_get: 1, meili_delete: 1]
+    only: [meili_put: 2, meili_get: 1, meili_delete: 1]
 
   def run(["index"]) do
     start_pleroma()

From 551534f3eeae0062a06e10a322ba17a6d4ee8b9a Mon Sep 17 00:00:00 2001
From: Lain Soykaf <lain@lain.com>
Date: Thu, 21 Nov 2024 16:07:09 +0400
Subject: [PATCH 190/212] B ReleaseTasks: Fix task module finding.

---
 changelog.d/module-search-in-pleroma-ctl.fix |  1 +
 lib/pleroma/release_tasks.ex                 | 23 +++++++++++++-------
 test/pleroma/release_tasks_test.exs          | 19 ++++++++++++++++
 3 files changed, 35 insertions(+), 8 deletions(-)
 create mode 100644 changelog.d/module-search-in-pleroma-ctl.fix
 create mode 100644 test/pleroma/release_tasks_test.exs

diff --git a/changelog.d/module-search-in-pleroma-ctl.fix b/changelog.d/module-search-in-pleroma-ctl.fix
new file mode 100644
index 000000000..d32fe3f33
--- /dev/null
+++ b/changelog.d/module-search-in-pleroma-ctl.fix
@@ -0,0 +1 @@
+Fix pleroma_ctl mix task calls sometimes not being found
diff --git a/lib/pleroma/release_tasks.ex b/lib/pleroma/release_tasks.ex
index bcfcd1243..af2d35c8f 100644
--- a/lib/pleroma/release_tasks.ex
+++ b/lib/pleroma/release_tasks.ex
@@ -16,17 +16,24 @@ defmodule Pleroma.ReleaseTasks do
     end
   end
 
+  def find_module(task) do
+    module_name =
+      task
+      |> String.split(".")
+      |> Enum.map(&String.capitalize/1)
+      |> then(fn x -> [Mix, Tasks, Pleroma] ++ x end)
+      |> Module.concat()
+
+    case Code.ensure_loaded(module_name) do
+      {:module, _} -> module_name
+      _ -> nil
+    end
+  end
+
   defp mix_task(task, args) do
     Application.load(:pleroma)
-    {:ok, modules} = :application.get_key(:pleroma, :modules)
 
-    module =
-      Enum.find(modules, fn module ->
-        module = Module.split(module)
-
-        match?(["Mix", "Tasks", "Pleroma" | _], module) and
-          String.downcase(List.last(module)) == task
-      end)
+    module = find_module(task)
 
     if module do
       module.run(args)
diff --git a/test/pleroma/release_tasks_test.exs b/test/pleroma/release_tasks_test.exs
new file mode 100644
index 000000000..5a4293189
--- /dev/null
+++ b/test/pleroma/release_tasks_test.exs
@@ -0,0 +1,19 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.ReleaseTaskTest do
+  use Pleroma.DataCase, async: true
+
+  alias Pleroma.ReleaseTasks
+
+  test "finding the module" do
+    task = "search.meilisearch"
+    assert Mix.Tasks.Pleroma.Search.Meilisearch == ReleaseTasks.find_module(task)
+
+    task = "user"
+    assert Mix.Tasks.Pleroma.User == ReleaseTasks.find_module(task)
+
+    refute ReleaseTasks.find_module("doesnt.exist")
+  end
+end

From 14dbf789b3e0e84f588999954f07a378a6ccfcf6 Mon Sep 17 00:00:00 2001
From: Lain Soykaf <lain@lain.com>
Date: Thu, 21 Nov 2024 16:32:05 +0400
Subject: [PATCH 191/212] Linting

---
 test/pleroma/{release_tasks_test.exs => release_task_test.exs} | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename test/pleroma/{release_tasks_test.exs => release_task_test.exs} (100%)

diff --git a/test/pleroma/release_tasks_test.exs b/test/pleroma/release_task_test.exs
similarity index 100%
rename from test/pleroma/release_tasks_test.exs
rename to test/pleroma/release_task_test.exs

From 462a6a2000d10e3b6047bc72143ff239caf40186 Mon Sep 17 00:00:00 2001
From: Mint <mint@plagu.ee>
Date: Thu, 21 Nov 2024 16:52:30 +0300
Subject: [PATCH 192/212] Revert "Docs: fix OTP mix task command for
 Meilisearch"

This reverts commit 3a82a51a6e8b25c2e58e75329e12a090ad977519.
---
 docs/configuration/search.md | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/docs/configuration/search.md b/docs/configuration/search.md
index de1a72203..d34f84d4f 100644
--- a/docs/configuration/search.md
+++ b/docs/configuration/search.md
@@ -73,7 +73,7 @@ you have to get the _private key_, which is actually used for authentication.
 
 === "OTP"
     ```sh
-    ./bin/pleroma_ctl meilisearch show-keys <your master key here>
+    ./bin/pleroma_ctl search.meilisearch show-keys <your master key here>
     ```
 
 === "From Source"
@@ -103,7 +103,7 @@ To start the initial indexing, run the `index` command:
 
 === "OTP"
     ```sh
-    ./bin/pleroma_ctl meilisearch index
+    ./bin/pleroma_ctl search.meilisearch index
     ```
 
 === "From Source"
@@ -118,7 +118,7 @@ of indexing and how many posts have actually been indexed, use the `stats` comma
 
 === "OTP"
     ```sh
-    ./bin/pleroma_ctl meilisearch stats
+    ./bin/pleroma_ctl search.meilisearch stats
     ```
 
 === "From Source"
@@ -133,7 +133,7 @@ use the `clear` command:
 
 === "OTP"
     ```sh
-    ./bin/pleroma_ctl meilisearch clear
+    ./bin/pleroma_ctl search.meilisearch clear
     ```
 
 === "From Source"

From ced6b10c70769e39ee7d3b6a3fe63b8c2aea3ec0 Mon Sep 17 00:00:00 2001
From: feld <feld@feld.me>
Date: Mon, 12 Aug 2024 19:52:37 +0000
Subject: [PATCH 193/212] Merge branch 'swoosh-mailgun' into 'develop'

Fix Swoosh Mailgun support

See merge request pleroma/pleroma!4217
---
 changelog.d/mailgun.fix | 1 +
 mix.exs                 | 1 +
 mix.lock                | 1 +
 3 files changed, 3 insertions(+)
 create mode 100644 changelog.d/mailgun.fix

diff --git a/changelog.d/mailgun.fix b/changelog.d/mailgun.fix
new file mode 100644
index 000000000..855588752
--- /dev/null
+++ b/changelog.d/mailgun.fix
@@ -0,0 +1 @@
+The Swoosh email adapter for Mailgun was missing a new dependency on :multipart
diff --git a/mix.exs b/mix.exs
index 69e52e526..e3c8559ba 100644
--- a/mix.exs
+++ b/mix.exs
@@ -202,6 +202,7 @@ defmodule Pleroma.Mixfile do
       {:bandit, "~> 1.5.2"},
       {:websock_adapter, "~> 0.5.6"},
       {:oban_live_dashboard, "~> 0.1.1"},
+      {:multipart, "~> 0.4.0", optional: true},
 
       ## dev & test
       {:phoenix_live_reload, "~> 1.3.3", only: :dev},
diff --git a/mix.lock b/mix.lock
index 61ede9e5e..37ac1768b 100644
--- a/mix.lock
+++ b/mix.lock
@@ -84,6 +84,7 @@
   "mock": {:hex, :mock, "0.3.8", "7046a306b71db2488ef54395eeb74df0a7f335a7caca4a3d3875d1fc81c884dd", [:mix], [{:meck, "~> 0.9.2", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm", "7fa82364c97617d79bb7d15571193fc0c4fe5afd0c932cef09426b3ee6fe2022"},
   "mogrify": {:hex, :mogrify, "0.8.0", "3506f3ca3f7b95a155f3b4ef803b5db176f5a0633723e3fe85e0d6399e3b11c8", [:mix], [], "hexpm", "2278d245f07056ea3b586e98801e933695147066fa4cf563f552c1b4f0ff8ad9"},
   "mox": {:hex, :mox, "1.1.0", "0f5e399649ce9ab7602f72e718305c0f9cdc351190f72844599545e4996af73c", [:mix], [], "hexpm", "d44474c50be02d5b72131070281a5d3895c0e7a95c780e90bc0cfe712f633a13"},
+  "multipart": {:hex, :multipart, "0.4.0", "634880a2148d4555d050963373d0e3bbb44a55b2badd87fa8623166172e9cda0", [:mix], [{:mime, "~> 1.2 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}], "hexpm", "3c5604bc2fb17b3137e5d2abdf5dacc2647e60c5cc6634b102cf1aef75a06f0a"},
   "nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"},
   "nimble_parsec": {:hex, :nimble_parsec, "0.6.0", "32111b3bf39137144abd7ba1cce0914533b2d16ef35e8abc5ec8be6122944263", [:mix], [], "hexpm", "27eac315a94909d4dc68bc07a4a83e06c8379237c5ea528a9acff4ca1c873c52"},
   "nimble_pool": {:hex, :nimble_pool, "0.2.6", "91f2f4c357da4c4a0a548286c84a3a28004f68f05609b4534526871a22053cde", [:mix], [], "hexpm", "1c715055095d3f2705c4e236c18b618420a35490da94149ff8b580a2144f653f"},

From 2977779e94cb34610d0c2369ecacf7d721ebc5ab Mon Sep 17 00:00:00 2001
From: feld <feld@feld.me>
Date: Fri, 6 Sep 2024 16:30:07 +0000
Subject: [PATCH 194/212] Merge branch 'well-known' into 'develop'

NodeInfo: Accept application/activity+json requests

See merge request pleroma/pleroma!4242
---
 changelog.d/well-known.change       |  1 +
 lib/pleroma/web/router.ex           |  2 +-
 test/pleroma/web/node_info_test.exs | 13 +++++++++++++
 3 files changed, 15 insertions(+), 1 deletion(-)
 create mode 100644 changelog.d/well-known.change

diff --git a/changelog.d/well-known.change b/changelog.d/well-known.change
new file mode 100644
index 000000000..e928124fb
--- /dev/null
+++ b/changelog.d/well-known.change
@@ -0,0 +1 @@
+Accept application/activity+json for requests to .well-known/nodeinfo
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index fc40a1143..4294dffa5 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -189,7 +189,7 @@ defmodule Pleroma.Web.Router do
   end
 
   pipeline :well_known do
-    plug(:accepts, ["json", "jrd", "jrd+json", "xml", "xrd+xml"])
+    plug(:accepts, ["activity+json", "json", "jrd", "jrd+json", "xml", "xrd+xml"])
   end
 
   pipeline :config do
diff --git a/test/pleroma/web/node_info_test.exs b/test/pleroma/web/node_info_test.exs
index f474220be..afe4ebb36 100644
--- a/test/pleroma/web/node_info_test.exs
+++ b/test/pleroma/web/node_info_test.exs
@@ -24,6 +24,19 @@ defmodule Pleroma.Web.NodeInfoTest do
       |> get(href)
       |> json_response(200)
     end)
+
+    accept_types = [
+      "application/activity+json",
+      "application/json",
+      "application/jrd+json"
+    ]
+
+    for type <- accept_types do
+      conn
+      |> put_req_header("accept", type)
+      |> get("/.well-known/nodeinfo")
+      |> json_response(200)
+    end
   end
 
   test "nodeinfo shows staff accounts", %{conn: conn} do

From a6e97c497b5ac418d9825200542d4d4d273f91f7 Mon Sep 17 00:00:00 2001
From: feld <feld@feld.me>
Date: Fri, 6 Sep 2024 13:27:06 +0000
Subject: [PATCH 195/212] Merge branch 'following-state-bug' into 'develop'

Fix Following status bug

See merge request pleroma/pleroma!4251
---
 changelog.d/following-state.fix               |  1 +
 .../web/mastodon_api/views/account_view.ex    | 19 +++++----
 mix.lock                                      |  2 +-
 .../mastodon_api/views/account_view_test.exs  | 39 +++++++++++++++++++
 4 files changed, 50 insertions(+), 11 deletions(-)
 create mode 100644 changelog.d/following-state.fix

diff --git a/changelog.d/following-state.fix b/changelog.d/following-state.fix
new file mode 100644
index 000000000..314ea6210
--- /dev/null
+++ b/changelog.d/following-state.fix
@@ -0,0 +1 @@
+Resolved edge case where the API can report you are following a user but the relationship is not fully established.
diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex
index 6976ca6e5..298c73986 100644
--- a/lib/pleroma/web/mastodon_api/views/account_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/account_view.ex
@@ -92,14 +92,13 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
         User.get_follow_state(reading_user, target)
       end
 
-    followed_by =
-      if following_relationships do
-        case FollowingRelationship.find(following_relationships, target, reading_user) do
-          %{state: :follow_accept} -> true
-          _ -> false
-        end
-      else
-        User.following?(target, reading_user)
+    followed_by = FollowingRelationship.following?(target, reading_user)
+    following = FollowingRelationship.following?(reading_user, target)
+
+    requested =
+      cond do
+        following -> false
+        true -> match?(:follow_pending, follow_state)
       end
 
     subscribing =
@@ -114,7 +113,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
     # NOTE: adjust UserRelationship.view_relationships_option/2 on new relation-related flags
     %{
       id: to_string(target.id),
-      following: follow_state == :follow_accept,
+      following: following,
       followed_by: followed_by,
       blocking:
         UserRelationship.exists?(
@@ -150,7 +149,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
         ),
       subscribing: subscribing,
       notifying: subscribing,
-      requested: follow_state == :follow_pending,
+      requested: requested,
       domain_blocking: User.blocks_domain?(reading_user, target),
       showing_reblogs:
         not UserRelationship.exists?(
diff --git a/mix.lock b/mix.lock
index 37ac1768b..09db91ffe 100644
--- a/mix.lock
+++ b/mix.lock
@@ -22,7 +22,7 @@
   "cowboy": {:hex, :cowboy, "2.12.0", "f276d521a1ff88b2b9b4c54d0e753da6c66dd7be6c9fca3d9418b561828a3731", [:make, :rebar3], [{:cowlib, "2.13.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "8a7abe6d183372ceb21caa2709bec928ab2b72e18a3911aa1771639bef82651e"},
   "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"},
   "cowlib": {:hex, :cowlib, "2.13.0", "db8f7505d8332d98ef50a3ef34b34c1afddec7506e4ee4dd4a3a266285d282ca", [:make, :rebar3], [], "hexpm", "e1e1284dc3fc030a64b1ad0d8382ae7e99da46c3246b815318a4b848873800a4"},
-  "credo": {:hex, :credo, "1.7.3", "05bb11eaf2f2b8db370ecaa6a6bda2ec49b2acd5e0418bc106b73b07128c0436", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "35ea675a094c934c22fb1dca3696f3c31f2728ae6ef5a53b5d648c11180a4535"},
+  "credo": {:hex, :credo, "1.7.7", "771445037228f763f9b2afd612b6aa2fd8e28432a95dbbc60d8e03ce71ba4446", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "8bc87496c9aaacdc3f90f01b7b0582467b69b4bd2441fe8aae3109d843cc2f2e"},
   "crontab": {:hex, :crontab, "1.1.8", "2ce0e74777dfcadb28a1debbea707e58b879e6aa0ffbf9c9bb540887bce43617", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"},
   "custom_base": {:hex, :custom_base, "0.2.1", "4a832a42ea0552299d81652aa0b1f775d462175293e99dfbe4d7dbaab785a706", [:mix], [], "hexpm", "8df019facc5ec9603e94f7270f1ac73ddf339f56ade76a721eaa57c1493ba463"},
   "db_connection": {:hex, :db_connection, "2.7.0", "b99faa9291bb09892c7da373bb82cba59aefa9b36300f6145c5f201c7adf48ec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dcf08f31b2701f857dfc787fbad78223d61a32204f217f15e881dd93e4bdd3ff"},
diff --git a/test/pleroma/web/mastodon_api/views/account_view_test.exs b/test/pleroma/web/mastodon_api/views/account_view_test.exs
index f0711fa0d..73ec67a3d 100644
--- a/test/pleroma/web/mastodon_api/views/account_view_test.exs
+++ b/test/pleroma/web/mastodon_api/views/account_view_test.exs
@@ -456,6 +456,45 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
       test_relationship_rendering(user, other_user, expected)
     end
 
+    test "relationship does not indicate following if a FollowingRelationship is missing" do
+      user = insert(:user)
+      other_user = insert(:user, local: false)
+
+      # Create a follow relationship with the real Follow Activity and Accept it
+      assert {:ok, _, _, _} = CommonAPI.follow(other_user, user)
+      assert {:ok, _} = CommonAPI.accept_follow_request(user, other_user)
+
+      assert %{data: %{"state" => "accept"}} =
+               Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(user, other_user)
+
+      # Fetch the relationship and forcibly delete it to simulate
+      # a Follow Accept that did not complete processing
+      %{following_relationships: [relationship]} =
+        Pleroma.UserRelationship.view_relationships_option(user, [other_user])
+
+      assert {:ok, _} = Pleroma.Repo.delete(relationship)
+
+      assert %{following_relationships: [], user_relationships: []} ==
+               Pleroma.UserRelationship.view_relationships_option(user, [other_user])
+
+      expected =
+        Map.merge(
+          @blank_response,
+          %{
+            following: false,
+            followed_by: false,
+            muting: false,
+            muting_notifications: false,
+            subscribing: false,
+            notifying: false,
+            showing_reblogs: true,
+            id: to_string(other_user.id)
+          }
+        )
+
+      test_relationship_rendering(user, other_user, expected)
+    end
+
     test "represent a relationship for the blocking and blocked user" do
       user = insert(:user)
       other_user = insert(:user)

From f45f17b5ff4e0bc454d9340c500e8b923c9e57cb Mon Sep 17 00:00:00 2001
From: lain <lain@soykaf.club>
Date: Thu, 8 Aug 2024 05:29:46 +0000
Subject: [PATCH 196/212] Merge branch 'follow-validator' into 'develop'

Do not require a cc field when validating an incoming Follow activity

See merge request pleroma/pleroma!4212
---
 changelog.d/follow-validator.fix                       |  1 +
 .../object_validators/accept_reject_validator.ex       |  2 +-
 .../activity_pub/object_validators/block_validator.ex  |  2 +-
 .../activity_pub/object_validators/follow_validator.ex |  2 +-
 .../object_validators/follow_validation_test.exs       | 10 ++++++++++
 5 files changed, 14 insertions(+), 3 deletions(-)
 create mode 100644 changelog.d/follow-validator.fix

diff --git a/changelog.d/follow-validator.fix b/changelog.d/follow-validator.fix
new file mode 100644
index 000000000..d49932b7b
--- /dev/null
+++ b/changelog.d/follow-validator.fix
@@ -0,0 +1 @@
+Improve the FollowValidator to successfully incoming activities with an errant cc field.
diff --git a/lib/pleroma/web/activity_pub/object_validators/accept_reject_validator.ex b/lib/pleroma/web/activity_pub/object_validators/accept_reject_validator.ex
index d611da051..03ab83347 100644
--- a/lib/pleroma/web/activity_pub/object_validators/accept_reject_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/accept_reject_validator.ex
@@ -29,7 +29,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AcceptRejectValidator do
 
   defp validate_data(cng) do
     cng
-    |> validate_required([:id, :type, :actor, :to, :cc, :object])
+    |> validate_required([:id, :type, :actor, :to, :object])
     |> validate_inclusion(:type, ["Accept", "Reject"])
     |> validate_actor_presence()
     |> validate_object_presence(allowed_types: ["Follow"])
diff --git a/lib/pleroma/web/activity_pub/object_validators/block_validator.ex b/lib/pleroma/web/activity_pub/object_validators/block_validator.ex
index 0de87a27e..98340545c 100644
--- a/lib/pleroma/web/activity_pub/object_validators/block_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/block_validator.ex
@@ -29,7 +29,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.BlockValidator do
 
   defp validate_data(cng) do
     cng
-    |> validate_required([:id, :type, :actor, :to, :cc, :object])
+    |> validate_required([:id, :type, :actor, :to, :object])
     |> validate_inclusion(:type, ["Block"])
     |> CommonValidations.validate_actor_presence()
     |> CommonValidations.validate_actor_presence(field_name: :object)
diff --git a/lib/pleroma/web/activity_pub/object_validators/follow_validator.ex b/lib/pleroma/web/activity_pub/object_validators/follow_validator.ex
index b3ca5b691..e4e97bf72 100644
--- a/lib/pleroma/web/activity_pub/object_validators/follow_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/follow_validator.ex
@@ -29,7 +29,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.FollowValidator do
 
   defp validate_data(cng) do
     cng
-    |> validate_required([:id, :type, :actor, :to, :cc, :object])
+    |> validate_required([:id, :type, :actor, :to, :object])
     |> validate_inclusion(:type, ["Follow"])
     |> validate_inclusion(:state, ~w{pending reject accept})
     |> validate_actor_presence()
diff --git a/test/pleroma/web/activity_pub/object_validators/follow_validation_test.exs b/test/pleroma/web/activity_pub/object_validators/follow_validation_test.exs
index 371368e0e..acf6e8d8f 100644
--- a/test/pleroma/web/activity_pub/object_validators/follow_validation_test.exs
+++ b/test/pleroma/web/activity_pub/object_validators/follow_validation_test.exs
@@ -22,5 +22,15 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.FollowValidationTest do
     test "validates a basic follow object", %{valid_follow: valid_follow} do
       assert {:ok, _follow, []} = ObjectValidator.validate(valid_follow, [])
     end
+
+    test "supports a nil cc", %{valid_follow: valid_follow} do
+      valid_follow_with_nil_cc = Map.put(valid_follow, "cc", nil)
+      assert {:ok, _follow, []} = ObjectValidator.validate(valid_follow_with_nil_cc, [])
+    end
+
+    test "supports an empty cc", %{valid_follow: valid_follow} do
+      valid_follow_with_empty_cc = Map.put(valid_follow, "cc", [])
+      assert {:ok, _follow, []} = ObjectValidator.validate(valid_follow_with_empty_cc, [])
+    end
   end
 end

From 53c2d2cd87d35094b0ae623b8daab4d303ed5fcb Mon Sep 17 00:00:00 2001
From: lain <lain@soykaf.club>
Date: Wed, 13 Nov 2024 08:22:44 +0000
Subject: [PATCH 197/212] Merge branch 'mastodon-websocket-fix' into 'develop'

Fix Mastodon WebSocket authentication

See merge request pleroma/pleroma!4206
---
 changelog.d/mastodon-websocket.fix                   |  1 +
 lib/pleroma/web/endpoint.ex                          |  1 +
 lib/pleroma/web/mastodon_api/websocket_handler.ex    | 11 ++++++++++-
 mix.exs                                              |  3 ++-
 mix.lock                                             |  2 +-
 test/pleroma/integration/mastodon_websocket_test.exs | 11 +++++++++++
 6 files changed, 26 insertions(+), 3 deletions(-)
 create mode 100644 changelog.d/mastodon-websocket.fix

diff --git a/changelog.d/mastodon-websocket.fix b/changelog.d/mastodon-websocket.fix
new file mode 100644
index 000000000..2c4fe86ef
--- /dev/null
+++ b/changelog.d/mastodon-websocket.fix
@@ -0,0 +1 @@
+Fix Mastodon WebSocket authentication
diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex
index fef907ace..bab3c9fd0 100644
--- a/lib/pleroma/web/endpoint.ex
+++ b/lib/pleroma/web/endpoint.ex
@@ -14,6 +14,7 @@ defmodule Pleroma.Web.Endpoint do
     websocket: [
       path: "/",
       compress: false,
+      connect_info: [:sec_websocket_protocol],
       error_handler: {Pleroma.Web.MastodonAPI.WebsocketHandler, :handle_error, []},
       fullsweep_after: 20
     ]
diff --git a/lib/pleroma/web/mastodon_api/websocket_handler.ex b/lib/pleroma/web/mastodon_api/websocket_handler.ex
index 730295a4c..3ed1cdd6c 100644
--- a/lib/pleroma/web/mastodon_api/websocket_handler.ex
+++ b/lib/pleroma/web/mastodon_api/websocket_handler.ex
@@ -22,7 +22,7 @@ defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do
   # This only prepares the connection and is not in the process yet
   @impl Phoenix.Socket.Transport
   def connect(%{params: params} = transport_info) do
-    with access_token <- Map.get(params, "access_token"),
+    with access_token <- find_access_token(transport_info),
          {:ok, user, oauth_token} <- authenticate_request(access_token),
          {:ok, topic} <-
            Streamer.get_topic(params["stream"], user, oauth_token, params) do
@@ -244,4 +244,13 @@ defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do
   def handle_error(conn, _reason) do
     Plug.Conn.send_resp(conn, 404, "Not Found")
   end
+
+  defp find_access_token(%{
+         connect_info: %{sec_websocket_protocol: [token]}
+       }),
+       do: token
+
+  defp find_access_token(%{params: %{"access_token" => token}}), do: token
+
+  defp find_access_token(_), do: nil
 end
diff --git a/mix.exs b/mix.exs
index e3c8559ba..88140c69b 100644
--- a/mix.exs
+++ b/mix.exs
@@ -132,7 +132,8 @@ defmodule Pleroma.Mixfile do
   # Type `mix help deps` for examples and options.
   defp deps do
     [
-      {:phoenix, "~> 1.7.3"},
+      {:phoenix,
+       git: "https://github.com/feld/phoenix", branch: "v1.7.14-websocket-headers", override: true},
       {:phoenix_ecto, "~> 4.4"},
       {:ecto_sql, "~> 3.10"},
       {:ecto_enum, "~> 1.4"},
diff --git a/mix.lock b/mix.lock
index 09db91ffe..4d0b9003c 100644
--- a/mix.lock
+++ b/mix.lock
@@ -95,7 +95,7 @@
   "open_api_spex": {:hex, :open_api_spex, "3.18.2", "8c855e83bfe8bf81603d919d6e892541eafece3720f34d1700b58024dadde247", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 3.0 or ~> 4.0 or ~> 5.0", [hex: :poison, repo: "hexpm", optional: true]}, {:ymlr, "~> 2.0 or ~> 3.0 or ~> 4.0", [hex: :ymlr, repo: "hexpm", optional: true]}], "hexpm", "aa3e6dcfc0ad6a02596b2172662da21c9dd848dac145ea9e603f54e3d81b8d2b"},
   "parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"},
   "pbkdf2_elixir": {:hex, :pbkdf2_elixir, "1.2.1", "9cbe354b58121075bd20eb83076900a3832324b7dd171a6895fab57b6bb2752c", [:mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}], "hexpm", "d3b40a4a4630f0b442f19eca891fcfeeee4c40871936fed2f68e1c4faa30481f"},
-  "phoenix": {:hex, :phoenix, "1.7.14", "a7d0b3f1bc95987044ddada111e77bd7f75646a08518942c72a8440278ae7825", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "c7859bc56cc5dfef19ecfc240775dae358cbaa530231118a9e014df392ace61a"},
+  "phoenix": {:git, "https://github.com/feld/phoenix", "fb6dc76c657422e49600896c64aab4253fceaef6", [branch: "v1.7.14-websocket-headers"]},
   "phoenix_ecto": {:hex, :phoenix_ecto, "4.4.3", "86e9878f833829c3f66da03d75254c155d91d72a201eb56ae83482328dc7ca93", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "d36c401206f3011fefd63d04e8ef626ec8791975d9d107f9a0817d426f61ac07"},
   "phoenix_html": {:hex, :phoenix_html, "3.3.4", "42a09fc443bbc1da37e372a5c8e6755d046f22b9b11343bf885067357da21cb3", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "0249d3abec3714aff3415e7ee3d9786cb325be3151e6c4b3021502c585bf53fb"},
   "phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.8.3", "7ff51c9b6609470f681fbea20578dede0e548302b0c8bdf338b5a753a4f045bf", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.5", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:ecto_sqlite3_extras, "~> 1.1.7 or ~> 1.2.0", [hex: :ecto_sqlite3_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.19 or ~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "f9470a0a8bae4f56430a23d42f977b5a6205fdba6559d76f932b876bfaec652d"},
diff --git a/test/pleroma/integration/mastodon_websocket_test.exs b/test/pleroma/integration/mastodon_websocket_test.exs
index f499f54ad..88f32762d 100644
--- a/test/pleroma/integration/mastodon_websocket_test.exs
+++ b/test/pleroma/integration/mastodon_websocket_test.exs
@@ -268,6 +268,17 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do
       end)
     end
 
+    test "accepts valid token on Sec-WebSocket-Protocol header", %{token: token} do
+      assert {:ok, _} = start_socket("?stream=user", [{"Sec-WebSocket-Protocol", token.token}])
+
+      capture_log(fn ->
+        assert {:error, %WebSockex.RequestError{code: 401}} =
+                 start_socket("?stream=user", [{"Sec-WebSocket-Protocol", "I am a friend"}])
+
+        Process.sleep(30)
+      end)
+    end
+
     test "accepts valid token on client-sent event", %{token: token} do
       assert {:ok, pid} = start_socket()
 

From 6a0883e5d33bd03fb3d71ad3a3560adc5ce6d626 Mon Sep 17 00:00:00 2001
From: feld <feld@feld.me>
Date: Fri, 16 Aug 2024 00:37:10 +0000
Subject: [PATCH 198/212] Merge branch 'bugfix-truncate-remote-user-fields'
 into 'develop'

User: truncate remote user fields instead of rejecting

See merge request pleroma/pleroma!4220
---
 .../bugfix-truncate-remote-user-fields.fix        |  1 +
 lib/pleroma/user.ex                               |  2 ++
 test/pleroma/user_test.exs                        | 15 +++++++++++++++
 .../transmogrifier/user_update_handling_test.exs  |  4 ++--
 4 files changed, 20 insertions(+), 2 deletions(-)
 create mode 100644 changelog.d/bugfix-truncate-remote-user-fields.fix

diff --git a/changelog.d/bugfix-truncate-remote-user-fields.fix b/changelog.d/bugfix-truncate-remote-user-fields.fix
new file mode 100644
index 000000000..239a3c224
--- /dev/null
+++ b/changelog.d/bugfix-truncate-remote-user-fields.fix
@@ -0,0 +1 @@
+Truncate remote user fields, avoids them getting rejected
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index e28d76a7c..4f6cdc03e 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -463,6 +463,7 @@ defmodule Pleroma.User do
   def remote_user_changeset(struct \\ %User{local: false}, params) do
     bio_limit = Config.get([:instance, :user_bio_length], 5000)
     name_limit = Config.get([:instance, :user_name_length], 100)
+    fields_limit = Config.get([:instance, :max_remote_account_fields], 0)
 
     name =
       case params[:name] do
@@ -476,6 +477,7 @@ defmodule Pleroma.User do
       |> Map.put_new(:last_refreshed_at, NaiveDateTime.utc_now())
       |> truncate_if_exists(:name, name_limit)
       |> truncate_if_exists(:bio, bio_limit)
+      |> Map.update(:fields, [], &Enum.take(&1, fields_limit))
       |> truncate_fields_param()
       |> fix_follower_address()
 
diff --git a/test/pleroma/user_test.exs b/test/pleroma/user_test.exs
index 036ae78fb..06afc0709 100644
--- a/test/pleroma/user_test.exs
+++ b/test/pleroma/user_test.exs
@@ -1075,6 +1075,21 @@ defmodule Pleroma.UserTest do
 
       refute cs.valid?
     end
+
+    test "it truncates fields" do
+      clear_config([:instance, :max_remote_account_fields], 2)
+
+      fields = [
+        %{"name" => "One", "value" => "Uno"},
+        %{"name" => "Two", "value" => "Dos"},
+        %{"name" => "Three", "value" => "Tres"}
+      ]
+
+      cs = User.remote_user_changeset(@valid_remote |> Map.put(:fields, fields))
+
+      assert [%{"name" => "One", "value" => "Uno"}, %{"name" => "Two", "value" => "Dos"}] ==
+               Ecto.Changeset.get_field(cs, :fields)
+    end
   end
 
   describe "followers and friends" do
diff --git a/test/pleroma/web/activity_pub/transmogrifier/user_update_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/user_update_handling_test.exs
index da46f063a..851c60850 100644
--- a/test/pleroma/web/activity_pub/transmogrifier/user_update_handling_test.exs
+++ b/test/pleroma/web/activity_pub/transmogrifier/user_update_handling_test.exs
@@ -119,8 +119,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.UserUpdateHandlingTest do
     user = User.get_cached_by_ap_id(user.ap_id)
 
     assert user.fields == [
-             %{"name" => "foo", "value" => "updated"},
-             %{"name" => "foo1", "value" => "updated"}
+             %{"name" => "foo", "value" => "bar"},
+             %{"name" => "foo11", "value" => "bar11"}
            ]
 
     update_data =

From 7bb2dccc058cd1659ab21942b06657abf9127365 Mon Sep 17 00:00:00 2001
From: "Haelwenn (lanodan) Monnier" <contact@hacktivis.me>
Date: Tue, 26 Nov 2024 14:09:09 +0100
Subject: [PATCH 199/212] Version 2.7.1

---
 CHANGELOG.md                                       | 12 ++++++++++++
 changelog.d/bugfix-truncate-remote-user-fields.fix |  1 -
 changelog.d/follow-validator.fix                   |  1 -
 changelog.d/following-state.fix                    |  1 -
 changelog.d/mailgun.fix                            |  1 -
 changelog.d/mastodon-websocket.fix                 |  1 -
 changelog.d/well-known.change                      |  1 -
 mix.exs                                            |  2 +-
 8 files changed, 13 insertions(+), 7 deletions(-)
 delete mode 100644 changelog.d/bugfix-truncate-remote-user-fields.fix
 delete mode 100644 changelog.d/follow-validator.fix
 delete mode 100644 changelog.d/following-state.fix
 delete mode 100644 changelog.d/mailgun.fix
 delete mode 100644 changelog.d/mastodon-websocket.fix
 delete mode 100644 changelog.d/well-known.change

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 61bb2ab54..424a9afbb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,18 @@ All notable changes to this project will be documented in this file.
 
 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 
+## 2.7.1
+
+### Changed
+- Accept `application/activity+json` for requests to `/.well-known/nodeinfo`
+
+### Fixed
+- Truncate remote user fields, avoids them getting rejected
+- Improve the `FollowValidator` to successfully incoming activities with an errant `cc` field.
+- Resolved edge case where the API can report you are following a user but the relationship is not fully established.
+- The Swoosh email adapter for Mailgun was missing a new dependency on `:multipart`
+- Fix Mastodon WebSocket authentication
+
 ## 2.7.0
 
 ### Security
diff --git a/changelog.d/bugfix-truncate-remote-user-fields.fix b/changelog.d/bugfix-truncate-remote-user-fields.fix
deleted file mode 100644
index 239a3c224..000000000
--- a/changelog.d/bugfix-truncate-remote-user-fields.fix
+++ /dev/null
@@ -1 +0,0 @@
-Truncate remote user fields, avoids them getting rejected
diff --git a/changelog.d/follow-validator.fix b/changelog.d/follow-validator.fix
deleted file mode 100644
index d49932b7b..000000000
--- a/changelog.d/follow-validator.fix
+++ /dev/null
@@ -1 +0,0 @@
-Improve the FollowValidator to successfully incoming activities with an errant cc field.
diff --git a/changelog.d/following-state.fix b/changelog.d/following-state.fix
deleted file mode 100644
index 314ea6210..000000000
--- a/changelog.d/following-state.fix
+++ /dev/null
@@ -1 +0,0 @@
-Resolved edge case where the API can report you are following a user but the relationship is not fully established.
diff --git a/changelog.d/mailgun.fix b/changelog.d/mailgun.fix
deleted file mode 100644
index 855588752..000000000
--- a/changelog.d/mailgun.fix
+++ /dev/null
@@ -1 +0,0 @@
-The Swoosh email adapter for Mailgun was missing a new dependency on :multipart
diff --git a/changelog.d/mastodon-websocket.fix b/changelog.d/mastodon-websocket.fix
deleted file mode 100644
index 2c4fe86ef..000000000
--- a/changelog.d/mastodon-websocket.fix
+++ /dev/null
@@ -1 +0,0 @@
-Fix Mastodon WebSocket authentication
diff --git a/changelog.d/well-known.change b/changelog.d/well-known.change
deleted file mode 100644
index e928124fb..000000000
--- a/changelog.d/well-known.change
+++ /dev/null
@@ -1 +0,0 @@
-Accept application/activity+json for requests to .well-known/nodeinfo
diff --git a/mix.exs b/mix.exs
index 88140c69b..2448b0c66 100644
--- a/mix.exs
+++ b/mix.exs
@@ -4,7 +4,7 @@ defmodule Pleroma.Mixfile do
   def project do
     [
       app: :pleroma,
-      version: version("2.7.0"),
+      version: version("2.7.1"),
       elixir: "~> 1.13",
       elixirc_paths: elixirc_paths(Mix.env()),
       compilers: Mix.compilers(),

From 3f98c8bd1b86a87e204879da4172178173050638 Mon Sep 17 00:00:00 2001
From: kPherox <kphrx@kpherox.dev>
Date: Wed, 27 Nov 2024 15:45:14 +0900
Subject: [PATCH 200/212] fix: skip directory entries

In OTP 27.1 or later, `:zip.unzip/2` without `:skip_directories` option returns directory entries.
However in OTP 26, passing `:skip_directories` returns a `:bad_option` error, so this option is not available for compatibility.
---
 lib/pleroma/frontend.ex | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/lib/pleroma/frontend.ex b/lib/pleroma/frontend.ex
index 816499917..a4f427ae5 100644
--- a/lib/pleroma/frontend.ex
+++ b/lib/pleroma/frontend.ex
@@ -74,11 +74,14 @@ defmodule Pleroma.Frontend do
 
         new_file_path = Path.join(dest, path)
 
-        new_file_path
+        path
         |> Path.dirname()
+        |> then(&Path.join(dest, &1))
         |> File.mkdir_p!()
 
-        File.write!(new_file_path, data)
+        if not File.dir?(new_file_path) do
+          File.write!(new_file_path, data)
+        end
       end)
     end
   end

From b51f5a84eb7e2f3acb2d7fed54213a9680983bce Mon Sep 17 00:00:00 2001
From: tusooa <tusooa@kazv.moe>
Date: Tue, 15 Oct 2024 20:03:20 -0400
Subject: [PATCH 201/212] Verify a local Update sent through AP C2S so users
 can only update their own objects

---
 changelog.d/c2s-update-verify.fix             |  1 +
 .../activity_pub/activity_pub_controller.ex   |  2 +-
 .../web/activity_pub/object_validator.ex      | 13 ++++--
 .../object_validators/update_validator.ex     | 43 ++++++++++++++++---
 .../activity_pub_controller_test.exs          | 22 ++++++++++
 5 files changed, 70 insertions(+), 11 deletions(-)
 create mode 100644 changelog.d/c2s-update-verify.fix

diff --git a/changelog.d/c2s-update-verify.fix b/changelog.d/c2s-update-verify.fix
new file mode 100644
index 000000000..a4dfe7c07
--- /dev/null
+++ b/changelog.d/c2s-update-verify.fix
@@ -0,0 +1 @@
+Verify a local Update sent through AP C2S so users can only update their own objects
diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex
index a08eda5f4..7ac0bbab4 100644
--- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex
@@ -482,7 +482,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
         |> put_status(:forbidden)
         |> json(message)
 
-      {:error, message} ->
+      {:error, message} when is_binary(message) ->
         conn
         |> put_status(:bad_request)
         |> json(message)
diff --git a/lib/pleroma/web/activity_pub/object_validator.ex b/lib/pleroma/web/activity_pub/object_validator.ex
index 35774d410..c509890f6 100644
--- a/lib/pleroma/web/activity_pub/object_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validator.ex
@@ -169,7 +169,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
          meta = Keyword.put(meta, :object_data, object_data),
          {:ok, update_activity} <-
            update_activity
-           |> UpdateValidator.cast_and_validate()
+           |> UpdateValidator.cast_and_validate(meta)
            |> Ecto.Changeset.apply_action(:insert) do
       update_activity = stringify_keys(update_activity)
       {:ok, update_activity, meta}
@@ -177,7 +177,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
       {:local, _} ->
         with {:ok, object} <-
                update_activity
-               |> UpdateValidator.cast_and_validate()
+               |> UpdateValidator.cast_and_validate(meta)
                |> Ecto.Changeset.apply_action(:insert) do
           object = stringify_keys(object)
           {:ok, object, meta}
@@ -207,9 +207,16 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
         "Answer" -> AnswerValidator
       end
 
+    cast_func =
+      if type == "Update" do
+        fn o -> validator.cast_and_validate(o, meta) end
+      else
+        fn o -> validator.cast_and_validate(o) end
+      end
+
     with {:ok, object} <-
            object
-           |> validator.cast_and_validate()
+           |> cast_func.()
            |> Ecto.Changeset.apply_action(:insert) do
       object = stringify_keys(object)
       {:ok, object, meta}
diff --git a/lib/pleroma/web/activity_pub/object_validators/update_validator.ex b/lib/pleroma/web/activity_pub/object_validators/update_validator.ex
index 1e940a400..aab90235f 100644
--- a/lib/pleroma/web/activity_pub/object_validators/update_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/update_validator.ex
@@ -6,6 +6,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.UpdateValidator do
   use Ecto.Schema
 
   alias Pleroma.EctoType.ActivityPub.ObjectValidators
+  alias Pleroma.Object
+  alias Pleroma.User
 
   import Ecto.Changeset
   import Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
@@ -31,23 +33,50 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.UpdateValidator do
     |> cast(data, __schema__(:fields))
   end
 
-  defp validate_data(cng) do
+  defp validate_data(cng, meta) do
     cng
     |> validate_required([:id, :type, :actor, :to, :cc, :object])
     |> validate_inclusion(:type, ["Update"])
     |> validate_actor_presence()
-    |> validate_updating_rights()
+    |> validate_updating_rights(meta)
   end
 
-  def cast_and_validate(data) do
+  def cast_and_validate(data, meta \\ []) do
     data
     |> cast_data
-    |> validate_data
+    |> validate_data(meta)
   end
 
-  # For now we only support updating users, and here the rule is easy:
-  # object id == actor id
-  def validate_updating_rights(cng) do
+  def validate_updating_rights(cng, meta) do
+    if meta[:local] do
+      validate_updating_rights_local(cng)
+    else
+      validate_updating_rights_remote(cng)
+    end
+  end
+
+  # For local Updates, verify the actor can edit the object
+  def validate_updating_rights_local(cng) do
+    actor = get_field(cng, :actor)
+    updated_object = get_field(cng, :object)
+
+    if {:ok, actor} == ObjectValidators.ObjectID.cast(updated_object) do
+      cng
+    else
+      with %User{} = user <- User.get_cached_by_ap_id(actor),
+           {_, %Object{} = orig_object} <- {:object, Object.normalize(updated_object)},
+           :ok <- Object.authorize_access(orig_object, user) do
+        cng
+      else
+        _e ->
+          cng
+          |> add_error(:object, "Can't be updated by this actor")
+      end
+    end
+  end
+
+  # For remote Updates, verify the host is the same.
+  def validate_updating_rights_remote(cng) do
     with actor = get_field(cng, :actor),
          object = get_field(cng, :object),
          {:ok, object_id} <- ObjectValidators.ObjectID.cast(object),
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 d4175b56f..b627478dc 100644
--- a/test/pleroma/web/activity_pub/activity_pub_controller_test.exs
+++ b/test/pleroma/web/activity_pub/activity_pub_controller_test.exs
@@ -1644,6 +1644,28 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
       assert json_response(conn, 403)
     end
 
+    test "it rejects update activity of object from other actor", %{conn: conn} do
+      note_activity = insert(:note_activity)
+      note_object = Object.normalize(note_activity, fetch: false)
+      user = insert(:user)
+
+      data = %{
+        type: "Update",
+        object: %{
+          id: note_object.data["id"]
+        }
+      }
+
+      conn =
+        conn
+        |> assign(:user, user)
+        |> put_req_header("content-type", "application/activity+json")
+        |> post("/users/#{user.nickname}/outbox", data)
+
+      assert json_response(conn, 400)
+      assert note_object == Object.normalize(note_activity, fetch: false)
+    end
+
     test "it increases like count when receiving a like action", %{conn: conn} do
       note_activity = insert(:note_activity)
       note_object = Object.normalize(note_activity, fetch: false)

From c0fdd0e2cf2e57aa02776c41d21b10c17f745193 Mon Sep 17 00:00:00 2001
From: Lain Soykaf <lain@lain.com>
Date: Mon, 9 Dec 2024 12:48:11 +0400
Subject: [PATCH 202/212] Update changelog

---
 CHANGELOG.md                                  | 59 +++++++++++++++++++
 changelog.d/activity-pub-metadata.add         |  1 -
 changelog.d/argon2-passwords.add              |  1 -
 changelog.d/atom-tag.change                   |  1 -
 changelog.d/bump-lexbor.change                |  1 -
 changelog.d/c2s-update-verify.fix             |  1 -
 changelog.d/ci-git-fetch.skip                 |  0
 changelog.d/commonapi.skip                    |  0
 changelog.d/debian-install-improve.skip       |  1 -
 changelog.d/dedupe-sharding.change            |  1 -
 changelog.d/deprecate-subscribe.change        |  1 -
 changelog.d/dialyzer.skip                     |  0
 changelog.d/docs-fix.skip                     |  0
 changelog.d/docs-vips.skip                    |  0
 changelog.d/drop-unwanted.change              |  1 -
 changelog.d/elixir-1.14-docker.skip           |  0
 changelog.d/elixir.change                     |  1 -
 changelog.d/follow-request.fix                |  1 -
 changelog.d/freebsd-docs.skip                 |  0
 changelog.d/get-statuses-param.change         |  1 -
 changelog.d/hashtag-feeds-restricted.add      |  1 -
 changelog.d/identity-proofs.remove            |  1 -
 changelog.d/incoming-blocks.fix               |  1 -
 changelog.d/ldap-ca.add                       |  1 -
 changelog.d/ldap-password-change.add          |  1 -
 changelog.d/ldap-refactor.change              |  1 -
 changelog.d/ldap-tls.fix                      |  1 -
 changelog.d/ldap-warning.skip                 |  0
 changelog.d/ldaps.fix                         |  1 -
 changelog.d/list-id-visibility.add            |  1 -
 changelog.d/manifest-icon-size.skip           |  0
 changelog.d/mediav2_status.fix                |  1 -
 changelog.d/meilisearch-misc-fixes.fix        |  1 -
 changelog.d/module-search-in-pleroma-ctl.fix  |  1 -
 changelog.d/mogrify.skip                      |  0
 changelog.d/mrf-cleanup.skip                  |  0
 changelog.d/mrf-fodirectreply.add             |  1 -
 changelog.d/mrf-id_filter.add                 |  1 -
 changelog.d/mrf-quietreply.add                |  1 -
 changelog.d/notifications-group-key.add       |  1 -
 changelog.d/notifications-marker.change       |  1 -
 changelog.d/oauth-app-spam.fix                |  1 -
 changelog.d/oban-recevier-improvements.fix    |  1 -
 changelog.d/oban-uniques.change               |  1 -
 changelog.d/oban-update.change                |  1 -
 changelog.d/oban_gun_snooze.change            |  1 -
 changelog.d/poll-refresh.change               |  1 -
 changelog.d/profile-image-descriptions.add    |  1 -
 changelog.d/profile-image-descriptions.skip   |  0
 changelog.d/publisher-reachability.fix        |  1 -
 changelog.d/release-tuning.change             |  1 -
 changelog.d/remote-object-fetcher.fix         |  1 -
 changelog.d/remote-report-policy.add          |  1 -
 changelog.d/rich-media-no-heads.change        |  1 -
 .../scrubbers-allow-mention-hashtag.add       |  1 -
 changelog.d/se-opt-out.change                 |  1 -
 .../stream-follow-relationships-count.fix     |  1 -
 changelog.d/swoosh-mua.add                    |  1 -
 changelog.d/text-extensions.skip              |  0
 changelog.d/todo-cleanup.skip                 |  0
 changelog.d/token-view-scopes.add             |  1 -
 changelog.d/update-oban.change                |  1 -
 changelog.d/user-factory.skip                 |  0
 changelog.d/user-imports.fix                  |  1 -
 changelog.d/vapid_keyword_fallback.fix        |  1 -
 changelog.d/workerhelper.change               |  1 -
 66 files changed, 59 insertions(+), 50 deletions(-)
 delete mode 100644 changelog.d/activity-pub-metadata.add
 delete mode 100644 changelog.d/argon2-passwords.add
 delete mode 100644 changelog.d/atom-tag.change
 delete mode 100644 changelog.d/bump-lexbor.change
 delete mode 100644 changelog.d/c2s-update-verify.fix
 delete mode 100644 changelog.d/ci-git-fetch.skip
 delete mode 100644 changelog.d/commonapi.skip
 delete mode 100644 changelog.d/debian-install-improve.skip
 delete mode 100644 changelog.d/dedupe-sharding.change
 delete mode 100644 changelog.d/deprecate-subscribe.change
 delete mode 100644 changelog.d/dialyzer.skip
 delete mode 100644 changelog.d/docs-fix.skip
 delete mode 100644 changelog.d/docs-vips.skip
 delete mode 100644 changelog.d/drop-unwanted.change
 delete mode 100644 changelog.d/elixir-1.14-docker.skip
 delete mode 100644 changelog.d/elixir.change
 delete mode 100644 changelog.d/follow-request.fix
 delete mode 100644 changelog.d/freebsd-docs.skip
 delete mode 100644 changelog.d/get-statuses-param.change
 delete mode 100644 changelog.d/hashtag-feeds-restricted.add
 delete mode 100644 changelog.d/identity-proofs.remove
 delete mode 100644 changelog.d/incoming-blocks.fix
 delete mode 100644 changelog.d/ldap-ca.add
 delete mode 100644 changelog.d/ldap-password-change.add
 delete mode 100644 changelog.d/ldap-refactor.change
 delete mode 100644 changelog.d/ldap-tls.fix
 delete mode 100644 changelog.d/ldap-warning.skip
 delete mode 100644 changelog.d/ldaps.fix
 delete mode 100644 changelog.d/list-id-visibility.add
 delete mode 100644 changelog.d/manifest-icon-size.skip
 delete mode 100644 changelog.d/mediav2_status.fix
 delete mode 100644 changelog.d/meilisearch-misc-fixes.fix
 delete mode 100644 changelog.d/module-search-in-pleroma-ctl.fix
 delete mode 100644 changelog.d/mogrify.skip
 delete mode 100644 changelog.d/mrf-cleanup.skip
 delete mode 100644 changelog.d/mrf-fodirectreply.add
 delete mode 100644 changelog.d/mrf-id_filter.add
 delete mode 100644 changelog.d/mrf-quietreply.add
 delete mode 100644 changelog.d/notifications-group-key.add
 delete mode 100644 changelog.d/notifications-marker.change
 delete mode 100644 changelog.d/oauth-app-spam.fix
 delete mode 100644 changelog.d/oban-recevier-improvements.fix
 delete mode 100644 changelog.d/oban-uniques.change
 delete mode 100644 changelog.d/oban-update.change
 delete mode 100644 changelog.d/oban_gun_snooze.change
 delete mode 100644 changelog.d/poll-refresh.change
 delete mode 100644 changelog.d/profile-image-descriptions.add
 delete mode 100644 changelog.d/profile-image-descriptions.skip
 delete mode 100644 changelog.d/publisher-reachability.fix
 delete mode 100644 changelog.d/release-tuning.change
 delete mode 100644 changelog.d/remote-object-fetcher.fix
 delete mode 100644 changelog.d/remote-report-policy.add
 delete mode 100644 changelog.d/rich-media-no-heads.change
 delete mode 100644 changelog.d/scrubbers-allow-mention-hashtag.add
 delete mode 100644 changelog.d/se-opt-out.change
 delete mode 100644 changelog.d/stream-follow-relationships-count.fix
 delete mode 100644 changelog.d/swoosh-mua.add
 delete mode 100644 changelog.d/text-extensions.skip
 delete mode 100644 changelog.d/todo-cleanup.skip
 delete mode 100644 changelog.d/token-view-scopes.add
 delete mode 100644 changelog.d/update-oban.change
 delete mode 100644 changelog.d/user-factory.skip
 delete mode 100644 changelog.d/user-imports.fix
 delete mode 100644 changelog.d/vapid_keyword_fallback.fix
 delete mode 100644 changelog.d/workerhelper.change

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 424a9afbb..71178c89a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,65 @@ All notable changes to this project will be documented in this file.
 
 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 
+## 2.8.0
+
+### Changed
+- Metadata: Do not include .atom feed links for remote accounts
+- Bumped `fast_html` to v2.3.0, which notably allows to use system-installed lexbor with passing `WITH_SYSTEM_LEXBOR=1` environment variable at build-time
+- Dedupe upload filter now uses a three-level sharding directory structure
+- Deprecate `/api/v1/pleroma/accounts/:id/subscribe`/`unsubscribe`
+- Restrict incoming activities from unknown actors to a subset that does not imply a previous relationship and early rejection of unrecognized activity types.
+- Elixir 1.14 and Erlang/OTP 23 is now the minimum supported release
+- Support `id` param in `GET /api/v1/statuses`
+- LDAP authentication has been refactored to operate as a GenServer process which will maintain an active connection to the LDAP server.
+- Fix 'Setting a marker should mark notifications as read'
+- Adjust more Oban workers to enforce unique job constraints.
+- Oban updated to 2.18.3
+- Publisher behavior improvement when snoozing Oban jobs due to Gun connection pool contention.
+- Poll results refreshing is handled asynchronously and will not attempt to keep fetching updates to a closed poll.
+- Tuning for release builds to lower CPU usage.
+- Rich Media preview fetching will skip making an HTTP HEAD request to check a URL for allowed content type and length if the Tesla adapter is Gun or Finch
+- Fix nonexisting user will not generate metadata for search engine opt-out
+- Update Oban to 2.18
+- Worker configuration is no longer available. This only affects custom max_retries values for a couple Oban queues.
+
+### Added
+- Add metadata provider for ActivityPub alternate links
+- Added support for argon2 passwords and their conversion for migration from Akkoma fork to upstream.
+- Respect :restrict_unauthenticated for hashtag rss/atom feeds
+- LDAP configuration now permits overriding the CA root certificate file for TLS validation.
+- LDAP now supports users changing their passwords
+- Include list id in StatusView
+- Added MRF.FODirectReply which changes replies to followers-only posts to be direct.
+- Add `id_filter` to MRF to filter URLs and their domain prior to fetching
+- Added MRF.QuietReply which prevents replies to public posts from being published to the timelines
+- Add `group_key` to notifications
+- Allow providing avatar/header descriptions
+- Added RemoteReportPolicy from Rebased for handling bogus federated reports
+- scrubbers/default: Allow "mention hashtag" classes used by Mastodon
+- Added dependencies for Swoosh's Mua mail adapter
+- Include session scopes in TokenView
+
+### Fixed
+- Verify a local Update sent through AP C2S so users can only update their own objects
+- Fixed malformed follow requests that cause them to appear stuck pending due to the recipient being unable to process them.
+- Fix incoming Block activities being rejected
+- STARTTLS certificate and hostname verification for LDAP authentication
+- LDAPS connections (implicit TLS) are now supported.
+- Fix /api/v2/media returning the wrong status code (202) for media processed synchronously
+- Miscellaneous fixes for Meilisearch support
+- Fix pleroma_ctl mix task calls sometimes not being found
+- Add a rate limiter to the OAuth App creation endpoint and ensure registered apps are assigned to users.
+- ReceiverWorker will cancel processing jobs instead of retrying if the user cannot be fetched due to 403, 404, or 410 errors or if the account is disabled locally.
+- Address case where instance reachability status couldn't be updated
+- Remote Fetcher Worker recognizes more permanent failure errors
+- StreamerView: Do not leak follows count if hidden
+- Imports of blocks, mutes, and follows would retry repeatedly due to incorrect error handling and all work executed in a single job
+- Make vapid_config return empty array, fixing preloading for instances without push notifications configured
+
+### Removed
+- Remove stub for /api/v1/accounts/:id/identity_proofs (deprecated by Mastodon 3.5.0)
+
 ## 2.7.1
 
 ### Changed
diff --git a/changelog.d/activity-pub-metadata.add b/changelog.d/activity-pub-metadata.add
deleted file mode 100644
index 2ad3d7b2d..000000000
--- a/changelog.d/activity-pub-metadata.add
+++ /dev/null
@@ -1 +0,0 @@
-Add metadata provider for ActivityPub alternate links
diff --git a/changelog.d/argon2-passwords.add b/changelog.d/argon2-passwords.add
deleted file mode 100644
index 36fd7faf2..000000000
--- a/changelog.d/argon2-passwords.add
+++ /dev/null
@@ -1 +0,0 @@
-Added support for argon2 passwords and their conversion for migration from Akkoma fork to upstream.
diff --git a/changelog.d/atom-tag.change b/changelog.d/atom-tag.change
deleted file mode 100644
index 1b3590dea..000000000
--- a/changelog.d/atom-tag.change
+++ /dev/null
@@ -1 +0,0 @@
-Metadata: Do not include .atom feed links for remote accounts
diff --git a/changelog.d/bump-lexbor.change b/changelog.d/bump-lexbor.change
deleted file mode 100644
index 2c7061a81..000000000
--- a/changelog.d/bump-lexbor.change
+++ /dev/null
@@ -1 +0,0 @@
-- Bumped `fast_html` to v2.3.0, which notably allows to use system-installed lexbor with passing `WITH_SYSTEM_LEXBOR=1` environment variable at build-time
\ No newline at end of file
diff --git a/changelog.d/c2s-update-verify.fix b/changelog.d/c2s-update-verify.fix
deleted file mode 100644
index a4dfe7c07..000000000
--- a/changelog.d/c2s-update-verify.fix
+++ /dev/null
@@ -1 +0,0 @@
-Verify a local Update sent through AP C2S so users can only update their own objects
diff --git a/changelog.d/ci-git-fetch.skip b/changelog.d/ci-git-fetch.skip
deleted file mode 100644
index e69de29bb..000000000
diff --git a/changelog.d/commonapi.skip b/changelog.d/commonapi.skip
deleted file mode 100644
index e69de29bb..000000000
diff --git a/changelog.d/debian-install-improve.skip b/changelog.d/debian-install-improve.skip
deleted file mode 100644
index 6068a3066..000000000
--- a/changelog.d/debian-install-improve.skip
+++ /dev/null
@@ -1 +0,0 @@
-Fixed a formatting issue that had a required commend embedded in a textblock, and change the language to make it a bit more idiomatic.
\ No newline at end of file
diff --git a/changelog.d/dedupe-sharding.change b/changelog.d/dedupe-sharding.change
deleted file mode 100644
index 2e140d8a2..000000000
--- a/changelog.d/dedupe-sharding.change
+++ /dev/null
@@ -1 +0,0 @@
-Dedupe upload filter now uses a three-level sharding directory structure
diff --git a/changelog.d/deprecate-subscribe.change b/changelog.d/deprecate-subscribe.change
deleted file mode 100644
index bd7e8aec7..000000000
--- a/changelog.d/deprecate-subscribe.change
+++ /dev/null
@@ -1 +0,0 @@
-Deprecate `/api/v1/pleroma/accounts/:id/subscribe`/`unsubscribe`
\ No newline at end of file
diff --git a/changelog.d/dialyzer.skip b/changelog.d/dialyzer.skip
deleted file mode 100644
index e69de29bb..000000000
diff --git a/changelog.d/docs-fix.skip b/changelog.d/docs-fix.skip
deleted file mode 100644
index e69de29bb..000000000
diff --git a/changelog.d/docs-vips.skip b/changelog.d/docs-vips.skip
deleted file mode 100644
index e69de29bb..000000000
diff --git a/changelog.d/drop-unwanted.change b/changelog.d/drop-unwanted.change
deleted file mode 100644
index 459d4bfe6..000000000
--- a/changelog.d/drop-unwanted.change
+++ /dev/null
@@ -1 +0,0 @@
-Restrict incoming activities from unknown actors to a subset that does not imply a previous relationship and early rejection of unrecognized activity types.
diff --git a/changelog.d/elixir-1.14-docker.skip b/changelog.d/elixir-1.14-docker.skip
deleted file mode 100644
index e69de29bb..000000000
diff --git a/changelog.d/elixir.change b/changelog.d/elixir.change
deleted file mode 100644
index 779c01562..000000000
--- a/changelog.d/elixir.change
+++ /dev/null
@@ -1 +0,0 @@
-Elixir 1.14 and Erlang/OTP 23 is now the minimum supported release
diff --git a/changelog.d/follow-request.fix b/changelog.d/follow-request.fix
deleted file mode 100644
index 59d34e9bf..000000000
--- a/changelog.d/follow-request.fix
+++ /dev/null
@@ -1 +0,0 @@
-Fixed malformed follow requests that cause them to appear stuck pending due to the recipient being unable to process them.
diff --git a/changelog.d/freebsd-docs.skip b/changelog.d/freebsd-docs.skip
deleted file mode 100644
index e69de29bb..000000000
diff --git a/changelog.d/get-statuses-param.change b/changelog.d/get-statuses-param.change
deleted file mode 100644
index 3edcad268..000000000
--- a/changelog.d/get-statuses-param.change
+++ /dev/null
@@ -1 +0,0 @@
-Support `id` param in `GET /api/v1/statuses`
\ No newline at end of file
diff --git a/changelog.d/hashtag-feeds-restricted.add b/changelog.d/hashtag-feeds-restricted.add
deleted file mode 100644
index accac9c9c..000000000
--- a/changelog.d/hashtag-feeds-restricted.add
+++ /dev/null
@@ -1 +0,0 @@
-Repesct :restrict_unauthenticated for hashtag rss/atom feeds
\ No newline at end of file
diff --git a/changelog.d/identity-proofs.remove b/changelog.d/identity-proofs.remove
deleted file mode 100644
index efe1c34f5..000000000
--- a/changelog.d/identity-proofs.remove
+++ /dev/null
@@ -1 +0,0 @@
-Remove stub for /api/v1/accounts/:id/identity_proofs (deprecated by Mastodon 3.5.0)
\ No newline at end of file
diff --git a/changelog.d/incoming-blocks.fix b/changelog.d/incoming-blocks.fix
deleted file mode 100644
index 3228d7318..000000000
--- a/changelog.d/incoming-blocks.fix
+++ /dev/null
@@ -1 +0,0 @@
-Fix incoming Block activities being rejected
diff --git a/changelog.d/ldap-ca.add b/changelog.d/ldap-ca.add
deleted file mode 100644
index 32ecbb5c0..000000000
--- a/changelog.d/ldap-ca.add
+++ /dev/null
@@ -1 +0,0 @@
-LDAP configuration now permits overriding the CA root certificate file for TLS validation.
diff --git a/changelog.d/ldap-password-change.add b/changelog.d/ldap-password-change.add
deleted file mode 100644
index 7ca555ee4..000000000
--- a/changelog.d/ldap-password-change.add
+++ /dev/null
@@ -1 +0,0 @@
-LDAP now supports users changing their passwords
diff --git a/changelog.d/ldap-refactor.change b/changelog.d/ldap-refactor.change
deleted file mode 100644
index 1510eea6a..000000000
--- a/changelog.d/ldap-refactor.change
+++ /dev/null
@@ -1 +0,0 @@
-LDAP authentication has been refactored to operate as a GenServer process which will maintain an active connection to the LDAP server.
diff --git a/changelog.d/ldap-tls.fix b/changelog.d/ldap-tls.fix
deleted file mode 100644
index b15137d77..000000000
--- a/changelog.d/ldap-tls.fix
+++ /dev/null
@@ -1 +0,0 @@
-STARTTLS certificate and hostname verification for LDAP authentication
diff --git a/changelog.d/ldap-warning.skip b/changelog.d/ldap-warning.skip
deleted file mode 100644
index e69de29bb..000000000
diff --git a/changelog.d/ldaps.fix b/changelog.d/ldaps.fix
deleted file mode 100644
index a1dc901ab..000000000
--- a/changelog.d/ldaps.fix
+++ /dev/null
@@ -1 +0,0 @@
-LDAPS connections (implicit TLS) are now supported.
diff --git a/changelog.d/list-id-visibility.add b/changelog.d/list-id-visibility.add
deleted file mode 100644
index 2fea2d771..000000000
--- a/changelog.d/list-id-visibility.add
+++ /dev/null
@@ -1 +0,0 @@
-Include list id in StatusView
\ No newline at end of file
diff --git a/changelog.d/manifest-icon-size.skip b/changelog.d/manifest-icon-size.skip
deleted file mode 100644
index e69de29bb..000000000
diff --git a/changelog.d/mediav2_status.fix b/changelog.d/mediav2_status.fix
deleted file mode 100644
index 28e93e030..000000000
--- a/changelog.d/mediav2_status.fix
+++ /dev/null
@@ -1 +0,0 @@
-Fix /api/v2/media returning the wrong status code (202) for media processed synchronously
diff --git a/changelog.d/meilisearch-misc-fixes.fix b/changelog.d/meilisearch-misc-fixes.fix
deleted file mode 100644
index 0f127d3a8..000000000
--- a/changelog.d/meilisearch-misc-fixes.fix
+++ /dev/null
@@ -1 +0,0 @@
-Miscellaneous fixes for Meilisearch support
diff --git a/changelog.d/module-search-in-pleroma-ctl.fix b/changelog.d/module-search-in-pleroma-ctl.fix
deleted file mode 100644
index d32fe3f33..000000000
--- a/changelog.d/module-search-in-pleroma-ctl.fix
+++ /dev/null
@@ -1 +0,0 @@
-Fix pleroma_ctl mix task calls sometimes not being found
diff --git a/changelog.d/mogrify.skip b/changelog.d/mogrify.skip
deleted file mode 100644
index e69de29bb..000000000
diff --git a/changelog.d/mrf-cleanup.skip b/changelog.d/mrf-cleanup.skip
deleted file mode 100644
index e69de29bb..000000000
diff --git a/changelog.d/mrf-fodirectreply.add b/changelog.d/mrf-fodirectreply.add
deleted file mode 100644
index 10fd5d16a..000000000
--- a/changelog.d/mrf-fodirectreply.add
+++ /dev/null
@@ -1 +0,0 @@
-Added MRF.FODirectReply which changes replies to followers-only posts to be direct.
diff --git a/changelog.d/mrf-id_filter.add b/changelog.d/mrf-id_filter.add
deleted file mode 100644
index f556f9bc4..000000000
--- a/changelog.d/mrf-id_filter.add
+++ /dev/null
@@ -1 +0,0 @@
-Add `id_filter` to MRF to filter URLs and their domain prior to fetching
\ No newline at end of file
diff --git a/changelog.d/mrf-quietreply.add b/changelog.d/mrf-quietreply.add
deleted file mode 100644
index 4ed20bce6..000000000
--- a/changelog.d/mrf-quietreply.add
+++ /dev/null
@@ -1 +0,0 @@
-Added MRF.QuietReply which prevents replies to public posts from being published to the timelines
diff --git a/changelog.d/notifications-group-key.add b/changelog.d/notifications-group-key.add
deleted file mode 100644
index 386927f4a..000000000
--- a/changelog.d/notifications-group-key.add
+++ /dev/null
@@ -1 +0,0 @@
-Add `group_key` to notifications
\ No newline at end of file
diff --git a/changelog.d/notifications-marker.change b/changelog.d/notifications-marker.change
deleted file mode 100644
index 9e350a95c..000000000
--- a/changelog.d/notifications-marker.change
+++ /dev/null
@@ -1 +0,0 @@
-Fix 'Setting a marker should mark notifications as read'
\ No newline at end of file
diff --git a/changelog.d/oauth-app-spam.fix b/changelog.d/oauth-app-spam.fix
deleted file mode 100644
index cdc2e816d..000000000
--- a/changelog.d/oauth-app-spam.fix
+++ /dev/null
@@ -1 +0,0 @@
-Add a rate limiter to the OAuth App creation endpoint and ensure registered apps are assigned to users.
diff --git a/changelog.d/oban-recevier-improvements.fix b/changelog.d/oban-recevier-improvements.fix
deleted file mode 100644
index f91502ed2..000000000
--- a/changelog.d/oban-recevier-improvements.fix
+++ /dev/null
@@ -1 +0,0 @@
-ReceiverWorker will cancel processing jobs instead of retrying if the user cannot be fetched due to 403, 404, or 410 errors or if the account is disabled locally.
diff --git a/changelog.d/oban-uniques.change b/changelog.d/oban-uniques.change
deleted file mode 100644
index d9deb4696..000000000
--- a/changelog.d/oban-uniques.change
+++ /dev/null
@@ -1 +0,0 @@
-Adjust more Oban workers to enforce unique job constraints.
diff --git a/changelog.d/oban-update.change b/changelog.d/oban-update.change
deleted file mode 100644
index 48a54ed2d..000000000
--- a/changelog.d/oban-update.change
+++ /dev/null
@@ -1 +0,0 @@
-Oban updated to 2.18.3
diff --git a/changelog.d/oban_gun_snooze.change b/changelog.d/oban_gun_snooze.change
deleted file mode 100644
index c94525b2a..000000000
--- a/changelog.d/oban_gun_snooze.change
+++ /dev/null
@@ -1 +0,0 @@
-Publisher behavior improvement when snoozing Oban jobs due to Gun connection pool contention.
diff --git a/changelog.d/poll-refresh.change b/changelog.d/poll-refresh.change
deleted file mode 100644
index b755128a1..000000000
--- a/changelog.d/poll-refresh.change
+++ /dev/null
@@ -1 +0,0 @@
-Poll results refreshing is handled asynchronously and will not attempt to keep fetching updates to a closed poll.
diff --git a/changelog.d/profile-image-descriptions.add b/changelog.d/profile-image-descriptions.add
deleted file mode 100644
index 85cc48083..000000000
--- a/changelog.d/profile-image-descriptions.add
+++ /dev/null
@@ -1 +0,0 @@
-Allow providing avatar/header descriptions
\ No newline at end of file
diff --git a/changelog.d/profile-image-descriptions.skip b/changelog.d/profile-image-descriptions.skip
deleted file mode 100644
index e69de29bb..000000000
diff --git a/changelog.d/publisher-reachability.fix b/changelog.d/publisher-reachability.fix
deleted file mode 100644
index 3f50be581..000000000
--- a/changelog.d/publisher-reachability.fix
+++ /dev/null
@@ -1 +0,0 @@
-Address case where instance reachability status couldn't be updated
diff --git a/changelog.d/release-tuning.change b/changelog.d/release-tuning.change
deleted file mode 100644
index bf9abc3ad..000000000
--- a/changelog.d/release-tuning.change
+++ /dev/null
@@ -1 +0,0 @@
-Tuning for release builds to lower CPU usage.
diff --git a/changelog.d/remote-object-fetcher.fix b/changelog.d/remote-object-fetcher.fix
deleted file mode 100644
index dcf2b1b31..000000000
--- a/changelog.d/remote-object-fetcher.fix
+++ /dev/null
@@ -1 +0,0 @@
-Remote Fetcher Worker recognizes more permanent failure errors
diff --git a/changelog.d/remote-report-policy.add b/changelog.d/remote-report-policy.add
deleted file mode 100644
index 1cf25b1a8..000000000
--- a/changelog.d/remote-report-policy.add
+++ /dev/null
@@ -1 +0,0 @@
-Added RemoteReportPolicy from Rebased for handling bogus federated reports
diff --git a/changelog.d/rich-media-no-heads.change b/changelog.d/rich-media-no-heads.change
deleted file mode 100644
index 0bab323aa..000000000
--- a/changelog.d/rich-media-no-heads.change
+++ /dev/null
@@ -1 +0,0 @@
-Rich Media preview fetching will skip making an HTTP HEAD request to check a URL for allowed content type and length if the Tesla adapter is Gun or Finch
diff --git a/changelog.d/scrubbers-allow-mention-hashtag.add b/changelog.d/scrubbers-allow-mention-hashtag.add
deleted file mode 100644
index c12ab1ffb..000000000
--- a/changelog.d/scrubbers-allow-mention-hashtag.add
+++ /dev/null
@@ -1 +0,0 @@
-scrubbers/default: Allow "mention hashtag" classes used by Mastodon
\ No newline at end of file
diff --git a/changelog.d/se-opt-out.change b/changelog.d/se-opt-out.change
deleted file mode 100644
index dd694033f..000000000
--- a/changelog.d/se-opt-out.change
+++ /dev/null
@@ -1 +0,0 @@
-Fix nonexisting user will not generate metadata for search engine opt-out
diff --git a/changelog.d/stream-follow-relationships-count.fix b/changelog.d/stream-follow-relationships-count.fix
deleted file mode 100644
index 68452a88b..000000000
--- a/changelog.d/stream-follow-relationships-count.fix
+++ /dev/null
@@ -1 +0,0 @@
-StreamerView: Do not leak follows count if hidden
\ No newline at end of file
diff --git a/changelog.d/swoosh-mua.add b/changelog.d/swoosh-mua.add
deleted file mode 100644
index d4c4bbd08..000000000
--- a/changelog.d/swoosh-mua.add
+++ /dev/null
@@ -1 +0,0 @@
-Added dependencies for Swoosh's Mua mail adapter
diff --git a/changelog.d/text-extensions.skip b/changelog.d/text-extensions.skip
deleted file mode 100644
index e69de29bb..000000000
diff --git a/changelog.d/todo-cleanup.skip b/changelog.d/todo-cleanup.skip
deleted file mode 100644
index e69de29bb..000000000
diff --git a/changelog.d/token-view-scopes.add b/changelog.d/token-view-scopes.add
deleted file mode 100644
index e24fa38e6..000000000
--- a/changelog.d/token-view-scopes.add
+++ /dev/null
@@ -1 +0,0 @@
-Include session scopes in TokenView
\ No newline at end of file
diff --git a/changelog.d/update-oban.change b/changelog.d/update-oban.change
deleted file mode 100644
index a67b3e3cf..000000000
--- a/changelog.d/update-oban.change
+++ /dev/null
@@ -1 +0,0 @@
-Update Oban to 2.18
diff --git a/changelog.d/user-factory.skip b/changelog.d/user-factory.skip
deleted file mode 100644
index e69de29bb..000000000
diff --git a/changelog.d/user-imports.fix b/changelog.d/user-imports.fix
deleted file mode 100644
index 0076c73d7..000000000
--- a/changelog.d/user-imports.fix
+++ /dev/null
@@ -1 +0,0 @@
-Imports of blocks, mutes, and follows would retry repeatedly due to incorrect error handling and all work executed in a single job
diff --git a/changelog.d/vapid_keyword_fallback.fix b/changelog.d/vapid_keyword_fallback.fix
deleted file mode 100644
index aa48f8938..000000000
--- a/changelog.d/vapid_keyword_fallback.fix
+++ /dev/null
@@ -1 +0,0 @@
-Make vapid_config return empty array, fixing preloading for instances without push notifications configured
\ No newline at end of file
diff --git a/changelog.d/workerhelper.change b/changelog.d/workerhelper.change
deleted file mode 100644
index 539c9b54f..000000000
--- a/changelog.d/workerhelper.change
+++ /dev/null
@@ -1 +0,0 @@
-Worker configuration is no longer available. This only affects custom max_retries values for a couple Oban queues.

From 89e92121c262511ec0b1628caa50cf6470c6fb1b Mon Sep 17 00:00:00 2001
From: Lain Soykaf <lain@lain.com>
Date: Fri, 20 Dec 2024 07:35:23 +0400
Subject: [PATCH 203/212] CI: Allow failure for non-musl arm for now

---
 .gitlab-ci.yml                         | 1 +
 changelog.d/ci-builder-skip-arm32.skip | 0
 2 files changed, 1 insertion(+)
 create mode 100644 changelog.d/ci-builder-skip-arm32.skip

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 39947c75e..fd53ab053 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -327,6 +327,7 @@ amd64-musl:
 
 arm:
   stage: release
+  allow_failure: true
   artifacts: *release-artifacts
   only: *release-only
   tags:
diff --git a/changelog.d/ci-builder-skip-arm32.skip b/changelog.d/ci-builder-skip-arm32.skip
new file mode 100644
index 000000000..e69de29bb

From 7dc90f5ea40c0a44d8b971e70dc1b3b09749e6a1 Mon Sep 17 00:00:00 2001
From: Lain Soykaf <lain@lain.com>
Date: Fri, 20 Dec 2024 16:14:08 +0400
Subject: [PATCH 204/212] Switch release builder to hexpm images (mostly)

---
 .gitlab-ci.yml | 17 +++++++++++------
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index fd53ab053..675d0e067 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -2,7 +2,7 @@ image: git.pleroma.social:5050/pleroma/pleroma/ci-base:elixir-1.14.5-otp-25
 
 variables: &global_variables
   # Only used for the release
-  ELIXIR_VER: 1.14.5
+  ELIXIR_VER: 1.17.3
   POSTGRES_DB: pleroma_test
   POSTGRES_USER: postgres
   POSTGRES_PASSWORD: postgres
@@ -272,7 +272,8 @@ stop_review_app:
 
 amd64:
   stage: release
-  image: elixir:$ELIXIR_VER
+  image: 
+    name: hexpm/elixir-amd64:1.17.3-erlang-26.2.5.6-ubuntu-focal-20241011
   only: &release-only
   - stable@pleroma/pleroma
   - develop@pleroma/pleroma
@@ -297,8 +298,9 @@ amd64:
   variables: &release-variables
     MIX_ENV: prod
     VIX_COMPILATION_MODE: PLATFORM_PROVIDED_LIBVIPS
+    DEBIAN_FRONTEND: noninteractive
   before_script: &before-release
-  - apt-get update && apt-get install -y cmake libmagic-dev libvips-dev erlang-dev
+  - apt-get update && apt-get install -y cmake libmagic-dev libvips-dev erlang-dev git
   - echo "import Config" > config/prod.secret.exs
   - mix local.hex --force
   - mix local.rebar --force
@@ -313,7 +315,8 @@ amd64-musl:
   stage: release
   artifacts: *release-artifacts
   only: *release-only
-  image: elixir:$ELIXIR_VER-alpine
+  image: 
+    name: hexpm/elixir-amd64:1.17.3-erlang-26.2.5.6-alpine-3.17.9
   tags:
     - amd64
   cache: *release-cache
@@ -356,7 +359,8 @@ arm64:
   only: *release-only
   tags:
     - arm
-  image: arm64v8/elixir:$ELIXIR_VER
+  image: 
+    name: hexpm/elixir-arm64:1.17.3-erlang-26.2.5.6-ubuntu-focal-20241011
   cache: *release-cache
   variables: *release-variables
   before_script: *before-release
@@ -368,7 +372,8 @@ arm64-musl:
   only: *release-only
   tags:
     - arm
-  image: arm64v8/elixir:$ELIXIR_VER-alpine
+  image: 
+    name: hexpm/elixir-arm64:1.17.3-erlang-26.2.5.6-alpine-3.17.9
   cache: *release-cache
   variables: *release-variables
   before_script: *before-release-musl

From 6f3d82e2a0685164dfe7d00bc66a4052002e10ee Mon Sep 17 00:00:00 2001
From: Lain Soykaf <lain@lain.com>
Date: Fri, 20 Dec 2024 16:16:54 +0400
Subject: [PATCH 205/212] Add changelog

---
 changelog.d/hexpm-build-images.skip | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 changelog.d/hexpm-build-images.skip

diff --git a/changelog.d/hexpm-build-images.skip b/changelog.d/hexpm-build-images.skip
new file mode 100644
index 000000000..e69de29bb

From 855294bb3d802b801e3ec064341e4134253089a6 Mon Sep 17 00:00:00 2001
From: mkljczk <git@mkljczk.pl>
Date: Thu, 9 Jan 2025 12:58:51 +0100
Subject: [PATCH 206/212] Link to exported outbox/followers/following
 collections in backup actor.json

Signed-off-by: mkljczk <git@mkljczk.pl>
---
 changelog.d/backup-links.add      | 1 +
 lib/pleroma/user/backup.ex        | 8 +++++++-
 test/pleroma/user/backup_test.exs | 6 +++---
 3 files changed, 11 insertions(+), 4 deletions(-)
 create mode 100644 changelog.d/backup-links.add

diff --git a/changelog.d/backup-links.add b/changelog.d/backup-links.add
new file mode 100644
index 000000000..ff19e736b
--- /dev/null
+++ b/changelog.d/backup-links.add
@@ -0,0 +1 @@
+Link to exported outbox/followers/following collections in backup actor.json
diff --git a/lib/pleroma/user/backup.ex b/lib/pleroma/user/backup.ex
index d77d49890..cdff297a9 100644
--- a/lib/pleroma/user/backup.ex
+++ b/lib/pleroma/user/backup.ex
@@ -246,7 +246,13 @@ defmodule Pleroma.User.Backup do
   defp actor(dir, user) do
     with {:ok, json} <-
            UserView.render("user.json", %{user: user})
-           |> Map.merge(%{"likes" => "likes.json", "bookmarks" => "bookmarks.json"})
+           |> Map.merge(%{
+             "bookmarks" => "bookmarks.json",
+             "likes" => "likes.json",
+             "outbox" => "outbox.json",
+             "followers" => "followers.json",
+             "following" => "following.json"
+           })
            |> Jason.encode() do
       File.write(Path.join(dir, "actor.json"), json)
     end
diff --git a/test/pleroma/user/backup_test.exs b/test/pleroma/user/backup_test.exs
index 24fe09f7e..f4b92adf8 100644
--- a/test/pleroma/user/backup_test.exs
+++ b/test/pleroma/user/backup_test.exs
@@ -185,13 +185,13 @@ defmodule Pleroma.User.BackupTest do
                %{"@language" => "und"}
              ],
              "bookmarks" => "bookmarks.json",
-             "followers" => "http://cofe.io/users/cofe/followers",
-             "following" => "http://cofe.io/users/cofe/following",
+             "followers" => "followers.json",
+             "following" => "following.json",
              "id" => "http://cofe.io/users/cofe",
              "inbox" => "http://cofe.io/users/cofe/inbox",
              "likes" => "likes.json",
              "name" => "Cofe",
-             "outbox" => "http://cofe.io/users/cofe/outbox",
+             "outbox" => "outbox.json",
              "preferredUsername" => "cofe",
              "publicKey" => %{
                "id" => "http://cofe.io/users/cofe#main-key",

From 38b17933e160beb5923283786ca829af1d6b4036 Mon Sep 17 00:00:00 2001
From: mkljczk <git@mkljczk.pl>
Date: Sun, 19 Jan 2025 16:26:46 +0100
Subject: [PATCH 207/212] Include "published" in actor view

Signed-off-by: mkljczk <git@mkljczk.pl>
---
 changelog.d/actor-published-date.add            | 1 +
 lib/pleroma/web/activity_pub/views/user_view.ex | 3 ++-
 2 files changed, 3 insertions(+), 1 deletion(-)
 create mode 100644 changelog.d/actor-published-date.add

diff --git a/changelog.d/actor-published-date.add b/changelog.d/actor-published-date.add
new file mode 100644
index 000000000..feac85894
--- /dev/null
+++ b/changelog.d/actor-published-date.add
@@ -0,0 +1 @@
+Include "published" in actor view
diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex
index cd485ed64..61975387b 100644
--- a/lib/pleroma/web/activity_pub/views/user_view.ex
+++ b/lib/pleroma/web/activity_pub/views/user_view.ex
@@ -127,7 +127,8 @@ defmodule Pleroma.Web.ActivityPub.UserView do
       "capabilities" => capabilities,
       "alsoKnownAs" => user.also_known_as,
       "vcard:bday" => birthday,
-      "webfinger" => "acct:#{User.full_nickname(user)}"
+      "webfinger" => "acct:#{User.full_nickname(user)}",
+      "published" => Pleroma.Web.CommonAPI.Utils.to_masto_date(user.inserted_at)
     }
     |> Map.merge(
       maybe_make_image(

From 22261718907d227a521bb9f898e617ea137c502d Mon Sep 17 00:00:00 2001
From: Lain Soykaf <lain@lain.com>
Date: Tue, 21 Jan 2025 11:59:25 +0400
Subject: [PATCH 208/212] MediaProxyController: Use 301 for permanent redirects

---
 changelog.d/301-small-image-redirect.change   |  1 +
 .../web/media_proxy/media_proxy_controller.ex |  8 +++--
 .../media_proxy_controller_test.exs           | 35 ++++++++++++++++---
 3 files changed, 38 insertions(+), 6 deletions(-)
 create mode 100644 changelog.d/301-small-image-redirect.change

diff --git a/changelog.d/301-small-image-redirect.change b/changelog.d/301-small-image-redirect.change
new file mode 100644
index 000000000..c5be80539
--- /dev/null
+++ b/changelog.d/301-small-image-redirect.change
@@ -0,0 +1 @@
+Performance: Use 301 (permanent) redirect instead of 302 (temporary) when redirecting small images in media proxy. This allows browsers to cache the redirect response. 
\ No newline at end of file
diff --git a/lib/pleroma/web/media_proxy/media_proxy_controller.ex b/lib/pleroma/web/media_proxy/media_proxy_controller.ex
index 0b446e0a6..a0aafc32e 100644
--- a/lib/pleroma/web/media_proxy/media_proxy_controller.ex
+++ b/lib/pleroma/web/media_proxy/media_proxy_controller.ex
@@ -71,11 +71,15 @@ defmodule Pleroma.Web.MediaProxy.MediaProxyController do
           drop_static_param_and_redirect(conn)
 
         content_type == "image/gif" ->
-          redirect(conn, external: media_proxy_url)
+          conn
+          |> put_status(301)
+          |> redirect(external: media_proxy_url)
 
         min_content_length_for_preview() > 0 and content_length > 0 and
             content_length < min_content_length_for_preview() ->
-          redirect(conn, external: media_proxy_url)
+          conn
+          |> put_status(301)
+          |> redirect(external: media_proxy_url)
 
         true ->
           handle_preview(content_type, conn, media_proxy_url)
diff --git a/test/pleroma/web/media_proxy/media_proxy_controller_test.exs b/test/pleroma/web/media_proxy/media_proxy_controller_test.exs
index f0c1dd640..f7e52483c 100644
--- a/test/pleroma/web/media_proxy/media_proxy_controller_test.exs
+++ b/test/pleroma/web/media_proxy/media_proxy_controller_test.exs
@@ -248,8 +248,8 @@ defmodule Pleroma.Web.MediaProxy.MediaProxyControllerTest do
 
       response = get(conn, url)
 
-      assert response.status == 302
-      assert redirected_to(response) == media_proxy_url
+      assert response.status == 301
+      assert redirected_to(response, 301) == media_proxy_url
     end
 
     test "with `static` param and non-GIF image preview requested, " <>
@@ -290,8 +290,8 @@ defmodule Pleroma.Web.MediaProxy.MediaProxyControllerTest do
 
       response = get(conn, url)
 
-      assert response.status == 302
-      assert redirected_to(response) == media_proxy_url
+      assert response.status == 301
+      assert redirected_to(response, 301) == media_proxy_url
     end
 
     test "thumbnails PNG images into PNG", %{
@@ -356,5 +356,32 @@ defmodule Pleroma.Web.MediaProxy.MediaProxyControllerTest do
       assert response.status == 302
       assert redirected_to(response) == media_proxy_url
     end
+
+    test "redirects to media proxy URI with 301 when image is too small for preview", %{
+      conn: conn,
+      url: url,
+      media_proxy_url: media_proxy_url
+    } do
+      clear_config([:media_preview_proxy],
+        enabled: true,
+        min_content_length: 1000,
+        image_quality: 85,
+        thumbnail_max_width: 100,
+        thumbnail_max_height: 100
+      )
+
+      Tesla.Mock.mock(fn
+        %{method: :head, url: ^media_proxy_url} ->
+          %Tesla.Env{
+            status: 200,
+            body: "",
+            headers: [{"content-type", "image/png"}, {"content-length", "500"}]
+          }
+      end)
+
+      response = get(conn, url)
+      assert response.status == 301
+      assert redirected_to(response, 301) == media_proxy_url
+    end
   end
 end

From 4128ea39481a8864bcc4631dbb8d1e3d922473ab Mon Sep 17 00:00:00 2001
From: mkljczk <git@mkljczk.pl>
Date: Tue, 21 Jan 2025 18:24:42 +0100
Subject: [PATCH 209/212] description.exs: Remove suggestion referencing a
 deleted module

Signed-off-by: mkljczk <git@mkljczk.pl>
---
 changelog.d/description-update-suggestions.skip | 0
 config/description.exs                          | 3 +--
 2 files changed, 1 insertion(+), 2 deletions(-)
 create mode 100644 changelog.d/description-update-suggestions.skip

diff --git a/changelog.d/description-update-suggestions.skip b/changelog.d/description-update-suggestions.skip
new file mode 100644
index 000000000..e69de29bb
diff --git a/config/description.exs b/config/description.exs
index 47f4771eb..e8d154124 100644
--- a/config/description.exs
+++ b/config/description.exs
@@ -3302,8 +3302,7 @@ config :pleroma, :config_description, [
         suggestions: [
           Pleroma.Web.Preload.Providers.Instance,
           Pleroma.Web.Preload.Providers.User,
-          Pleroma.Web.Preload.Providers.Timelines,
-          Pleroma.Web.Preload.Providers.StatusNet
+          Pleroma.Web.Preload.Providers.Timelines
         ]
       }
     ]

From 8cd77168726e2e44d7612c29914c6b6398ff675d Mon Sep 17 00:00:00 2001
From: mkljczk <git@mkljczk.pl>
Date: Tue, 28 Jan 2025 22:28:34 +0100
Subject: [PATCH 210/212] Fix Mastodon incoming edits with inlined "likes"

Signed-off-by: mkljczk <git@mkljczk.pl>
---
 changelog.d/fix-mastodon-edits.fix            |  1 +
 .../article_note_page_validator.ex            |  1 +
 .../audio_image_video_validator.ex            |  1 +
 .../object_validators/common_fixes.ex         |  7 ++
 .../object_validators/event_validator.ex      |  1 +
 .../object_validators/question_validator.ex   |  1 +
 test/fixtures/mastodon-update-with-likes.json | 90 +++++++++++++++++++
 .../article_note_page_validator_test.exs      | 11 +++
 8 files changed, 113 insertions(+)
 create mode 100644 changelog.d/fix-mastodon-edits.fix
 create mode 100644 test/fixtures/mastodon-update-with-likes.json

diff --git a/changelog.d/fix-mastodon-edits.fix b/changelog.d/fix-mastodon-edits.fix
new file mode 100644
index 000000000..2e79977e0
--- /dev/null
+++ b/changelog.d/fix-mastodon-edits.fix
@@ -0,0 +1 @@
+Fix Mastodon incoming edits with inlined "likes"
diff --git a/lib/pleroma/web/activity_pub/object_validators/article_note_page_validator.ex b/lib/pleroma/web/activity_pub/object_validators/article_note_page_validator.ex
index 1b5b2e8fb..ada1a4ea9 100644
--- a/lib/pleroma/web/activity_pub/object_validators/article_note_page_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/article_note_page_validator.ex
@@ -85,6 +85,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidator do
     |> fix_replies()
     |> fix_attachments()
     |> CommonFixes.fix_quote_url()
+    |> CommonFixes.fix_likes()
     |> Transmogrifier.fix_emoji()
     |> Transmogrifier.fix_content_map()
   end
diff --git a/lib/pleroma/web/activity_pub/object_validators/audio_image_video_validator.ex b/lib/pleroma/web/activity_pub/object_validators/audio_image_video_validator.ex
index 65ac6bb93..034c6f33f 100644
--- a/lib/pleroma/web/activity_pub/object_validators/audio_image_video_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/audio_image_video_validator.ex
@@ -100,6 +100,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AudioImageVideoValidator do
     |> CommonFixes.fix_actor()
     |> CommonFixes.fix_object_defaults()
     |> CommonFixes.fix_quote_url()
+    |> CommonFixes.fix_likes()
     |> Transmogrifier.fix_emoji()
     |> fix_url()
     |> fix_content()
diff --git a/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex b/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex
index 4699029d4..a39110e10 100644
--- a/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex
@@ -114,6 +114,13 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do
 
   def fix_quote_url(data), do: data
 
+  # On Mastodon, `"likes"` attribute includes an inlined `Collection` with `totalItems`,
+  # not a list of users.
+  # https://github.com/mastodon/mastodon/pull/32007
+  def fix_likes(%{"likes" => %{}} = data), do: Map.drop(data, ["likes"])
+
+  def fix_likes(data), do: data
+
   # https://codeberg.org/fediverse/fep/src/branch/main/fep/e232/fep-e232.md
   def object_link_tag?(%{
         "type" => "Link",
diff --git a/lib/pleroma/web/activity_pub/object_validators/event_validator.ex b/lib/pleroma/web/activity_pub/object_validators/event_validator.ex
index ab204f69a..c87515e80 100644
--- a/lib/pleroma/web/activity_pub/object_validators/event_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/event_validator.ex
@@ -47,6 +47,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EventValidator do
     data
     |> CommonFixes.fix_actor()
     |> CommonFixes.fix_object_defaults()
+    |> CommonFixes.fix_likes()
     |> Transmogrifier.fix_emoji()
   end
 
diff --git a/lib/pleroma/web/activity_pub/object_validators/question_validator.ex b/lib/pleroma/web/activity_pub/object_validators/question_validator.ex
index 7f9d4d648..21940f4f1 100644
--- a/lib/pleroma/web/activity_pub/object_validators/question_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/question_validator.ex
@@ -64,6 +64,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.QuestionValidator do
     |> CommonFixes.fix_actor()
     |> CommonFixes.fix_object_defaults()
     |> CommonFixes.fix_quote_url()
+    |> CommonFixes.fix_likes()
     |> Transmogrifier.fix_emoji()
     |> fix_closed()
   end
diff --git a/test/fixtures/mastodon-update-with-likes.json b/test/fixtures/mastodon-update-with-likes.json
new file mode 100644
index 000000000..3bdb3ba3d
--- /dev/null
+++ b/test/fixtures/mastodon-update-with-likes.json
@@ -0,0 +1,90 @@
+{
+  "@context": [
+    "https://www.w3.org/ns/activitystreams",
+    {
+      "atomUri": "ostatus:atomUri",
+      "conversation": "ostatus:conversation",
+      "inReplyToAtomUri": "ostatus:inReplyToAtomUri",
+      "ostatus": "http://ostatus.org#",
+      "sensitive": "as:sensitive",
+      "toot": "http://joinmastodon.org/ns#",
+      "votersCount": "toot:votersCount"
+    },
+    "https://w3id.org/security/v1"
+  ],
+  "actor": "https://pol.social/users/mkljczk",
+  "cc": ["https://www.w3.org/ns/activitystreams#Public",
+   "https://pol.social/users/aemstuz", "https://gts.mkljczk.pl/users/mkljczk",
+   "https://pl.fediverse.pl/users/mkljczk",
+   "https://fedi.kutno.pl/users/mkljczk"],
+  "id": "https://pol.social/users/mkljczk/statuses/113907871635572263#updates/1738096776",
+  "object": {
+    "atomUri": "https://pol.social/users/mkljczk/statuses/113907871635572263",
+    "attachment": [],
+    "attributedTo": "https://pol.social/users/mkljczk",
+    "cc": ["https://www.w3.org/ns/activitystreams#Public",
+     "https://pol.social/users/aemstuz", "https://gts.mkljczk.pl/users/mkljczk",
+     "https://pl.fediverse.pl/users/mkljczk",
+     "https://fedi.kutno.pl/users/mkljczk"],
+    "content": "<p>test</p>",
+    "contentMap": {
+      "pl": "<p>test</p>"
+    },
+    "conversation": "https://fedi.kutno.pl/contexts/43c14c70-d3fb-42b4-a36d-4eacfab9695a",
+    "id": "https://pol.social/users/mkljczk/statuses/113907871635572263",
+    "inReplyTo": "https://pol.social/users/aemstuz/statuses/113907854282654767",
+    "inReplyToAtomUri": "https://pol.social/users/aemstuz/statuses/113907854282654767",
+    "likes": {
+      "id": "https://pol.social/users/mkljczk/statuses/113907871635572263/likes",
+      "totalItems": 1,
+      "type": "Collection"
+    },
+    "published": "2025-01-28T20:29:45Z",
+    "replies": {
+      "first": {
+        "items": [],
+        "next": "https://pol.social/users/mkljczk/statuses/113907871635572263/replies?only_other_accounts=true&page=true",
+        "partOf": "https://pol.social/users/mkljczk/statuses/113907871635572263/replies",
+        "type": "CollectionPage"
+      },
+      "id": "https://pol.social/users/mkljczk/statuses/113907871635572263/replies",
+      "type": "Collection"
+    },
+    "sensitive": false,
+    "shares": {
+      "id": "https://pol.social/users/mkljczk/statuses/113907871635572263/shares",
+      "totalItems": 0,
+      "type": "Collection"
+    },
+    "summary": null,
+    "tag": [
+      {
+        "href": "https://pol.social/users/aemstuz",
+        "name": "@aemstuz",
+        "type": "Mention"
+      },
+      {
+        "href": "https://gts.mkljczk.pl/users/mkljczk",
+        "name": "@mkljczk@gts.mkljczk.pl",
+        "type": "Mention"
+      },
+      {
+        "href": "https://pl.fediverse.pl/users/mkljczk",
+        "name": "@mkljczk@fediverse.pl",
+        "type": "Mention"
+      },
+      {
+        "href": "https://fedi.kutno.pl/users/mkljczk",
+        "name": "@mkljczk@fedi.kutno.pl",
+        "type": "Mention"
+      }
+    ],
+    "to": ["https://pol.social/users/mkljczk/followers"],
+    "type": "Note",
+    "updated": "2025-01-28T20:39:36Z",
+    "url": "https://pol.social/@mkljczk/113907871635572263"
+  },
+  "published": "2025-01-28T20:39:36Z",
+  "to": ["https://pol.social/users/mkljczk/followers"],
+  "type": "Update"
+}
diff --git a/test/pleroma/web/activity_pub/object_validators/article_note_page_validator_test.exs b/test/pleroma/web/activity_pub/object_validators/article_note_page_validator_test.exs
index e1dbb20c3..b1cbdbe81 100644
--- a/test/pleroma/web/activity_pub/object_validators/article_note_page_validator_test.exs
+++ b/test/pleroma/web/activity_pub/object_validators/article_note_page_validator_test.exs
@@ -128,6 +128,17 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidatorTest
     %{valid?: true} = ArticleNotePageValidator.cast_and_validate(note)
   end
 
+  test "a Note with validated likes collection validates" do
+    insert(:user, ap_id: "https://pol.social/users/mkljczk")
+
+    %{"object" => note} =
+      "test/fixtures/mastodon-update-with-likes.json"
+      |> File.read!()
+      |> Jason.decode!()
+
+    %{valid?: true} = ArticleNotePageValidator.cast_and_validate(note)
+  end
+
   test "Fedibird quote post" do
     insert(:user, ap_id: "https://fedibird.com/users/noellabo")
 

From 81ab906466f8e46ac2a16011faa8d0c2bd009957 Mon Sep 17 00:00:00 2001
From: Lain Soykaf <lain@lain.com>
Date: Thu, 30 Jan 2025 12:18:20 +0400
Subject: [PATCH 211/212] AnalyzeMetadata: Don't crash on grayscale image
 blurhash

---
 lib/pleroma/upload/filter/analyze_metadata.ex  |  10 +++++++---
 test/fixtures/break_analyze.png                | Bin 0 -> 368176 bytes
 .../upload/filter/analyze_metadata_test.exs    |  14 ++++++++++++++
 3 files changed, 21 insertions(+), 3 deletions(-)
 create mode 100644 test/fixtures/break_analyze.png

diff --git a/lib/pleroma/upload/filter/analyze_metadata.ex b/lib/pleroma/upload/filter/analyze_metadata.ex
index 7ee643277..a8480bf36 100644
--- a/lib/pleroma/upload/filter/analyze_metadata.ex
+++ b/lib/pleroma/upload/filter/analyze_metadata.ex
@@ -90,9 +90,13 @@ defmodule Pleroma.Upload.Filter.AnalyzeMetadata do
       {:ok, rgb} =
         if Image.has_alpha?(resized_image) do
           # remove alpha channel
-          resized_image
-          |> Operation.extract_band!(0, n: 3)
-          |> Image.write_to_binary()
+          case Operation.extract_band(resized_image, 0, n: 3) do
+            {:ok, data} ->
+              Image.write_to_binary(data)
+
+            _ ->
+              Image.write_to_binary(resized_image)
+          end
         else
           Image.write_to_binary(resized_image)
         end
diff --git a/test/fixtures/break_analyze.png b/test/fixtures/break_analyze.png
new file mode 100644
index 0000000000000000000000000000000000000000..b5e91b08a651f1dd53773342c99050a72532bba0
GIT binary patch
literal 368176
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%0DYalFJI{e*}SZgrBy;h=U7qChS(56KxeSO(Zy%6
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%0AM{_JOM6RUQNif
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%0D_NSM(B+)eM|7D^O4;RR8DxEJ
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%0D;1Bm1Moj{-uM3<#v8
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
O9wU9A9{i?5<i7y-Mo9wz

literal 0
HcmV?d00001

diff --git a/test/pleroma/upload/filter/analyze_metadata_test.exs b/test/pleroma/upload/filter/analyze_metadata_test.exs
index e4ac673b2..6e1f2afaf 100644
--- a/test/pleroma/upload/filter/analyze_metadata_test.exs
+++ b/test/pleroma/upload/filter/analyze_metadata_test.exs
@@ -34,6 +34,20 @@ defmodule Pleroma.Upload.Filter.AnalyzeMetadataTest do
     assert meta.blurhash == "eXJi-E:SwCEm5rCmn$+YWYn+15K#5A$xxCi{SiV]s*W:Efa#s.jE-T"
   end
 
+  test "it gets dimensions for grayscale images" do
+    upload = %Pleroma.Upload{
+      name: "break_analyze.png",
+      content_type: "image/png",
+      path: Path.absname("test/fixtures/break_analyze.png"),
+      tempfile: Path.absname("test/fixtures/break_analyze.png")
+    }
+
+    {:ok, :filtered, meta} = AnalyzeMetadata.filter(upload)
+
+    assert %{width: 1410, height: 2048} = meta
+    assert is_nil(meta.blurhash)
+  end
+
   test "adds the dimensions for videos" do
     upload = %Pleroma.Upload{
       name: "coolvideo.mp4",

From ebd827891050bf772b0d02a459db00360d53feb8 Mon Sep 17 00:00:00 2001
From: Lain Soykaf <lain@lain.com>
Date: Thu, 30 Jan 2025 12:32:16 +0400
Subject: [PATCH 212/212] Add changelog

---
 changelog.d/vips-blurhash.fix | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 changelog.d/vips-blurhash.fix

diff --git a/changelog.d/vips-blurhash.fix b/changelog.d/vips-blurhash.fix
new file mode 100644
index 000000000..9e8951b15
--- /dev/null
+++ b/changelog.d/vips-blurhash.fix
@@ -0,0 +1 @@
+Fix blurhash generation crashes