Fix validate_webfinger when running a different domain for Webfinger

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
marcin mikołajczak 2023-08-24 00:37:39 +02:00 committed by Floatingghost
parent 50403351f4
commit 0d66237205
3 changed files with 26 additions and 11 deletions

View file

@ -179,7 +179,8 @@ defp cachex_children do
build_cachex("translations", default_ttl: :timer.hours(24 * 30), limit: 2500),
build_cachex("instances", default_ttl: :timer.hours(24), ttl_interval: 1000, limit: 2500),
build_cachex("request_signatures", default_ttl: :timer.hours(24 * 30), limit: 3000),
build_cachex("rel_me", default_ttl: :timer.hours(24 * 30), limit: 300)
build_cachex("rel_me", default_ttl: :timer.hours(24 * 30), limit: 300),
build_cachex("host_meta", default_ttl: :timer.minutes(120), limit: 5000)
]
end

View file

@ -156,7 +156,16 @@ def get_template_from_xml(body) do
end
end
@cachex Pleroma.Config.get([:cachex, :provider], Cachex)
def find_lrdd_template(domain) do
@cachex.fetch!(:host_meta_cache, domain, fn _ ->
{:commit, fetch_lrdd_template(domain)}
end)
rescue
e -> {:error, "Cachex error: #{inspect(e)}"}
end
defp fetch_lrdd_template(domain) do
# WebFinger is restricted to HTTPS - https://tools.ietf.org/html/rfc7033#section-9.1
meta_url = "https://#{domain}/.well-known/host-meta"
@ -169,7 +178,7 @@ def find_lrdd_template(domain) do
end
end
defp get_address_from_domain(domain, encoded_account) when is_binary(domain) do
defp get_address_from_domain(domain, "acct:" <> _ = encoded_account) when is_binary(domain) do
case find_lrdd_template(domain) do
{:ok, template} ->
String.replace(template, "{uri}", encoded_account)
@ -179,6 +188,11 @@ defp get_address_from_domain(domain, encoded_account) when is_binary(domain) do
end
end
defp get_address_from_domain(domain, account) when is_binary(domain) do
encoded_account = URI.encode("acct:#{account}")
get_address_from_domain(domain, encoded_account)
end
defp get_address_from_domain(_, _), do: {:error, :webfinger_no_domain}
@spec finger(String.t()) :: {:ok, map()} | {:error, any()}
@ -193,9 +207,7 @@ def finger(account) do
URI.parse(account).host
end
encoded_account = URI.encode("acct:#{account}")
with address when is_binary(address) <- get_address_from_domain(domain, encoded_account),
with address when is_binary(address) <- get_address_from_domain(domain, account),
{:ok, %{status: status, body: body, headers: headers}} when status in 200..299 <-
HTTP.get(
address,
@ -229,13 +241,15 @@ def finger(account) do
end
end
defp validate_webfinger(url, %{"subject" => "acct:" <> acct} = data) do
with %URI{host: request_host} <- URI.parse(url),
[_name, acct_host] <- String.split(acct, "@"),
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
{:ok, data}
else
_ -> {:error, {:webfinger_invalid, url, data}}
_ -> {:error, {:webfinger_invalid, request_url, data}}
end
end

View file

@ -765,7 +765,7 @@ test "gets an existing user by nickname starting with http" do
setup do: clear_config([Pleroma.Web.WebFinger, :update_nickname_on_user_fetch], true)
test "for mastodon" do
Tesla.Mock.mock(fn
Tesla.Mock.mock_global(fn
%{url: "https://example.com/.well-known/host-meta"} ->
%Tesla.Env{
status: 302,
@ -823,7 +823,7 @@ test "for mastodon" do
end
test "for pleroma" do
Tesla.Mock.mock(fn
Tesla.Mock.mock_global(fn
%{url: "https://example.com/.well-known/host-meta"} ->
%Tesla.Env{
status: 302,