Skip to content
Snippets Groups Projects
Commit ce6cc84a authored by lain's avatar lain
Browse files

Add basic webfinger.

parent 6a0e69a8
No related branches found
No related tags found
No related merge requests found
......@@ -26,6 +26,10 @@
format: "$time $metadata[$level] $message\n",
metadata: [:request_id]
config :mime, :types, %{
"application/xrd+xml" => ["xrd+xml"]
}
# Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above.
import_config "#{Mix.env}.exs"
......@@ -19,6 +19,10 @@ def user_fetcher(username) do
plug Pleroma.Plugs.AuthenticationPlug, %{fetcher: &Pleroma.Web.Router.user_fetcher/1}
end
pipeline :well_known do
plug :accepts, ["xml", "xrd+xml"]
end
scope "/api", Pleroma.Web do
pipe_through :api
......@@ -49,4 +53,11 @@ def user_fetcher(username) do
post "/statuses/retweet/:id", TwitterAPI.Controller, :retweet
post "/qvitter/update_avatar", TwitterAPI.Controller, :update_avatar
end
scope "/.well-known", Pleroma.Web do
pipe_through :well_known
get "/host-meta", WebFinger.WebFingerController, :host_meta
get "/webfinger", WebFinger.WebFingerController, :webfinger
end
end
......@@ -61,12 +61,17 @@ defmacro __using__(which) when is_atom(which) do
apply(__MODULE__, which, [])
end
def host do
settings = Application.get_env(:pleroma, Pleroma.Web.Endpoint)
settings
|> Keyword.fetch!(:url)
|> Keyword.fetch!(:host)
end
def base_url do
settings = Application.get_env(:pleroma, Pleroma.Web.Endpoint)
host =
settings
|> Keyword.fetch!(:url)
|> Keyword.fetch!(:host)
host = host()
protocol = settings |> Keyword.fetch!(:protocol)
......
defmodule Pleroma.Web.WebFinger do
alias Pleroma.XmlBuilder
alias Pleroma.User
def host_meta() do
base_url = Pleroma.Web.base_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) do
host = Pleroma.Web.host
regex = ~r/acct:(?<username>\w+)@#{host}/
case Regex.named_captures(regex, resource) do
%{"username" => username} ->
user = User.get_cached_by_nickname(username)
{:ok, represent_user(user)}
_ -> nil
end
end
def represent_user(user) do
{
:XRD, %{xmlns: "http://docs.oasis-open.org/ns/xri/xrd-1.0"},
[
{:Subject, "acct:#{user.nickname}@#{Pleroma.Web.host}"},
{:Alias, user.ap_id},
{:Link, %{rel: "http://schemas.google.com/g/2010#updates-from", type: "application/atom+xml", href: "#{user.ap_id}.atom"}}
]
}
|> XmlBuilder.to_doc
end
end
defmodule Pleroma.Web.WebFinger.WebFingerController do
use Pleroma.Web, :controller
alias Pleroma.Web.WebFinger
def host_meta(conn, _params) do
xml = WebFinger.host_meta
conn
|> put_resp_content_type("application/xrd+xml")
|> send_resp(200, xml)
end
def webfinger(conn, %{"resource" => resource}) do
{:ok, response} = Pleroma.Web.WebFinger.webfinger(resource)
conn
|> put_resp_content_type("application/xrd+xml")
|> send_resp(200, response)
end
end
defmodule Pleroma.XmlBuilder do
def to_xml({tag, attributes, content}) do
open_tag = make_open_tag(tag, attributes)
content_xml = to_xml(content)
"<#{open_tag}>#{content_xml}</#{tag}>"
end
def to_xml({tag, %{} = attributes}) do
open_tag = make_open_tag(tag, attributes)
"<#{open_tag} />"
end
def to_xml({tag, content}), do: to_xml({tag, %{}, content})
def to_xml(content) when is_binary(content) do
to_string(content)
end
def to_xml(content) when is_list(content) do
for element <- content do
to_xml(element)
end
|> Enum.join
end
def to_xml(%NaiveDateTime{} = time) do
NaiveDateTime.to_iso8601(time)
end
def to_doc(content), do: "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" <> to_xml(content)
defp make_open_tag(tag, attributes) do
attributes_string = for {attribute, value} <- attributes do
"#{attribute}=\"#{value}\""
end |> Enum.join(" ")
Enum.join([tag, attributes_string], " ") |> String.strip
end
end
defmodule Pleroma.Web.WebFingerTest do
use Pleroma.DataCase
describe "host meta" do
test "returns a link to the xml lrdd" do
host_info = Pleroma.Web.WebFinger.host_meta
assert String.contains?(host_info, Pleroma.Web.base_url)
end
end
end
defmodule Pleroma.XmlBuilderTest do
use Pleroma.DataCase
alias Pleroma.XmlBuilder
test "Build a basic xml string from a tuple" do
data = { :feed, %{ xmlns: "http://www.w3.org/2005/Atom"}, "Some content" }
expected_xml = "<feed xmlns=\"http://www.w3.org/2005/Atom\">Some content</feed>"
assert XmlBuilder.to_xml(data) == expected_xml
end
test "returns a complete document" do
data = { :feed, %{ xmlns: "http://www.w3.org/2005/Atom"}, "Some content" }
expected_xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><feed xmlns=\"http://www.w3.org/2005/Atom\">Some content</feed>"
assert XmlBuilder.to_doc(data) == expected_xml
end
test "Works without attributes" do
data = {
:feed,
"Some content"
}
expected_xml = "<feed>Some content</feed>"
assert XmlBuilder.to_xml(data) == expected_xml
end
test "It works with nested tuples" do
data = {
:feed,
[
{:guy, "brush"},
{:lament, %{ configuration: "puzzle" }, "pinhead" }
]
}
expected_xml = ~s[<feed><guy>brush</guy><lament configuration="puzzle">pinhead</lament></feed>]
assert XmlBuilder.to_xml(data) == expected_xml
end
test "Represents NaiveDateTime as iso8601" do
assert XmlBuilder.to_xml(~N[2000-01-01 13:13:33]) == "2000-01-01T13:13:33"
end
test "Uses self-closing tags when no content is giving" do
data = {
:link,
%{ rel: "self" }
}
expected_xml = ~s[<link rel="self" />]
assert XmlBuilder.to_xml(data) == expected_xml
end
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment