From ee37b2d8c64b8fee5f6f1634ad817da64e631b98 Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Tue, 17 Jun 2025 21:12:20 +0300 Subject: [PATCH 01/22] Return 404 when an activity is sent to a deactivated user's /inbox Also return 404 when the user who sent the activity is believed to be deactivated. It was already an error, now it just returns a better reason than "Invalid request". Also send proper errors when either user is not known at all. --- changelog.d/deactivated-404-inbox.change | 1 + .../activity_pub/activity_pub_controller.ex | 28 ++++++++- .../activity_pub_controller_test.exs | 61 +++++++++++++------ 3 files changed, 71 insertions(+), 19 deletions(-) create mode 100644 changelog.d/deactivated-404-inbox.change diff --git a/changelog.d/deactivated-404-inbox.change b/changelog.d/deactivated-404-inbox.change new file mode 100644 index 000000000..3912c53ef --- /dev/null +++ b/changelog.d/deactivated-404-inbox.change @@ -0,0 +1 @@ +Return 404 with a better error message instead of 400 when receiving an activity for a deactivated user \ No newline at end of file diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex index 7ac0bbab4..71e0a24de 100644 --- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex +++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex @@ -274,13 +274,37 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do end def inbox(%{assigns: %{valid_signature: true}} = conn, %{"nickname" => nickname} = params) do - with %User{is_active: true} = recipient <- User.get_cached_by_nickname(nickname), - {:ok, %User{is_active: true} = actor} <- User.get_or_fetch_by_ap_id(params["actor"]), + with {:recipient_exists, %User{} = recipient} <- + {:recipient_exists, User.get_cached_by_nickname(nickname)}, + {:sender_exists, {:ok, %User{} = actor}} <- + {:sender_exists, User.get_or_fetch_by_ap_id(params["actor"])}, + {:recipient_active, true} <- {:recipient_active, recipient.is_active}, + {:sender_active, true} <- {:sender_active, actor.is_active}, true <- Utils.recipient_in_message(recipient, actor, params), params <- Utils.maybe_splice_recipient(recipient.ap_id, params) do Federator.incoming_ap_doc(params) json(conn, "ok") else + {:recipient_exists, _} -> + conn + |> put_status(:not_found) + |> json("User does not exist") + + {:sender_exists, _} -> + conn + |> put_status(:not_found) + |> json("Sender does not exist") + + {:recipient_active, _} -> + conn + |> put_status(:not_found) + |> json("User deactivated") + + {:sender_active, _} -> + conn + |> put_status(:not_found) + |> json("Sender deactivated") + _ -> conn |> put_status(:bad_request) 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 46b3d5f0d..ded5d9d99 100644 --- a/test/pleroma/web/activity_pub/activity_pub_controller_test.exs +++ b/test/pleroma/web/activity_pub/activity_pub_controller_test.exs @@ -941,23 +941,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do assert Activity.get_by_ap_id(data["id"]) end - test "it rejects an invalid incoming activity", %{conn: conn, data: data} do - user = insert(:user, is_active: false) - - data = - data - |> Map.put("bcc", [user.ap_id]) - |> Kernel.put_in(["object", "bcc"], [user.ap_id]) - - conn = - conn - |> assign(:valid_signature, true) - |> put_req_header("content-type", "application/activity+json") - |> post("/users/#{user.nickname}/inbox", data) - - assert "Invalid request." == json_response(conn, 400) - end - test "it accepts messages with to as string instead of array", %{conn: conn, data: data} do user = insert(:user) @@ -1341,6 +1324,50 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do ObanHelpers.perform(all_enqueued(worker: ReceiverWorker)) assert Activity.get_by_ap_id(data["id"]) end + + test "it returns an error when receiving an activity sent to a deactivated user", %{ + conn: conn, + data: data + } do + user = insert(:user) + {:ok, _} = User.set_activation(user, false) + + data = + data + |> Map.put("bcc", [user.ap_id]) + |> Kernel.put_in(["object", "bcc"], [user.ap_id]) + + conn = + conn + |> assign(:valid_signature, true) + |> put_req_header("content-type", "application/activity+json") + |> post("/users/#{user.nickname}/inbox", data) + + assert "User deactivated" == json_response(conn, 404) + end + + test "it returns an error when receiving an activity sent from a deactivated user", %{ + conn: conn, + data: data + } do + sender = insert(:user) + user = insert(:user) + {:ok, _} = User.set_activation(sender, false) + + data = + data + |> Map.put("bcc", [user.ap_id]) + |> Map.put("actor", sender.ap_id) + |> Kernel.put_in(["object", "bcc"], [user.ap_id]) + + conn = + conn + |> assign(:valid_signature, true) + |> put_req_header("content-type", "application/activity+json") + |> post("/users/#{user.nickname}/inbox", data) + + assert "Sender deactivated" == json_response(conn, 404) + end end describe "GET /users/:nickname/outbox" do From 9eb3fc2d3b66bb7865f6c3699a39ca34ee327cf0 Mon Sep 17 00:00:00 2001 From: Phantasm Date: Mon, 30 Jun 2025 23:25:56 +0200 Subject: [PATCH 02/22] Docs: Avoid long DB restore times and update few things Mostly to avoid long restore times thanks to an index not being built before it's needed by restoring the DB schema first. https://blog.freespeechextremist.com/blog/activities-visibility-index-slowness.html Also updates backup command to compress DB backups, removes Pleroma users's home directory, replaces "role" with "user" in PostgreSQL contexts since they are the same now. --- changelog.d/db-restore-docs.change | 1 + docs/administration/backup.md | 64 +++++++++++++++++++++++------- 2 files changed, 51 insertions(+), 14 deletions(-) create mode 100644 changelog.d/db-restore-docs.change diff --git a/changelog.d/db-restore-docs.change b/changelog.d/db-restore-docs.change new file mode 100644 index 000000000..21e0f8e97 --- /dev/null +++ b/changelog.d/db-restore-docs.change @@ -0,0 +1 @@ +Docs: Restore DB schema before data to avoid long restore times diff --git a/docs/administration/backup.md b/docs/administration/backup.md index 93325e702..794e82b19 100644 --- a/docs/administration/backup.md +++ b/docs/administration/backup.md @@ -4,7 +4,10 @@ 1. Stop the Pleroma service. 2. Go to the working directory of Pleroma (default is `/opt/pleroma`) -3. Run `sudo -Hu postgres pg_dump -d --format=custom -f ` (make sure the postgres user has write access to the destination file) +3. Run (make sure the postgres user has write access to the destination file): +``` +# sudo -Hu postgres pg_dump -d -v --format=custom --compress=9 -f +``` 4. Copy `pleroma.pgdump`, `config/prod.secret.exs`, `config/setup_db.psql` (if still available) and the `uploads` folder to your backup destination. If you have other modifications, copy those changes too. 5. Restart the Pleroma service. @@ -14,16 +17,33 @@ 2. Stop the Pleroma service. 3. Go to the working directory of Pleroma (default is `/opt/pleroma`) 4. Copy the above mentioned files back to their original position. -5. Drop the existing database and user if restoring in-place. `sudo -Hu postgres psql -c 'DROP DATABASE ;';` `sudo -Hu postgres psql -c 'DROP USER ;'` -6. Restore the database schema and pleroma postgres role the with the original `setup_db.psql` if you have it: `sudo -Hu postgres psql -f config/setup_db.psql`. +5. Drop the existing database and user if restoring in-place. +``` +# sudo -Hu postgres dropdb +# sudo -Hu postgres dropuser +``` +6. Restore the database schema and pleroma database user the with the original `setup_db.psql` if you have it: +``` +# sudo -Hu postgres psql -f config/setup_db.psql +``` - Alternatively, run the `mix pleroma.instance gen` task again. You can ignore most of the questions, but make the database user, name, and password the same as found in your backup of `config/prod.secret.exs`. Then run the restoration of the pleroma role and schema with of the generated `config/setup_db.psql` as instructed above. You may delete the `config/generated_config.exs` file as it is not needed. + Alternatively, run the `mix pleroma.instance gen` task again. You can ignore most of the questions, but make the database user, name, and password the same as found in your backup of `config/prod.secret.exs`. Then run the restoration of the pleroma user and schema with the generated `config/setup_db.psql` as instructed above. You may delete the `config/generated_config.exs` file as it is not needed. -7. Now restore the Pleroma instance's data into the empty database schema: `sudo -Hu postgres pg_restore -d -v -1 ` -8. If you installed a newer Pleroma version, you should run `mix ecto.migrate`[^1]. This task performs database migrations, if there were any. -9. Restart the Pleroma service. -10. Run `sudo -Hu postgres vacuumdb --all --analyze-in-stages`. This will quickly generate the statistics so that postgres can properly plan queries. -11. If setting up on a new server configure Nginx by using the `installation/pleroma.nginx` config sample or reference the Pleroma installation guide for your OS which contains the Nginx configuration instructions. +7. Now restore the Pleroma instance's schema into the empty database schema: +``` +# sudo -Hu postgres pg_restore -d -v -s -1 +``` +8. Now restore the Pleroma instance's data into the database: +``` +# sudo -Hu postgres pg_restore -d -v -a -1 --disable-triggers +``` +9. If you installed a newer Pleroma version, you should run `mix ecto.migrate`[^1]. This task performs database migrations, if there were any. +10. Generate the statistics so that PostgreSQL can properly plan queries. +``` +# sudo -Hu postgres vacuumdb -v --all --analyze-in-stages +``` +11. Restart the Pleroma service. +12. If setting up on a new server, configure Nginx by using your original configuration or by using the `installation/pleroma.nginx` config sample or reference the Pleroma installation guide for your OS which contains the Nginx configuration instructions. [^1]: Prefix with `MIX_ENV=prod` to run it using the production config file. @@ -32,10 +52,26 @@ 1. Optionally you can remove the users of your instance. This will trigger delete requests for their accounts and posts. Note that this is 'best effort' and doesn't mean that all traces of your instance will be gone from the fediverse. * You can do this from the admin-FE where you can select all local users and delete the accounts using the *Moderate multiple users* dropdown. * You can also list local users and delete them individually using the CLI tasks for [Managing users](./CLI_tasks/user.md). -2. Stop the Pleroma service `systemctl stop pleroma` -3. Disable pleroma from systemd `systemctl disable pleroma` +2. Stop the Pleroma service: +``` +# systemctl stop pleroma +``` +3. Disable pleroma from systemd: +``` +# systemctl disable pleroma +``` 4. Remove the files and folders you created during installation (see installation guide). This includes the pleroma, nginx and systemd files and folders. -5. Reload nginx now that the configuration is removed `systemctl reload nginx` -6. Remove the database and database user `sudo -Hu postgres psql -c 'DROP DATABASE ;';` `sudo -Hu postgres psql -c 'DROP USER ;'` -7. Remove the system user `userdel pleroma` +5. Reload nginx now that the configuration is removed: +``` +# systemctl reload nginx +``` +6. Remove the database and database user: +``` +# sudo -Hu postgres dropdb +# sudo -Hu postgres dropuser +``` +7. Remove the system user: +``` +# userdel -r pleroma +``` 8. Remove the dependencies that you don't need anymore (see installation guide). Make sure you don't remove packages that are still needed for other software that you have running! From d736d313082c5939e3421921ee51ded2ec5aebce Mon Sep 17 00:00:00 2001 From: Phantasm Date: Tue, 15 Jul 2025 16:08:58 +0200 Subject: [PATCH 03/22] Docs: Add systemctl commands to DB backup/restore --- docs/administration/backup.md | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/docs/administration/backup.md b/docs/administration/backup.md index 794e82b19..326f095ec 100644 --- a/docs/administration/backup.md +++ b/docs/administration/backup.md @@ -2,22 +2,31 @@ ## Backup -1. Stop the Pleroma service. -2. Go to the working directory of Pleroma (default is `/opt/pleroma`) +1. Stop the Pleroma service: +``` +# sudo systemctl stop pleroma +``` +2. Go to the working directory of Pleroma (default is `/opt/pleroma`). 3. Run (make sure the postgres user has write access to the destination file): ``` # sudo -Hu postgres pg_dump -d -v --format=custom --compress=9 -f ``` 4. Copy `pleroma.pgdump`, `config/prod.secret.exs`, `config/setup_db.psql` (if still available) and the `uploads` folder to your backup destination. If you have other modifications, copy those changes too. -5. Restart the Pleroma service. +5. Restart the Pleroma service: +``` +# sudo systemctl start pleroma +``` ## Restore/Move 1. Optionally reinstall Pleroma (either on the same server or on another server if you want to move servers). -2. Stop the Pleroma service. -3. Go to the working directory of Pleroma (default is `/opt/pleroma`) +2. Stop the Pleroma service: +``` +# sudo systemctl stop pleroma +``` +3. Go to the working directory of Pleroma (default is `/opt/pleroma`). 4. Copy the above mentioned files back to their original position. -5. Drop the existing database and user if restoring in-place. +5. Drop the existing database and user if restoring in-place: ``` # sudo -Hu postgres dropdb # sudo -Hu postgres dropuser @@ -38,11 +47,14 @@ # sudo -Hu postgres pg_restore -d -v -a -1 --disable-triggers ``` 9. If you installed a newer Pleroma version, you should run `mix ecto.migrate`[^1]. This task performs database migrations, if there were any. -10. Generate the statistics so that PostgreSQL can properly plan queries. +10. Generate the statistics so that PostgreSQL can properly plan queries: ``` # sudo -Hu postgres vacuumdb -v --all --analyze-in-stages ``` -11. Restart the Pleroma service. +11. Restart the Pleroma service: +``` +# sudo systemctl start pleroma +``` 12. If setting up on a new server, configure Nginx by using your original configuration or by using the `installation/pleroma.nginx` config sample or reference the Pleroma installation guide for your OS which contains the Nginx configuration instructions. [^1]: Prefix with `MIX_ENV=prod` to run it using the production config file. @@ -74,4 +86,4 @@ ``` # userdel -r pleroma ``` -8. Remove the dependencies that you don't need anymore (see installation guide). Make sure you don't remove packages that are still needed for other software that you have running! +8. Remove the dependencies that you don't need anymore (see installation guide). **Make sure you don't remove packages that are still needed for other software that you have running!** From 1d8eafc0d2c38fdcac34af6b71291e9c8833a20b Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Wed, 30 Jul 2025 10:13:54 -0700 Subject: [PATCH 04/22] Add failing test case for URL encoding issue --- test/pleroma/http_test.exs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/pleroma/http_test.exs b/test/pleroma/http_test.exs index de359e599..058cb96c0 100644 --- a/test/pleroma/http_test.exs +++ b/test/pleroma/http_test.exs @@ -25,6 +25,9 @@ defmodule Pleroma.HTTPTest do %{method: :post, url: "http://example.com/world"} -> %Tesla.Env{status: 200, body: "world"} + + %{method: :get, url: "https://tsundere.love/emoji/Pack%201/koronebless.png"} -> + %Tesla.Env{status: 200, body: "emoji data"} end) :ok @@ -67,4 +70,18 @@ defmodule Pleroma.HTTPTest do } end end + + test "URL encoding properly encodes URLs with spaces" do + url_with_space = "https://tsundere.love/emoji/Pack 1/koronebless.png" + + result = HTTP.get(url_with_space) + + assert result == {:ok, %Tesla.Env{status: 200, body: "emoji data"}} + + properly_encoded_url = "https://tsundere.love/emoji/Pack%201/koronebless.png" + + result = HTTP.get(properly_encoded_url) + + assert result == {:ok, %Tesla.Env{status: 200, body: "emoji data"}} + end end From 11d27349e32d23649dd4e5ba6a3597f62199e6e5 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Wed, 30 Jul 2025 11:05:49 -0700 Subject: [PATCH 05/22] Fix HTTP client making invalid requests due to no percent encoding processing or validation. --- changelog.d/url-encoding.fix | 1 + lib/pleroma/http.ex | 10 ++-- lib/pleroma/tesla/middleware/encode_url.ex | 53 ++++++++++++++++++++++ 3 files changed, 61 insertions(+), 3 deletions(-) create mode 100644 changelog.d/url-encoding.fix create mode 100644 lib/pleroma/tesla/middleware/encode_url.ex diff --git a/changelog.d/url-encoding.fix b/changelog.d/url-encoding.fix new file mode 100644 index 000000000..3cca87ded --- /dev/null +++ b/changelog.d/url-encoding.fix @@ -0,0 +1 @@ +Fix HTTP client making invalid requests due to no percent encoding processing or validation. diff --git a/lib/pleroma/http.ex b/lib/pleroma/http.ex index c11317850..1833f5f85 100644 --- a/lib/pleroma/http.ex +++ b/lib/pleroma/http.ex @@ -105,20 +105,24 @@ defmodule Pleroma.HTTP do end defp adapter_middlewares(Tesla.Adapter.Gun, extra_middleware) do - [Tesla.Middleware.FollowRedirects, Pleroma.Tesla.Middleware.ConnectionPool] ++ + default_middleware() ++ + [Pleroma.Tesla.Middleware.ConnectionPool] ++ extra_middleware end defp adapter_middlewares({Tesla.Adapter.Finch, _}, extra_middleware) do - [Tesla.Middleware.FollowRedirects] ++ extra_middleware + default_middleware() ++ extra_middleware end defp adapter_middlewares(_, extra_middleware) do if Pleroma.Config.get(:env) == :test do # Emulate redirects in test env, which are handled by adapters in other environments - [Tesla.Middleware.FollowRedirects] + default_middleware() else extra_middleware end end + + defp default_middleware(), + do: [Tesla.Middleware.FollowRedirects, Pleroma.Tesla.Middleware.EncodeUrl] end diff --git a/lib/pleroma/tesla/middleware/encode_url.ex b/lib/pleroma/tesla/middleware/encode_url.ex new file mode 100644 index 000000000..df10e13c2 --- /dev/null +++ b/lib/pleroma/tesla/middleware/encode_url.ex @@ -0,0 +1,53 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2025 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Tesla.Middleware.EncodeUrl do + @moduledoc """ + Middleware to encode URLs properly + + We must decode and then re-encode to ensure correct encoding. + If we only encode it will re-encode each % as %25 causing a space + already encoded as %20 to be %2520. + + Similar problem for query parameters which need spaces to be the + character + """ + + @behaviour Tesla.Middleware + + @impl Tesla.Middleware + def call(%Tesla.Env{url: url} = env, next, _) do + url = + URI.parse(url) + |> then(fn parsed -> + path = encode_path(parsed.path) + query = encode_query(parsed.query) + + %{parsed | path: path, query: query} + end) + |> URI.to_string() + + env = %{env | url: url} + + case Tesla.run(env, next) do + {:ok, env} -> {:ok, env} + err -> err + end + end + + defp encode_path(nil), do: nil + + defp encode_path(path) when is_binary(path) do + path + |> URI.decode() + |> URI.encode() + end + + defp encode_query(nil), do: nil + + defp encode_query(query) when is_binary(query) do + query + |> URI.decode_query() + |> URI.encode_query() + end +end From 4217ababfc0f75559d48e58cc9d966aae5059476 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Wed, 30 Jul 2025 13:17:50 -0700 Subject: [PATCH 06/22] Improve design so existing tests do not break --- lib/pleroma/http.ex | 19 ++++++++++++++----- lib/pleroma/tesla/middleware/encode_url.ex | 21 ++++++++++++--------- test/pleroma/http_test.exs | 2 ++ 3 files changed, 28 insertions(+), 14 deletions(-) diff --git a/lib/pleroma/http.ex b/lib/pleroma/http.ex index 1833f5f85..75570d281 100644 --- a/lib/pleroma/http.ex +++ b/lib/pleroma/http.ex @@ -115,11 +115,20 @@ defmodule Pleroma.HTTP do end defp adapter_middlewares(_, extra_middleware) do - if Pleroma.Config.get(:env) == :test do - # Emulate redirects in test env, which are handled by adapters in other environments - default_middleware() - else - extra_middleware + # A lot of tests are written expecting unencoded URLs + # and the burden of fixing that is high. Also it makes + # them hard to read. Tests will opt-in when we want to validate + # the encoding is being done correctly. + cond do + Pleroma.Config.get(:env) == :test and Pleroma.Config.get(:test_url_encoding) -> + default_middleware() + + Pleroma.Config.get(:env) == :test -> + # Emulate redirects in test env, which are handled by adapters in other environments + [Tesla.Middleware.FollowRedirects] + + true -> + extra_middleware end end diff --git a/lib/pleroma/tesla/middleware/encode_url.ex b/lib/pleroma/tesla/middleware/encode_url.ex index df10e13c2..ee74c41a1 100644 --- a/lib/pleroma/tesla/middleware/encode_url.ex +++ b/lib/pleroma/tesla/middleware/encode_url.ex @@ -17,15 +17,7 @@ defmodule Pleroma.Tesla.Middleware.EncodeUrl do @impl Tesla.Middleware def call(%Tesla.Env{url: url} = env, next, _) do - url = - URI.parse(url) - |> then(fn parsed -> - path = encode_path(parsed.path) - query = encode_query(parsed.query) - - %{parsed | path: path, query: query} - end) - |> URI.to_string() + url = encode_url(url) env = %{env | url: url} @@ -35,6 +27,17 @@ defmodule Pleroma.Tesla.Middleware.EncodeUrl do end end + defp encode_url(url) when is_binary(url) do + URI.parse(url) + |> then(fn parsed -> + path = encode_path(parsed.path) + query = encode_query(parsed.query) + + %{parsed | path: path, query: query} + end) + |> URI.to_string() + end + defp encode_path(nil), do: nil defp encode_path(path) when is_binary(path) do diff --git a/test/pleroma/http_test.exs b/test/pleroma/http_test.exs index 058cb96c0..803bd451a 100644 --- a/test/pleroma/http_test.exs +++ b/test/pleroma/http_test.exs @@ -72,6 +72,8 @@ defmodule Pleroma.HTTPTest do end test "URL encoding properly encodes URLs with spaces" do + clear_config(:test_url_encoding, true) + url_with_space = "https://tsundere.love/emoji/Pack 1/koronebless.png" result = HTTP.get(url_with_space) From 404e09126076dcbd895fb2d17f872c553cc31249 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Wed, 30 Jul 2025 13:48:16 -0700 Subject: [PATCH 07/22] Credo --- lib/pleroma/http.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/http.ex b/lib/pleroma/http.ex index 75570d281..f0e01d589 100644 --- a/lib/pleroma/http.ex +++ b/lib/pleroma/http.ex @@ -132,6 +132,6 @@ defmodule Pleroma.HTTP do end end - defp default_middleware(), + defp default_middleware, do: [Tesla.Middleware.FollowRedirects, Pleroma.Tesla.Middleware.EncodeUrl] end From c49dece0ddf7f6704afde2e1fc969537e423a455 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Wed, 30 Jul 2025 15:13:43 -0700 Subject: [PATCH 08/22] Update test to also cover query encoding --- test/pleroma/http_test.exs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/pleroma/http_test.exs b/test/pleroma/http_test.exs index 803bd451a..6325ea3c5 100644 --- a/test/pleroma/http_test.exs +++ b/test/pleroma/http_test.exs @@ -26,7 +26,7 @@ defmodule Pleroma.HTTPTest do %{method: :post, url: "http://example.com/world"} -> %Tesla.Env{status: 200, body: "world"} - %{method: :get, url: "https://tsundere.love/emoji/Pack%201/koronebless.png"} -> + %{method: :get, url: "https://tsundere.love/emoji/Pack%201/koronebless.png?foo=bar+baz"} -> %Tesla.Env{status: 200, body: "emoji data"} end) @@ -74,13 +74,13 @@ defmodule Pleroma.HTTPTest do test "URL encoding properly encodes URLs with spaces" do clear_config(:test_url_encoding, true) - url_with_space = "https://tsundere.love/emoji/Pack 1/koronebless.png" + url_with_space = "https://tsundere.love/emoji/Pack 1/koronebless.png?foo=bar baz" result = HTTP.get(url_with_space) assert result == {:ok, %Tesla.Env{status: 200, body: "emoji data"}} - properly_encoded_url = "https://tsundere.love/emoji/Pack%201/koronebless.png" + properly_encoded_url = "https://tsundere.love/emoji/Pack%201/koronebless.png?foo=bar+baz" result = HTTP.get(properly_encoded_url) From 842090945aa5700faa222e47985cad542d375314 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Wed, 30 Jul 2025 15:42:49 -0700 Subject: [PATCH 09/22] Ensure Hackney and Finch both get the default middleware --- lib/pleroma/http.ex | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/pleroma/http.ex b/lib/pleroma/http.ex index f0e01d589..bdeb2171e 100644 --- a/lib/pleroma/http.ex +++ b/lib/pleroma/http.ex @@ -110,10 +110,6 @@ defmodule Pleroma.HTTP do extra_middleware end - defp adapter_middlewares({Tesla.Adapter.Finch, _}, extra_middleware) do - default_middleware() ++ extra_middleware - end - defp adapter_middlewares(_, extra_middleware) do # A lot of tests are written expecting unencoded URLs # and the burden of fixing that is high. Also it makes @@ -127,8 +123,9 @@ defmodule Pleroma.HTTP do # Emulate redirects in test env, which are handled by adapters in other environments [Tesla.Middleware.FollowRedirects] + # Hackney and Finch true -> - extra_middleware + default_middleware() ++ extra_middleware end end From 49ba6c88655669fe83b8c58d4070bd7ca5f215f1 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Wed, 30 Jul 2025 17:07:22 -0700 Subject: [PATCH 10/22] Rework the URL encoding so it is a public function: Pleroma.HTTP.encode_url/1 --- lib/pleroma/http.ex | 27 ++++++++++++++++++++ lib/pleroma/tesla/middleware/encode_url.ex | 29 +--------------------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/lib/pleroma/http.ex b/lib/pleroma/http.ex index bdeb2171e..9a0868d33 100644 --- a/lib/pleroma/http.ex +++ b/lib/pleroma/http.ex @@ -131,4 +131,31 @@ defmodule Pleroma.HTTP do defp default_middleware, do: [Tesla.Middleware.FollowRedirects, Pleroma.Tesla.Middleware.EncodeUrl] + + def encode_url(url) when is_binary(url) do + URI.parse(url) + |> then(fn parsed -> + path = encode_path(parsed.path) + query = encode_query(parsed.query) + + %{parsed | path: path, query: query} + end) + |> URI.to_string() + end + + defp encode_path(nil), do: nil + + defp encode_path(path) when is_binary(path) do + path + |> URI.decode() + |> URI.encode() + end + + defp encode_query(nil), do: nil + + defp encode_query(query) when is_binary(query) do + query + |> URI.decode_query() + |> URI.encode_query() + end end diff --git a/lib/pleroma/tesla/middleware/encode_url.ex b/lib/pleroma/tesla/middleware/encode_url.ex index ee74c41a1..32c559d3b 100644 --- a/lib/pleroma/tesla/middleware/encode_url.ex +++ b/lib/pleroma/tesla/middleware/encode_url.ex @@ -17,7 +17,7 @@ defmodule Pleroma.Tesla.Middleware.EncodeUrl do @impl Tesla.Middleware def call(%Tesla.Env{url: url} = env, next, _) do - url = encode_url(url) + url = Pleroma.HTTP.encode_url(url) env = %{env | url: url} @@ -26,31 +26,4 @@ defmodule Pleroma.Tesla.Middleware.EncodeUrl do err -> err end end - - defp encode_url(url) when is_binary(url) do - URI.parse(url) - |> then(fn parsed -> - path = encode_path(parsed.path) - query = encode_query(parsed.query) - - %{parsed | path: path, query: query} - end) - |> URI.to_string() - end - - defp encode_path(nil), do: nil - - defp encode_path(path) when is_binary(path) do - path - |> URI.decode() - |> URI.encode() - end - - defp encode_query(nil), do: nil - - defp encode_query(query) when is_binary(query) do - query - |> URI.decode_query() - |> URI.encode_query() - end end From ab4edf7933f245c9e955d4942471fb938a2f7c0e Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Wed, 30 Jul 2025 17:20:42 -0700 Subject: [PATCH 11/22] Add proper ReverseProxy test cases --- test/pleroma/reverse_proxy_test.exs | 36 +++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/test/pleroma/reverse_proxy_test.exs b/test/pleroma/reverse_proxy_test.exs index 85e1d0910..034ab28a5 100644 --- a/test/pleroma/reverse_proxy_test.exs +++ b/test/pleroma/reverse_proxy_test.exs @@ -395,4 +395,40 @@ defmodule Pleroma.ReverseProxyTest do assert Conn.get_resp_header(conn, "content-type") == ["application/octet-stream"] end end + + # Hackey is used for Reverse Proxy when Hackney or Finch is the Tesla Adapter + # Gun is able to proxy through Tesla, so it does not need testing as the + # test cases in the Pleroma.HTTPTest module are sufficient + describe "Hackney URL encoding:" do + setup do + ClientMock + |> expect(:request, fn :get, + "https://example.com/emoji/Pack%201/koronebless.png?foo=bar+baz", + _headers, + _body, + _opts -> + {:ok, 200, [{"content-type", "image/png"}], "It works!"} + end) + |> stub(:stream_body, fn _ -> :done end) + |> stub(:close, fn _ -> :ok end) + + :ok + end + + test "properly encodes URLs with spaces", %{conn: conn} do + url_with_space = "https://example.com/emoji/Pack 1/koronebless.png?foo=bar baz" + + result = ReverseProxy.call(conn, url_with_space) + + assert result.status == 200 + end + + test "properly encoded URL should not be altered", %{conn: conn} do + properly_encoded_url = "https://example.com/emoji/Pack%201/koronebless.png?foo=bar+baz" + + result = ReverseProxy.call(conn, properly_encoded_url) + + assert result.status == 200 + end + end end From 425329bacd59cbf15c017aaa4ab271c768076120 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Wed, 30 Jul 2025 17:32:08 -0700 Subject: [PATCH 12/22] Add fix to ensure URL is encoded when reverse proxying --- lib/pleroma/reverse_proxy.ex | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/lib/pleroma/reverse_proxy.ex b/lib/pleroma/reverse_proxy.ex index 3c82f9996..cd58f29e4 100644 --- a/lib/pleroma/reverse_proxy.ex +++ b/lib/pleroma/reverse_proxy.ex @@ -158,6 +158,8 @@ defmodule Pleroma.ReverseProxy do Logger.debug("#{__MODULE__} #{method} #{url} #{inspect(headers)}") method = method |> String.downcase() |> String.to_existing_atom() + url = maybe_encode_url(url) + case client().request(method, url, headers, "", opts) do {:ok, code, headers, client} when code in @valid_resp_codes -> {:ok, code, downcase_headers(headers), client} @@ -449,4 +451,18 @@ defmodule Pleroma.ReverseProxy do _ -> delete_resp_header(conn, "content-length") end end + + # Only when Tesla adapter is Hackney or Finch does the URL + # need encoding before Reverse Proxying as both end up + # using the raw Hackney client and cannot leverage our + # EncodeUrl Tesla middleware + # Also do it for test environment + defp maybe_encode_url(url) do + case Application.get_env(:tesla, :adapter) do + Tesla.Adapter.Hackney -> Pleroma.HTTP.encode_url(url) + {Tesla.Adapter.Finch, _} -> Pleroma.HTTP.encode_url(url) + Tesla.Mock -> Pleroma.HTTP.encode_url(url) + _ -> url + end + end end From 4e6f0af4ce66b17687092746d397c04afc56e281 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Wed, 30 Jul 2025 17:32:49 -0700 Subject: [PATCH 13/22] Better assertion logic --- test/pleroma/http_test.exs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/pleroma/http_test.exs b/test/pleroma/http_test.exs index 6325ea3c5..0e2551755 100644 --- a/test/pleroma/http_test.exs +++ b/test/pleroma/http_test.exs @@ -76,14 +76,14 @@ defmodule Pleroma.HTTPTest do url_with_space = "https://tsundere.love/emoji/Pack 1/koronebless.png?foo=bar baz" - result = HTTP.get(url_with_space) + {:ok, result} = HTTP.get(url_with_space) - assert result == {:ok, %Tesla.Env{status: 200, body: "emoji data"}} + assert result.status == 200 properly_encoded_url = "https://tsundere.love/emoji/Pack%201/koronebless.png?foo=bar+baz" - result = HTTP.get(properly_encoded_url) + {:ok, result} = HTTP.get(properly_encoded_url) - assert result == {:ok, %Tesla.Env{status: 200, body: "emoji data"}} + assert result.status == 200 end end From 44e56ed756e19a1de324afebc71103c0c6e7ed31 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Wed, 30 Jul 2025 18:26:56 -0700 Subject: [PATCH 14/22] Switch to example domain name --- test/pleroma/http_test.exs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/pleroma/http_test.exs b/test/pleroma/http_test.exs index 0e2551755..61347015d 100644 --- a/test/pleroma/http_test.exs +++ b/test/pleroma/http_test.exs @@ -26,7 +26,7 @@ defmodule Pleroma.HTTPTest do %{method: :post, url: "http://example.com/world"} -> %Tesla.Env{status: 200, body: "world"} - %{method: :get, url: "https://tsundere.love/emoji/Pack%201/koronebless.png?foo=bar+baz"} -> + %{method: :get, url: "https://example.com/emoji/Pack%201/koronebless.png?foo=bar+baz"} -> %Tesla.Env{status: 200, body: "emoji data"} end) @@ -74,13 +74,13 @@ defmodule Pleroma.HTTPTest do test "URL encoding properly encodes URLs with spaces" do clear_config(:test_url_encoding, true) - url_with_space = "https://tsundere.love/emoji/Pack 1/koronebless.png?foo=bar baz" + url_with_space = "https://example.com/emoji/Pack 1/koronebless.png?foo=bar baz" {:ok, result} = HTTP.get(url_with_space) assert result.status == 200 - properly_encoded_url = "https://tsundere.love/emoji/Pack%201/koronebless.png?foo=bar+baz" + properly_encoded_url = "https://example.com/emoji/Pack%201/koronebless.png?foo=bar+baz" {:ok, result} = HTTP.get(properly_encoded_url) From f66a877af7dcb12f7206f339fd350b265c27e1e9 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Fri, 1 Aug 2025 10:52:04 -0700 Subject: [PATCH 15/22] Disable automatic CI jobs for every pushed branch --- .gitlab-ci.yml | 3 ++- changelog.d/gitlabci.skip | 0 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 changelog.d/gitlabci.skip diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index bfd9bf414..bd36387c9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -14,9 +14,10 @@ variables: &global_variables workflow: rules: - if: $CI_PIPELINE_SOURCE == "merge_request_event" + - if: $CI_COMMIT_BRANCH == "develop" + - if: $CI_COMMIT_BRANCH == "stable" - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS when: never - - if: $CI_COMMIT_BRANCH cache: &global_cache_policy key: $CI_JOB_IMAGE-$CI_COMMIT_SHORT_SHA diff --git a/changelog.d/gitlabci.skip b/changelog.d/gitlabci.skip new file mode 100644 index 000000000..e69de29bb From 4b01c0f165d1f930291fa1d533dfda599e6e7aab Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Fri, 1 Aug 2025 11:41:36 -0700 Subject: [PATCH 16/22] Update Tesla to 1.15.3 --- changelog.d/tesla.change | 1 + mix.lock | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) create mode 100644 changelog.d/tesla.change diff --git a/changelog.d/tesla.change b/changelog.d/tesla.change new file mode 100644 index 000000000..bd0ec6e94 --- /dev/null +++ b/changelog.d/tesla.change @@ -0,0 +1 @@ +Updated Tesla to 1.15.3 diff --git a/mix.lock b/mix.lock index a708087c9..2f02ba6f1 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", "e7b7cc34cc16b383461b966484c297e4ec9aeef6", [ref: "e7b7cc34cc16b383461b966484c297e4ec9aeef6"]}, - "castore": {:hex, :castore, "1.0.8", "dedcf20ea746694647f883590b82d9e96014057aff1d44d03ec90f36a5c0dc6e", [:mix], [], "hexpm", "0b2b66d2ee742cb1d9cb8c8be3b43c3a70ee8651f37b75a8b982e036752983f1"}, + "castore": {:hex, :castore, "1.0.14", "4582dd7d630b48cf5e1ca8d3d42494db51e406b7ba704e81fbd401866366896a", [:mix], [], "hexpm", "7bc1b65249d31701393edaaac18ec8398d8974d52c647b7904d01b964137b9f4"}, "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"}, @@ -22,7 +22,7 @@ "covertool": {:hex, :covertool, "2.0.6", "4a291b4e3449025b0595d8f44c8d7635d4f48f033be2ce88d22a329f36f94a91", [:rebar3], [], "hexpm", "5db3fcd82180d8ea4ad857d4d1ab21a8d31b5aee0d60d2f6c0f9e25a411d1e21"}, "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"}, + "cowlib": {:hex, :cowlib, "2.15.0", "3c97a318a933962d1c12b96ab7c1d728267d2c523c25a5b57b0f93392b6e9e25", [:make, :rebar3], [], "hexpm", "4f00c879a64b4fe7c8fcb42a4281925e9ffdb928820b03c3ad325a617e857532"}, "credo": {:hex, :credo, "1.7.12", "9e3c20463de4b5f3f23721527fcaf16722ec815e70ff6c60b86412c695d426c1", [: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", "8493d45c656c5427d9c729235b99d498bd133421f3e0a683e5c1b561471291e5"}, "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"}, @@ -80,8 +80,8 @@ "meck": {:hex, :meck, "0.9.2", "85ccbab053f1db86c7ca240e9fc718170ee5bda03810a6292b5306bf31bae5f5", [:rebar3], [], "hexpm", "81344f561357dc40a8344afa53767c32669153355b626ea9fcbc8da6b3045826"}, "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, "mime": {:hex, :mime, "1.6.0", "dabde576a497cef4bbdd60aceee8160e02a6c89250d6c0b29e56c0dfb00db3d2", [:mix], [], "hexpm", "31a1a8613f8321143dde1dafc36006a17d28d02bdfecb9e95a880fa7aabd19a7"}, - "mimerl": {:hex, :mimerl, "1.3.0", "d0cd9fc04b9061f82490f6581e0128379830e78535e017f7780f37fea7545726", [:rebar3], [], "hexpm", "a1e15a50d1887217de95f0b9b0793e32853f7c258a5cd227650889b38839fe9d"}, - "mint": {:hex, :mint, "1.6.1", "065e8a5bc9bbd46a41099dfea3e0656436c5cbcb6e741c80bd2bad5cd872446f", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "4fc518dcc191d02f433393a72a7ba3f6f94b101d094cb6bf532ea54c89423780"}, + "mimerl": {:hex, :mimerl, "1.4.0", "3882a5ca67fbbe7117ba8947f27643557adec38fa2307490c4c4207624cb213b", [:rebar3], [], "hexpm", "13af15f9f68c65884ecca3a3891d50a7b57d82152792f3e19d88650aa126b144"}, + "mint": {:hex, :mint, "1.7.1", "113fdb2b2f3b59e47c7955971854641c61f378549d73e829e1768de90fc1abf1", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0 or ~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "fceba0a4d0f24301ddee3024ae116df1c3f4bb7a563a731f45fdfeb9d39a231b"}, "mochiweb": {:hex, :mochiweb, "2.18.0", "eb55f1db3e6e960fac4e6db4e2db9ec3602cc9f30b86cd1481d56545c3145d2e", [:rebar3], [], "hexpm"}, "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"}, @@ -139,14 +139,14 @@ "telemetry_metrics": {:hex, :telemetry_metrics, "0.6.2", "2caabe9344ec17eafe5403304771c3539f3b6e2f7fb6a6f602558c825d0d0bfb", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9b43db0dc33863930b9ef9d27137e78974756f5f198cae18409970ed6fa5b561"}, "telemetry_metrics_prometheus_core": {:hex, :telemetry_metrics_prometheus_core, "1.2.0", "b583c3f18508f5c5561b674d16cf5d9afd2ea3c04505b7d92baaeac93c1b8260", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "9cba950e1c4733468efbe3f821841f34ac05d28e7af7798622f88ecdbbe63ea3"}, "telemetry_poller": {:hex, :telemetry_poller, "1.0.0", "db91bb424e07f2bb6e73926fcafbfcbcb295f0193e0a00e825e589a0a47e8453", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b3a24eafd66c3f42da30fc3ca7dda1e9d546c12250a2d60d7b81d264fbec4f6e"}, - "tesla": {:hex, :tesla, "1.11.0", "81b2b10213dddb27105ec6102d9eb0cc93d7097a918a0b1594f2dfd1a4601190", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:finch, "~> 0.13", [hex: :finch, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, ">= 1.0.0", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.2", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:msgpax, "~> 2.3", [hex: :msgpax, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "b83ab5d4c2d202e1ea2b7e17a49f788d49a699513d7c4f08f2aef2c281be69db"}, + "tesla": {:hex, :tesla, "1.15.3", "3a2b5c37f09629b8dcf5d028fbafc9143c0099753559d7fe567eaabfbd9b8663", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:finch, "~> 0.13", [hex: :finch, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, ">= 1.0.0", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.21", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.2", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:mox, "~> 1.0", [hex: :mox, repo: "hexpm", optional: true]}, {:msgpax, "~> 2.3", [hex: :msgpax, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "98bb3d4558abc67b92fb7be4cd31bb57ca8d80792de26870d362974b58caeda7"}, "thousand_island": {:hex, :thousand_island, "1.3.5", "6022b6338f1635b3d32406ff98d68b843ba73b3aa95cfc27154223244f3a6ca5", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2be6954916fdfe4756af3239fb6b6d75d0b8063b5df03ba76fd8a4c87849e180"}, "timex": {:hex, :timex, "3.7.7", "3ed093cae596a410759104d878ad7b38e78b7c2151c6190340835515d4a46b8a", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "0ec4b09f25fe311321f9fc04144a7e3affe48eb29481d7a5583849b6c4dfa0a7"}, "toml": {:hex, :toml, "0.7.0", "fbcd773caa937d0c7a02c301a1feea25612720ac3fa1ccb8bfd9d30d822911de", [:mix], [], "hexpm", "0690246a2478c1defd100b0c9b89b4ea280a22be9a7b313a8a058a2408a2fa70"}, "trailing_format_plug": {:hex, :trailing_format_plug, "0.0.7", "64b877f912cf7273bed03379936df39894149e35137ac9509117e59866e10e45", [:mix], [{:plug, "> 0.12.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "bd4fde4c15f3e993a999e019d64347489b91b7a9096af68b2bdadd192afa693f"}, "tzdata": {:hex, :tzdata, "1.0.5", "69f1ee029a49afa04ad77801febaf69385f3d3e3d1e4b56b9469025677b89a28", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "55519aa2a99e5d2095c1e61cc74c9be69688f8ab75c27da724eb8279ff402a5a"}, "ueberauth": {:hex, :ueberauth, "0.10.7", "5a31cbe11e7ce5c7484d745dc9e1f11948e89662f8510d03c616de03df581ebd", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "0bccf73e2ffd6337971340832947ba232877aa8122dba4c95be9f729c8987377"}, - "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, + "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.1", "a48703a25c170eedadca83b11e88985af08d35f37c6f664d6dcfb106a97782fc", [:rebar3], [], "hexpm", "b3a917854ce3ae233619744ad1e0102e05673136776fb2fa76234f3e03b23642"}, "unsafe": {:hex, :unsafe, "1.0.2", "23c6be12f6c1605364801f4b47007c0c159497d0446ad378b5cf05f1855c0581", [:mix], [], "hexpm", "b485231683c3ab01a9cd44cb4a79f152c6f3bb87358439c6f68791b85c2df675"}, "vix": {:hex, :vix, "0.26.0", "027f10b6969b759318be84bd0bd8c88af877445e4e41cf96a0460392cea5399c", [:make, :mix], [{:castore, "~> 1.0 or ~> 0.1", [hex: :castore, repo: "hexpm", optional: false]}, {:cc_precompiler, "~> 0.2 or ~> 0.1.4", [hex: :cc_precompiler, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.8 or ~> 0.7.3", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:kino, "~> 0.7", [hex: :kino, repo: "hexpm", optional: true]}], "hexpm", "71b0a79ae7f199cacfc8e679b0e4ba25ee47dc02e182c5b9097efb29fbe14efd"}, "web_push_encryption": {:hex, :web_push_encryption, "0.3.1", "76d0e7375142dfee67391e7690e89f92578889cbcf2879377900b5620ee4708d", [:mix], [{:httpoison, "~> 1.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:jose, "~> 1.11.1", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "4f82b2e57622fb9337559058e8797cb0df7e7c9790793bdc4e40bc895f70e2a2"}, From 3c36bcfaa6d09436ba06699655934e4d01dba31b Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Fri, 1 Aug 2025 12:19:41 -0700 Subject: [PATCH 17/22] Remove deprecated "use Tesla" macro usage --- lib/pleroma/search/qdrant_search.ex | 55 +++++++++++++++++----- test/pleroma/search/qdrant_search_test.exs | 6 +-- 2 files changed, 45 insertions(+), 16 deletions(-) diff --git a/lib/pleroma/search/qdrant_search.ex b/lib/pleroma/search/qdrant_search.ex index b659bb682..5142a273f 100644 --- a/lib/pleroma/search/qdrant_search.ex +++ b/lib/pleroma/search/qdrant_search.ex @@ -157,26 +157,55 @@ defmodule Pleroma.Search.QdrantSearch do end defmodule Pleroma.Search.QdrantSearch.OpenAIClient do - use Tesla alias Pleroma.Config.Getting, as: Config - plug(Tesla.Middleware.BaseUrl, Config.get([Pleroma.Search.QdrantSearch, :openai_url])) - plug(Tesla.Middleware.JSON) + def post(path, body) do + Tesla.post(client(), path, body) + end - plug(Tesla.Middleware.Headers, [ - {"Authorization", - "Bearer #{Pleroma.Config.get([Pleroma.Search.QdrantSearch, :openai_api_key])}"} - ]) + defp client do + Tesla.client(middleware()) + end + + defp middleware do + [ + {Tesla.Middleware.BaseUrl, Config.get([Pleroma.Search.QdrantSearch, :openai_url])}, + Tesla.Middleware.JSON, + {Tesla.Middleware.Headers, + [ + {"Authorization", "Bearer #{Config.get([Pleroma.Search.QdrantSearch, :openai_api_key])}"} + ]} + ] + end end defmodule Pleroma.Search.QdrantSearch.QdrantClient do - use Tesla alias Pleroma.Config.Getting, as: Config - plug(Tesla.Middleware.BaseUrl, Config.get([Pleroma.Search.QdrantSearch, :qdrant_url])) - plug(Tesla.Middleware.JSON) + def delete(path) do + Tesla.delete(client(), path) + end - plug(Tesla.Middleware.Headers, [ - {"api-key", Pleroma.Config.get([Pleroma.Search.QdrantSearch, :qdrant_api_key])} - ]) + def post(path, body) do + Tesla.post(client(), path, body) + end + + def put(path, body) do + Tesla.put(client(), path, body) + end + + defp client do + Tesla.client(middleware()) + end + + defp middleware do + [ + {Tesla.Middleware.BaseUrl, Config.get([Pleroma.Search.QdrantSearch, :qdrant_url])}, + Tesla.Middleware.JSON, + {Tesla.Middleware.Headers, + [ + {"api-key", Pleroma.Config.get([Pleroma.Search.QdrantSearch, :qdrant_api_key])} + ]} + ] + end end diff --git a/test/pleroma/search/qdrant_search_test.exs b/test/pleroma/search/qdrant_search_test.exs index 47a77a391..daf8eeb69 100644 --- a/test/pleroma/search/qdrant_search_test.exs +++ b/test/pleroma/search/qdrant_search_test.exs @@ -51,7 +51,7 @@ defmodule Pleroma.Search.QdrantSearchTest do }) Config - |> expect(:get, 3, fn + |> expect(:get, 4, fn [Pleroma.Search, :module], nil -> QdrantSearch @@ -93,7 +93,7 @@ defmodule Pleroma.Search.QdrantSearchTest do }) Config - |> expect(:get, 3, fn + |> expect(:get, 4, fn [Pleroma.Search, :module], nil -> QdrantSearch @@ -158,7 +158,7 @@ defmodule Pleroma.Search.QdrantSearchTest do end) Config - |> expect(:get, 6, fn + |> expect(:get, 7, fn [Pleroma.Search, :module], nil -> QdrantSearch From 09eb7dbf8eb876b9847d7323fd2b93ee04c5be2a Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Fri, 1 Aug 2025 23:31:54 +0300 Subject: [PATCH 18/22] Change mailer example to use Mua --- changelog.d/smtp-docs.change | 1 + docs/configuration/cheatsheet.md | 8 +++----- 2 files changed, 4 insertions(+), 5 deletions(-) create mode 100644 changelog.d/smtp-docs.change diff --git a/changelog.d/smtp-docs.change b/changelog.d/smtp-docs.change new file mode 100644 index 000000000..fb9925e43 --- /dev/null +++ b/changelog.d/smtp-docs.change @@ -0,0 +1 @@ +Change SMTP example to use the Mua adapter that works with OTP>25 \ No newline at end of file diff --git a/docs/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md index 6e2fddcb6..07414f69a 100644 --- a/docs/configuration/cheatsheet.md +++ b/docs/configuration/cheatsheet.md @@ -733,13 +733,11 @@ An example for SMTP adapter: ```elixir config :pleroma, Pleroma.Emails.Mailer, enabled: true, - adapter: Swoosh.Adapters.SMTP, + adapter: Swoosh.Adapters.Mua, relay: "smtp.gmail.com", - username: "YOUR_USERNAME@gmail.com", - password: "YOUR_SMTP_PASSWORD", + auth: [username: "YOUR_USERNAME@gmail.com", password: "YOUR_SMTP_PASSWORD"], port: 465, - ssl: true, - auth: :always + protocol: :ssl ``` An example for Mua adapter: From 44898845a69814aad9d09e8af82df0679a8d5f7f Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Fri, 1 Aug 2025 12:52:29 -0700 Subject: [PATCH 19/22] Update Plug/Cowboy/Gun --- mix.exs | 6 +++--- mix.lock | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/mix.exs b/mix.exs index a79aaca8f..a8b08cf67 100644 --- a/mix.exs +++ b/mix.exs @@ -135,7 +135,7 @@ defmodule Pleroma.Mixfile do {:telemetry_metrics, "~> 0.6"}, {:telemetry_poller, "~> 1.0"}, {:tzdata, "~> 1.0.3"}, - {:plug_cowboy, "~> 2.5"}, + {:plug_cowboy, "~> 2.7"}, {:oban, "~> 2.19.0"}, {:gettext, "~> 0.20"}, {:bcrypt_elixir, "~> 2.2"}, @@ -146,8 +146,8 @@ defmodule Pleroma.Mixfile do {:cachex, "~> 3.2"}, {:tesla, "~> 1.11"}, {:castore, "~> 1.0"}, - {:cowlib, "~> 2.9", override: true}, - {:gun, "~> 2.0.0-rc.1", override: true}, + {:cowlib, "~> 2.15"}, + {:gun, "~> 2.2"}, {:finch, "~> 0.15"}, {:jason, "~> 1.2"}, {:mogrify, "~> 0.9.0", override: "true"}, diff --git a/mix.lock b/mix.lock index a708087c9..93f41bba8 100644 --- a/mix.lock +++ b/mix.lock @@ -20,9 +20,9 @@ "connection": {:hex, :connection, "1.1.0", "ff2a49c4b75b6fb3e674bfc5536451607270aac754ffd1bdfe175abe4a6d7a68", [:mix], [], "hexpm", "722c1eb0a418fbe91ba7bd59a47e28008a189d47e37e0e7bb85585a016b2869c"}, "cors_plug": {:hex, :cors_plug, "2.0.3", "316f806d10316e6d10f09473f19052d20ba0a0ce2a1d910ddf57d663dac402ae", [:mix], [{:plug, "~> 1.8", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "ee4ae1418e6ce117fc42c2ba3e6cbdca4e95ecd2fe59a05ec6884ca16d469aea"}, "covertool": {:hex, :covertool, "2.0.6", "4a291b4e3449025b0595d8f44c8d7635d4f48f033be2ce88d22a329f36f94a91", [:rebar3], [], "hexpm", "5db3fcd82180d8ea4ad857d4d1ab21a8d31b5aee0d60d2f6c0f9e25a411d1e21"}, - "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": {:hex, :cowboy, "2.13.0", "09d770dd5f6a22cc60c071f432cd7cb87776164527f205c5a6b0f24ff6b38990", [:make, :rebar3], [{:cowlib, ">= 2.14.0 and < 3.0.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, ">= 1.8.0 and < 3.0.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "e724d3a70995025d654c1992c7b11dbfea95205c047d86ff9bf1cda92ddc5614"}, "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"}, + "cowlib": {:hex, :cowlib, "2.15.0", "3c97a318a933962d1c12b96ab7c1d728267d2c523c25a5b57b0f93392b6e9e25", [:make, :rebar3], [], "hexpm", "4f00c879a64b4fe7c8fcb42a4281925e9ffdb928820b03c3ad325a617e857532"}, "credo": {:hex, :credo, "1.7.12", "9e3c20463de4b5f3f23721527fcaf16722ec815e70ff6c60b86412c695d426c1", [: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", "8493d45c656c5427d9c729235b99d498bd133421f3e0a683e5c1b561471291e5"}, "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"}, @@ -58,7 +58,7 @@ "floki": {:hex, :floki, "0.35.2", "87f8c75ed8654b9635b311774308b2760b47e9a579dabf2e4d5f1e1d42c39e0b", [:mix], [], "hexpm", "6b05289a8e9eac475f644f09c2e4ba7e19201fd002b89c28c1293e7bd16773d9"}, "gen_smtp": {:hex, :gen_smtp, "0.15.0", "9f51960c17769b26833b50df0b96123605a8024738b62db747fece14eb2fbfcc", [:rebar3], [], "hexpm", "29bd14a88030980849c7ed2447b8db6d6c9278a28b11a44cafe41b791205440f"}, "gettext": {:hex, :gettext, "0.24.0", "6f4d90ac5f3111673cbefc4ebee96fe5f37a114861ab8c7b7d5b30a1108ce6d8", [:mix], [{:expo, "~> 0.5.1", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "bdf75cdfcbe9e4622dd18e034b227d77dd17f0f133853a1c73b97b3d6c770e8b"}, - "gun": {:hex, :gun, "2.0.1", "160a9a5394800fcba41bc7e6d421295cf9a7894c2252c0678244948e3336ad73", [:make, :rebar3], [{:cowlib, "2.12.1", [hex: :cowlib, repo: "hexpm", optional: false]}], "hexpm", "a10bc8d6096b9502205022334f719cc9a08d9adcfbfc0dbee9ef31b56274a20b"}, + "gun": {:hex, :gun, "2.2.0", "b8f6b7d417e277d4c2b0dc3c07dfdf892447b087f1cc1caff9c0f556b884e33d", [:make, :rebar3], [{:cowlib, ">= 2.15.0 and < 3.0.0", [hex: :cowlib, repo: "hexpm", optional: false]}], "hexpm", "76022700c64287feb4df93a1795cff6741b83fb37415c40c34c38d2a4645261a"}, "hackney": {:hex, :hackney, "1.18.2", "d7ff544ddae5e1cb49e9cf7fa4e356d7f41b283989a1c304bfc47a8cc1cf966f", [:rebar3], [{:certifi, "~>2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "af94d5c9f97857db257090a4a10e5426ecb6f4918aa5cc666798566ae14b65fd"}, "hpax": {:hex, :hpax, "0.2.0", "5a58219adcb75977b2edce5eb22051de9362f08236220c9e859a47111c194ff5", [:mix], [], "hexpm", "bea06558cdae85bed075e6c036993d43cd54d447f76d8190a8db0dc5893fa2f1"}, "html_entities": {:hex, :html_entities, "0.5.2", "9e47e70598da7de2a9ff6af8758399251db6dbb7eebe2b013f2bbd2515895c3c", [:mix], [], "hexpm", "c53ba390403485615623b9531e97696f076ed415e8d8058b1dbaa28181f4fdcc"}, @@ -108,9 +108,9 @@ "phoenix_swoosh": {:hex, :phoenix_swoosh, "1.2.1", "b74ccaa8046fbc388a62134360ee7d9742d5a8ae74063f34eb050279de7a99e1", [:mix], [{:finch, "~> 0.8", [hex: :finch, repo: "hexpm", optional: true]}, {:hackney, "~> 1.10", [hex: :hackney, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6", [hex: :phoenix, repo: "hexpm", optional: true]}, {:phoenix_html, "~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_view, "~> 1.0 or ~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:swoosh, "~> 1.5", [hex: :swoosh, repo: "hexpm", optional: false]}], "hexpm", "4000eeba3f9d7d1a6bf56d2bd56733d5cadf41a7f0d8ffe5bb67e7d667e204a2"}, "phoenix_template": {:hex, :phoenix_template, "1.0.4", "e2092c132f3b5e5b2d49c96695342eb36d0ed514c5b252a77048d5969330d639", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "2c0c81f0e5c6753faf5cca2f229c9709919aba34fab866d3bc05060c9c444206"}, "phoenix_view": {:hex, :phoenix_view, "2.0.4", "b45c9d9cf15b3a1af5fb555c674b525391b6a1fe975f040fb4d913397b31abf4", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}], "hexpm", "4e992022ce14f31fe57335db27a28154afcc94e9983266835bb3040243eb620b"}, - "plug": {:hex, :plug, "1.16.1", "40c74619c12f82736d2214557dedec2e9762029b2438d6d175c5074c933edc9d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a13ff6b9006b03d7e33874945b2755253841b238c34071ed85b0e86057f8cddc"}, - "plug_cowboy": {:hex, :plug_cowboy, "2.7.1", "87677ffe3b765bc96a89be7960f81703223fe2e21efa42c125fcd0127dd9d6b2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "02dbd5f9ab571b864ae39418db7811618506256f6d13b4a45037e5fe78dc5de3"}, - "plug_crypto": {:hex, :plug_crypto, "2.1.0", "f44309c2b06d249c27c8d3f65cfe08158ade08418cf540fd4f72d4d6863abb7b", [:mix], [], "hexpm", "131216a4b030b8f8ce0f26038bc4421ae60e4bb95c5cf5395e1421437824c4fa"}, + "plug": {:hex, :plug, "1.18.1", "5067f26f7745b7e31bc3368bc1a2b818b9779faa959b49c934c17730efc911cf", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "57a57db70df2b422b564437d2d33cf8d33cd16339c1edb190cd11b1a3a546cc2"}, + "plug_cowboy": {:hex, :plug_cowboy, "2.7.4", "729c752d17cf364e2b8da5bdb34fb5804f56251e88bb602aff48ae0bd8673d11", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "9b85632bd7012615bae0a5d70084deb1b25d2bcbb32cab82d1e9a1e023168aa3"}, + "plug_crypto": {:hex, :plug_crypto, "2.1.1", "19bda8184399cb24afa10be734f84a16ea0a2bc65054e23a62bb10f06bc89491", [:mix], [], "hexpm", "6470bce6ffe41c8bd497612ffde1a7e4af67f36a15eea5f921af71cf3e11247c"}, "plug_static_index_html": {:hex, :plug_static_index_html, "1.0.0", "840123d4d3975585133485ea86af73cb2600afd7f2a976f9f5fd8b3808e636a0", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "79fd4fcf34d110605c26560cbae8f23c603ec4158c08298bd4360fdea90bb5cf"}, "poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm", "fec8660eb7733ee4117b85f55799fd3833eb769a6df71ccf8903e8dc5447cfce"}, "poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm", "dad79704ce5440f3d5a3681c8590b9dc25d1a561e8f5a9c995281012860901e3"}, @@ -124,7 +124,7 @@ "prometheus_phx": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/prometheus-phx.git", "9cd8f248c9381ffedc799905050abce194a97514", [branch: "no-logging"]}, "prometheus_plugs": {:hex, :prometheus_plugs, "1.1.5", "25933d48f8af3a5941dd7b621c889749894d8a1082a6ff7c67cc99dec26377c5", [:mix], [{:accept, "~> 0.1", [hex: :accept, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}, {:prometheus_process_collector, "~> 1.1", [hex: :prometheus_process_collector, repo: "hexpm", optional: true]}], "hexpm", "0273a6483ccb936d79ca19b0ab629aef0dba958697c94782bb728b920dfc6a79"}, "quantile_estimator": {:hex, :quantile_estimator, "0.2.1", "ef50a361f11b5f26b5f16d0696e46a9e4661756492c981f7b2229ef42ff1cd15", [:rebar3], [], "hexpm", "282a8a323ca2a845c9e6f787d166348f776c1d4a41ede63046d72d422e3da946"}, - "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, + "ranch": {:hex, :ranch, "2.2.0", "25528f82bc8d7c6152c57666ca99ec716510fe0925cb188172f41ce93117b1b0", [:make, :rebar3], [], "hexpm", "fa0b99a1780c80218a4197a59ea8d3bdae32fbff7e88527d7d8a4787eff4f8e7"}, "recon": {:hex, :recon, "2.5.4", "05dd52a119ee4059fa9daa1ab7ce81bc7a8161a2f12e9d42e9d551ffd2ba901c", [:mix, :rebar3], [], "hexpm", "e9ab01ac7fc8572e41eb59385efeb3fb0ff5bf02103816535bacaedf327d0263"}, "remote_ip": {:git, "https://git.pleroma.social/pleroma/remote_ip.git", "b647d0deecaa3acb140854fe4bda5b7e1dc6d1c8", [ref: "b647d0deecaa3acb140854fe4bda5b7e1dc6d1c8"]}, "rustler": {:hex, :rustler, "0.30.0", "cefc49922132b072853fa9b0ca4dc2ffcb452f68fb73b779042b02d545e097fb", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:toml, "~> 0.6", [hex: :toml, repo: "hexpm", optional: false]}], "hexpm", "9ef1abb6a7dda35c47cfc649e6a5a61663af6cf842a55814a554a84607dee389"}, From 7b8d6eca65c660ae3fb8e606649d927231cc1a53 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Fri, 1 Aug 2025 12:53:15 -0700 Subject: [PATCH 20/22] Remove deprecated "use Plug.Test" --- test/pleroma/web/plugs/cache_test.exs | 3 ++- test/pleroma/web/plugs/digest_plug_test.exs | 3 ++- test/pleroma/web/plugs/idempotency_plug_test.exs | 3 ++- test/pleroma/web/plugs/remote_ip_test.exs | 3 ++- test/pleroma/web/plugs/set_format_plug_test.exs | 3 ++- test/pleroma/web/plugs/set_locale_plug_test.exs | 2 +- 6 files changed, 11 insertions(+), 6 deletions(-) diff --git a/test/pleroma/web/plugs/cache_test.exs b/test/pleroma/web/plugs/cache_test.exs index 0c119528d..09065e94e 100644 --- a/test/pleroma/web/plugs/cache_test.exs +++ b/test/pleroma/web/plugs/cache_test.exs @@ -5,7 +5,8 @@ defmodule Pleroma.Web.Plugs.CacheTest do # Relies on Cachex, has to stay synchronous use Pleroma.DataCase - use Plug.Test + import Plug.Conn + import Plug.Test alias Pleroma.Web.Plugs.Cache diff --git a/test/pleroma/web/plugs/digest_plug_test.exs b/test/pleroma/web/plugs/digest_plug_test.exs index 19f8a6f49..21ccddd88 100644 --- a/test/pleroma/web/plugs/digest_plug_test.exs +++ b/test/pleroma/web/plugs/digest_plug_test.exs @@ -4,7 +4,8 @@ defmodule Pleroma.Web.Plugs.DigestPlugTest do use ExUnit.Case, async: true - use Plug.Test + import Plug.Conn + import Plug.Test test "digest algorithm is taken from digest header" do body = "{\"hello\": \"world\"}" diff --git a/test/pleroma/web/plugs/idempotency_plug_test.exs b/test/pleroma/web/plugs/idempotency_plug_test.exs index cc55d341f..3b0131596 100644 --- a/test/pleroma/web/plugs/idempotency_plug_test.exs +++ b/test/pleroma/web/plugs/idempotency_plug_test.exs @@ -5,7 +5,8 @@ defmodule Pleroma.Web.Plugs.IdempotencyPlugTest do # Relies on Cachex, has to stay synchronous use Pleroma.DataCase - use Plug.Test + import Plug.Conn + import Plug.Test alias Pleroma.Web.Plugs.IdempotencyPlug alias Plug.Conn diff --git a/test/pleroma/web/plugs/remote_ip_test.exs b/test/pleroma/web/plugs/remote_ip_test.exs index aea0940f4..37b751370 100644 --- a/test/pleroma/web/plugs/remote_ip_test.exs +++ b/test/pleroma/web/plugs/remote_ip_test.exs @@ -4,7 +4,8 @@ defmodule Pleroma.Web.Plugs.RemoteIpTest do use ExUnit.Case - use Plug.Test + import Plug.Conn + import Plug.Test alias Pleroma.Web.Plugs.RemoteIp diff --git a/test/pleroma/web/plugs/set_format_plug_test.exs b/test/pleroma/web/plugs/set_format_plug_test.exs index 4d64fdde6..08a2b02a2 100644 --- a/test/pleroma/web/plugs/set_format_plug_test.exs +++ b/test/pleroma/web/plugs/set_format_plug_test.exs @@ -4,7 +4,8 @@ defmodule Pleroma.Web.Plugs.SetFormatPlugTest do use ExUnit.Case, async: true - use Plug.Test + import Plug.Conn + import Plug.Test alias Pleroma.Web.Plugs.SetFormatPlug diff --git a/test/pleroma/web/plugs/set_locale_plug_test.exs b/test/pleroma/web/plugs/set_locale_plug_test.exs index 4f664f84e..a7691ea11 100644 --- a/test/pleroma/web/plugs/set_locale_plug_test.exs +++ b/test/pleroma/web/plugs/set_locale_plug_test.exs @@ -4,7 +4,7 @@ defmodule Pleroma.Web.Plugs.SetLocalePlugTest do use ExUnit.Case, async: true - use Plug.Test + import Plug.Test alias Pleroma.Web.Plugs.SetLocalePlug alias Plug.Conn From d67ab670b0707951f905076a823e3d2a4d31749a Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Fri, 1 Aug 2025 13:13:01 -0700 Subject: [PATCH 21/22] Fix Gopher server to use modern :ranch --- lib/pleroma/gopher/server.ex | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/lib/pleroma/gopher/server.ex b/lib/pleroma/gopher/server.ex index 54245c9fa..add3ba925 100644 --- a/lib/pleroma/gopher/server.ex +++ b/lib/pleroma/gopher/server.ex @@ -22,14 +22,18 @@ defmodule Pleroma.Gopher.Server do def init([ip, port]) do Logger.info("Starting gopher server on #{port}") - :ranch.start_listener( - :gopher, - 100, - :ranch_tcp, - [ip: ip, port: port], - __MODULE__.ProtocolHandler, - [] - ) + {:ok, _pid} = + :ranch.start_listener( + :gopher, + :ranch_tcp, + %{ + num_acceptors: 100, + max_connections: 100, + socket_opts: [ip: ip, port: port] + }, + __MODULE__.ProtocolHandler, + [] + ) {:ok, %{ip: ip, port: port}} end @@ -43,13 +47,13 @@ defmodule Pleroma.Gopher.Server.ProtocolHandler do alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.Visibility - def start_link(ref, socket, transport, opts) do - pid = spawn_link(__MODULE__, :init, [ref, socket, transport, opts]) + def start_link(ref, transport, opts) do + pid = spawn_link(__MODULE__, :init, [ref, transport, opts]) {:ok, pid} end - def init(ref, socket, transport, [] = _Opts) do - :ok = :ranch.accept_ack(ref) + def init(ref, transport, opts \\ []) do + {:ok, socket} = :ranch.handshake(ref, opts) loop(socket, transport) end From 9195cfb2bc5f3e5db0f2ff98bee0473ee00dbaca Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Fri, 1 Aug 2025 16:23:20 -0700 Subject: [PATCH 22/22] Document Gun, Cowboy, and Plug update --- changelog.d/gun.change | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/gun.change diff --git a/changelog.d/gun.change b/changelog.d/gun.change new file mode 100644 index 000000000..3d72b7701 --- /dev/null +++ b/changelog.d/gun.change @@ -0,0 +1 @@ +Update Cowboy, Gun, and Plug family of dependencies