Merge branch 'develop' of https://git.pleroma.social/pleroma/pleroma into develop
[akkoma] / test / web / activity_pub / transmogrifier_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
6 use Pleroma.DataCase
7 alias Pleroma.Activity
8 alias Pleroma.Object
9 alias Pleroma.Object.Fetcher
10 alias Pleroma.Repo
11 alias Pleroma.User
12 alias Pleroma.Web.ActivityPub.ActivityPub
13 alias Pleroma.Web.ActivityPub.Transmogrifier
14 alias Pleroma.Web.CommonAPI
15 alias Pleroma.Web.OStatus
16 alias Pleroma.Web.Websub.WebsubClientSubscription
17
18 import Mock
19 import Pleroma.Factory
20 import ExUnit.CaptureLog
21
22 setup_all do
23 Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
24 :ok
25 end
26
27 describe "handle_incoming" do
28 test "it ignores an incoming notice if we already have it" do
29 activity = insert(:note_activity)
30
31 data =
32 File.read!("test/fixtures/mastodon-post-activity.json")
33 |> Poison.decode!()
34 |> Map.put("object", Object.normalize(activity).data)
35
36 {:ok, returned_activity} = Transmogrifier.handle_incoming(data)
37
38 assert activity == returned_activity
39 end
40
41 test "it fetches replied-to activities if we don't have them" do
42 data =
43 File.read!("test/fixtures/mastodon-post-activity.json")
44 |> Poison.decode!()
45
46 object =
47 data["object"]
48 |> Map.put("inReplyTo", "https://shitposter.club/notice/2827873")
49
50 data = Map.put(data, "object", object)
51 {:ok, returned_activity} = Transmogrifier.handle_incoming(data)
52 returned_object = Object.normalize(returned_activity, false)
53
54 assert activity =
55 Activity.get_create_by_object_ap_id(
56 "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"
57 )
58
59 assert returned_object.data["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873"
60 end
61
62 test "it does not fetch replied-to activities beyond max_replies_depth" do
63 data =
64 File.read!("test/fixtures/mastodon-post-activity.json")
65 |> Poison.decode!()
66
67 object =
68 data["object"]
69 |> Map.put("inReplyTo", "https://shitposter.club/notice/2827873")
70
71 data = Map.put(data, "object", object)
72
73 with_mock Pleroma.Web.Federator,
74 allowed_incoming_reply_depth?: fn _ -> false end do
75 {:ok, returned_activity} = Transmogrifier.handle_incoming(data)
76
77 returned_object = Object.normalize(returned_activity, false)
78
79 refute Activity.get_create_by_object_ap_id(
80 "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"
81 )
82
83 assert returned_object.data["inReplyToAtomUri"] ==
84 "https://shitposter.club/notice/2827873"
85 end
86 end
87
88 test "it does not crash if the object in inReplyTo can't be fetched" do
89 data =
90 File.read!("test/fixtures/mastodon-post-activity.json")
91 |> Poison.decode!()
92
93 object =
94 data["object"]
95 |> Map.put("inReplyTo", "https://404.site/whatever")
96
97 data =
98 data
99 |> Map.put("object", object)
100
101 assert capture_log(fn ->
102 {:ok, _returned_activity} = Transmogrifier.handle_incoming(data)
103 end) =~ "[error] Couldn't fetch \"\"https://404.site/whatever\"\", error: nil"
104 end
105
106 test "it works for incoming notices" do
107 data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!()
108
109 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
110
111 assert data["id"] ==
112 "http://mastodon.example.org/users/admin/statuses/99512778738411822/activity"
113
114 assert data["context"] ==
115 "tag:mastodon.example.org,2018-02-12:objectId=20:objectType=Conversation"
116
117 assert data["to"] == ["https://www.w3.org/ns/activitystreams#Public"]
118
119 assert data["cc"] == [
120 "http://mastodon.example.org/users/admin/followers",
121 "http://localtesting.pleroma.lol/users/lain"
122 ]
123
124 assert data["actor"] == "http://mastodon.example.org/users/admin"
125
126 object_data = Object.normalize(data["object"]).data
127
128 assert object_data["id"] ==
129 "http://mastodon.example.org/users/admin/statuses/99512778738411822"
130
131 assert object_data["to"] == ["https://www.w3.org/ns/activitystreams#Public"]
132
133 assert object_data["cc"] == [
134 "http://mastodon.example.org/users/admin/followers",
135 "http://localtesting.pleroma.lol/users/lain"
136 ]
137
138 assert object_data["actor"] == "http://mastodon.example.org/users/admin"
139 assert object_data["attributedTo"] == "http://mastodon.example.org/users/admin"
140
141 assert object_data["context"] ==
142 "tag:mastodon.example.org,2018-02-12:objectId=20:objectType=Conversation"
143
144 assert object_data["sensitive"] == true
145
146 user = User.get_cached_by_ap_id(object_data["actor"])
147
148 assert user.info.note_count == 1
149 end
150
151 test "it works for incoming notices with hashtags" do
152 data = File.read!("test/fixtures/mastodon-post-activity-hashtag.json") |> Poison.decode!()
153
154 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
155 object = Object.normalize(data["object"])
156
157 assert Enum.at(object.data["tag"], 2) == "moo"
158 end
159
160 test "it works for incoming questions" do
161 data = File.read!("test/fixtures/mastodon-question-activity.json") |> Poison.decode!()
162
163 {:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data)
164
165 object = Object.normalize(activity)
166
167 assert Enum.all?(object.data["oneOf"], fn choice ->
168 choice["name"] in [
169 "Dunno",
170 "Everyone knows that!",
171 "25 char limit is dumb",
172 "I can't even fit a funny"
173 ]
174 end)
175 end
176
177 test "it rewrites Note votes to Answers and increments vote counters on question activities" do
178 user = insert(:user)
179
180 {:ok, activity} =
181 CommonAPI.post(user, %{
182 "status" => "suya...",
183 "poll" => %{"options" => ["suya", "suya.", "suya.."], "expires_in" => 10}
184 })
185
186 object = Object.normalize(activity)
187
188 data =
189 File.read!("test/fixtures/mastodon-vote.json")
190 |> Poison.decode!()
191 |> Kernel.put_in(["to"], user.ap_id)
192 |> Kernel.put_in(["object", "inReplyTo"], object.data["id"])
193 |> Kernel.put_in(["object", "to"], user.ap_id)
194
195 {:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data)
196 answer_object = Object.normalize(activity)
197 assert answer_object.data["type"] == "Answer"
198 object = Object.get_by_ap_id(object.data["id"])
199
200 assert Enum.any?(
201 object.data["oneOf"],
202 fn
203 %{"name" => "suya..", "replies" => %{"totalItems" => 1}} -> true
204 _ -> false
205 end
206 )
207 end
208
209 test "it works for incoming notices with contentMap" do
210 data =
211 File.read!("test/fixtures/mastodon-post-activity-contentmap.json") |> Poison.decode!()
212
213 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
214 object = Object.normalize(data["object"])
215
216 assert object.data["content"] ==
217 "<p><span class=\"h-card\"><a href=\"http://localtesting.pleroma.lol/users/lain\" class=\"u-url mention\">@<span>lain</span></a></span></p>"
218 end
219
220 test "it works for incoming notices with to/cc not being an array (kroeg)" do
221 data = File.read!("test/fixtures/kroeg-post-activity.json") |> Poison.decode!()
222
223 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
224 object = Object.normalize(data["object"])
225
226 assert object.data["content"] ==
227 "<p>henlo from my Psion netBook</p><p>message sent from my Psion netBook</p>"
228 end
229
230 test "it works for incoming announces with actor being inlined (kroeg)" do
231 data = File.read!("test/fixtures/kroeg-announce-with-inline-actor.json") |> Poison.decode!()
232
233 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
234
235 assert data["actor"] == "https://puckipedia.com/"
236 end
237
238 test "it works for incoming notices with tag not being an array (kroeg)" do
239 data = File.read!("test/fixtures/kroeg-array-less-emoji.json") |> Poison.decode!()
240
241 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
242 object = Object.normalize(data["object"])
243
244 assert object.data["emoji"] == %{
245 "icon_e_smile" => "https://puckipedia.com/forum/images/smilies/icon_e_smile.png"
246 }
247
248 data = File.read!("test/fixtures/kroeg-array-less-hashtag.json") |> Poison.decode!()
249
250 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
251 object = Object.normalize(data["object"])
252
253 assert "test" in object.data["tag"]
254 end
255
256 test "it works for incoming notices with url not being a string (prismo)" do
257 data = File.read!("test/fixtures/prismo-url-map.json") |> Poison.decode!()
258
259 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
260 object = Object.normalize(data["object"])
261
262 assert object.data["url"] == "https://prismo.news/posts/83"
263 end
264
265 test "it cleans up incoming notices which are not really DMs" do
266 user = insert(:user)
267 other_user = insert(:user)
268
269 to = [user.ap_id, other_user.ap_id]
270
271 data =
272 File.read!("test/fixtures/mastodon-post-activity.json")
273 |> Poison.decode!()
274 |> Map.put("to", to)
275 |> Map.put("cc", [])
276
277 object =
278 data["object"]
279 |> Map.put("to", to)
280 |> Map.put("cc", [])
281
282 data = Map.put(data, "object", object)
283
284 {:ok, %Activity{data: data, local: false} = activity} = Transmogrifier.handle_incoming(data)
285
286 assert data["to"] == []
287 assert data["cc"] == to
288
289 object_data = Object.normalize(activity).data
290
291 assert object_data["to"] == []
292 assert object_data["cc"] == to
293 end
294
295 test "it works for incoming likes" do
296 user = insert(:user)
297 {:ok, activity} = CommonAPI.post(user, %{"status" => "hello"})
298
299 data =
300 File.read!("test/fixtures/mastodon-like.json")
301 |> Poison.decode!()
302 |> Map.put("object", activity.data["object"])
303
304 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
305
306 assert data["actor"] == "http://mastodon.example.org/users/admin"
307 assert data["type"] == "Like"
308 assert data["id"] == "http://mastodon.example.org/users/admin#likes/2"
309 assert data["object"] == activity.data["object"]
310 end
311
312 test "it returns an error for incoming unlikes wihout a like activity" do
313 user = insert(:user)
314 {:ok, activity} = CommonAPI.post(user, %{"status" => "leave a like pls"})
315
316 data =
317 File.read!("test/fixtures/mastodon-undo-like.json")
318 |> Poison.decode!()
319 |> Map.put("object", activity.data["object"])
320
321 assert Transmogrifier.handle_incoming(data) == :error
322 end
323
324 test "it works for incoming unlikes with an existing like activity" do
325 user = insert(:user)
326 {:ok, activity} = CommonAPI.post(user, %{"status" => "leave a like pls"})
327
328 like_data =
329 File.read!("test/fixtures/mastodon-like.json")
330 |> Poison.decode!()
331 |> Map.put("object", activity.data["object"])
332
333 {:ok, %Activity{data: like_data, local: false}} = Transmogrifier.handle_incoming(like_data)
334
335 data =
336 File.read!("test/fixtures/mastodon-undo-like.json")
337 |> Poison.decode!()
338 |> Map.put("object", like_data)
339 |> Map.put("actor", like_data["actor"])
340
341 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
342
343 assert data["actor"] == "http://mastodon.example.org/users/admin"
344 assert data["type"] == "Undo"
345 assert data["id"] == "http://mastodon.example.org/users/admin#likes/2/undo"
346 assert data["object"]["id"] == "http://mastodon.example.org/users/admin#likes/2"
347 end
348
349 test "it works for incoming announces" do
350 data = File.read!("test/fixtures/mastodon-announce.json") |> Poison.decode!()
351
352 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
353
354 assert data["actor"] == "http://mastodon.example.org/users/admin"
355 assert data["type"] == "Announce"
356
357 assert data["id"] ==
358 "http://mastodon.example.org/users/admin/statuses/99542391527669785/activity"
359
360 assert data["object"] ==
361 "http://mastodon.example.org/users/admin/statuses/99541947525187367"
362
363 assert Activity.get_create_by_object_ap_id(data["object"])
364 end
365
366 test "it works for incoming announces with an existing activity" do
367 user = insert(:user)
368 {:ok, activity} = CommonAPI.post(user, %{"status" => "hey"})
369
370 data =
371 File.read!("test/fixtures/mastodon-announce.json")
372 |> Poison.decode!()
373 |> Map.put("object", activity.data["object"])
374
375 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
376
377 assert data["actor"] == "http://mastodon.example.org/users/admin"
378 assert data["type"] == "Announce"
379
380 assert data["id"] ==
381 "http://mastodon.example.org/users/admin/statuses/99542391527669785/activity"
382
383 assert data["object"] == activity.data["object"]
384
385 assert Activity.get_create_by_object_ap_id(data["object"]).id == activity.id
386 end
387
388 test "it does not clobber the addressing on announce activities" do
389 user = insert(:user)
390 {:ok, activity} = CommonAPI.post(user, %{"status" => "hey"})
391
392 data =
393 File.read!("test/fixtures/mastodon-announce.json")
394 |> Poison.decode!()
395 |> Map.put("object", Object.normalize(activity).data["id"])
396 |> Map.put("to", ["http://mastodon.example.org/users/admin/followers"])
397 |> Map.put("cc", [])
398
399 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
400
401 assert data["to"] == ["http://mastodon.example.org/users/admin/followers"]
402 end
403
404 test "it ensures that as:Public activities make it to their followers collection" do
405 user = insert(:user)
406
407 data =
408 File.read!("test/fixtures/mastodon-post-activity.json")
409 |> Poison.decode!()
410 |> Map.put("actor", user.ap_id)
411 |> Map.put("to", ["https://www.w3.org/ns/activitystreams#Public"])
412 |> Map.put("cc", [])
413
414 object =
415 data["object"]
416 |> Map.put("attributedTo", user.ap_id)
417 |> Map.put("to", ["https://www.w3.org/ns/activitystreams#Public"])
418 |> Map.put("cc", [])
419 |> Map.put("id", user.ap_id <> "/activities/12345678")
420
421 data = Map.put(data, "object", object)
422
423 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
424
425 assert data["cc"] == [User.ap_followers(user)]
426 end
427
428 test "it ensures that address fields become lists" do
429 user = insert(:user)
430
431 data =
432 File.read!("test/fixtures/mastodon-post-activity.json")
433 |> Poison.decode!()
434 |> Map.put("actor", user.ap_id)
435 |> Map.put("to", nil)
436 |> Map.put("cc", nil)
437
438 object =
439 data["object"]
440 |> Map.put("attributedTo", user.ap_id)
441 |> Map.put("to", nil)
442 |> Map.put("cc", nil)
443 |> Map.put("id", user.ap_id <> "/activities/12345678")
444
445 data = Map.put(data, "object", object)
446
447 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
448
449 assert !is_nil(data["to"])
450 assert !is_nil(data["cc"])
451 end
452
453 test "it works for incoming update activities" do
454 data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!()
455
456 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
457 update_data = File.read!("test/fixtures/mastodon-update.json") |> Poison.decode!()
458
459 object =
460 update_data["object"]
461 |> Map.put("actor", data["actor"])
462 |> Map.put("id", data["actor"])
463
464 update_data =
465 update_data
466 |> Map.put("actor", data["actor"])
467 |> Map.put("object", object)
468
469 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(update_data)
470
471 user = User.get_cached_by_ap_id(data["actor"])
472 assert user.name == "gargle"
473
474 assert user.avatar["url"] == [
475 %{
476 "href" =>
477 "https://cd.niu.moe/accounts/avatars/000/033/323/original/fd7f8ae0b3ffedc9.jpeg"
478 }
479 ]
480
481 assert user.info.banner["url"] == [
482 %{
483 "href" =>
484 "https://cd.niu.moe/accounts/headers/000/033/323/original/850b3448fa5fd477.png"
485 }
486 ]
487
488 assert user.bio == "<p>Some bio</p>"
489 end
490
491 test "it works for incoming update activities which lock the account" do
492 data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!()
493
494 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
495 update_data = File.read!("test/fixtures/mastodon-update.json") |> Poison.decode!()
496
497 object =
498 update_data["object"]
499 |> Map.put("actor", data["actor"])
500 |> Map.put("id", data["actor"])
501 |> Map.put("manuallyApprovesFollowers", true)
502
503 update_data =
504 update_data
505 |> Map.put("actor", data["actor"])
506 |> Map.put("object", object)
507
508 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(update_data)
509
510 user = User.get_cached_by_ap_id(data["actor"])
511 assert user.info.locked == true
512 end
513
514 test "it works for incoming deletes" do
515 activity = insert(:note_activity)
516
517 data =
518 File.read!("test/fixtures/mastodon-delete.json")
519 |> Poison.decode!()
520
521 object =
522 data["object"]
523 |> Map.put("id", activity.data["object"])
524
525 data =
526 data
527 |> Map.put("object", object)
528 |> Map.put("actor", activity.data["actor"])
529
530 {:ok, %Activity{local: false}} = Transmogrifier.handle_incoming(data)
531
532 refute Activity.get_by_id(activity.id)
533 end
534
535 test "it fails for incoming deletes with spoofed origin" do
536 activity = insert(:note_activity)
537
538 data =
539 File.read!("test/fixtures/mastodon-delete.json")
540 |> Poison.decode!()
541
542 object =
543 data["object"]
544 |> Map.put("id", activity.data["object"])
545
546 data =
547 data
548 |> Map.put("object", object)
549
550 assert capture_log(fn ->
551 :error = Transmogrifier.handle_incoming(data)
552 end) =~
553 "[error] Could not decode user at fetch http://mastodon.example.org/users/gargron, {:error, {:error, :nxdomain}}"
554
555 assert Activity.get_by_id(activity.id)
556 end
557
558 test "it works for incoming user deletes" do
559 %{ap_id: ap_id} = insert(:user, ap_id: "http://mastodon.example.org/users/admin")
560
561 data =
562 File.read!("test/fixtures/mastodon-delete-user.json")
563 |> Poison.decode!()
564
565 {:ok, _} = Transmogrifier.handle_incoming(data)
566
567 refute User.get_cached_by_ap_id(ap_id)
568 end
569
570 test "it fails for incoming user deletes with spoofed origin" do
571 %{ap_id: ap_id} = insert(:user)
572
573 data =
574 File.read!("test/fixtures/mastodon-delete-user.json")
575 |> Poison.decode!()
576 |> Map.put("actor", ap_id)
577
578 assert :error == Transmogrifier.handle_incoming(data)
579 assert User.get_cached_by_ap_id(ap_id)
580 end
581
582 test "it works for incoming unannounces with an existing notice" do
583 user = insert(:user)
584 {:ok, activity} = CommonAPI.post(user, %{"status" => "hey"})
585
586 announce_data =
587 File.read!("test/fixtures/mastodon-announce.json")
588 |> Poison.decode!()
589 |> Map.put("object", activity.data["object"])
590
591 {:ok, %Activity{data: announce_data, local: false}} =
592 Transmogrifier.handle_incoming(announce_data)
593
594 data =
595 File.read!("test/fixtures/mastodon-undo-announce.json")
596 |> Poison.decode!()
597 |> Map.put("object", announce_data)
598 |> Map.put("actor", announce_data["actor"])
599
600 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
601
602 assert data["type"] == "Undo"
603 assert object_data = data["object"]
604 assert object_data["type"] == "Announce"
605 assert object_data["object"] == activity.data["object"]
606
607 assert object_data["id"] ==
608 "http://mastodon.example.org/users/admin/statuses/99542391527669785/activity"
609 end
610
611 test "it works for incomming unfollows with an existing follow" do
612 user = insert(:user)
613
614 follow_data =
615 File.read!("test/fixtures/mastodon-follow-activity.json")
616 |> Poison.decode!()
617 |> Map.put("object", user.ap_id)
618
619 {:ok, %Activity{data: _, local: false}} = Transmogrifier.handle_incoming(follow_data)
620
621 data =
622 File.read!("test/fixtures/mastodon-unfollow-activity.json")
623 |> Poison.decode!()
624 |> Map.put("object", follow_data)
625
626 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
627
628 assert data["type"] == "Undo"
629 assert data["object"]["type"] == "Follow"
630 assert data["object"]["object"] == user.ap_id
631 assert data["actor"] == "http://mastodon.example.org/users/admin"
632
633 refute User.following?(User.get_cached_by_ap_id(data["actor"]), user)
634 end
635
636 test "it works for incoming blocks" do
637 user = insert(:user)
638
639 data =
640 File.read!("test/fixtures/mastodon-block-activity.json")
641 |> Poison.decode!()
642 |> Map.put("object", user.ap_id)
643
644 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
645
646 assert data["type"] == "Block"
647 assert data["object"] == user.ap_id
648 assert data["actor"] == "http://mastodon.example.org/users/admin"
649
650 blocker = User.get_cached_by_ap_id(data["actor"])
651
652 assert User.blocks?(blocker, user)
653 end
654
655 test "incoming blocks successfully tear down any follow relationship" do
656 blocker = insert(:user)
657 blocked = insert(:user)
658
659 data =
660 File.read!("test/fixtures/mastodon-block-activity.json")
661 |> Poison.decode!()
662 |> Map.put("object", blocked.ap_id)
663 |> Map.put("actor", blocker.ap_id)
664
665 {:ok, blocker} = User.follow(blocker, blocked)
666 {:ok, blocked} = User.follow(blocked, blocker)
667
668 assert User.following?(blocker, blocked)
669 assert User.following?(blocked, blocker)
670
671 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
672
673 assert data["type"] == "Block"
674 assert data["object"] == blocked.ap_id
675 assert data["actor"] == blocker.ap_id
676
677 blocker = User.get_cached_by_ap_id(data["actor"])
678 blocked = User.get_cached_by_ap_id(data["object"])
679
680 assert User.blocks?(blocker, blocked)
681
682 refute User.following?(blocker, blocked)
683 refute User.following?(blocked, blocker)
684 end
685
686 test "it works for incoming unblocks with an existing block" do
687 user = insert(:user)
688
689 block_data =
690 File.read!("test/fixtures/mastodon-block-activity.json")
691 |> Poison.decode!()
692 |> Map.put("object", user.ap_id)
693
694 {:ok, %Activity{data: _, local: false}} = Transmogrifier.handle_incoming(block_data)
695
696 data =
697 File.read!("test/fixtures/mastodon-unblock-activity.json")
698 |> Poison.decode!()
699 |> Map.put("object", block_data)
700
701 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
702 assert data["type"] == "Undo"
703 assert data["object"]["type"] == "Block"
704 assert data["object"]["object"] == user.ap_id
705 assert data["actor"] == "http://mastodon.example.org/users/admin"
706
707 blocker = User.get_cached_by_ap_id(data["actor"])
708
709 refute User.blocks?(blocker, user)
710 end
711
712 test "it works for incoming accepts which were pre-accepted" do
713 follower = insert(:user)
714 followed = insert(:user)
715
716 {:ok, follower} = User.follow(follower, followed)
717 assert User.following?(follower, followed) == true
718
719 {:ok, follow_activity} = ActivityPub.follow(follower, followed)
720
721 accept_data =
722 File.read!("test/fixtures/mastodon-accept-activity.json")
723 |> Poison.decode!()
724 |> Map.put("actor", followed.ap_id)
725
726 object =
727 accept_data["object"]
728 |> Map.put("actor", follower.ap_id)
729 |> Map.put("id", follow_activity.data["id"])
730
731 accept_data = Map.put(accept_data, "object", object)
732
733 {:ok, activity} = Transmogrifier.handle_incoming(accept_data)
734 refute activity.local
735
736 assert activity.data["object"] == follow_activity.data["id"]
737
738 follower = User.get_cached_by_id(follower.id)
739
740 assert User.following?(follower, followed) == true
741 end
742
743 test "it works for incoming accepts which were orphaned" do
744 follower = insert(:user)
745 followed = insert(:user, %{info: %User.Info{locked: true}})
746
747 {:ok, follow_activity} = ActivityPub.follow(follower, followed)
748
749 accept_data =
750 File.read!("test/fixtures/mastodon-accept-activity.json")
751 |> Poison.decode!()
752 |> Map.put("actor", followed.ap_id)
753
754 accept_data =
755 Map.put(accept_data, "object", Map.put(accept_data["object"], "actor", follower.ap_id))
756
757 {:ok, activity} = Transmogrifier.handle_incoming(accept_data)
758 assert activity.data["object"] == follow_activity.data["id"]
759
760 follower = User.get_cached_by_id(follower.id)
761
762 assert User.following?(follower, followed) == true
763 end
764
765 test "it works for incoming accepts which are referenced by IRI only" do
766 follower = insert(:user)
767 followed = insert(:user, %{info: %User.Info{locked: true}})
768
769 {:ok, follow_activity} = ActivityPub.follow(follower, followed)
770
771 accept_data =
772 File.read!("test/fixtures/mastodon-accept-activity.json")
773 |> Poison.decode!()
774 |> Map.put("actor", followed.ap_id)
775 |> Map.put("object", follow_activity.data["id"])
776
777 {:ok, activity} = Transmogrifier.handle_incoming(accept_data)
778 assert activity.data["object"] == follow_activity.data["id"]
779
780 follower = User.get_cached_by_id(follower.id)
781
782 assert User.following?(follower, followed) == true
783 end
784
785 test "it fails for incoming accepts which cannot be correlated" do
786 follower = insert(:user)
787 followed = insert(:user, %{info: %User.Info{locked: true}})
788
789 accept_data =
790 File.read!("test/fixtures/mastodon-accept-activity.json")
791 |> Poison.decode!()
792 |> Map.put("actor", followed.ap_id)
793
794 accept_data =
795 Map.put(accept_data, "object", Map.put(accept_data["object"], "actor", follower.ap_id))
796
797 :error = Transmogrifier.handle_incoming(accept_data)
798
799 follower = User.get_cached_by_id(follower.id)
800
801 refute User.following?(follower, followed) == true
802 end
803
804 test "it fails for incoming rejects which cannot be correlated" do
805 follower = insert(:user)
806 followed = insert(:user, %{info: %User.Info{locked: true}})
807
808 accept_data =
809 File.read!("test/fixtures/mastodon-reject-activity.json")
810 |> Poison.decode!()
811 |> Map.put("actor", followed.ap_id)
812
813 accept_data =
814 Map.put(accept_data, "object", Map.put(accept_data["object"], "actor", follower.ap_id))
815
816 :error = Transmogrifier.handle_incoming(accept_data)
817
818 follower = User.get_cached_by_id(follower.id)
819
820 refute User.following?(follower, followed) == true
821 end
822
823 test "it works for incoming rejects which are orphaned" do
824 follower = insert(:user)
825 followed = insert(:user, %{info: %User.Info{locked: true}})
826
827 {:ok, follower} = User.follow(follower, followed)
828 {:ok, _follow_activity} = ActivityPub.follow(follower, followed)
829
830 assert User.following?(follower, followed) == true
831
832 reject_data =
833 File.read!("test/fixtures/mastodon-reject-activity.json")
834 |> Poison.decode!()
835 |> Map.put("actor", followed.ap_id)
836
837 reject_data =
838 Map.put(reject_data, "object", Map.put(reject_data["object"], "actor", follower.ap_id))
839
840 {:ok, activity} = Transmogrifier.handle_incoming(reject_data)
841 refute activity.local
842
843 follower = User.get_cached_by_id(follower.id)
844
845 assert User.following?(follower, followed) == false
846 end
847
848 test "it works for incoming rejects which are referenced by IRI only" do
849 follower = insert(:user)
850 followed = insert(:user, %{info: %User.Info{locked: true}})
851
852 {:ok, follower} = User.follow(follower, followed)
853 {:ok, follow_activity} = ActivityPub.follow(follower, followed)
854
855 assert User.following?(follower, followed) == true
856
857 reject_data =
858 File.read!("test/fixtures/mastodon-reject-activity.json")
859 |> Poison.decode!()
860 |> Map.put("actor", followed.ap_id)
861 |> Map.put("object", follow_activity.data["id"])
862
863 {:ok, %Activity{data: _}} = Transmogrifier.handle_incoming(reject_data)
864
865 follower = User.get_cached_by_id(follower.id)
866
867 assert User.following?(follower, followed) == false
868 end
869
870 test "it rejects activities without a valid ID" do
871 user = insert(:user)
872
873 data =
874 File.read!("test/fixtures/mastodon-follow-activity.json")
875 |> Poison.decode!()
876 |> Map.put("object", user.ap_id)
877 |> Map.put("id", "")
878
879 :error = Transmogrifier.handle_incoming(data)
880 end
881
882 test "it remaps video URLs as attachments if necessary" do
883 {:ok, object} =
884 Fetcher.fetch_object_from_id(
885 "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3"
886 )
887
888 attachment = %{
889 "type" => "Link",
890 "mediaType" => "video/mp4",
891 "href" =>
892 "https://peertube.moe/static/webseed/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-480.mp4",
893 "mimeType" => "video/mp4",
894 "size" => 5_015_880,
895 "url" => [
896 %{
897 "href" =>
898 "https://peertube.moe/static/webseed/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-480.mp4",
899 "mediaType" => "video/mp4",
900 "type" => "Link"
901 }
902 ],
903 "width" => 480
904 }
905
906 assert object.data["url"] ==
907 "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3"
908
909 assert object.data["attachment"] == [attachment]
910 end
911
912 test "it accepts Flag activities" do
913 user = insert(:user)
914 other_user = insert(:user)
915
916 {:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
917 object = Object.normalize(activity)
918
919 message = %{
920 "@context" => "https://www.w3.org/ns/activitystreams",
921 "cc" => [user.ap_id],
922 "object" => [user.ap_id, object.data["id"]],
923 "type" => "Flag",
924 "content" => "blocked AND reported!!!",
925 "actor" => other_user.ap_id
926 }
927
928 assert {:ok, activity} = Transmogrifier.handle_incoming(message)
929
930 assert activity.data["object"] == [user.ap_id, object.data["id"]]
931 assert activity.data["content"] == "blocked AND reported!!!"
932 assert activity.data["actor"] == other_user.ap_id
933 assert activity.data["cc"] == [user.ap_id]
934 end
935 end
936
937 describe "prepare outgoing" do
938 test "it turns mentions into tags" do
939 user = insert(:user)
940 other_user = insert(:user)
941
942 {:ok, activity} =
943 CommonAPI.post(user, %{"status" => "hey, @#{other_user.nickname}, how are ya? #2hu"})
944
945 {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
946 object = modified["object"]
947
948 expected_mention = %{
949 "href" => other_user.ap_id,
950 "name" => "@#{other_user.nickname}",
951 "type" => "Mention"
952 }
953
954 expected_tag = %{
955 "href" => Pleroma.Web.Endpoint.url() <> "/tags/2hu",
956 "type" => "Hashtag",
957 "name" => "#2hu"
958 }
959
960 assert Enum.member?(object["tag"], expected_tag)
961 assert Enum.member?(object["tag"], expected_mention)
962 end
963
964 test "it adds the sensitive property" do
965 user = insert(:user)
966
967 {:ok, activity} = CommonAPI.post(user, %{"status" => "#nsfw hey"})
968 {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
969
970 assert modified["object"]["sensitive"]
971 end
972
973 test "it adds the json-ld context and the conversation property" do
974 user = insert(:user)
975
976 {:ok, activity} = CommonAPI.post(user, %{"status" => "hey"})
977 {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
978
979 assert modified["@context"] ==
980 Pleroma.Web.ActivityPub.Utils.make_json_ld_header()["@context"]
981
982 assert modified["object"]["conversation"] == modified["context"]
983 end
984
985 test "it sets the 'attributedTo' property to the actor of the object if it doesn't have one" do
986 user = insert(:user)
987
988 {:ok, activity} = CommonAPI.post(user, %{"status" => "hey"})
989 {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
990
991 assert modified["object"]["actor"] == modified["object"]["attributedTo"]
992 end
993
994 test "it translates ostatus IDs to external URLs" do
995 incoming = File.read!("test/fixtures/incoming_note_activity.xml")
996 {:ok, [referent_activity]} = OStatus.handle_incoming(incoming)
997
998 user = insert(:user)
999
1000 {:ok, activity, _} = CommonAPI.favorite(referent_activity.id, user)
1001 {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
1002
1003 assert modified["object"] == "http://gs.example.org:4040/index.php/notice/29"
1004 end
1005
1006 test "it translates ostatus reply_to IDs to external URLs" do
1007 incoming = File.read!("test/fixtures/incoming_note_activity.xml")
1008 {:ok, [referred_activity]} = OStatus.handle_incoming(incoming)
1009
1010 user = insert(:user)
1011
1012 {:ok, activity} =
1013 CommonAPI.post(user, %{"status" => "HI!", "in_reply_to_status_id" => referred_activity.id})
1014
1015 {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
1016
1017 assert modified["object"]["inReplyTo"] == "http://gs.example.org:4040/index.php/notice/29"
1018 end
1019
1020 test "it strips internal hashtag data" do
1021 user = insert(:user)
1022
1023 {:ok, activity} = CommonAPI.post(user, %{"status" => "#2hu"})
1024
1025 expected_tag = %{
1026 "href" => Pleroma.Web.Endpoint.url() <> "/tags/2hu",
1027 "type" => "Hashtag",
1028 "name" => "#2hu"
1029 }
1030
1031 {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
1032
1033 assert modified["object"]["tag"] == [expected_tag]
1034 end
1035
1036 test "it strips internal fields" do
1037 user = insert(:user)
1038
1039 {:ok, activity} = CommonAPI.post(user, %{"status" => "#2hu :firefox:"})
1040
1041 {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
1042
1043 assert length(modified["object"]["tag"]) == 2
1044
1045 assert is_nil(modified["object"]["emoji"])
1046 assert is_nil(modified["object"]["like_count"])
1047 assert is_nil(modified["object"]["announcements"])
1048 assert is_nil(modified["object"]["announcement_count"])
1049 assert is_nil(modified["object"]["context_id"])
1050 end
1051
1052 test "it strips internal fields of article" do
1053 activity = insert(:article_activity)
1054
1055 {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
1056
1057 assert length(modified["object"]["tag"]) == 2
1058
1059 assert is_nil(modified["object"]["emoji"])
1060 assert is_nil(modified["object"]["like_count"])
1061 assert is_nil(modified["object"]["announcements"])
1062 assert is_nil(modified["object"]["announcement_count"])
1063 assert is_nil(modified["object"]["context_id"])
1064 end
1065
1066 test "it adds like collection to object" do
1067 activity = insert(:note_activity)
1068 {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
1069
1070 assert modified["object"]["likes"]["type"] == "OrderedCollection"
1071 assert modified["object"]["likes"]["totalItems"] == 0
1072 end
1073
1074 test "the directMessage flag is present" do
1075 user = insert(:user)
1076 other_user = insert(:user)
1077
1078 {:ok, activity} = CommonAPI.post(user, %{"status" => "2hu :moominmamma:"})
1079
1080 {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
1081
1082 assert modified["directMessage"] == false
1083
1084 {:ok, activity} =
1085 CommonAPI.post(user, %{"status" => "@#{other_user.nickname} :moominmamma:"})
1086
1087 {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
1088
1089 assert modified["directMessage"] == false
1090
1091 {:ok, activity} =
1092 CommonAPI.post(user, %{
1093 "status" => "@#{other_user.nickname} :moominmamma:",
1094 "visibility" => "direct"
1095 })
1096
1097 {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
1098
1099 assert modified["directMessage"] == true
1100 end
1101
1102 test "it strips BCC field" do
1103 user = insert(:user)
1104 {:ok, list} = Pleroma.List.create("foo", user)
1105
1106 {:ok, activity} =
1107 CommonAPI.post(user, %{"status" => "foobar", "visibility" => "list:#{list.id}"})
1108
1109 {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
1110
1111 assert is_nil(modified["bcc"])
1112 end
1113 end
1114
1115 describe "user upgrade" do
1116 test "it upgrades a user to activitypub" do
1117 user =
1118 insert(:user, %{
1119 nickname: "rye@niu.moe",
1120 local: false,
1121 ap_id: "https://niu.moe/users/rye",
1122 follower_address: User.ap_followers(%User{nickname: "rye@niu.moe"})
1123 })
1124
1125 user_two = insert(:user, %{following: [user.follower_address]})
1126
1127 {:ok, activity} = CommonAPI.post(user, %{"status" => "test"})
1128 {:ok, unrelated_activity} = CommonAPI.post(user_two, %{"status" => "test"})
1129 assert "http://localhost:4001/users/rye@niu.moe/followers" in activity.recipients
1130
1131 user = User.get_cached_by_id(user.id)
1132 assert user.info.note_count == 1
1133
1134 {:ok, user} = Transmogrifier.upgrade_user_from_ap_id("https://niu.moe/users/rye")
1135 assert user.info.ap_enabled
1136 assert user.info.note_count == 1
1137 assert user.follower_address == "https://niu.moe/users/rye/followers"
1138 assert user.following_address == "https://niu.moe/users/rye/following"
1139
1140 user = User.get_cached_by_id(user.id)
1141 assert user.info.note_count == 1
1142
1143 activity = Activity.get_by_id(activity.id)
1144 assert user.follower_address in activity.recipients
1145
1146 assert %{
1147 "url" => [
1148 %{
1149 "href" =>
1150 "https://cdn.niu.moe/accounts/avatars/000/033/323/original/fd7f8ae0b3ffedc9.jpeg"
1151 }
1152 ]
1153 } = user.avatar
1154
1155 assert %{
1156 "url" => [
1157 %{
1158 "href" =>
1159 "https://cdn.niu.moe/accounts/headers/000/033/323/original/850b3448fa5fd477.png"
1160 }
1161 ]
1162 } = user.info.banner
1163
1164 refute "..." in activity.recipients
1165
1166 unrelated_activity = Activity.get_by_id(unrelated_activity.id)
1167 refute user.follower_address in unrelated_activity.recipients
1168
1169 user_two = User.get_cached_by_id(user_two.id)
1170 assert user.follower_address in user_two.following
1171 refute "..." in user_two.following
1172 end
1173 end
1174
1175 describe "maybe_retire_websub" do
1176 test "it deletes all websub client subscripitions with the user as topic" do
1177 subscription = %WebsubClientSubscription{topic: "https://niu.moe/users/rye.atom"}
1178 {:ok, ws} = Repo.insert(subscription)
1179
1180 subscription = %WebsubClientSubscription{topic: "https://niu.moe/users/pasty.atom"}
1181 {:ok, ws2} = Repo.insert(subscription)
1182
1183 Transmogrifier.maybe_retire_websub("https://niu.moe/users/rye")
1184
1185 refute Repo.get(WebsubClientSubscription, ws.id)
1186 assert Repo.get(WebsubClientSubscription, ws2.id)
1187 end
1188 end
1189
1190 describe "actor rewriting" do
1191 test "it fixes the actor URL property to be a proper URI" do
1192 data = %{
1193 "url" => %{"href" => "http://example.com"}
1194 }
1195
1196 rewritten = Transmogrifier.maybe_fix_user_object(data)
1197 assert rewritten["url"] == "http://example.com"
1198 end
1199 end
1200
1201 describe "actor origin containment" do
1202 test "it rejects activities which reference objects with bogus origins" do
1203 data = %{
1204 "@context" => "https://www.w3.org/ns/activitystreams",
1205 "id" => "http://mastodon.example.org/users/admin/activities/1234",
1206 "actor" => "http://mastodon.example.org/users/admin",
1207 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
1208 "object" => "https://info.pleroma.site/activity.json",
1209 "type" => "Announce"
1210 }
1211
1212 :error = Transmogrifier.handle_incoming(data)
1213 end
1214
1215 test "it rejects activities which reference objects that have an incorrect attribution (variant 1)" do
1216 data = %{
1217 "@context" => "https://www.w3.org/ns/activitystreams",
1218 "id" => "http://mastodon.example.org/users/admin/activities/1234",
1219 "actor" => "http://mastodon.example.org/users/admin",
1220 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
1221 "object" => "https://info.pleroma.site/activity2.json",
1222 "type" => "Announce"
1223 }
1224
1225 :error = Transmogrifier.handle_incoming(data)
1226 end
1227
1228 test "it rejects activities which reference objects that have an incorrect attribution (variant 2)" do
1229 data = %{
1230 "@context" => "https://www.w3.org/ns/activitystreams",
1231 "id" => "http://mastodon.example.org/users/admin/activities/1234",
1232 "actor" => "http://mastodon.example.org/users/admin",
1233 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
1234 "object" => "https://info.pleroma.site/activity3.json",
1235 "type" => "Announce"
1236 }
1237
1238 :error = Transmogrifier.handle_incoming(data)
1239 end
1240 end
1241
1242 describe "reserialization" do
1243 test "successfully reserializes a message with inReplyTo == nil" do
1244 user = insert(:user)
1245
1246 message = %{
1247 "@context" => "https://www.w3.org/ns/activitystreams",
1248 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
1249 "cc" => [],
1250 "type" => "Create",
1251 "object" => %{
1252 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
1253 "cc" => [],
1254 "type" => "Note",
1255 "content" => "Hi",
1256 "inReplyTo" => nil,
1257 "attributedTo" => user.ap_id
1258 },
1259 "actor" => user.ap_id
1260 }
1261
1262 {:ok, activity} = Transmogrifier.handle_incoming(message)
1263
1264 {:ok, _} = Transmogrifier.prepare_outgoing(activity.data)
1265 end
1266
1267 test "successfully reserializes a message with AS2 objects in IR" do
1268 user = insert(:user)
1269
1270 message = %{
1271 "@context" => "https://www.w3.org/ns/activitystreams",
1272 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
1273 "cc" => [],
1274 "type" => "Create",
1275 "object" => %{
1276 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
1277 "cc" => [],
1278 "type" => "Note",
1279 "content" => "Hi",
1280 "inReplyTo" => nil,
1281 "attributedTo" => user.ap_id,
1282 "tag" => [
1283 %{"name" => "#2hu", "href" => "http://example.com/2hu", "type" => "Hashtag"},
1284 %{"name" => "Bob", "href" => "http://example.com/bob", "type" => "Mention"}
1285 ]
1286 },
1287 "actor" => user.ap_id
1288 }
1289
1290 {:ok, activity} = Transmogrifier.handle_incoming(message)
1291
1292 {:ok, _} = Transmogrifier.prepare_outgoing(activity.data)
1293 end
1294 end
1295
1296 test "Rewrites Answers to Notes" do
1297 user = insert(:user)
1298
1299 {:ok, poll_activity} =
1300 CommonAPI.post(user, %{
1301 "status" => "suya...",
1302 "poll" => %{"options" => ["suya", "suya.", "suya.."], "expires_in" => 10}
1303 })
1304
1305 poll_object = Object.normalize(poll_activity)
1306 # TODO: Replace with CommonAPI vote creation when implemented
1307 data =
1308 File.read!("test/fixtures/mastodon-vote.json")
1309 |> Poison.decode!()
1310 |> Kernel.put_in(["to"], user.ap_id)
1311 |> Kernel.put_in(["object", "inReplyTo"], poll_object.data["id"])
1312 |> Kernel.put_in(["object", "to"], user.ap_id)
1313
1314 {:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data)
1315 {:ok, data} = Transmogrifier.prepare_outgoing(activity.data)
1316
1317 assert data["object"]["type"] == "Note"
1318 end
1319
1320 describe "fix_explicit_addressing" do
1321 setup do
1322 user = insert(:user)
1323 [user: user]
1324 end
1325
1326 test "moves non-explicitly mentioned actors to cc", %{user: user} do
1327 explicitly_mentioned_actors = [
1328 "https://pleroma.gold/users/user1",
1329 "https://pleroma.gold/user2"
1330 ]
1331
1332 object = %{
1333 "actor" => user.ap_id,
1334 "to" => explicitly_mentioned_actors ++ ["https://social.beepboop.ga/users/dirb"],
1335 "cc" => [],
1336 "tag" =>
1337 Enum.map(explicitly_mentioned_actors, fn href ->
1338 %{"type" => "Mention", "href" => href}
1339 end)
1340 }
1341
1342 fixed_object = Transmogrifier.fix_explicit_addressing(object)
1343 assert Enum.all?(explicitly_mentioned_actors, &(&1 in fixed_object["to"]))
1344 refute "https://social.beepboop.ga/users/dirb" in fixed_object["to"]
1345 assert "https://social.beepboop.ga/users/dirb" in fixed_object["cc"]
1346 end
1347
1348 test "does not move actor's follower collection to cc", %{user: user} do
1349 object = %{
1350 "actor" => user.ap_id,
1351 "to" => [user.follower_address],
1352 "cc" => []
1353 }
1354
1355 fixed_object = Transmogrifier.fix_explicit_addressing(object)
1356 assert user.follower_address in fixed_object["to"]
1357 refute user.follower_address in fixed_object["cc"]
1358 end
1359
1360 test "removes recipient's follower collection from cc", %{user: user} do
1361 recipient = insert(:user)
1362
1363 object = %{
1364 "actor" => user.ap_id,
1365 "to" => [recipient.ap_id, "https://www.w3.org/ns/activitystreams#Public"],
1366 "cc" => [user.follower_address, recipient.follower_address]
1367 }
1368
1369 fixed_object = Transmogrifier.fix_explicit_addressing(object)
1370
1371 assert user.follower_address in fixed_object["cc"]
1372 refute recipient.follower_address in fixed_object["cc"]
1373 refute recipient.follower_address in fixed_object["to"]
1374 end
1375 end
1376
1377 test "update_following_followers_counters/1" do
1378 user1 =
1379 insert(:user,
1380 local: false,
1381 follower_address: "http://localhost:4001/users/masto_closed/followers",
1382 following_address: "http://localhost:4001/users/masto_closed/following"
1383 )
1384
1385 user2 =
1386 insert(:user,
1387 local: false,
1388 follower_address: "http://localhost:4001/users/fuser2/followers",
1389 following_address: "http://localhost:4001/users/fuser2/following"
1390 )
1391
1392 Transmogrifier.update_following_followers_counters(user1)
1393 Transmogrifier.update_following_followers_counters(user2)
1394
1395 %{follower_count: followers, following_count: following} = User.get_cached_user_info(user1)
1396 assert followers == 437
1397 assert following == 152
1398
1399 %{follower_count: followers, following_count: following} = User.get_cached_user_info(user2)
1400
1401 assert followers == 527
1402 assert following == 267
1403 end
1404 end