[#534] Federation reachability filtering tests.
authorIvan Tashkinov <ivantashkinov@gmail.com>
Fri, 25 Jan 2019 17:38:54 +0000 (20:38 +0300)
committerIvan Tashkinov <ivantashkinov@gmail.com>
Fri, 25 Jan 2019 17:38:54 +0000 (20:38 +0300)
test/support/factory.ex
test/web/activity_pub/activity_pub_controller_test.exs
test/web/federator_test.exs
test/web/ostatus/ostatus_controller_test.exs
test/web/websub/websub_controller_test.exs

index 4ac77981a76de3d021cf4738ca060c3f0d889ac0..964b2b61c6b8354cfebf2c5ae5bb832dee819e37 100644 (file)
@@ -193,7 +193,7 @@ defmodule Pleroma.Factory do
   def websub_subscription_factory do
     %Pleroma.Web.Websub.WebsubServerSubscription{
       topic: "http://example.org",
-      callback: "http://example/org/callback",
+      callback: "http://example.org/callback",
       secret: "here's a secret",
       valid_until: NaiveDateTime.add(NaiveDateTime.utc_now(), 100),
       state: "requested"
index 52e67f0467d0bf27e843ae65fa1fa46436a9e873..1b704330f0bfa159d1c24352578e6553a8c954c3 100644 (file)
@@ -6,8 +6,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
   use Pleroma.Web.ConnCase
   import Pleroma.Factory
   alias Pleroma.Web.ActivityPub.{UserView, ObjectView}
-  alias Pleroma.{Object, Repo, User}
-  alias Pleroma.Activity
+  alias Pleroma.{Object, Repo, Activity, User, Instances}
 
   setup_all do
     Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
@@ -144,6 +143,24 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
       :timer.sleep(500)
       assert Activity.get_by_ap_id(data["id"])
     end
+
+    test "it clears `unreachable` federation status of the sender", %{conn: conn} do
+      sender_url = "https://pleroma.soykaf.com"
+      Instances.set_unreachable(sender_url, Instances.reachability_datetime_threshold())
+      refute Instances.reachable?(sender_url)
+
+      data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!()
+
+      conn =
+        conn
+        |> assign(:valid_signature, true)
+        |> put_req_header("content-type", "application/activity+json")
+        |> put_req_header("referer", sender_url)
+        |> post("/inbox", data)
+
+      assert "ok" == json_response(conn, 200)
+      assert Instances.reachable?(sender_url)
+    end
   end
 
   describe "/users/:nickname/inbox" do
@@ -191,6 +208,29 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
 
       assert response(conn, 200) =~ note_activity.data["object"]["content"]
     end
+
+    test "it clears `unreachable` federation status of the sender", %{conn: conn} do
+      sender_host = "pleroma.soykaf.com"
+      Instances.set_unreachable(sender_host, Instances.reachability_datetime_threshold())
+      refute Instances.reachable?(sender_host)
+
+      user = insert(:user)
+
+      data =
+        File.read!("test/fixtures/mastodon-post-activity.json")
+        |> Poison.decode!()
+        |> Map.put("bcc", [user.ap_id])
+
+      conn =
+        conn
+        |> assign(:valid_signature, true)
+        |> put_req_header("content-type", "application/activity+json")
+        |> put_req_header("referer", "https://#{sender_host}")
+        |> post("/users/#{user.nickname}/inbox", data)
+
+      assert "ok" == json_response(conn, 200)
+      assert Instances.reachable?(sender_host)
+    end
   end
 
   describe "/users/:nickname/outbox" do
index a49265c0c7d93054ae69de572c12b55caac18d8d..f4234aea8785e8302b996a42cc3fe82dca6b965b 100644 (file)
@@ -3,8 +3,8 @@
 # SPDX-License-Identifier: AGPL-3.0-only
 
 defmodule Pleroma.Web.FederatorTest do
-  alias Pleroma.Web.Federator
-  alias Pleroma.Web.CommonAPI
+  alias Pleroma.Web.{CommonAPI, Federator}
+  alias Pleroma.Instances
   use Pleroma.DataCase
   import Pleroma.Factory
   import Mock
@@ -71,6 +71,103 @@ defmodule Pleroma.Web.FederatorTest do
     end
   end
 
+  describe "Targets reachability filtering in `publish`" do
+    test_with_mock "it federates only to reachable instances via AP",
+                   Federator,
+                   [:passthrough],
+                   [] do
+      user = insert(:user)
+
+      {inbox1, inbox2} =
+        {"https://domain.com/users/nick1/inbox", "https://domain2.com/users/nick2/inbox"}
+
+      insert(:user, %{
+        local: false,
+        nickname: "nick1@domain.com",
+        ap_id: "https://domain.com/users/nick1",
+        info: %{ap_enabled: true, source_data: %{"inbox" => inbox1}}
+      })
+
+      insert(:user, %{
+        local: false,
+        nickname: "nick2@domain2.com",
+        ap_id: "https://domain2.com/users/nick2",
+        info: %{ap_enabled: true, source_data: %{"inbox" => inbox2}}
+      })
+
+      Instances.set_unreachable(
+        URI.parse(inbox2).host,
+        Instances.reachability_datetime_threshold()
+      )
+
+      {:ok, _activity} =
+        CommonAPI.post(user, %{"status" => "HI @nick1@domain.com, @nick2@domain2.com!"})
+
+      assert called(Federator.enqueue(:publish_single_ap, %{inbox: inbox1}))
+      refute called(Federator.enqueue(:publish_single_ap, %{inbox: inbox2}))
+    end
+
+    test_with_mock "it federates only to reachable instances via Websub",
+                   Federator,
+                   [:passthrough],
+                   [] do
+      user = insert(:user)
+      websub_topic = Pleroma.Web.OStatus.feed_path(user)
+
+      sub1 =
+        insert(:websub_subscription, %{
+          topic: websub_topic,
+          state: "active",
+          callback: "http://pleroma.soykaf.com/cb"
+        })
+
+      sub2 =
+        insert(:websub_subscription, %{
+          topic: websub_topic,
+          state: "active",
+          callback: "https://pleroma2.soykaf.com/cb"
+        })
+
+      Instances.set_unreachable(sub1.callback, Instances.reachability_datetime_threshold())
+
+      {:ok, _activity} = CommonAPI.post(user, %{"status" => "HI"})
+
+      assert called(Federator.enqueue(:publish_single_websub, %{callback: sub2.callback}))
+      refute called(Federator.enqueue(:publish_single_websub, %{callback: sub1.callback}))
+    end
+
+    test_with_mock "it federates only to reachable instances via Salmon",
+                   Federator,
+                   [:passthrough],
+                   [] do
+      user = insert(:user)
+
+      remote_user1 =
+        insert(:user, %{
+          local: false,
+          nickname: "nick1@domain.com",
+          ap_id: "https://domain.com/users/nick1",
+          info: %{salmon: "https://domain.com/salmon"}
+        })
+
+      remote_user2 =
+        insert(:user, %{
+          local: false,
+          nickname: "nick2@domain2.com",
+          ap_id: "https://domain2.com/users/nick2",
+          info: %{salmon: "https://domain2.com/salmon"}
+        })
+
+      Instances.set_unreachable("domain.com", Instances.reachability_datetime_threshold())
+
+      {:ok, _activity} =
+        CommonAPI.post(user, %{"status" => "HI @nick1@domain.com, @nick2@domain2.com!"})
+
+      assert called(Federator.enqueue(:publish_single_salmon, {remote_user2, :_, :_}))
+      refute called(Federator.enqueue(:publish_single_websub, {remote_user1, :_, :_}))
+    end
+  end
+
   describe "Receive an activity" do
     test "successfully processes incoming AP docs with correct origin" do
       params = %{
index 995cc00d6359973393a0c1f6f5dd9a684d6d0498..ca447aa5d95fe69beeb1706d26561a7fc24be6df 100644 (file)
@@ -5,7 +5,7 @@
 defmodule Pleroma.Web.OStatus.OStatusControllerTest do
   use Pleroma.Web.ConnCase
   import Pleroma.Factory
-  alias Pleroma.{User, Repo, Object}
+  alias Pleroma.{User, Repo, Object, Instances}
   alias Pleroma.Web.CommonAPI
   alias Pleroma.Web.OStatus.ActivityRepresenter
 
@@ -14,49 +14,69 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do
     :ok
   end
 
-  test "decodes a salmon", %{conn: conn} do
-    user = insert(:user)
-    salmon = File.read!("test/fixtures/salmon.xml")
-
-    conn =
-      conn
-      |> put_req_header("content-type", "application/atom+xml")
-      |> post("/users/#{user.nickname}/salmon", salmon)
-
-    assert response(conn, 200)
-  end
-
-  test "decodes a salmon with a changed magic key", %{conn: conn} do
-    user = insert(:user)
-    salmon = File.read!("test/fixtures/salmon.xml")
-
-    conn =
-      conn
-      |> put_req_header("content-type", "application/atom+xml")
-      |> post("/users/#{user.nickname}/salmon", salmon)
-
-    assert response(conn, 200)
-
-    # Set a wrong magic-key for a user so it has to refetch
-    salmon_user = User.get_by_ap_id("http://gs.example.org:4040/index.php/user/1")
-    # Wrong key
-    info_cng =
-      User.Info.remote_user_creation(salmon_user.info, %{
-        magic_key:
-          "RSA.pu0s-halox4tu7wmES1FVSx6u-4wc0YrUFXcqWXZG4-27UmbCOpMQftRCldNRfyA-qLbz-eqiwrong1EwUvjsD4cYbAHNGHwTvDOyx5AKthQUP44ykPv7kjKGh3DWKySJvcs9tlUG87hlo7AvnMo9pwRS_Zz2CacQ-MKaXyDepk=.AQAB"
-      })
-
-    salmon_user
-    |> Ecto.Changeset.change()
-    |> Ecto.Changeset.put_embed(:info, info_cng)
-    |> Repo.update()
-
-    conn =
-      build_conn()
-      |> put_req_header("content-type", "application/atom+xml")
-      |> post("/users/#{user.nickname}/salmon", salmon)
-
-    assert response(conn, 200)
+  describe "salmon_incoming" do
+    test "decodes a salmon", %{conn: conn} do
+      user = insert(:user)
+      salmon = File.read!("test/fixtures/salmon.xml")
+
+      conn =
+        conn
+        |> put_req_header("content-type", "application/atom+xml")
+        |> post("/users/#{user.nickname}/salmon", salmon)
+
+      assert response(conn, 200)
+    end
+
+    test "decodes a salmon with a changed magic key", %{conn: conn} do
+      user = insert(:user)
+      salmon = File.read!("test/fixtures/salmon.xml")
+
+      conn =
+        conn
+        |> put_req_header("content-type", "application/atom+xml")
+        |> post("/users/#{user.nickname}/salmon", salmon)
+
+      assert response(conn, 200)
+
+      # Set a wrong magic-key for a user so it has to refetch
+      salmon_user = User.get_by_ap_id("http://gs.example.org:4040/index.php/user/1")
+      # Wrong key
+      info_cng =
+        User.Info.remote_user_creation(salmon_user.info, %{
+          magic_key:
+            "RSA.pu0s-halox4tu7wmES1FVSx6u-4wc0YrUFXcqWXZG4-27UmbCOpMQftRCldNRfyA-qLbz-eqiwrong1EwUvjsD4cYbAHNGHwTvDOyx5AKthQUP44ykPv7kjKGh3DWKySJvcs9tlUG87hlo7AvnMo9pwRS_Zz2CacQ-MKaXyDepk=.AQAB"
+        })
+
+      salmon_user
+      |> Ecto.Changeset.change()
+      |> Ecto.Changeset.put_embed(:info, info_cng)
+      |> Repo.update()
+
+      conn =
+        build_conn()
+        |> put_req_header("content-type", "application/atom+xml")
+        |> post("/users/#{user.nickname}/salmon", salmon)
+
+      assert response(conn, 200)
+    end
+
+    test "it clears `unreachable` federation status of the sender", %{conn: conn} do
+      sender_url = "https://pleroma.soykaf.com"
+      Instances.set_unreachable(sender_url, Instances.reachability_datetime_threshold())
+      refute Instances.reachable?(sender_url)
+
+      user = insert(:user)
+      salmon = File.read!("test/fixtures/salmon.xml")
+
+      conn =
+        conn
+        |> put_req_header("content-type", "application/atom+xml")
+        |> put_req_header("referer", sender_url)
+        |> post("/users/#{user.nickname}/salmon", salmon)
+
+      assert response(conn, 200)
+      assert Instances.reachable?(sender_url)
+    end
   end
 
   test "gets a feed", %{conn: conn} do
index 9cbcda063e4186a9b27cfabd9ac70fa068a61258..c445ed676e8b3aa82f1c6632106e496212cbb899 100644 (file)
@@ -6,7 +6,7 @@ defmodule Pleroma.Web.Websub.WebsubControllerTest do
   use Pleroma.Web.ConnCase
   import Pleroma.Factory
   alias Pleroma.Web.Websub.WebsubClientSubscription
-  alias Pleroma.{Repo, Activity}
+  alias Pleroma.{Repo, Activity, Instances}
   alias Pleroma.Web.Websub
 
   test "websub subscription request", %{conn: conn} do
@@ -50,35 +50,57 @@ defmodule Pleroma.Web.Websub.WebsubControllerTest do
     assert_in_delta NaiveDateTime.diff(websub.valid_until, NaiveDateTime.utc_now()), 100, 5
   end
 
-  test "handles incoming feed updates", %{conn: conn} do
-    websub = insert(:websub_client_subscription)
-    doc = "some stuff"
-    signature = Websub.sign(websub.secret, doc)
-
-    conn =
-      conn
-      |> put_req_header("x-hub-signature", "sha1=" <> signature)
-      |> put_req_header("content-type", "application/atom+xml")
-      |> post("/push/subscriptions/#{websub.id}", doc)
-
-    assert response(conn, 200) == "OK"
-
-    assert length(Repo.all(Activity)) == 1
-  end
-
-  test "rejects incoming feed updates with the wrong signature", %{conn: conn} do
-    websub = insert(:websub_client_subscription)
-    doc = "some stuff"
-    signature = Websub.sign("wrong secret", doc)
-
-    conn =
-      conn
-      |> put_req_header("x-hub-signature", "sha1=" <> signature)
-      |> put_req_header("content-type", "application/atom+xml")
-      |> post("/push/subscriptions/#{websub.id}", doc)
-
-    assert response(conn, 500) == "Error"
-
-    assert length(Repo.all(Activity)) == 0
+  describe "websub_incoming" do
+    test "handles incoming feed updates", %{conn: conn} do
+      websub = insert(:websub_client_subscription)
+      doc = "some stuff"
+      signature = Websub.sign(websub.secret, doc)
+
+      conn =
+        conn
+        |> put_req_header("x-hub-signature", "sha1=" <> signature)
+        |> put_req_header("content-type", "application/atom+xml")
+        |> post("/push/subscriptions/#{websub.id}", doc)
+
+      assert response(conn, 200) == "OK"
+
+      assert length(Repo.all(Activity)) == 1
+    end
+
+    test "rejects incoming feed updates with the wrong signature", %{conn: conn} do
+      websub = insert(:websub_client_subscription)
+      doc = "some stuff"
+      signature = Websub.sign("wrong secret", doc)
+
+      conn =
+        conn
+        |> put_req_header("x-hub-signature", "sha1=" <> signature)
+        |> put_req_header("content-type", "application/atom+xml")
+        |> post("/push/subscriptions/#{websub.id}", doc)
+
+      assert response(conn, 500) == "Error"
+
+      assert length(Repo.all(Activity)) == 0
+    end
+
+    test "it clears `unreachable` federation status of the sender", %{conn: conn} do
+      sender_url = "https://pleroma.soykaf.com"
+      Instances.set_unreachable(sender_url, Instances.reachability_datetime_threshold())
+      refute Instances.reachable?(sender_url)
+
+      websub = insert(:websub_client_subscription)
+      doc = "some stuff"
+      signature = Websub.sign(websub.secret, doc)
+
+      conn =
+        conn
+        |> put_req_header("x-hub-signature", "sha1=" <> signature)
+        |> put_req_header("content-type", "application/atom+xml")
+        |> put_req_header("referer", sender_url)
+        |> post("/push/subscriptions/#{websub.id}", doc)
+
+      assert response(conn, 200) == "OK"
+      assert Instances.reachable?(sender_url)
+    end
   end
 end