Merge branch 'nodeinfo-relay' into 'main'

feat(activitypub): implement FEP-2677 to identify the application actor used for federation

Closes #1367

See merge request framasoft/mobilizon!1507
This commit is contained in:
Thomas Citharel 2023-12-18 15:44:15 +00:00
commit 707add36dd
4 changed files with 56 additions and 5 deletions

View file

@ -13,7 +13,7 @@ defmodule Mobilizon.Federation.ActivityPub.Relay do
alias Mobilizon.Federation.ActivityPub.{Actions, Activity, Transmogrifier} alias Mobilizon.Federation.ActivityPub.{Actions, Activity, Transmogrifier}
alias Mobilizon.Federation.ActivityPub.Actor, as: ActivityPubActor alias Mobilizon.Federation.ActivityPub.Actor, as: ActivityPubActor
alias Mobilizon.Federation.WebFinger alias Mobilizon.Federation.{NodeInfo, WebFinger}
alias Mobilizon.GraphQL.API.Follows alias Mobilizon.GraphQL.API.Follows
alias Mobilizon.Service.Workers.Background alias Mobilizon.Service.Workers.Background
import Mobilizon.Federation.ActivityPub.Utils, only: [create_full_domain_string: 1] import Mobilizon.Federation.ActivityPub.Utils, only: [create_full_domain_string: 1]
@ -192,10 +192,10 @@ defmodule Mobilizon.Federation.ActivityPub.Relay do
check_actor(address) check_actor(address)
!is_nil(host) -> !is_nil(host) ->
uri case NodeInfo.application_actor(host) do
|> create_full_domain_string() nil -> check_actor("relay@#{host}")
|> then(&Kernel.<>("relay@", &1)) actor_url when is_binary(actor_url) -> {:ok, actor_url}
|> check_actor() end
true -> true ->
{:error, :bad_url} {:error, :bad_url}

View file

@ -0,0 +1,33 @@
defmodule Mobilizon.Federation.NodeInfo do
@moduledoc """
Performs NodeInfo requests
"""
alias Mobilizon.Service.HTTP.WebfingerClient
require Logger
@application_uri "https://www.w3.org/ns/activitystreams#Application"
@env Application.compile_env(:mobilizon, :env)
@spec application_actor(String.t()) :: String.t() | nil
def application_actor(host) do
prefix = if @env !== :dev, do: "https", else: "http"
case WebfingerClient.get("#{prefix}://#{host}/.well-known/nodeinfo") do
{:ok, %{body: body, status: code}} when code in 200..299 ->
extract_application_actor(body)
err ->
Logger.debug("Failed to fetch NodeInfo data #{inspect(err)}")
nil
end
end
defp extract_application_actor(body) do
body
|> Enum.find(%{rel: @application_uri, href: nil}, fn %{rel: rel, href: href} ->
rel == @application_uri and is_binary(href)
end)
|> Map.get(:href)
end
end

View file

@ -7,13 +7,17 @@ defmodule Mobilizon.Web.NodeInfoController do
use Mobilizon.Web, :controller use Mobilizon.Web, :controller
alias Mobilizon.Config alias Mobilizon.Config
alias Mobilizon.Federation.ActivityPub.Relay
alias Mobilizon.Service.Statistics alias Mobilizon.Service.Statistics
@node_info_supported_versions ["2.0", "2.1"] @node_info_supported_versions ["2.0", "2.1"]
@node_info_schema_uri "http://nodeinfo.diaspora.software/ns/schema/" @node_info_schema_uri "http://nodeinfo.diaspora.software/ns/schema/"
@application_uri "https://www.w3.org/ns/activitystreams#Application"
@spec schemas(Plug.Conn.t(), any) :: Plug.Conn.t() @spec schemas(Plug.Conn.t(), any) :: Plug.Conn.t()
def schemas(conn, _params) do def schemas(conn, _params) do
relay = Relay.get_actor()
links = links =
@node_info_supported_versions @node_info_supported_versions
|> Enum.map(fn version -> |> Enum.map(fn version ->
@ -22,6 +26,12 @@ defmodule Mobilizon.Web.NodeInfoController do
href: url(~p"/.well-known/nodeinfo/#{version}") href: url(~p"/.well-known/nodeinfo/#{version}")
} }
end) end)
|> Kernel.++([
%{
rel: @application_uri,
href: relay.url
}
])
json(conn, %{ json(conn, %{
links: links links: links

View file

@ -2,12 +2,16 @@ defmodule Mobilizon.Web.NodeInfoControllerTest do
use Mobilizon.Web.ConnCase use Mobilizon.Web.ConnCase
alias Mobilizon.Config alias Mobilizon.Config
alias Mobilizon.Federation.ActivityPub.Relay
use Mobilizon.Web, :verified_routes use Mobilizon.Web, :verified_routes
test "Get node info schemas", %{conn: conn} do test "Get node info schemas", %{conn: conn} do
conn = get(conn, url(~p"/.well-known/nodeinfo")) conn = get(conn, url(~p"/.well-known/nodeinfo"))
relay = Relay.get_actor()
relay_url = relay.url
assert json_response(conn, 200) == %{ assert json_response(conn, 200) == %{
"links" => [ "links" => [
%{ %{
@ -17,6 +21,10 @@ defmodule Mobilizon.Web.NodeInfoControllerTest do
%{ %{
"href" => url(~p"/.well-known/nodeinfo/2.1"), "href" => url(~p"/.well-known/nodeinfo/2.1"),
"rel" => "http://nodeinfo.diaspora.software/ns/schema/2.1" "rel" => "http://nodeinfo.diaspora.software/ns/schema/2.1"
},
%{
"href" => relay_url,
"rel" => "https://www.w3.org/ns/activitystreams#Application"
} }
] ]
} }