expanding WebFinger

This commit is contained in:
Alexander Strizhakov 2021-03-04 13:06:12 +03:00 committed by Mark Felder
parent da0ef154a6
commit 4121bca895
18 changed files with 410 additions and 65 deletions

View file

@ -869,6 +869,8 @@ config :pleroma, ConcurrentLimiter, [
{Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy, [max_running: 5, max_waiting: 5]} {Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy, [max_running: 5, max_waiting: 5]}
] ]
config :pleroma, Pleroma.Web.WebFinger, domain: nil, update_nickname_on_user_fetch: true
# Import environment specific config. This must remain at the bottom # Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above. # of this file so it overrides the configuration defined above.
import_config "#{Mix.env()}.exs" import_config "#{Mix.env()}.exs"

View file

@ -129,6 +129,8 @@ config :pleroma, :pipeline,
config :pleroma, :cachex, provider: Pleroma.CachexMock config :pleroma, :cachex, provider: Pleroma.CachexMock
config :pleroma, Pleroma.Web.WebFinger, update_nickname_on_user_fetch: false
config :pleroma, :side_effects, config :pleroma, :side_effects,
ap_streamer: Pleroma.Web.ActivityPub.ActivityPubMock, ap_streamer: Pleroma.Web.ActivityPub.ActivityPubMock,
logger: Pleroma.LoggerMock logger: Pleroma.LoggerMock

View file

@ -106,5 +106,12 @@ defmodule Pleroma.HTTP do
[Tesla.Middleware.FollowRedirects, Pleroma.Tesla.Middleware.ConnectionPool] [Tesla.Middleware.FollowRedirects, Pleroma.Tesla.Middleware.ConnectionPool]
end end
defp adapter_middlewares(_), do: [] defp adapter_middlewares(_) do
if Pleroma.Config.get(:env) == :test do
# Emulate redirects in test env, which are handled by adapters in other environments
[Tesla.Middleware.FollowRedirects]
else
[]
end
end
end end

View file

@ -1482,7 +1482,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
defp normalize_image(urls) when is_list(urls), do: urls |> List.first() |> normalize_image() defp normalize_image(urls) when is_list(urls), do: urls |> List.first() |> normalize_image()
defp normalize_image(_), do: nil defp normalize_image(_), do: nil
defp object_to_user_data(data) do defp object_to_user_data(data, additional) do
fields = fields =
data data
|> Map.get("attachment", []) |> Map.get("attachment", [])
@ -1514,15 +1514,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
public_key = public_key =
if is_map(data["publicKey"]) && is_binary(data["publicKey"]["publicKeyPem"]) do if is_map(data["publicKey"]) && is_binary(data["publicKey"]["publicKeyPem"]) do
data["publicKey"]["publicKeyPem"] data["publicKey"]["publicKeyPem"]
else
nil
end end
shared_inbox = shared_inbox =
if is_map(data["endpoints"]) && is_binary(data["endpoints"]["sharedInbox"]) do if is_map(data["endpoints"]) && is_binary(data["endpoints"]["sharedInbox"]) do
data["endpoints"]["sharedInbox"] data["endpoints"]["sharedInbox"]
else
nil
end end
birthday = birthday =
@ -1531,13 +1527,15 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
{:ok, date} -> date {:ok, date} -> date
{:error, _} -> nil {:error, _} -> nil
end end
else
nil
end end
show_birthday = !!birthday show_birthday = !!birthday
user_data = %{ # if WebFinger request was already done, we probably have acct, otherwise
# we request WebFinger here
nickname = additional[:nickname_from_acct] || generate_nickname(data)
%{
ap_id: data["id"], ap_id: data["id"],
uri: get_actor_url(data["url"]), uri: get_actor_url(data["url"]),
ap_enabled: true, ap_enabled: true,
@ -1559,22 +1557,28 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
inbox: data["inbox"], inbox: data["inbox"],
shared_inbox: shared_inbox, shared_inbox: shared_inbox,
accepts_chat_messages: accepts_chat_messages, accepts_chat_messages: accepts_chat_messages,
pinned_objects: pinned_objects,
birthday: birthday, birthday: birthday,
show_birthday: show_birthday show_birthday: show_birthday,
pinned_objects: pinned_objects,
nickname: nickname
} }
end
defp generate_nickname(%{"preferredUsername" => username} = data) when is_binary(username) do
generated = "#{username}@#{URI.parse(data["id"]).host}"
if Config.get([WebFinger, :update_nickname_on_user_fetch]) do
case WebFinger.finger(generated) do
{:ok, %{"subject" => "acct:" <> acct}} -> acct
_ -> generated
end
else
generated
end
end
# nickname can be nil because of virtual actors # nickname can be nil because of virtual actors
if data["preferredUsername"] do defp generate_nickname(_), do: nil
Map.put(
user_data,
:nickname,
"#{data["preferredUsername"]}@#{URI.parse(data["id"]).host}"
)
else
Map.put(user_data, :nickname, nil)
end
end
def fetch_follow_information_for_user(user) do def fetch_follow_information_for_user(user) do
with {:ok, following_data} <- with {:ok, following_data} <-
@ -1647,17 +1651,17 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
defp collection_private(_data), do: {:ok, true} defp collection_private(_data), do: {:ok, true}
def user_data_from_user_object(data) do def user_data_from_user_object(data, additional \\ []) do
with {:ok, data} <- MRF.filter(data) do with {:ok, data} <- MRF.filter(data) do
{:ok, object_to_user_data(data)} {:ok, object_to_user_data(data, additional)}
else else
e -> {:error, e} e -> {:error, e}
end end
end end
def fetch_and_prepare_user_from_ap_id(ap_id) do def fetch_and_prepare_user_from_ap_id(ap_id, additional \\ []) do
with {:ok, data} <- Fetcher.fetch_and_contain_remote_object_from_id(ap_id), with {:ok, data} <- Fetcher.fetch_and_contain_remote_object_from_id(ap_id),
{:ok, data} <- user_data_from_user_object(data) do {:ok, data} <- user_data_from_user_object(data, additional) do
{:ok, maybe_update_follow_information(data)} {:ok, maybe_update_follow_information(data)}
else else
# If this has been deleted, only log a debug and not an error # If this has been deleted, only log a debug and not an error
@ -1735,13 +1739,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end end
end end
def make_user_from_ap_id(ap_id) do def make_user_from_ap_id(ap_id, additional \\ []) do
user = User.get_cached_by_ap_id(ap_id) user = User.get_cached_by_ap_id(ap_id)
if user && !User.ap_enabled?(user) do if user && !User.ap_enabled?(user) do
Transmogrifier.upgrade_user_from_ap_id(ap_id) Transmogrifier.upgrade_user_from_ap_id(ap_id)
else else
with {:ok, data} <- fetch_and_prepare_user_from_ap_id(ap_id) do with {:ok, data} <- fetch_and_prepare_user_from_ap_id(ap_id, additional) do
{:ok, _pid} = Task.start(fn -> pinned_fetch_task(data) end) {:ok, _pid} = Task.start(fn -> pinned_fetch_task(data) end)
if user do if user do
@ -1761,8 +1765,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end end
def make_user_from_nickname(nickname) do def make_user_from_nickname(nickname) do
with {:ok, %{"ap_id" => ap_id}} when not is_nil(ap_id) <- WebFinger.finger(nickname) do with {:ok, %{"ap_id" => ap_id, "subject" => "acct:" <> acct}} when not is_nil(ap_id) <-
make_user_from_ap_id(ap_id) WebFinger.finger(nickname) do
make_user_from_ap_id(ap_id, nickname_from_acct: acct)
else else
_e -> {:error, "No AP id in WebFinger"} _e -> {:error, "No AP id in WebFinger"}
end end

View file

@ -32,7 +32,13 @@ defmodule Pleroma.Web.WebFinger do
def webfinger(resource, fmt) when fmt in ["XML", "JSON"] do def webfinger(resource, fmt) when fmt in ["XML", "JSON"] do
host = Pleroma.Web.Endpoint.host() host = Pleroma.Web.Endpoint.host()
regex = ~r/(acct:)?(?<username>[a-z0-9A-Z_\.-]+)@#{host}/
regex =
if webfinger_domain = Pleroma.Config.get([__MODULE__, :domain]) do
~r/(acct:)?(?<username>[a-z0-9A-Z_\.-]+)@(#{host}|#{webfinger_domain})/
else
~r/(acct:)?(?<username>[a-z0-9A-Z_\.-]+)@#{host}/
end
with %{"username" => username} <- Regex.named_captures(regex, resource), with %{"username" => username} <- Regex.named_captures(regex, resource),
%User{} = user <- User.get_cached_by_nickname(username) do %User{} = user <- User.get_cached_by_nickname(username) do
@ -63,8 +69,12 @@ defmodule Pleroma.Web.WebFinger do
end end
def represent_user(user, "JSON") do def represent_user(user, "JSON") do
{:ok, user} = User.ensure_keys_present(user)
domain = Pleroma.Config.get([__MODULE__, :domain]) || Pleroma.Web.Endpoint.host()
%{ %{
"subject" => "acct:#{user.nickname}@#{Pleroma.Web.Endpoint.host()}", "subject" => "acct:#{user.nickname}@#{domain}",
"aliases" => gather_aliases(user), "aliases" => gather_aliases(user),
"links" => gather_links(user) "links" => gather_links(user)
} }
@ -146,17 +156,15 @@ defmodule Pleroma.Web.WebFinger do
end end
def find_lrdd_template(domain) do def find_lrdd_template(domain) do
with {:ok, %{status: status, body: body}} when status in 200..299 <- # WebFinger is restricted to HTTPS - https://tools.ietf.org/html/rfc7033#section-9.1
HTTP.get("http://#{domain}/.well-known/host-meta") do meta_url = "https://#{domain}/.well-known/host-meta"
with {:ok, %{status: status, body: body}} when status in 200..299 <- HTTP.get(meta_url) do
get_template_from_xml(body) get_template_from_xml(body)
else else
_ -> error ->
with {:ok, %{body: body, status: status}} when status in 200..299 <- Logger.warn("Can't find LRDD template in #{inspect(meta_url)}: #{inspect(error)}")
HTTP.get("https://#{domain}/.well-known/host-meta") do {:error, :lrdd_not_found}
get_template_from_xml(body)
else
e -> {:error, "Can't find LRDD template: #{inspect(e)}"}
end
end end
end end
@ -170,7 +178,7 @@ defmodule Pleroma.Web.WebFinger do
end end
end end
defp get_address_from_domain(_, _), do: nil defp get_address_from_domain(_, _), do: {:error, :webfinger_no_domain}
@spec finger(String.t()) :: {:ok, map()} | {:error, any()} @spec finger(String.t()) :: {:ok, map()} | {:error, any()}
def finger(account) do def finger(account) do
@ -187,13 +195,11 @@ defmodule Pleroma.Web.WebFinger do
encoded_account = URI.encode("acct:#{account}") 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, encoded_account),
response <- {:ok, %{status: status, body: body, headers: headers}} when status in 200..299 <-
HTTP.get( HTTP.get(
address, address,
[{"accept", "application/xrd+xml,application/jrd+json"}] [{"accept", "application/xrd+xml,application/jrd+json"}]
), ) do
{:ok, %{status: status, body: body, headers: headers}} when status in 200..299 <-
response do
case List.keyfind(headers, "content-type", 0) do case List.keyfind(headers, "content-type", 0) do
{_, content_type} -> {_, content_type} ->
case Plug.Conn.Utils.media_type(content_type) do case Plug.Conn.Utils.media_type(content_type) do
@ -211,10 +217,9 @@ defmodule Pleroma.Web.WebFinger do
{:error, {:content_type, nil}} {:error, {:content_type, nil}}
end end
else else
e -> error ->
Logger.debug(fn -> "Couldn't finger #{account}" end) Logger.debug("Couldn't finger #{account}: #{inspect(error)}")
Logger.debug(fn -> inspect(e) end) error
{:error, e}
end end
end end
end end

View file

@ -1,2 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0"><hm:Host xmlns:hm="http://host-meta.net/xrd/1.0">framatube.org</hm:Host><Link rel="lrdd" template="http://framatube.org/main/xrd?uri={uri}"><Title>Resource Descriptor</Title></Link></XRD> <XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0"><hm:Host xmlns:hm="http://host-meta.net/xrd/1.0">framatube.org</hm:Host><Link rel="lrdd" template="https://framatube.org/main/xrd?uri={uri}"><Title>Resource Descriptor</Title></Link></XRD>

View file

@ -1,2 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0"><hm:Host xmlns:hm="http://host-meta.net/xrd/1.0">status.alpicola.com</hm:Host><Link rel="lrdd" template="http://status.alpicola.com/main/xrd?uri={uri}"><Title>Resource Descriptor</Title></Link></XRD> <XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0"><hm:Host xmlns:hm="http://host-meta.net/xrd/1.0">status.alpicola.com</hm:Host><Link rel="lrdd" template="https://status.alpicola.com/main/xrd?uri={uri}"><Title>Resource Descriptor</Title></Link></XRD>

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
<Link rel="lrdd" template="https://{{domain}}/.well-known/webfinger?resource={uri}"/>
</XRD>

92
test/fixtures/webfinger/masto-user.json vendored Normal file
View file

@ -0,0 +1,92 @@
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{
"manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
"toot": "http://joinmastodon.org/ns#",
"featured": {
"@id": "toot:featured",
"@type": "@id"
},
"featuredTags": {
"@id": "toot:featuredTags",
"@type": "@id"
},
"alsoKnownAs": {
"@id": "as:alsoKnownAs",
"@type": "@id"
},
"movedTo": {
"@id": "as:movedTo",
"@type": "@id"
},
"schema": "http://schema.org#",
"PropertyValue": "schema:PropertyValue",
"value": "schema:value",
"IdentityProof": "toot:IdentityProof",
"discoverable": "toot:discoverable",
"Device": "toot:Device",
"Ed25519Signature": "toot:Ed25519Signature",
"Ed25519Key": "toot:Ed25519Key",
"Curve25519Key": "toot:Curve25519Key",
"EncryptedMessage": "toot:EncryptedMessage",
"publicKeyBase64": "toot:publicKeyBase64",
"deviceId": "toot:deviceId",
"claim": {
"@type": "@id",
"@id": "toot:claim"
},
"fingerprintKey": {
"@type": "@id",
"@id": "toot:fingerprintKey"
},
"identityKey": {
"@type": "@id",
"@id": "toot:identityKey"
},
"devices": {
"@type": "@id",
"@id": "toot:devices"
},
"messageFranking": "toot:messageFranking",
"messageType": "toot:messageType",
"cipherText": "toot:cipherText",
"suspended": "toot:suspended",
"focalPoint": {
"@container": "@list",
"@id": "toot:focalPoint"
}
}
],
"id": "https://{{domain}}/users/{{nickname}}",
"type": "Person",
"following": "https://{{domain}}/users/{{nickname}}/following",
"followers": "https://{{domain}}/users/{{nickname}}/followers",
"inbox": "https://{{domain}}/users/{{nickname}}/inbox",
"outbox": "https://{{domain}}/users/{{nickname}}/outbox",
"featured": "https://{{domain}}/users/{{nickname}}/collections/featured",
"featuredTags": "https://{{domain}}/users/{{nickname}}/collections/tags",
"preferredUsername": "{{nickname}}",
"name": "Name Name",
"summary": "<p>Summary</p>",
"url": "https://{{domain}}/@{{nickname}}",
"manuallyApprovesFollowers": false,
"discoverable": false,
"devices": "https://{{domain}}/users/{{nickname}}/collections/devices",
"publicKey": {
"id": "https://{{domain}}/users/{{nickname}}#main-key",
"owner": "https://{{domain}}/users/{{nickname}}",
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvwDujxmxoYHs64MyVB3L\nG5ZyBxV3ufaMRBFu42bkcTpISq1WwZ+3Zb6CI8zOO+nM+Q2llrVRYjZa4ZFnOLvM\nTq/Kf+Zf5wy2aCRer88gX+MsJOAtItSi412y0a/rKOuFaDYLOLeTkRvmGLgZWbsr\nZJOp+YWb3zQ5qsIOInkc5BwI172tMsGeFtsnbNApPV4lrmtTGaJ8RiM8MR7XANBO\nfOHggSt1+eAIKGIsCmINEMzs1mG9D75xKtC/sM8GfbvBclQcBstGkHAEj1VHPW0c\nh6Bok5/QQppicyb8UA1PAA9bznSFtKlYE4xCH8rlCDSDTBRtdnBWHKcj619Ujz4Q\nawIDAQAB\n-----END PUBLIC KEY-----\n"
},
"tag": [],
"attachment": [],
"endpoints": {
"sharedInbox": "https://{{domain}}/inbox"
},
"icon": {
"type": "Image",
"mediaType": "image/jpeg",
"url": "https://s3.wasabisys.com/merp/accounts/avatars/000/000/001/original/6fdd3eee632af247.jpg"
}
}

View file

@ -0,0 +1,23 @@
{
"subject": "acct:{{nickname}}@{{domain}}",
"aliases": [
"https://{{subdomain}}/@{{nickname}}",
"https://{{subdomain}}/users/{{nickname}}"
],
"links": [
{
"rel": "http://webfinger.net/rel/profile-page",
"type": "text/html",
"href": "https://{{subdomain}}/@{{nickname}}"
},
{
"rel": "self",
"type": "application/activity+json",
"href": "https://{{subdomain}}/users/{{nickname}}"
},
{
"rel": "http://ostatus.org/schema/1.0/subscribe",
"template": "https://{{subdomain}}/authorize_interaction?uri={uri}"
}
]
}

View file

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0"><Link rel="lrdd" template="https://{{domain}}/.well-known/webfinger?resource={uri}" type="application/xrd+xml" /></XRD>

View file

@ -0,0 +1,58 @@
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://{{domain}}/schemas/litepub-0.1.jsonld",
{
"@language": "und"
}
],
"alsoKnownAs": [],
"attachment": [],
"capabilities": {
"acceptsChatMessages": true
},
"discoverable": true,
"endpoints": {
"oauthAuthorizationEndpoint": "https://{{domain}}/oauth/authorize",
"oauthRegistrationEndpoint": "https://{{domain}}/api/v1/apps",
"oauthTokenEndpoint": "https://{{domain}}/oauth/token",
"sharedInbox": "https://{{domain}}/inbox",
"uploadMedia": "https://{{domain}}/api/ap/upload_media"
},
"followers": "https://{{domain}}/users/{{nickname}}/followers",
"following": "https://{{domain}}/users/{{nickname}}/following",
"icon": {
"type": "Image",
"url": "https://{{domain}}/media/a932a27f158b63c3a97e3a57d5384f714a82249274c6fc66c9eca581b4fd8af2.jpg"
},
"id": "https://{{domain}}/users/{{nickname}}",
"image": {
"type": "Image",
"url": "https://{{domain}}/media/db15f476d0ad14488db4762b7800479e6ef67b1824f8b9ea5c1fa05b7525c5b7.jpg"
},
"inbox": "https://{{domain}}/users/{{nickname}}/inbox",
"manuallyApprovesFollowers": false,
"name": "{{nickname}} :verified:",
"outbox": "https://{{domain}}/users/{{nickname}}/outbox",
"preferredUsername": "{{nickname}}",
"publicKey": {
"id": "https://{{domain}}/users/{{nickname}}#main-key",
"owner": "https://{{domain}}/users/{{nickname}}",
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu4XOAopC4nRIxNlHlt60\n//nCicuedu5wvLGIoQ+KUM2u7/PhLrrTDEqr1A7yQL95S0X8ryYtALgFLI5A54ww\nqjMIbIGAs44lEmDLMEd+XI+XxREE8wdsFpb4QQzWug0DTyqlMouTU25k0tfKh1rF\n4PMJ3uBSjDTAGgFvLNyFWTiVVgChbTNgGOmrEBucRl4NmKzQ69/FIUwENV88oQSU\n3bWvQTEH9rWH1rCLpkmQwdRiWfnhFX/4EUqXukfgoskvenKR8ff3nYhElDqFoE0e\nqUnIW1OZceyl8JewVLcL6m0/wdKeosTsfrcWc8DKfnRYQcBGNoBEq9GrOHDU0q2v\nyQIDAQAB\n-----END PUBLIC KEY-----\n\n"
},
"summary": "Pleroma BE dev",
"tag": [
{
"icon": {
"type": "Image",
"url": "https://{{domain}}/emoji/mine/6143373a807b1ae7.png"
},
"id": "https://{{domain}}/emoji/mine/6143373a807b1ae7.png",
"name": ":verified:",
"type": "Emoji",
"updated": "1970-01-01T00:00:00Z"
}
],
"type": "Person",
"url": "https://{{domain}}/users/{{nickname}}"
}

View file

@ -0,0 +1,27 @@
{
"aliases": [
"https://{{subdomain}}/users/{{nickname}}"
],
"links": [
{
"href": "https://{{subdomain}}/users/{{nickname}}",
"rel": "http://webfinger.net/rel/profile-page",
"type": "text/html"
},
{
"href": "https://{{subdomain}}/users/{{nickname}}",
"rel": "self",
"type": "application/activity+json"
},
{
"href": "https://{{subdomain}}/users/{{nickname}}",
"rel": "self",
"type": "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""
},
{
"rel": "http://ostatus.org/schema/1.0/subscribe",
"template": "https://{{subdomain}}/ostatus_subscribe?acct={uri}"
}
],
"subject": "acct:{{nickname}}@{{domain}}"
}

View file

@ -859,6 +859,104 @@ defmodule Pleroma.UserTest do
end end
end end
describe "get_or_fetch/1 remote users with tld, while BE is runned on subdomain" do
setup do: clear_config([Pleroma.Web.WebFinger, :update_nickname_on_user_fetch], true)
test "for mastodon" do
Tesla.Mock.mock(fn
%{url: "https://example.com/.well-known/host-meta"} ->
%Tesla.Env{
status: 302,
headers: [{"location", "https://sub.example.com/.well-known/host-meta"}]
}
%{url: "https://sub.example.com/.well-known/host-meta"} ->
%Tesla.Env{
status: 200,
body:
"test/fixtures/webfinger/masto-host-meta.xml"
|> File.read!()
|> String.replace("{{domain}}", "sub.example.com")
}
%{url: "https://sub.example.com/.well-known/webfinger?resource=acct:a@example.com"} ->
%Tesla.Env{
status: 200,
body:
"test/fixtures/webfinger/masto-webfinger.json"
|> File.read!()
|> String.replace("{{nickname}}", "a")
|> String.replace("{{domain}}", "example.com")
|> String.replace("{{subdomain}}", "sub.example.com")
}
%{url: "https://sub.example.com/users/a"} ->
%Tesla.Env{
status: 200,
body:
"test/fixtures/webfinger/masto-user.json"
|> File.read!()
|> String.replace("{{nickname}}", "a")
|> String.replace("{{domain}}", "sub.example.com"),
headers: [{"content-type", "application/activity+json"}]
}
end)
ap_id = "a@example.com"
{:ok, fetched_user} = User.get_or_fetch(ap_id)
assert fetched_user.ap_id == "https://sub.example.com/users/a"
assert fetched_user.nickname == "a@example.com"
end
test "for pleroma" do
Tesla.Mock.mock(fn
%{url: "https://example.com/.well-known/host-meta"} ->
%Tesla.Env{
status: 302,
headers: [{"location", "https://sub.example.com/.well-known/host-meta"}]
}
%{url: "https://sub.example.com/.well-known/host-meta"} ->
%Tesla.Env{
status: 200,
body:
"test/fixtures/webfinger/pleroma-host-meta.xml"
|> File.read!()
|> String.replace("{{domain}}", "sub.example.com")
}
%{url: "https://sub.example.com/.well-known/webfinger?resource=acct:a@example.com"} ->
%Tesla.Env{
status: 200,
body:
"test/fixtures/webfinger/pleroma-webfinger.json"
|> File.read!()
|> String.replace("{{nickname}}", "a")
|> String.replace("{{domain}}", "example.com")
|> String.replace("{{subdomain}}", "sub.example.com")
}
%{url: "https://sub.example.com/users/a"} ->
%Tesla.Env{
status: 200,
body:
"test/fixtures/webfinger/pleroma-user.json"
|> File.read!()
|> String.replace("{{nickname}}", "a")
|> String.replace("{{domain}}", "sub.example.com"),
headers: [{"content-type", "application/activity+json"}]
}
end)
ap_id = "a@example.com"
{:ok, fetched_user} = User.get_or_fetch(ap_id)
assert fetched_user.ap_id == "https://sub.example.com/users/a"
assert fetched_user.nickname == "a@example.com"
end
end
describe "fetching a user from nickname or trying to build one" do describe "fetching a user from nickname or trying to build one" do
test "gets an existing user" do test "gets an existing user" do
user = insert(:user) user = insert(:user)

View file

@ -3,7 +3,7 @@
# SPDX-License-Identifier: AGPL-3.0-only # SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do
use Pleroma.Web.ConnCase use Pleroma.Web.ConnCase, async: true
alias Pleroma.MFA alias Pleroma.MFA
alias Pleroma.MFA.TOTP alias Pleroma.MFA.TOTP

View file

@ -48,6 +48,35 @@ defmodule Pleroma.Web.WebFinger.WebFingerControllerTest do
] ]
end end
test "reach user on tld, while pleroma is runned on subdomain" do
Pleroma.Web.Endpoint.config_change(
[{Pleroma.Web.Endpoint, url: [host: "sub.example.com"]}],
[]
)
clear_config([Pleroma.Web.Endpoint, :url, :host], "sub.example.com")
clear_config([Pleroma.Web.WebFinger, :domain], "example.com")
user = insert(:user, ap_id: "https://sub.example.com/users/bobby", nickname: "bobby")
response =
build_conn()
|> put_req_header("accept", "application/jrd+json")
|> get("/.well-known/webfinger?resource=acct:#{user.nickname}@example.com")
|> json_response(200)
assert response["subject"] == "acct:#{user.nickname}@example.com"
assert response["aliases"] == ["https://sub.example.com/users/#{user.nickname}"]
on_exit(fn ->
Pleroma.Web.Endpoint.config_change(
[{Pleroma.Web.Endpoint, url: [host: "localhost"]}],
[]
)
end)
end
test "it returns 404 when user isn't found (JSON)" do test "it returns 404 when user isn't found (JSON)" do
result = result =
build_conn() build_conn()

View file

@ -120,7 +120,7 @@ defmodule Pleroma.Web.WebFingerTest do
test "it gets the xrd endpoint for statusnet" do test "it gets the xrd endpoint for statusnet" do
{:ok, template} = WebFinger.find_lrdd_template("status.alpicola.com") {:ok, template} = WebFinger.find_lrdd_template("status.alpicola.com")
assert template == "http://status.alpicola.com/main/xrd?uri={uri}" assert template == "https://status.alpicola.com/main/xrd?uri={uri}"
end end
test "it works with idna domains as nickname" do test "it works with idna domains as nickname" do

View file

@ -424,14 +424,6 @@ defmodule HttpRequestMock do
{:error, :nxdomain} {:error, :nxdomain}
end end
def get("http://osada.macgirvin.com/.well-known/host-meta", _, _, _) do
{:ok,
%Tesla.Env{
status: 404,
body: ""
}}
end
def get("https://osada.macgirvin.com/.well-known/host-meta", _, _, _) do def get("https://osada.macgirvin.com/.well-known/host-meta", _, _, _) do
{:ok, {:ok,
%Tesla.Env{ %Tesla.Env{
@ -765,7 +757,7 @@ defmodule HttpRequestMock do
{:ok, %Tesla.Env{status: 406, body: ""}} {:ok, %Tesla.Env{status: 406, body: ""}}
end end
def get("http://squeet.me/.well-known/host-meta", _, _, _) do def get("https://squeet.me/.well-known/host-meta", _, _, _) do
{:ok, {:ok,
%Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/squeet.me_host_meta")}} %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/squeet.me_host_meta")}}
end end
@ -806,7 +798,7 @@ defmodule HttpRequestMock do
{:ok, %Tesla.Env{status: 200, body: "", headers: [{"content-type", "application/jrd+json"}]}} {:ok, %Tesla.Env{status: 200, body: "", headers: [{"content-type", "application/jrd+json"}]}}
end end
def get("http://framatube.org/.well-known/host-meta", _, _, _) do def get("https://framatube.org/.well-known/host-meta", _, _, _) do
{:ok, {:ok,
%Tesla.Env{ %Tesla.Env{
status: 200, status: 200,
@ -815,7 +807,7 @@ defmodule HttpRequestMock do
end end
def get( def get(
"http://framatube.org/main/xrd?uri=acct:framasoft@framatube.org", "https://framatube.org/main/xrd?uri=acct:framasoft@framatube.org",
_, _,
_, _,
[{"accept", "application/xrd+xml,application/jrd+json"}] [{"accept", "application/xrd+xml,application/jrd+json"}]
@ -850,7 +842,7 @@ defmodule HttpRequestMock do
}} }}
end end
def get("http://status.alpicola.com/.well-known/host-meta", _, _, _) do def get("https://status.alpicola.com/.well-known/host-meta", _, _, _) do
{:ok, {:ok,
%Tesla.Env{ %Tesla.Env{
status: 200, status: 200,
@ -858,7 +850,7 @@ defmodule HttpRequestMock do
}} }}
end end
def get("http://macgirvin.com/.well-known/host-meta", _, _, _) do def get("https://macgirvin.com/.well-known/host-meta", _, _, _) do
{:ok, {:ok,
%Tesla.Env{ %Tesla.Env{
status: 200, status: 200,
@ -866,7 +858,7 @@ defmodule HttpRequestMock do
}} }}
end end
def get("http://gerzilla.de/.well-known/host-meta", _, _, _) do def get("https://gerzilla.de/.well-known/host-meta", _, _, _) do
{:ok, {:ok,
%Tesla.Env{ %Tesla.Env{
status: 200, status: 200,