Remove vapidPublicKey from Nodeinfo
[akkoma] / test / web / activity_pub / publisher_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.ActivityPub.PublisherTest do
6 use Pleroma.Web.ConnCase
7
8 import ExUnit.CaptureLog
9 import Pleroma.Factory
10 import Tesla.Mock
11 import Mock
12
13 alias Pleroma.Activity
14 alias Pleroma.Instances
15 alias Pleroma.Object
16 alias Pleroma.Web.ActivityPub.Publisher
17 alias Pleroma.Web.CommonAPI
18
19 @as_public "https://www.w3.org/ns/activitystreams#Public"
20
21 setup do
22 mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
23 :ok
24 end
25
26 setup_all do: clear_config([:instance, :federating], true)
27
28 describe "gather_webfinger_links/1" do
29 test "it returns links" do
30 user = insert(:user)
31
32 expected_links = [
33 %{"href" => user.ap_id, "rel" => "self", "type" => "application/activity+json"},
34 %{
35 "href" => user.ap_id,
36 "rel" => "self",
37 "type" => "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""
38 },
39 %{
40 "rel" => "http://ostatus.org/schema/1.0/subscribe",
41 "template" => "#{Pleroma.Web.base_url()}/ostatus_subscribe?acct={uri}"
42 }
43 ]
44
45 assert expected_links == Publisher.gather_webfinger_links(user)
46 end
47 end
48
49 describe "determine_inbox/2" do
50 test "it returns sharedInbox for messages involving as:Public in to" do
51 user =
52 insert(:user, %{
53 source_data: %{"endpoints" => %{"sharedInbox" => "http://example.com/inbox"}}
54 })
55
56 activity = %Activity{
57 data: %{"to" => [@as_public], "cc" => [user.follower_address]}
58 }
59
60 assert Publisher.determine_inbox(activity, user) == "http://example.com/inbox"
61 end
62
63 test "it returns sharedInbox for messages involving as:Public in cc" do
64 user =
65 insert(:user, %{
66 source_data: %{"endpoints" => %{"sharedInbox" => "http://example.com/inbox"}}
67 })
68
69 activity = %Activity{
70 data: %{"cc" => [@as_public], "to" => [user.follower_address]}
71 }
72
73 assert Publisher.determine_inbox(activity, user) == "http://example.com/inbox"
74 end
75
76 test "it returns sharedInbox for messages involving multiple recipients in to" do
77 user =
78 insert(:user, %{
79 source_data: %{"endpoints" => %{"sharedInbox" => "http://example.com/inbox"}}
80 })
81
82 user_two = insert(:user)
83 user_three = insert(:user)
84
85 activity = %Activity{
86 data: %{"cc" => [], "to" => [user.ap_id, user_two.ap_id, user_three.ap_id]}
87 }
88
89 assert Publisher.determine_inbox(activity, user) == "http://example.com/inbox"
90 end
91
92 test "it returns sharedInbox for messages involving multiple recipients in cc" do
93 user =
94 insert(:user, %{
95 source_data: %{"endpoints" => %{"sharedInbox" => "http://example.com/inbox"}}
96 })
97
98 user_two = insert(:user)
99 user_three = insert(:user)
100
101 activity = %Activity{
102 data: %{"to" => [], "cc" => [user.ap_id, user_two.ap_id, user_three.ap_id]}
103 }
104
105 assert Publisher.determine_inbox(activity, user) == "http://example.com/inbox"
106 end
107
108 test "it returns sharedInbox for messages involving multiple recipients in total" do
109 user =
110 insert(:user,
111 source_data: %{
112 "inbox" => "http://example.com/personal-inbox",
113 "endpoints" => %{"sharedInbox" => "http://example.com/inbox"}
114 }
115 )
116
117 user_two = insert(:user)
118
119 activity = %Activity{
120 data: %{"to" => [user_two.ap_id], "cc" => [user.ap_id]}
121 }
122
123 assert Publisher.determine_inbox(activity, user) == "http://example.com/inbox"
124 end
125
126 test "it returns inbox for messages involving single recipients in total" do
127 user =
128 insert(:user,
129 source_data: %{
130 "inbox" => "http://example.com/personal-inbox",
131 "endpoints" => %{"sharedInbox" => "http://example.com/inbox"}
132 }
133 )
134
135 activity = %Activity{
136 data: %{"to" => [user.ap_id], "cc" => []}
137 }
138
139 assert Publisher.determine_inbox(activity, user) == "http://example.com/personal-inbox"
140 end
141 end
142
143 describe "publish_one/1" do
144 test_with_mock "calls `Instances.set_reachable` on successful federation if `unreachable_since` is not specified",
145 Instances,
146 [:passthrough],
147 [] do
148 actor = insert(:user)
149 inbox = "http://200.site/users/nick1/inbox"
150
151 assert {:ok, _} = Publisher.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
152
153 assert called(Instances.set_reachable(inbox))
154 end
155
156 test_with_mock "calls `Instances.set_reachable` on successful federation if `unreachable_since` is set",
157 Instances,
158 [:passthrough],
159 [] do
160 actor = insert(:user)
161 inbox = "http://200.site/users/nick1/inbox"
162
163 assert {:ok, _} =
164 Publisher.publish_one(%{
165 inbox: inbox,
166 json: "{}",
167 actor: actor,
168 id: 1,
169 unreachable_since: NaiveDateTime.utc_now()
170 })
171
172 assert called(Instances.set_reachable(inbox))
173 end
174
175 test_with_mock "does NOT call `Instances.set_reachable` on successful federation if `unreachable_since` is nil",
176 Instances,
177 [:passthrough],
178 [] do
179 actor = insert(:user)
180 inbox = "http://200.site/users/nick1/inbox"
181
182 assert {:ok, _} =
183 Publisher.publish_one(%{
184 inbox: inbox,
185 json: "{}",
186 actor: actor,
187 id: 1,
188 unreachable_since: nil
189 })
190
191 refute called(Instances.set_reachable(inbox))
192 end
193
194 test_with_mock "calls `Instances.set_unreachable` on target inbox on non-2xx HTTP response code",
195 Instances,
196 [:passthrough],
197 [] do
198 actor = insert(:user)
199 inbox = "http://404.site/users/nick1/inbox"
200
201 assert {:error, _} = Publisher.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
202
203 assert called(Instances.set_unreachable(inbox))
204 end
205
206 test_with_mock "it calls `Instances.set_unreachable` on target inbox on request error of any kind",
207 Instances,
208 [:passthrough],
209 [] do
210 actor = insert(:user)
211 inbox = "http://connrefused.site/users/nick1/inbox"
212
213 assert capture_log(fn ->
214 assert {:error, _} =
215 Publisher.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
216 end) =~ "connrefused"
217
218 assert called(Instances.set_unreachable(inbox))
219 end
220
221 test_with_mock "does NOT call `Instances.set_unreachable` if target is reachable",
222 Instances,
223 [:passthrough],
224 [] do
225 actor = insert(:user)
226 inbox = "http://200.site/users/nick1/inbox"
227
228 assert {:ok, _} = Publisher.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
229
230 refute called(Instances.set_unreachable(inbox))
231 end
232
233 test_with_mock "does NOT call `Instances.set_unreachable` if target instance has non-nil `unreachable_since`",
234 Instances,
235 [:passthrough],
236 [] do
237 actor = insert(:user)
238 inbox = "http://connrefused.site/users/nick1/inbox"
239
240 assert capture_log(fn ->
241 assert {:error, _} =
242 Publisher.publish_one(%{
243 inbox: inbox,
244 json: "{}",
245 actor: actor,
246 id: 1,
247 unreachable_since: NaiveDateTime.utc_now()
248 })
249 end) =~ "connrefused"
250
251 refute called(Instances.set_unreachable(inbox))
252 end
253 end
254
255 describe "publish/2" do
256 test_with_mock "publishes an activity with BCC to all relevant peers.",
257 Pleroma.Web.Federator.Publisher,
258 [:passthrough],
259 [] do
260 follower =
261 insert(:user,
262 local: false,
263 source_data: %{"inbox" => "https://domain.com/users/nick1/inbox"},
264 ap_enabled: true
265 )
266
267 actor = insert(:user, follower_address: follower.ap_id)
268 user = insert(:user)
269
270 {:ok, _follower_one} = Pleroma.User.follow(follower, actor)
271 actor = refresh_record(actor)
272
273 note_activity =
274 insert(:note_activity,
275 recipients: [follower.ap_id],
276 data_attrs: %{"bcc" => [user.ap_id]}
277 )
278
279 res = Publisher.publish(actor, note_activity)
280 assert res == :ok
281
282 assert called(
283 Pleroma.Web.Federator.Publisher.enqueue_one(Publisher, %{
284 inbox: "https://domain.com/users/nick1/inbox",
285 actor_id: actor.id,
286 id: note_activity.data["id"]
287 })
288 )
289 end
290
291 test_with_mock "publishes a delete activity to peers who signed fetch requests to the create acitvity/object.",
292 Pleroma.Web.Federator.Publisher,
293 [:passthrough],
294 [] do
295 fetcher =
296 insert(:user,
297 local: false,
298 source_data: %{"inbox" => "https://domain.com/users/nick1/inbox"},
299 ap_enabled: true
300 )
301
302 another_fetcher =
303 insert(:user,
304 local: false,
305 source_data: %{"inbox" => "https://domain2.com/users/nick1/inbox"},
306 ap_enabled: true
307 )
308
309 actor = insert(:user)
310
311 note_activity = insert(:note_activity, user: actor)
312 object = Object.normalize(note_activity)
313
314 activity_path = String.trim_leading(note_activity.data["id"], Pleroma.Web.Endpoint.url())
315 object_path = String.trim_leading(object.data["id"], Pleroma.Web.Endpoint.url())
316
317 build_conn()
318 |> put_req_header("accept", "application/activity+json")
319 |> assign(:user, fetcher)
320 |> get(object_path)
321 |> json_response(200)
322
323 build_conn()
324 |> put_req_header("accept", "application/activity+json")
325 |> assign(:user, another_fetcher)
326 |> get(activity_path)
327 |> json_response(200)
328
329 {:ok, delete} = CommonAPI.delete(note_activity.id, actor)
330
331 res = Publisher.publish(actor, delete)
332 assert res == :ok
333
334 assert called(
335 Pleroma.Web.Federator.Publisher.enqueue_one(Publisher, %{
336 inbox: "https://domain.com/users/nick1/inbox",
337 actor_id: actor.id,
338 id: delete.data["id"]
339 })
340 )
341
342 assert called(
343 Pleroma.Web.Federator.Publisher.enqueue_one(Publisher, %{
344 inbox: "https://domain2.com/users/nick1/inbox",
345 actor_id: actor.id,
346 id: delete.data["id"]
347 })
348 )
349 end
350 end
351 end