logo

pleroma

My custom branche(s) on git.pleroma.social/pleroma/pleroma git clone https://anongit.hacktivis.me/git/pleroma.git/
commit: 3e2573f1c4688a227dae2a8fa96141c0a65cffbc
parent d7b0115124d1968a817c944001455f691d9b09ff
Author: nicole mikołajczyk <git@mkljczk.pl>
Date:   Mon, 15 Dec 2025 16:52:45 +0100

Fix WebFinger for split-domain set ups

Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>

Diffstat:

Mlib/pleroma/web/web_finger.ex34++++++++++++++++++++++++++--------
Mtest/pleroma/web/web_finger_test.exs38+++++++++++++++++++++++++-------------
Mtest/support/http_request_mock.ex3++-
3 files changed, 53 insertions(+), 22 deletions(-)

diff --git a/lib/pleroma/web/web_finger.ex b/lib/pleroma/web/web_finger.ex @@ -194,8 +194,8 @@ defmodule Pleroma.Web.WebFinger do defp get_address_from_domain(_, _), do: {:error, :webfinger_no_domain} - @spec finger(String.t()) :: {:ok, map()} | {:error, any()} - def finger(account) do + @spec finger(String.t(), boolean()) :: {:ok, map()} | {:error, any()} + def finger(account, follow_redirects \\ true) do account = String.trim_leading(account, "@") domain = @@ -229,8 +229,15 @@ defmodule Pleroma.Web.WebFinger do {:error, {:content_type, nil}} end |> case do - {:ok, data} -> validate_webfinger(address, data) - error -> error + {:ok, data} -> + if follow_redirects do + validate_webfinger(address, data) + else + {:ok, data} + end + + error -> + error end else error -> @@ -241,10 +248,8 @@ defmodule Pleroma.Web.WebFinger do defp validate_webfinger(request_url, %{"subject" => "acct:" <> acct = subject} = data) do with [_name, acct_host] <- String.split(acct, "@"), - {_, url} <- {:address, get_address_from_domain(acct_host, subject)}, - %URI{host: request_host} <- URI.parse(request_url), - %URI{host: acct_host} <- URI.parse(url), - {_, true} <- {:hosts_match, acct_host == request_host} do + {_, resolved_url} <- {:address, get_address_from_domain(acct_host, subject)}, + {_, true} <- {:url_match, resolved_webfinger_matches?(request_url, resolved_url, data)} do {:ok, data} else _ -> {:error, {:webfinger_invalid, request_url, data}} @@ -252,4 +257,17 @@ defmodule Pleroma.Web.WebFinger do end defp validate_webfinger(url, data), do: {:error, {:webfinger_invalid, url, data}} + + defp resolved_webfinger_matches?(request_url, resolved_url, _data) + when request_url == resolved_url do + true + end + + defp resolved_webfinger_matches?(_request_url, _resolved_url, %{"subject" => "acct:" <> acct}) do + with {:ok, %{"subject" => "acct:" <> new_acct}} <- finger(acct, false) do + acct == new_acct + else + _ -> false + end + end end diff --git a/test/pleroma/web/web_finger_test.exs b/test/pleroma/web/web_finger_test.exs @@ -93,7 +93,7 @@ defmodule Pleroma.Web.WebFingerTest do {:ok, _data} = WebFinger.finger(user) end - test "it work for AP-only user" do + test "it works for AP-only user" do user = "kpherox@mstdn.jp" {:ok, data} = WebFinger.finger(user) @@ -224,24 +224,36 @@ defmodule Pleroma.Web.WebFingerTest do status: 200, body: File.read!("test/fixtures/tesla_mock/gleasonator.com_host_meta") }} + + %{url: "https://whitehouse.gov/.well-known/webfinger?resource=acct:trump@whitehouse.gov"} -> + {:ok, %Tesla.Env{status: 404}} end) {:error, _data} = WebFinger.finger("alex@gleasonator.com") end - end - test "prevents forgeries" do - Tesla.Mock.mock(fn - %{url: "https://fba.ryona.agency/.well-known/webfinger?resource=acct:graf@fba.ryona.agency"} -> - fake_webfinger = - File.read!("test/fixtures/webfinger/graf-imposter-webfinger.json") |> Jason.decode!() - - Tesla.Mock.json(fake_webfinger) + test "prevents forgeries" do + Tesla.Mock.mock(fn + %{url: "https://fba.ryona.agency/.well-known/webfinger?resource=acct:graf@fba.ryona.agency"} -> + fake_webfinger = + File.read!("test/fixtures/webfinger/graf-imposter-webfinger.json") |> Jason.decode!() + + Tesla.Mock.json(fake_webfinger) + + %{url: url} + when url in [ + "https://poa.st/.well-known/webfinger?resource=acct:graf@poa.st", + "https://fba.ryona.agency/.well-known/host-meta" + ] -> + {:ok, %Tesla.Env{status: 404}} + end) - %{url: "https://fba.ryona.agency/.well-known/host-meta"} -> - {:ok, %Tesla.Env{status: 404}} - end) + assert {:error, _} = WebFinger.finger("graf@fba.ryona.agency") + end - assert {:error, _} = WebFinger.finger("graf@fba.ryona.agency") + test "works for correctly set up split-domain instances" do + {:ok, _data} = WebFinger.finger("a@mastodon.example") + {:ok, _data} = WebFinger.finger("a@sub.mastodon.example") + end end end diff --git a/test/support/http_request_mock.ex b/test/support/http_request_mock.ex @@ -1229,7 +1229,8 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{status: 404, body: ""}} end - def get("https://mstdn.jp/.well-known/webfinger?resource=acct:kpherox@mstdn.jp", _, _, _) do + def get("https://mstdn.jp/.well-known/webfinger?resource=acct:" <> acct, _, _, _) + when acct in ["kpherox@mstdn.jp", "kPherox@mstdn.jp"] do {:ok, %Tesla.Env{ status: 200,