From 4807a52284250e1663da0ba31c57a0c05861b797 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Mon, 6 Aug 2018 05:46:37 +0000 Subject: [PATCH 01/22] user: support creating an actor which represents the instance itself --- lib/pleroma/user.ex | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index df22d29a8..640c34aec 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -637,6 +637,22 @@ def get_or_fetch_by_ap_id(ap_id) do end end + def get_or_create_instance_user do + if user = get_by_ap_id(Pleroma.Web.Endpoint.url()) do + user + else + changes = + %User{} + |> cast(%{}, [:ap_id, :nickname, :local]) + |> put_change(:ap_id, Pleroma.Web.Endpoint.url()) + |> put_change(:nickname, nil) + |> put_change(:local, true) + + {:ok, user} = Repo.insert(changes) + user + end + end + # AP style def public_key_from_info(%{ "source_data" => %{"publicKey" => %{"publicKeyPem" => public_key_pem}} From 00e890264c10b21d780c0106d29e42c507df1cbb Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Mon, 6 Aug 2018 06:11:51 +0000 Subject: [PATCH 02/22] activitypub: represent relay actor at instance root --- .../activity_pub/activity_pub_controller.ex | 11 ++++++++ .../web/activity_pub/views/user_view.ex | 27 +++++++++++++++++++ lib/pleroma/web/router.ex | 6 +++++ 3 files changed, 44 insertions(+) diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex index d337532d0..a858b5df9 100644 --- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex +++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex @@ -107,6 +107,17 @@ def inbox(conn, params) do json(conn, "ok") end + def relay(conn, params) do + with %User{} = user <- User.get_or_create_instance_user(), + {: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/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex index 41bfe5048..52f09fcd5 100644 --- a/lib/pleroma/web/activity_pub/views/user_view.ex +++ b/lib/pleroma/web/activity_pub/views/user_view.ex @@ -9,6 +9,33 @@ 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", + "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/router.ex b/lib/pleroma/web/router.ex index fc7a947aa..1f9bccf55 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -318,6 +318,12 @@ def user_fetcher(username) do end if @federating do + scope "/", Pleroma.Web.ActivityPub do + # XXX: not really ostatus either + pipe_through(:ostatus) + get("/", ActivityPubController, :relay) + end + scope "/", Pleroma.Web.ActivityPub do pipe_through(:activitypub) post("/users/:nickname/inbox", ActivityPubController, :inbox) From b7ca7f282ac43fcbda63c822553497baa0009835 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Mon, 6 Aug 2018 06:15:22 +0000 Subject: [PATCH 03/22] activitypub: refactor relay concerns into new relay module --- lib/pleroma/web/activity_pub/activity_pub_controller.ex | 3 ++- lib/pleroma/web/activity_pub/relay.ex | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 lib/pleroma/web/activity_pub/relay.ex diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex index a858b5df9..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 @@ -108,7 +109,7 @@ def inbox(conn, params) do end def relay(conn, params) do - with %User{} = user <- User.get_or_create_instance_user(), + 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") diff --git a/lib/pleroma/web/activity_pub/relay.ex b/lib/pleroma/web/activity_pub/relay.ex new file mode 100644 index 000000000..736d0e406 --- /dev/null +++ b/lib/pleroma/web/activity_pub/relay.ex @@ -0,0 +1,7 @@ +defmodule Pleroma.Web.ActivityPub.Relay do + alias Pleroma.User + + def get_actor do + User.get_or_create_instance_user() + end +end From 7bed350a23c8028d279214f1a0b1c344300af133 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Mon, 6 Aug 2018 06:18:15 +0000 Subject: [PATCH 04/22] config: allow relaying to be disabled --- config/config.exs | 1 + lib/pleroma/web/router.ex | 11 +++++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/config/config.exs b/config/config.exs index 3a7301348..f3102aea3 100644 --- a/config/config.exs +++ b/config/config.exs @@ -59,6 +59,7 @@ upload_limit: 16_000_000, registrations_open: true, federating: true, + allow_relay: true, rewrite_policy: Pleroma.Web.ActivityPub.MRF.NoOpPolicy, public: true, quarantined_instances: [] diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 1f9bccf55..fc9d2d988 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) @@ -318,10 +319,12 @@ def user_fetcher(username) do end if @federating do - scope "/", Pleroma.Web.ActivityPub do - # XXX: not really ostatus either - pipe_through(:ostatus) - get("/", ActivityPubController, :relay) + if @allow_relay do + scope "/", Pleroma.Web.ActivityPub do + # XXX: not really ostatus either + pipe_through(:ostatus) + get("/", ActivityPubController, :relay) + end end scope "/", Pleroma.Web.ActivityPub do From 1c90f88393c10198f34aa3a19f09169bcddeeac3 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Mon, 6 Aug 2018 06:50:18 +0000 Subject: [PATCH 05/22] user: remote actors can have no nickname if they are virtual services --- lib/pleroma/user.ex | 2 +- lib/pleroma/web/activity_pub/activity_pub.ex | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 640c34aec..82a2a7833 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -77,7 +77,7 @@ def remote_user_creation(params) do changes = %User{} |> cast(params, [:bio, :name, :ap_id, :nickname, :info, :avatar]) - |> validate_required([:name, :ap_id, :nickname]) + |> validate_required([:name, :ap_id]) |> unique_constraint(:nickname) |> validate_format(:nickname, @email_regex) |> validate_length(:bio, max: 5000) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index ec605b694..bab272323 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -554,12 +554,19 @@ def user_data_from_user_object(data) 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 From 99be3d3dccbbd7877192c6291bbaae92f66e06bf Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Mon, 6 Aug 2018 07:14:16 +0000 Subject: [PATCH 06/22] relay: add relay follow/unfollow tasks --- lib/mix/tasks/relay_follow.ex | 12 ++++++++++++ lib/mix/tasks/relay_unfollow.ex | 12 ++++++++++++ lib/pleroma/web/activity_pub/relay.ex | 28 +++++++++++++++++++++++++++ 3 files changed, 52 insertions(+) create mode 100644 lib/mix/tasks/relay_follow.ex create mode 100644 lib/mix/tasks/relay_unfollow.ex diff --git a/lib/mix/tasks/relay_follow.ex b/lib/mix/tasks/relay_follow.ex new file mode 100644 index 000000000..a8152d96f --- /dev/null +++ b/lib/mix/tasks/relay_follow.ex @@ -0,0 +1,12 @@ +defmodule Mix.Tasks.RelayFollow do + use Mix.Task + require Logger + alias Pleroma.Web.ActivityPub.Relay + + @shortdoc "Follows a remote relay" + def run([target]) do + Mix.Task.run("app.start") + + :ok = Relay.follow(target) + end +end diff --git a/lib/mix/tasks/relay_unfollow.ex b/lib/mix/tasks/relay_unfollow.ex new file mode 100644 index 000000000..81b7197b2 --- /dev/null +++ b/lib/mix/tasks/relay_unfollow.ex @@ -0,0 +1,12 @@ +defmodule Mix.Tasks.RelayUnfollow do + use Mix.Task + require Logger + alias Pleroma.Web.ActivityPub.Relay + + @shortdoc "Follows a remote relay" + def run([target]) do + Mix.Task.run("app.start") + + :ok = Relay.unfollow(target) + end +end diff --git a/lib/pleroma/web/activity_pub/relay.ex b/lib/pleroma/web/activity_pub/relay.ex index 736d0e406..8b49188fb 100644 --- a/lib/pleroma/web/activity_pub/relay.ex +++ b/lib/pleroma/web/activity_pub/relay.ex @@ -1,7 +1,35 @@ defmodule Pleroma.Web.ActivityPub.Relay do alias Pleroma.User + 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 + ActivityPub.publish(local_user, activity) + 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 + ActivityPub.publish(local_user, activity) + Logger.info("relay: unfollowed instance: #{target_instance}: id=#{activity.data["id"]}") + else + e -> Logger.error("error: #{inspect(e)}") + end + + :ok + end end From 266b3140519eacc6c0adaccd959e2f3167e1fc13 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Mon, 6 Aug 2018 07:27:11 +0000 Subject: [PATCH 07/22] relay: fix invoking federator, use a timer to sleep the mix task to force a context switch --- lib/mix/tasks/relay_follow.ex | 3 +++ lib/mix/tasks/relay_unfollow.ex | 3 +++ lib/pleroma/web/activity_pub/relay.ex | 2 -- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/mix/tasks/relay_follow.ex b/lib/mix/tasks/relay_follow.ex index a8152d96f..ac6f20924 100644 --- a/lib/mix/tasks/relay_follow.ex +++ b/lib/mix/tasks/relay_follow.ex @@ -8,5 +8,8 @@ def run([target]) do Mix.Task.run("app.start") :ok = Relay.follow(target) + + # put this task to sleep to allow the genserver to push out the messages + :timer.sleep(500) end end diff --git a/lib/mix/tasks/relay_unfollow.ex b/lib/mix/tasks/relay_unfollow.ex index 81b7197b2..4621ace83 100644 --- a/lib/mix/tasks/relay_unfollow.ex +++ b/lib/mix/tasks/relay_unfollow.ex @@ -8,5 +8,8 @@ def run([target]) do Mix.Task.run("app.start") :ok = Relay.unfollow(target) + + # put this task to sleep to allow the genserver to push out the messages + :timer.sleep(500) end end diff --git a/lib/pleroma/web/activity_pub/relay.ex b/lib/pleroma/web/activity_pub/relay.ex index 8b49188fb..29ece7f1b 100644 --- a/lib/pleroma/web/activity_pub/relay.ex +++ b/lib/pleroma/web/activity_pub/relay.ex @@ -11,7 +11,6 @@ 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 - ActivityPub.publish(local_user, activity) Logger.info("relay: followed instance: #{target_instance}; id=#{activity.data["id"]}") else e -> Logger.error("error: #{inspect(e)}") @@ -24,7 +23,6 @@ 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 - ActivityPub.publish(local_user, activity) Logger.info("relay: unfollowed instance: #{target_instance}: id=#{activity.data["id"]}") else e -> Logger.error("error: #{inspect(e)}") From f9b0fc4ddb84a064e2da927a6a00ddc5ad23c5ee Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Mon, 6 Aug 2018 07:34:39 +0000 Subject: [PATCH 08/22] relay: remove @allow_relay for the moment --- lib/pleroma/web/router.ex | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index fc9d2d988..3cb996262 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -319,12 +319,10 @@ def user_fetcher(username) do end if @federating do - if @allow_relay do - scope "/", Pleroma.Web.ActivityPub do - # XXX: not really ostatus either - pipe_through(:ostatus) - get("/", ActivityPubController, :relay) - end + scope "/", Pleroma.Web.ActivityPub do + # XXX: not really ostatus either + pipe_through(:ostatus) + get("/", ActivityPubController, :relay) end scope "/", Pleroma.Web.ActivityPub do From 1c40a631e809ed7ab7bdd0ef46ff97a124b858e8 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Mon, 6 Aug 2018 07:43:37 +0000 Subject: [PATCH 09/22] federator: actually relay the public activities --- lib/pleroma/web/activity_pub/relay.ex | 11 ++++++++++- lib/pleroma/web/federator/federator.ex | 4 ++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/web/activity_pub/relay.ex b/lib/pleroma/web/activity_pub/relay.ex index 29ece7f1b..f5cf8b7f5 100644 --- a/lib/pleroma/web/activity_pub/relay.ex +++ b/lib/pleroma/web/activity_pub/relay.ex @@ -1,5 +1,5 @@ defmodule Pleroma.Web.ActivityPub.Relay do - alias Pleroma.User + alias Pleroma.{User, Object} alias Pleroma.Web.ActivityPub.ActivityPub require Logger @@ -30,4 +30,13 @@ def unfollow(target_instance) do :ok end + + def publish(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 end diff --git a/lib/pleroma/web/federator/federator.ex b/lib/pleroma/web/federator/federator.ex index ccefb0bdf..94e3979be 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,9 @@ def handle(:publish, activity) do Logger.info(fn -> "Sending #{activity.data["id"]} out via Salmon" end) Pleroma.Web.Salmon.publish(actor, activity) + + Logger.info(fn -> "Relaying #{activity.data["id"]} out" end) + Pleroma.Web.ActivityPub.Relay.publish(activity) end Logger.info(fn -> "Sending #{activity.data["id"]} out via AP" end) From 56dc8db58212940cf81f159f4c4730211fef38b9 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Mon, 6 Aug 2018 07:48:08 +0000 Subject: [PATCH 10/22] activitypub: relay: add relay following/followers collection URLs --- lib/pleroma/web/activity_pub/views/user_view.ex | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex index 52f09fcd5..adfbcab49 100644 --- a/lib/pleroma/web/activity_pub/views/user_view.ex +++ b/lib/pleroma/web/activity_pub/views/user_view.ex @@ -20,6 +20,8 @@ def render("user.json", %{user: %{nickname: nil} = user}) do "@context" => "https://www.w3.org/ns/activitystreams", "id" => user.ap_id, "type" => "Application", + "following" => "#{user.ap_id}/relay/following", + "followers" => "#{user.ap_id}/relay/followers", "inbox" => "#{user.ap_id}/inbox", "name" => "Pleroma", "summary" => "Virtual actor for Pleroma relay", From ae3cb652b6d75bc58e0fac3333d5820d8c335f48 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Mon, 6 Aug 2018 08:03:00 +0000 Subject: [PATCH 11/22] user: set up a valid followers address to use --- lib/pleroma/user.ex | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 82a2a7833..327eb3ea3 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -647,6 +647,7 @@ def get_or_create_instance_user do |> put_change(:ap_id, Pleroma.Web.Endpoint.url()) |> put_change(:nickname, nil) |> put_change(:local, true) + |> put_change(:follower_address, Pleroma.Web.Endpoint.url() <> "/relay/followers") {:ok, user} = Repo.insert(changes) user From 2b628f23410edc310d10e692ae0502136e999fd3 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Mon, 6 Aug 2018 08:03:10 +0000 Subject: [PATCH 12/22] relay: only relay create activities --- lib/pleroma/web/activity_pub/relay.ex | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/pleroma/web/activity_pub/relay.ex b/lib/pleroma/web/activity_pub/relay.ex index f5cf8b7f5..d30853d62 100644 --- a/lib/pleroma/web/activity_pub/relay.ex +++ b/lib/pleroma/web/activity_pub/relay.ex @@ -1,5 +1,5 @@ defmodule Pleroma.Web.ActivityPub.Relay do - alias Pleroma.{User, Object} + alias Pleroma.{User, Object, Activity} alias Pleroma.Web.ActivityPub.ActivityPub require Logger @@ -31,7 +31,7 @@ def unfollow(target_instance) do :ok end - def publish(activity) do + 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) @@ -39,4 +39,6 @@ def publish(activity) do e -> Logger.error("error: #{inspect(e)}") end end + + def publish(_), do: nil end From e49131bb7212ba5d1b79fc20c83223325a2e98c4 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Mon, 6 Aug 2018 08:13:05 +0000 Subject: [PATCH 13/22] relay: move to /relay endpoint from / due to webapp issues --- lib/pleroma/user.ex | 8 +++++--- lib/pleroma/web/router.ex | 9 ++++++--- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 327eb3ea3..8d8c53dfc 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -638,16 +638,18 @@ def get_or_fetch_by_ap_id(ap_id) do end def get_or_create_instance_user do - if user = get_by_ap_id(Pleroma.Web.Endpoint.url()) do + relay_uri = "#{Pleroma.Web.Endpoint.url()}/relay" + + if user = get_by_ap_id(relay_uri) do user else changes = %User{} |> cast(%{}, [:ap_id, :nickname, :local]) - |> put_change(:ap_id, Pleroma.Web.Endpoint.url()) + |> put_change(:ap_id, relay_uri) |> put_change(:nickname, nil) |> put_change(:local, true) - |> put_change(:follower_address, Pleroma.Web.Endpoint.url() <> "/relay/followers") + |> put_change(:follower_address, relay_uri <> "/followers") {:ok, user} = Repo.insert(changes) user diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 3cb996262..48c3fb9a5 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -283,6 +283,10 @@ def user_fetcher(username) 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 @@ -319,9 +323,8 @@ def user_fetcher(username) do end if @federating do - scope "/", Pleroma.Web.ActivityPub do - # XXX: not really ostatus either - pipe_through(:ostatus) + scope "/relay", Pleroma.Web.ActivityPub do + pipe_through(:ap_relay) get("/", ActivityPubController, :relay) end From 1e1a29f084967586b412425a868240240ac833b8 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Mon, 6 Aug 2018 08:15:18 +0000 Subject: [PATCH 14/22] activitypub: relay: fix up AS2 actor object --- lib/pleroma/web/activity_pub/views/user_view.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex index adfbcab49..6ecb8862e 100644 --- a/lib/pleroma/web/activity_pub/views/user_view.ex +++ b/lib/pleroma/web/activity_pub/views/user_view.ex @@ -20,8 +20,8 @@ def render("user.json", %{user: %{nickname: nil} = user}) do "@context" => "https://www.w3.org/ns/activitystreams", "id" => user.ap_id, "type" => "Application", - "following" => "#{user.ap_id}/relay/following", - "followers" => "#{user.ap_id}/relay/followers", + "following" => "#{user.ap_id}/following", + "followers" => "#{user.ap_id}/followers", "inbox" => "#{user.ap_id}/inbox", "name" => "Pleroma", "summary" => "Virtual actor for Pleroma relay", From 5abf9ad6025eb7464deee7fb5a77e651272f44a1 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Mon, 6 Aug 2018 08:20:21 +0000 Subject: [PATCH 15/22] relay: reintroduce @allow_relay --- lib/pleroma/web/router.ex | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 48c3fb9a5..eb9860864 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -323,9 +323,11 @@ def user_fetcher(username) do end if @federating do - scope "/relay", Pleroma.Web.ActivityPub do - pipe_through(:ap_relay) - get("/", ActivityPubController, :relay) + if @allow_relay do + scope "/relay", Pleroma.Web.ActivityPub do + pipe_through(:ap_relay) + get("/", ActivityPubController, :relay) + end end scope "/", Pleroma.Web.ActivityPub do From 0ca9b9ff964f7a64a2225056991068320e085d62 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Mon, 6 Aug 2018 08:26:36 +0000 Subject: [PATCH 16/22] run mix format --- lib/pleroma/web/activity_pub/activity_pub.ex | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index bab272323..a07bf1629 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -562,7 +562,11 @@ def user_data_from_user_object(data) do # 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}") + Map.put( + user_data, + :nickname, + "#{data["preferredUsername"]}@#{URI.parse(data["id"]).host}" + ) else Map.put(user_data, :nickname, nil) end From 5202d4ce107d00866e6cb284b4c2a2614154a489 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Mon, 6 Aug 2018 08:35:56 +0000 Subject: [PATCH 17/22] relay: do not relay in test mode --- lib/pleroma/web/federator/federator.ex | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/pleroma/web/federator/federator.ex b/lib/pleroma/web/federator/federator.ex index 94e3979be..078f3ec11 100644 --- a/lib/pleroma/web/federator/federator.ex +++ b/lib/pleroma/web/federator/federator.ex @@ -71,8 +71,10 @@ def handle(:publish, activity) do Logger.info(fn -> "Sending #{activity.data["id"]} out via Salmon" end) Pleroma.Web.Salmon.publish(actor, activity) - Logger.info(fn -> "Relaying #{activity.data["id"]} out" end) - Pleroma.Web.ActivityPub.Relay.publish(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) From aea23468c60eec90468d4812cbbb4d9f7e85cb11 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Mon, 6 Aug 2018 08:46:06 +0000 Subject: [PATCH 18/22] test: nickname is no longer a required field --- test/user_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/user_test.exs b/test/user_test.exs index 352a16687..5c61b0930 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -220,7 +220,7 @@ test "it enforces the fqn format for nicknames" do end test "it has required fields" do - [:name, :nickname, :ap_id] + [:name, :ap_id] |> Enum.each(fn field -> cs = User.remote_user_creation(Map.delete(@valid_remote, field)) refute cs.valid? From de6be63b1be19bffd17e374f16983934034f7b74 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Mon, 6 Aug 2018 10:37:52 +0000 Subject: [PATCH 19/22] activitypub: do not show observable effects of non-public boosts --- lib/pleroma/web/activity_pub/utils.ex | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 8b41a3bec..a2e5c5002 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -302,6 +302,24 @@ def get_existing_announce(actor, %{data: %{"id" => id}}) 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, @@ -356,12 +374,19 @@ def make_unlike_data( 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 with announcements <- [actor | object.data["announcements"] || []] |> Enum.uniq() do update_element_in_object("announcement", announcements, object) end end + def add_announce_to_object(_, object), do: {:ok, object} + def remove_announce_from_object(%Activity{data: %{"actor" => actor}}, object) do with announcements <- (object.data["announcements"] || []) |> List.delete(actor) do update_element_in_object("announcement", announcements, object) From ecfd4b21066f7df7450d5aace403ac97c0d7778a Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Mon, 6 Aug 2018 10:44:25 +0000 Subject: [PATCH 20/22] user: hide virtual actors from statistics queries --- lib/pleroma/user.ex | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 8d8c53dfc..5e46208c3 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -578,7 +578,11 @@ def unblock_domain(user, domain) do end def local_user_query() do - from(u in User, where: u.local == true) + from( + u in User, + where: u.local == true, + where: not is_nil(u.nickname) + ) end def deactivate(%User{} = user) do From d91fd48edf8241c5d0b7dc61c36fa2c3e8c1ccd4 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Mon, 6 Aug 2018 10:57:19 +0000 Subject: [PATCH 21/22] user: do not leak virtuals in account search --- lib/pleroma/user.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 5e46208c3..748fdbca4 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -499,7 +499,8 @@ def search(query, resolve) do u.nickname, u.name ) - } + }, + where: not is_nil(u.nickname) ) q = From 30261772063a30ca0ef299f441cfed4630ffb630 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Mon, 6 Aug 2018 11:10:49 +0000 Subject: [PATCH 22/22] test: use private visibility for twitterapi update consistency test, to ensure that a second activity isn't relayed --- test/web/twitter_api/twitter_api_controller_test.exs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs index 3a035e298..87bcdaf71 100644 --- a/test/web/twitter_api/twitter_api_controller_test.exs +++ b/test/web/twitter_api/twitter_api_controller_test.exs @@ -77,7 +77,8 @@ test "with credentials", %{conn: conn, user: user} do conn = conn_with_creds |> post(request_path, %{status: " "}) assert json_response(conn, 400) == error_response - conn = conn_with_creds |> post(request_path, %{status: "Nice meme."}) + # we post with visibility private in order to avoid triggering relay + conn = conn_with_creds |> post(request_path, %{status: "Nice meme.", visibility: "private"}) assert json_response(conn, 200) == ActivityRepresenter.to_map(Repo.one(Activity), %{user: user})