diff options
Diffstat (limited to 'lib/pleroma/web')
-rw-r--r-- | lib/pleroma/web/activity_pub/activity_pub.ex | 13 | ||||
-rw-r--r-- | lib/pleroma/web/activity_pub/activity_pub_controller.ex | 12 | ||||
-rw-r--r-- | lib/pleroma/web/activity_pub/relay.ex | 44 | ||||
-rw-r--r-- | lib/pleroma/web/activity_pub/utils.ex | 27 | ||||
-rw-r--r-- | lib/pleroma/web/activity_pub/views/user_view.ex | 29 | ||||
-rw-r--r-- | lib/pleroma/web/federator/federator.ex | 6 | ||||
-rw-r--r-- | lib/pleroma/web/router.ex | 12 |
7 files changed, 141 insertions, 2 deletions
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 298d7817a..68b398786 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -572,12 +572,23 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do "locked" => locked }, avatar: avatar, - nickname: "#{data["preferredUsername"]}@#{URI.parse(data["id"]).host}", name: data["name"], follower_address: data["followers"], bio: data["summary"] } + # nickname can be nil because of virtual actors + user_data = + if data["preferredUsername"] do + Map.put( + user_data, + :nickname, + "#{data["preferredUsername"]}@#{URI.parse(data["id"]).host}" + ) + else + Map.put(user_data, :nickname, nil) + end + {:ok, user_data} end diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex index d337532d0..52b2a467e 100644 --- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex +++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex @@ -3,6 +3,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do alias Pleroma.{User, Object} alias Pleroma.Web.ActivityPub.{ObjectView, UserView} alias Pleroma.Web.ActivityPub.ActivityPub + alias Pleroma.Web.ActivityPub.Relay alias Pleroma.Web.Federator require Logger @@ -107,6 +108,17 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do json(conn, "ok") end + def relay(conn, params) do + with %User{} = user <- Relay.get_actor(), + {:ok, user} <- Pleroma.Web.WebFinger.ensure_keys_present(user) do + conn + |> put_resp_header("content-type", "application/activity+json") + |> json(UserView.render("user.json", %{user: user})) + else + nil -> {:error, :not_found} + end + end + def errors(conn, {:error, :not_found}) do conn |> put_status(404) diff --git a/lib/pleroma/web/activity_pub/relay.ex b/lib/pleroma/web/activity_pub/relay.ex new file mode 100644 index 000000000..d30853d62 --- /dev/null +++ b/lib/pleroma/web/activity_pub/relay.ex @@ -0,0 +1,44 @@ +defmodule Pleroma.Web.ActivityPub.Relay do + alias Pleroma.{User, Object, Activity} + alias Pleroma.Web.ActivityPub.ActivityPub + require Logger + + def get_actor do + User.get_or_create_instance_user() + end + + def follow(target_instance) do + with %User{} = local_user <- get_actor(), + %User{} = target_user <- User.get_or_fetch_by_ap_id(target_instance), + {:ok, activity} <- ActivityPub.follow(local_user, target_user) do + Logger.info("relay: followed instance: #{target_instance}; id=#{activity.data["id"]}") + else + e -> Logger.error("error: #{inspect(e)}") + end + + :ok + end + + def unfollow(target_instance) do + with %User{} = local_user <- get_actor(), + %User{} = target_user <- User.get_or_fetch_by_ap_id(target_instance), + {:ok, activity} <- ActivityPub.unfollow(local_user, target_user) do + Logger.info("relay: unfollowed instance: #{target_instance}: id=#{activity.data["id"]}") + else + e -> Logger.error("error: #{inspect(e)}") + end + + :ok + end + + def publish(%Activity{data: %{"type" => "Create"}} = activity) do + with %User{} = user <- get_actor(), + %Object{} = object <- Object.normalize(activity.data["object"]["id"]) do + ActivityPub.announce(user, object) + else + e -> Logger.error("error: #{inspect(e)}") + end + end + + def publish(_), do: nil +end diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 7cdc1656b..0664b5a2e 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -306,6 +306,24 @@ defmodule Pleroma.Web.ActivityPub.Utils do @doc """ Make announce activity data for the given actor and object """ + # for relayed messages, we only want to send to subscribers + def make_announce_data( + %User{ap_id: ap_id, nickname: nil} = user, + %Object{data: %{"id" => id}} = object, + activity_id + ) do + data = %{ + "type" => "Announce", + "actor" => ap_id, + "object" => id, + "to" => [user.follower_address], + "cc" => [], + "context" => object.data["context"] + } + + if activity_id, do: Map.put(data, "id", activity_id), else: data + end + def make_announce_data( %User{ap_id: ap_id} = user, %Object{data: %{"id" => id}} = object, @@ -360,7 +378,12 @@ defmodule Pleroma.Web.ActivityPub.Utils do if activity_id, do: Map.put(data, "id", activity_id), else: data end - def add_announce_to_object(%Activity{data: %{"actor" => actor}}, object) do + def add_announce_to_object( + %Activity{ + data: %{"actor" => actor, "cc" => ["https://www.w3.org/ns/activitystreams#Public"]} + }, + object + ) do announcements = if is_list(object.data["announcements"]), do: object.data["announcements"], else: [] @@ -369,6 +392,8 @@ defmodule Pleroma.Web.ActivityPub.Utils do end end + def add_announce_to_object(_, object), do: {:ok, object} + def remove_announce_from_object(%Activity{data: %{"actor" => actor}}, object) do announcements = if is_list(object.data["announcements"]), do: object.data["announcements"], else: [] diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex index fc76f2940..16419e1b7 100644 --- a/lib/pleroma/web/activity_pub/views/user_view.ex +++ b/lib/pleroma/web/activity_pub/views/user_view.ex @@ -9,6 +9,35 @@ defmodule Pleroma.Web.ActivityPub.UserView do alias Pleroma.Web.ActivityPub.Utils import Ecto.Query + # the instance itself is not a Person, but instead an Application + def render("user.json", %{user: %{nickname: nil} = user}) do + {:ok, user} = WebFinger.ensure_keys_present(user) + {:ok, _, public_key} = Salmon.keys_from_pem(user.info["keys"]) + public_key = :public_key.pem_entry_encode(:SubjectPublicKeyInfo, public_key) + public_key = :public_key.pem_encode([public_key]) + + %{ + "@context" => "https://www.w3.org/ns/activitystreams", + "id" => user.ap_id, + "type" => "Application", + "following" => "#{user.ap_id}/following", + "followers" => "#{user.ap_id}/followers", + "inbox" => "#{user.ap_id}/inbox", + "name" => "Pleroma", + "summary" => "Virtual actor for Pleroma relay", + "url" => user.ap_id, + "manuallyApprovesFollowers" => false, + "publicKey" => %{ + "id" => "#{user.ap_id}#main-key", + "owner" => user.ap_id, + "publicKeyPem" => public_key + }, + "endpoints" => %{ + "sharedInbox" => "#{Pleroma.Web.Endpoint.url()}/inbox" + } + } + end + def render("user.json", %{user: user}) do {:ok, user} = WebFinger.ensure_keys_present(user) {:ok, _, public_key} = Salmon.keys_from_pem(user.info["keys"]) diff --git a/lib/pleroma/web/federator/federator.ex b/lib/pleroma/web/federator/federator.ex index ccefb0bdf..078f3ec11 100644 --- a/lib/pleroma/web/federator/federator.ex +++ b/lib/pleroma/web/federator/federator.ex @@ -4,6 +4,7 @@ defmodule Pleroma.Web.Federator do alias Pleroma.Activity alias Pleroma.Web.{WebFinger, Websub} alias Pleroma.Web.ActivityPub.ActivityPub + alias Pleroma.Web.ActivityPub.Relay alias Pleroma.Web.ActivityPub.Transmogrifier alias Pleroma.Web.ActivityPub.Utils require Logger @@ -69,6 +70,11 @@ defmodule Pleroma.Web.Federator do Logger.info(fn -> "Sending #{activity.data["id"]} out via Salmon" end) Pleroma.Web.Salmon.publish(actor, activity) + + if Mix.env() != :test do + Logger.info(fn -> "Relaying #{activity.data["id"]} out" end) + Pleroma.Web.ActivityPub.Relay.publish(activity) + end end Logger.info(fn -> "Sending #{activity.data["id"]} out via AP" end) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 68e159f6a..927323794 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -5,6 +5,7 @@ defmodule Pleroma.Web.Router do @instance Application.get_env(:pleroma, :instance) @federating Keyword.get(@instance, :federating) + @allow_relay Keyword.get(@instance, :allow_relay) @public Keyword.get(@instance, :public) @registrations_open Keyword.get(@instance, :registrations_open) @@ -293,6 +294,10 @@ defmodule Pleroma.Web.Router do get("/externalprofile/show", TwitterAPI.Controller, :external_profile) end + pipeline :ap_relay do + plug(:accepts, ["activity+json"]) + end + pipeline :ostatus do plug(:accepts, ["xml", "atom", "html", "activity+json"]) end @@ -329,6 +334,13 @@ defmodule Pleroma.Web.Router do end if @federating do + if @allow_relay do + scope "/relay", Pleroma.Web.ActivityPub do + pipe_through(:ap_relay) + get("/", ActivityPubController, :relay) + end + end + scope "/", Pleroma.Web.ActivityPub do pipe_through(:activitypub) post("/users/:nickname/inbox", ActivityPubController, :inbox) |