diff options
Diffstat (limited to 'lib/pleroma/web/activity_pub')
-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 |
5 files changed, 123 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"]) |