total rebase
[anni] / test / pleroma / web / federator_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.FederatorTest do
6   alias Pleroma.Instances
7   alias Pleroma.Tests.ObanHelpers
8   alias Pleroma.Web.CommonAPI
9   alias Pleroma.Web.Federator
10   alias Pleroma.Workers.PublisherWorker
11
12   use Pleroma.DataCase
13   use Oban.Testing, repo: Pleroma.Repo
14
15   import Pleroma.Factory
16   import Mock
17
18   setup_all do
19     Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
20
21     :ok
22   end
23
24   setup_all do: clear_config([:instance, :federating], true)
25   setup do: clear_config([:instance, :allow_relay])
26   setup do: clear_config([:mrf, :policies])
27   setup do: clear_config([:mrf_keyword])
28
29   describe "Publish an activity" do
30     setup do
31       user = insert(:user)
32       {:ok, activity} = CommonAPI.post(user, %{status: "HI"})
33
34       relay_mock = {
35         Pleroma.Web.ActivityPub.Relay,
36         [],
37         [publish: fn _activity -> send(self(), :relay_publish) end]
38       }
39
40       %{activity: activity, relay_mock: relay_mock}
41     end
42
43     test "to shared inbox when multiple actors from same instance are recipients" do
44       user = insert(:user)
45
46       shared_inbox = "https://domain.com/inbox"
47
48       follower_one =
49         insert(:user, %{
50           local: false,
51           nickname: "nick1@domain.com",
52           ap_id: "https://domain.com/users/nick1",
53           inbox: "https://domain.com/users/nick1/inbox",
54           shared_inbox: shared_inbox
55         })
56
57       follower_two =
58         insert(:user, %{
59           local: false,
60           nickname: "nick2@domain.com",
61           ap_id: "https://domain.com/users/nick2",
62           inbox: "https://domain.com/users/nick2/inbox",
63           shared_inbox: shared_inbox
64         })
65
66       {:ok, _, _} = Pleroma.User.follow(follower_one, user)
67       {:ok, _, _} = Pleroma.User.follow(follower_two, user)
68
69       {:ok, _activity} = CommonAPI.post(user, %{status: "Happy Friday everyone!"})
70
71       ObanHelpers.perform(all_enqueued(worker: PublisherWorker))
72
73       inboxes =
74         all_enqueued(worker: PublisherWorker)
75         |> Enum.filter(&(get_in(&1, [Access.key(:args), Access.key("op")]) == "publish_one"))
76         |> Enum.map(&get_in(&1, [Access.key(:args), Access.key("params"), Access.key("inbox")]))
77
78       assert [shared_inbox] == inboxes
79     end
80
81     test "with relays active, it publishes to the relay", %{
82       activity: activity,
83       relay_mock: relay_mock
84     } do
85       with_mocks([relay_mock]) do
86         Federator.publish(activity)
87         ObanHelpers.perform(all_enqueued(worker: PublisherWorker))
88       end
89
90       assert_received :relay_publish
91     end
92
93     test "with relays deactivated, it does not publish to the relay", %{
94       activity: activity,
95       relay_mock: relay_mock
96     } do
97       clear_config([:instance, :allow_relay], false)
98
99       with_mocks([relay_mock]) do
100         Federator.publish(activity)
101         ObanHelpers.perform(all_enqueued(worker: PublisherWorker))
102       end
103
104       refute_received :relay_publish
105     end
106   end
107
108   describe "Targets reachability filtering in `publish`" do
109     test "it federates only to reachable instances via AP" do
110       user = insert(:user)
111
112       {inbox1, inbox2} =
113         {"https://domain.com/users/nick1/inbox", "https://domain2.com/users/nick2/inbox"}
114
115       insert(:user, %{
116         local: false,
117         nickname: "nick1@domain.com",
118         ap_id: "https://domain.com/users/nick1",
119         inbox: inbox1
120       })
121
122       insert(:user, %{
123         local: false,
124         nickname: "nick2@domain2.com",
125         ap_id: "https://domain2.com/users/nick2",
126         inbox: inbox2
127       })
128
129       dt = NaiveDateTime.utc_now()
130       Instances.set_unreachable(inbox1, dt)
131
132       Instances.set_consistently_unreachable(URI.parse(inbox2).host)
133
134       {:ok, _activity} =
135         CommonAPI.post(user, %{status: "HI @nick1@domain.com, @nick2@domain2.com!"})
136
137       expected_dt = NaiveDateTime.to_iso8601(dt)
138
139       ObanHelpers.perform(all_enqueued(worker: PublisherWorker))
140
141       assert ObanHelpers.member?(
142                %{
143                  "op" => "publish_one",
144                  "params" => %{"inbox" => inbox1, "unreachable_since" => expected_dt}
145                },
146                all_enqueued(worker: PublisherWorker)
147              )
148     end
149   end
150
151   describe "Receive an activity" do
152     test "successfully processes incoming AP docs with correct origin" do
153       params = %{
154         "@context" => "https://www.w3.org/ns/activitystreams",
155         "actor" => "http://mastodon.example.org/users/admin",
156         "type" => "Create",
157         "id" => "http://mastodon.example.org/users/admin/activities/1",
158         "object" => %{
159           "type" => "Note",
160           "content" => "hi world!",
161           "id" => "http://mastodon.example.org/users/admin/objects/1",
162           "attributedTo" => "http://mastodon.example.org/users/admin",
163           "to" => ["https://www.w3.org/ns/activitystreams#Public"]
164         },
165         "to" => ["https://www.w3.org/ns/activitystreams#Public"]
166       }
167
168       assert {:ok, job} = Federator.incoming_ap_doc(params)
169       assert {:ok, _activity} = ObanHelpers.perform(job)
170
171       assert {:ok, job} = Federator.incoming_ap_doc(params)
172       assert {:cancel, :already_present} = ObanHelpers.perform(job)
173     end
174
175     test "rejects incoming AP docs with incorrect origin" do
176       params = %{
177         "@context" => "https://www.w3.org/ns/activitystreams",
178         "actor" => "https://niu.moe/users/rye",
179         "type" => "Create",
180         "id" => "http://mastodon.example.org/users/admin/activities/1",
181         "object" => %{
182           "type" => "Note",
183           "content" => "hi world!",
184           "id" => "http://mastodon.example.org/users/admin/objects/1",
185           "attributedTo" => "http://mastodon.example.org/users/admin",
186           "to" => ["https://www.w3.org/ns/activitystreams#Public"]
187         },
188         "to" => ["https://www.w3.org/ns/activitystreams#Public"]
189       }
190
191       assert {:ok, job} = Federator.incoming_ap_doc(params)
192       assert {:cancel, :origin_containment_failed} = ObanHelpers.perform(job)
193     end
194
195     test "it does not crash if MRF rejects the post" do
196       clear_config([:mrf_keyword, :reject], ["lain"])
197
198       clear_config(
199         [:mrf, :policies],
200         Pleroma.Web.ActivityPub.MRF.KeywordPolicy
201       )
202
203       params =
204         File.read!("test/fixtures/mastodon-post-activity.json")
205         |> Jason.decode!()
206
207       assert {:ok, job} = Federator.incoming_ap_doc(params)
208       assert {:cancel, _} = ObanHelpers.perform(job)
209     end
210   end
211 end