diff --git a/lib/mix/tasks/pleroma/relay.ex b/lib/mix/tasks/pleroma/relay.ex index c6ca888d4..c3312507e 100644 --- a/lib/mix/tasks/pleroma/relay.ex +++ b/lib/mix/tasks/pleroma/relay.ex @@ -35,7 +35,7 @@ defmodule Mix.Tasks.Pleroma.Relay do def run(["list"]) do start_pleroma() - with {:ok, list} <- Relay.list() do + with {:ok, list} <- Relay.list(true) do list |> Enum.each(&shell_info(&1)) else {:error, e} -> shell_error("Error while fetching relay subscription list: #{inspect(e)}") diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index 397eb6e3f..6ca05f74e 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -308,6 +308,13 @@ defmodule Pleroma.Activity do |> where([a], fragment("? ->> 'state' = 'pending'", a.data)) end + def following_requests_for_actor(%Pleroma.User{ap_id: ap_id}) do + Queries.by_type("Follow") + |> where([a], fragment("?->>'state' = 'pending'", a.data)) + |> where([a], a.actor == ^ap_id) + |> Repo.all() + end + def restrict_deactivated_users(query) do deactivated_users = from(u in User.Query.build(%{deactivated: true}), select: u.ap_id) diff --git a/lib/pleroma/web/activity_pub/relay.ex b/lib/pleroma/web/activity_pub/relay.ex index bb5542c89..729c23af7 100644 --- a/lib/pleroma/web/activity_pub/relay.ex +++ b/lib/pleroma/web/activity_pub/relay.ex @@ -60,15 +60,28 @@ defmodule Pleroma.Web.ActivityPub.Relay do def publish(_), do: {:error, "Not implemented"} - @spec list() :: {:ok, [String.t()]} | {:error, any()} - def list do + @spec list(boolean()) :: {:ok, [String.t()]} | {:error, any()} + def list(with_not_accepted \\ false) do with %User{} = user <- get_actor() do - list = + accepted = user |> User.following() |> Enum.map(fn entry -> URI.parse(entry).host end) |> Enum.uniq() + list = + if with_not_accepted do + without_accept = + user + |> Pleroma.Activity.following_requests_for_actor() + |> Enum.map(fn a -> URI.parse(a.data["object"]).host <> " (no Accept received)" end) + |> Enum.uniq() + + accepted ++ without_accept + else + accepted + end + {:ok, list} else error -> format_error(error) diff --git a/test/fixtures/relay/accept-follow.json b/test/fixtures/relay/accept-follow.json new file mode 100644 index 000000000..1b166f2da --- /dev/null +++ b/test/fixtures/relay/accept-follow.json @@ -0,0 +1,15 @@ +{ + "@context": "https://www.w3.org/ns/activitystreams", + "actor": "https://relay.mastodon.host/actor", + "id": "https://relay.mastodon.host/activities/ec477b69-db26-4019-923e-cf809de516ab", + "object": { + "actor": "{{ap_id}}", + "id": "{{activity_id}}", + "object": "https://relay.mastodon.host/actor", + "type": "Follow" + }, + "to": [ + "{{ap_id}}" + ], + "type": "Accept" +} \ No newline at end of file diff --git a/test/fixtures/relay/relay.json b/test/fixtures/relay/relay.json new file mode 100644 index 000000000..77ae7f06c --- /dev/null +++ b/test/fixtures/relay/relay.json @@ -0,0 +1,20 @@ +{ + "@context": "https://www.w3.org/ns/activitystreams", + "endpoints": { + "sharedInbox": "https://relay.mastodon.host/inbox" + }, + "followers": "https://relay.mastodon.host/followers", + "following": "https://relay.mastodon.host/following", + "inbox": "https://relay.mastodon.host/inbox", + "name": "ActivityRelay", + "type": "Application", + "id": "https://relay.mastodon.host/actor", + "publicKey": { + "id": "https://relay.mastodon.host/actor#main-key", + "owner": "https://relay.mastodon.host/actor", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAuNYHNYETdsZFsdcTTEQo\nlsTP9yz4ZjOGrQ1EjoBA7NkjBUxxUAPxZbBjWPT9F+L3IbCX1IwI2OrBM/KwDlug\nV41xnjNmxSCUNpxX5IMZtFaAz9/hWu6xkRTs9Bh6XWZxi+db905aOqszb9Mo3H2g\nQJiAYemXwTh2kBO7XlBDbsMhO11Tu8FxcWTMdR54vlGv4RoiVh8dJRa06yyiTs+m\njbj/OJwR06mHHwlKYTVT/587NUb+e9QtCK6t/dqpyZ1o7vKSK5PSldZVjwHt292E\nXVxFOQVXi7JazTwpdPww79ECSe8ThCykOYCNkm3RjsKuLuokp7Vzq1hXIoeBJ7z2\ndU8vbgg/JyazsOsTxkVs2nd2i9/QW2SH+sX9X3357+XLSCh/A8p8fv/GeoN7UCXe\n4DWHFJZDlItNFfymiPbQH+omuju8qrfW9ngk1gFeI2mahXFQVu7x0qsaZYioCIrZ\nwq0zPnUGl9u0tLUXQz+ZkInRrEz+JepDVauy5/3QdzMLG420zCj/ygDrFzpBQIrc\n62Z6URueUBJox0UK71K+usxqOrepgw8haFGMvg3STFo34pNYjoK4oKO+h5qZEDFD\nb1n57t6JWUaBocZbJns9RGASq5gih+iMk2+zPLWp1x64yvuLsYVLPLBHxjCxS6lA\ndWcopZHi7R/OsRz+vTT7420CAwEAAQ==\n-----END PUBLIC KEY-----" + }, + "summary": "ActivityRelay bot", + "preferredUsername": "relay", + "url": "https://relay.mastodon.host/actor" +} \ No newline at end of file diff --git a/test/support/http_request_mock.ex b/test/support/http_request_mock.ex index d46887865..e72638814 100644 --- a/test/support/http_request_mock.ex +++ b/test/support/http_request_mock.ex @@ -1277,6 +1277,10 @@ defmodule HttpRequestMock do {:ok, %Tesla.Env{status: 404, body: ""}} end + def get("https://relay.mastodon.host/actor", _, _, _) do + {:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/relay/relay.json")}} + end + def get(url, query, body, headers) do {:error, "Mock response not implemented for GET #{inspect(url)}, #{query}, #{inspect(body)}, #{ @@ -1289,6 +1293,10 @@ defmodule HttpRequestMock do def post(url, query \\ [], body \\ [], headers \\ []) + def post("https://relay.mastodon.host/inbox", _, _, _) do + {:ok, %Tesla.Env{status: 200, body: ""}} + end + def post("http://example.org/needs_refresh", _, _, _) do {:ok, %Tesla.Env{ diff --git a/test/tasks/relay_test.exs b/test/tasks/relay_test.exs index 08855f245..d3d88467d 100644 --- a/test/tasks/relay_test.exs +++ b/test/tasks/relay_test.exs @@ -38,6 +38,9 @@ defmodule Mix.Tasks.Pleroma.RelayTest do assert activity.data["type"] == "Follow" assert activity.data["actor"] == local_user.ap_id assert activity.data["object"] == target_user.ap_id + + :ok = Mix.Tasks.Pleroma.Relay.run(["list"]) + assert_receive {:mix_shell, :info, ["mastodon.example.org (no Accept received)"]} end end diff --git a/test/web/activity_pub/activity_pub_controller_test.exs b/test/web/activity_pub/activity_pub_controller_test.exs index 9151034da..b2352538a 100644 --- a/test/web/activity_pub/activity_pub_controller_test.exs +++ b/test/web/activity_pub/activity_pub_controller_test.exs @@ -341,6 +341,44 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do assert "ok" == json_response(conn, 200) assert Instances.reachable?(sender_url) end + + test "accept follow activity", %{conn: conn} do + Pleroma.Config.put([:instance, :federating], true) + relay = Relay.get_actor() + + assert {:ok, %Activity{} = activity} = Relay.follow("https://relay.mastodon.host/actor") + + followed_relay = Pleroma.User.get_by_ap_id("https://relay.mastodon.host/actor") + relay = refresh_record(relay) + + accept = + File.read!("test/fixtures/relay/accept-follow.json") + |> String.replace("{{ap_id}}", relay.ap_id) + |> String.replace("{{activity_id}}", activity.data["id"]) + + assert "ok" == + conn + |> assign(:valid_signature, true) + |> put_req_header("content-type", "application/activity+json") + |> post("/inbox", accept) + |> json_response(200) + + ObanHelpers.perform(all_enqueued(worker: ReceiverWorker)) + + assert Pleroma.FollowingRelationship.following?( + relay, + followed_relay + ) + + Mix.shell(Mix.Shell.Process) + + on_exit(fn -> + Mix.shell(Mix.Shell.IO) + end) + + :ok = Mix.Tasks.Pleroma.Relay.run(["list"]) + assert_receive {:mix_shell, :info, ["relay.mastodon.host"]} + end end describe "/users/:nickname/inbox" do