mobilizon.chapril.org-mobil.../lib/service/web_finger/web_finger.ex

95 lines
2.4 KiB
Elixir

defmodule Eventos.Service.WebFinger do
alias Eventos.Actors
alias Eventos.Service.XmlBuilder
alias Eventos.Repo
require Jason
require Logger
def host_meta do
base_url = EventosWeb.Endpoint.url()
{
:XRD,
%{xmlns: "http://docs.oasis-open.org/ns/xri/xrd-1.0"},
{
:Link,
%{
rel: "lrdd",
type: "application/xrd+xml",
template: "#{base_url}/.well-known/webfinger?resource={uri}"
}
}
}
|> XmlBuilder.to_doc()
end
def webfinger(resource, "JSON") do
host = EventosWeb.Endpoint.host()
regex = ~r/(acct:)?(?<name>\w+)@#{host}/
with %{"name" => name} <- Regex.named_captures(regex, resource) do
user = Actors.get_local_actor_by_name(name)
{:ok, represent_user(user, "JSON")}
else
_e ->
with user when not is_nil(user) <- Actors.get_actor_by_url(resource) do
{:ok, represent_user(user, "JSON")}
else
_e ->
{:error, "Couldn't find user"}
end
end
end
def represent_user(user, "JSON") do
%{
"subject" => "acct:#{user.preferred_username}@#{EventosWeb.Endpoint.host() <> ":4001"}",
"aliases" => [user.url],
"links" => [
%{"rel" => "self", "type" => "application/activity+json", "href" => user.url},
]
}
end
defp webfinger_from_json(doc) do
data =
Enum.reduce(doc["links"], %{"subject" => doc["subject"]}, fn link, data ->
case {link["type"], link["rel"]} do
{"application/activity+json", "self"} ->
Map.put(data, "url", link["href"])
_ ->
Logger.debug("Unhandled type: #{inspect(link["type"])}")
data
end
end)
{:ok, data}
end
def finger(actor) do
actor = String.trim_leading(actor, "@")
domain =
with [_name, domain] <- String.split(actor, "@") do
domain
else
_e ->
URI.parse(actor).host
end
address = "http://#{domain}/.well-known/webfinger?resource=acct:#{actor}"
with response <- HTTPoison.get(address, [Accept: "application/json"],follow_redirect: true),
{:ok, %{status_code: status_code, body: body}} when status_code in 200..299 <- response do
{:ok, doc} = Jason.decode(body)
webfinger_from_json(doc)
else
e ->
Logger.debug(fn -> "Couldn't finger #{actor}" end)
Logger.debug(fn -> inspect(e) end)
{:error, e}
end
end
end