commit: 977097e870000c72a8265cf7be475acd7f0e674f
parent cf6587d344d2832dec0768e90e7e8e0a4f292b6c
Author: feld <feld@feld.me>
Date: Thu, 3 Jul 2025 19:51:11 +0000
Merge branch 'webfinger-regex' into 'develop'
Enforce an exact domain match for WebFinger resolution
See merge request pleroma/pleroma!4380
Diffstat:
4 files changed, 145 insertions(+), 64 deletions(-)
diff --git a/changelog.d/webfinger-resolution.fix b/changelog.d/webfinger-resolution.fix
@@ -0,0 +1 @@
+Enforce an exact domain match for WebFinger resolution
diff --git a/lib/pleroma/web/web_finger.ex b/lib/pleroma/web/web_finger.ex
@@ -35,9 +35,9 @@ defmodule Pleroma.Web.WebFinger do
regex =
if webfinger_domain = Pleroma.Config.get([__MODULE__, :domain]) do
- ~r/(acct:)?(?<username>[a-z0-9A-Z_\.-]+)@(#{host}|#{webfinger_domain})/
+ ~r/(acct:)?(?<username>[a-z0-9A-Z_\.-]+)@(#{host}|#{webfinger_domain})$/
else
- ~r/(acct:)?(?<username>[a-z0-9A-Z_\.-]+)@#{host}/
+ ~r/(acct:)?(?<username>[a-z0-9A-Z_\.-]+)@#{host}$/
end
with %{"username" => username} <- Regex.named_captures(regex, resource),
diff --git a/test/pleroma/web/web_finger/web_finger_controller_test.exs b/test/pleroma/web/web_finger/web_finger_controller_test.exs
@@ -33,47 +33,122 @@ defmodule Pleroma.Web.WebFinger.WebFingerControllerTest do
assert match?(^response_xml, expected_xml)
end
- test "Webfinger JRD" do
- user =
- insert(:user,
- ap_id: "https://hyrule.world/users/zelda",
- also_known_as: ["https://mushroom.kingdom/users/toad"]
- )
-
- response =
- build_conn()
- |> put_req_header("accept", "application/jrd+json")
- |> get("/.well-known/webfinger?resource=acct:#{user.nickname}@localhost")
- |> json_response(200)
-
- assert response["subject"] == "acct:#{user.nickname}@localhost"
-
- assert response["aliases"] == [
- "https://hyrule.world/users/zelda",
- "https://mushroom.kingdom/users/toad"
- ]
+ describe "Webfinger" do
+ test "JRD" do
+ clear_config([Pleroma.Web.Endpoint, :url, :host], "hyrule.world")
+ clear_config([Pleroma.Web.WebFinger, :domain], "hyrule.world")
+
+ user =
+ insert(:user,
+ ap_id: "https://hyrule.world/users/zelda"
+ )
+
+ response =
+ build_conn()
+ |> put_req_header("accept", "application/jrd+json")
+ |> get("/.well-known/webfinger?resource=acct:#{user.nickname}@hyrule.world")
+ |> json_response(200)
+
+ assert response["subject"] == "acct:#{user.nickname}@hyrule.world"
+
+ assert response["aliases"] == [
+ "https://hyrule.world/users/zelda"
+ ]
+ end
+
+ test "XML" do
+ clear_config([Pleroma.Web.Endpoint, :url, :host], "hyrule.world")
+ clear_config([Pleroma.Web.WebFinger, :domain], "hyrule.world")
+
+ user =
+ insert(:user,
+ ap_id: "https://hyrule.world/users/zelda"
+ )
+
+ response =
+ build_conn()
+ |> put_req_header("accept", "application/xrd+xml")
+ |> get("/.well-known/webfinger?resource=acct:#{user.nickname}@localhost")
+ |> response(200)
+
+ assert response =~ "<Alias>https://hyrule.world/users/zelda</Alias>"
+ end
end
test "Webfinger defaults to JSON when no Accept header is provided" do
+ clear_config([Pleroma.Web.Endpoint, :url, :host], "hyrule.world")
+ clear_config([Pleroma.Web.WebFinger, :domain], "hyrule.world")
+
user =
insert(:user,
- ap_id: "https://hyrule.world/users/zelda",
- also_known_as: ["https://mushroom.kingdom/users/toad"]
+ ap_id: "https://hyrule.world/users/zelda"
)
response =
build_conn()
- |> get("/.well-known/webfinger?resource=acct:#{user.nickname}@localhost")
+ |> get("/.well-known/webfinger?resource=acct:#{user.nickname}@hyrule.world")
|> json_response(200)
- assert response["subject"] == "acct:#{user.nickname}@localhost"
+ assert response["subject"] == "acct:#{user.nickname}@hyrule.world"
assert response["aliases"] == [
- "https://hyrule.world/users/zelda",
- "https://mushroom.kingdom/users/toad"
+ "https://hyrule.world/users/zelda"
]
end
+ describe "Webfinger returns also_known_as / aliases in the response" do
+ test "JSON" do
+ clear_config([Pleroma.Web.Endpoint, :url, :host], "hyrule.world")
+ clear_config([Pleroma.Web.WebFinger, :domain], "hyrule.world")
+
+ user =
+ insert(:user,
+ ap_id: "https://hyrule.world/users/zelda",
+ also_known_as: [
+ "https://mushroom.kingdom/users/toad",
+ "https://luigi.mansion/users/kingboo"
+ ]
+ )
+
+ response =
+ build_conn()
+ |> get("/.well-known/webfinger?resource=acct:#{user.nickname}@hyrule.world")
+ |> json_response(200)
+
+ assert response["subject"] == "acct:#{user.nickname}@hyrule.world"
+
+ assert response["aliases"] == [
+ "https://hyrule.world/users/zelda",
+ "https://mushroom.kingdom/users/toad",
+ "https://luigi.mansion/users/kingboo"
+ ]
+ end
+
+ test "XML" do
+ clear_config([Pleroma.Web.Endpoint, :url, :host], "hyrule.world")
+ clear_config([Pleroma.Web.WebFinger, :domain], "hyrule.world")
+
+ user =
+ insert(:user,
+ ap_id: "https://hyrule.world/users/zelda",
+ also_known_as: [
+ "https://mushroom.kingdom/users/toad",
+ "https://luigi.mansion/users/kingboo"
+ ]
+ )
+
+ response =
+ build_conn()
+ |> put_req_header("accept", "application/xrd+xml")
+ |> get("/.well-known/webfinger?resource=acct:#{user.nickname}@localhost")
+ |> response(200)
+
+ assert response =~ "<Alias>https://hyrule.world/users/zelda</Alias>"
+ assert response =~ "<Alias>https://mushroom.kingdom/users/toad</Alias>"
+ assert response =~ "<Alias>https://luigi.mansion/users/kingboo</Alias>"
+ end
+ end
+
test "reach user on tld, while pleroma is running on subdomain" do
clear_config([Pleroma.Web.Endpoint, :url, :host], "sub.example.com")
@@ -91,44 +166,32 @@ defmodule Pleroma.Web.WebFinger.WebFingerControllerTest do
assert response["aliases"] == ["https://sub.example.com/users/#{user.nickname}"]
end
- test "it returns 404 when user isn't found (JSON)" do
- result =
- build_conn()
- |> put_req_header("accept", "application/jrd+json")
- |> get("/.well-known/webfinger?resource=acct:jimm@localhost")
- |> json_response(404)
-
- assert result == "Couldn't find user"
- end
-
- test "Webfinger XML" do
- user =
- insert(:user,
- ap_id: "https://hyrule.world/users/zelda",
- also_known_as: ["https://mushroom.kingdom/users/toad"]
- )
-
- response =
- build_conn()
- |> put_req_header("accept", "application/xrd+xml")
- |> get("/.well-known/webfinger?resource=acct:#{user.nickname}@localhost")
- |> response(200)
-
- assert response =~ "<Alias>https://hyrule.world/users/zelda</Alias>"
- assert response =~ "<Alias>https://mushroom.kingdom/users/toad</Alias>"
- end
-
- test "it returns 404 when user isn't found (XML)" do
- result =
- build_conn()
- |> put_req_header("accept", "application/xrd+xml")
- |> get("/.well-known/webfinger?resource=acct:jimm@localhost")
- |> response(404)
-
- assert result == "Couldn't find user"
+ describe "it returns 404 when user isn't found" do
+ test "JSON" do
+ result =
+ build_conn()
+ |> put_req_header("accept", "application/jrd+json")
+ |> get("/.well-known/webfinger?resource=acct:jimm@localhost")
+ |> json_response(404)
+
+ assert result == "Couldn't find user"
+ end
+
+ test "XML" do
+ result =
+ build_conn()
+ |> put_req_header("accept", "application/xrd+xml")
+ |> get("/.well-known/webfinger?resource=acct:jimm@localhost")
+ |> response(404)
+
+ assert result == "Couldn't find user"
+ end
end
test "Returns JSON when format is not supported" do
+ clear_config([Pleroma.Web.Endpoint, :url, :host], "hyrule.world")
+ clear_config([Pleroma.Web.WebFinger, :domain], "hyrule.world")
+
user =
insert(:user,
ap_id: "https://hyrule.world/users/zelda",
@@ -138,10 +201,10 @@ defmodule Pleroma.Web.WebFinger.WebFingerControllerTest do
response =
build_conn()
|> put_req_header("accept", "text/html")
- |> get("/.well-known/webfinger?resource=acct:#{user.nickname}@localhost")
+ |> get("/.well-known/webfinger?resource=acct:#{user.nickname}@hyrule.world")
|> json_response(200)
- assert response["subject"] == "acct:#{user.nickname}@localhost"
+ assert response["subject"] == "acct:#{user.nickname}@hyrule.world"
assert response["aliases"] == [
"https://hyrule.world/users/zelda",
diff --git a/test/pleroma/web/web_finger_test.exs b/test/pleroma/web/web_finger_test.exs
@@ -39,6 +39,23 @@ defmodule Pleroma.Web.WebFingerTest do
end
end
+ test "requires exact match for Endpoint host or WebFinger domain" do
+ clear_config([Pleroma.Web.WebFinger, :domain], "pleroma.dev")
+ user = insert(:user)
+
+ assert {:error, "Couldn't find user"} ==
+ WebFinger.webfinger("#{user.nickname}@#{Pleroma.Web.Endpoint.host()}xxxx", "JSON")
+
+ assert {:error, "Couldn't find user"} ==
+ WebFinger.webfinger("#{user.nickname}@pleroma.devxxxx", "JSON")
+
+ assert {:ok, _} =
+ WebFinger.webfinger("#{user.nickname}@#{Pleroma.Web.Endpoint.host()}", "JSON")
+
+ assert {:ok, _} =
+ WebFinger.webfinger("#{user.nickname}@pleroma.dev", "JSON")
+ end
+
describe "fingering" do
test "returns error for nonsensical input" do
assert {:error, _} = WebFinger.finger("bliblablu")