Merge branch 'security/ir-generic-containment' 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 end
1102
1103 describe "user upgrade" do
1104 test "it upgrades a user to activitypub" do
1105 user =
1106 insert(:user, %{
1107 nickname: "rye@niu.moe",
1108 local: false,
1109 ap_id: "https://niu.moe/users/rye",
1110 follower_address: User.ap_followers(%User{nickname: "rye@niu.moe"})
1111 })
1112
1113 user_two = insert(:user, %{following: [user.follower_address]})
1114
1115 {:ok, activity} = CommonAPI.post(user, %{"status" => "test"})
1116 {:ok, unrelated_activity} = CommonAPI.post(user_two, %{"status" => "test"})
1117 assert "http://localhost:4001/users/rye@niu.moe/followers" in activity.recipients
1118
1119 user = User.get_cached_by_id(user.id)
1120 assert user.info.note_count == 1
1121
1122 {:ok, user} = Transmogrifier.upgrade_user_from_ap_id("https://niu.moe/users/rye")
1123 assert user.info.ap_enabled
1124 assert user.info.note_count == 1
1125 assert user.follower_address == "https://niu.moe/users/rye/followers"
1126 assert user.following_address == "https://niu.moe/users/rye/following"
1127
1128 user = User.get_cached_by_id(user.id)
1129 assert user.info.note_count == 1
1130
1131 activity = Activity.get_by_id(activity.id)
1132 assert user.follower_address in activity.recipients
1133
1134 assert %{
1135 "url" => [
1136 %{
1137 "href" =>
1138 "https://cdn.niu.moe/accounts/avatars/000/033/323/original/fd7f8ae0b3ffedc9.jpeg"
1139 }
1140 ]
1141 } = user.avatar
1142
1143 assert %{
1144 "url" => [
1145 %{
1146 "href" =>
1147 "https://cdn.niu.moe/accounts/headers/000/033/323/original/850b3448fa5fd477.png"
1148 }
1149 ]
1150 } = user.info.banner
1151
1152 refute "..." in activity.recipients
1153
1154 unrelated_activity = Activity.get_by_id(unrelated_activity.id)
1155 refute user.follower_address in unrelated_activity.recipients
1156
1157 user_two = User.get_cached_by_id(user_two.id)
1158 assert user.follower_address in user_two.following
1159 refute "..." in user_two.following
1160 end
1161 end
1162
1163 describe "maybe_retire_websub" do
1164 test "it deletes all websub client subscripitions with the user as topic" do
1165 subscription = %WebsubClientSubscription{topic: "https://niu.moe/users/rye.atom"}
1166 {:ok, ws} = Repo.insert(subscription)
1167
1168 subscription = %WebsubClientSubscription{topic: "https://niu.moe/users/pasty.atom"}
1169 {:ok, ws2} = Repo.insert(subscription)
1170
1171 Transmogrifier.maybe_retire_websub("https://niu.moe/users/rye")
1172
1173 refute Repo.get(WebsubClientSubscription, ws.id)
1174 assert Repo.get(WebsubClientSubscription, ws2.id)
1175 end
1176 end
1177
1178 describe "actor rewriting" do
1179 test "it fixes the actor URL property to be a proper URI" do
1180 data = %{
1181 "url" => %{"href" => "http://example.com"}
1182 }
1183
1184 rewritten = Transmogrifier.maybe_fix_user_object(data)
1185 assert rewritten["url"] == "http://example.com"
1186 end
1187 end
1188
1189 describe "actor origin containment" do
1190 test "it rejects activities which reference objects with bogus origins" do
1191 data = %{
1192 "@context" => "https://www.w3.org/ns/activitystreams",
1193 "id" => "http://mastodon.example.org/users/admin/activities/1234",
1194 "actor" => "http://mastodon.example.org/users/admin",
1195 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
1196 "object" => "https://info.pleroma.site/activity.json",
1197 "type" => "Announce"
1198 }
1199
1200 :error = Transmogrifier.handle_incoming(data)
1201 end
1202
1203 test "it rejects activities which reference objects that have an incorrect attribution (variant 1)" do
1204 data = %{
1205 "@context" => "https://www.w3.org/ns/activitystreams",
1206 "id" => "http://mastodon.example.org/users/admin/activities/1234",
1207 "actor" => "http://mastodon.example.org/users/admin",
1208 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
1209 "object" => "https://info.pleroma.site/activity2.json",
1210 "type" => "Announce"
1211 }
1212
1213 :error = Transmogrifier.handle_incoming(data)
1214 end
1215
1216 test "it rejects activities which reference objects that have an incorrect attribution (variant 2)" do
1217 data = %{
1218 "@context" => "https://www.w3.org/ns/activitystreams",
1219 "id" => "http://mastodon.example.org/users/admin/activities/1234",
1220 "actor" => "http://mastodon.example.org/users/admin",
1221 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
1222 "object" => "https://info.pleroma.site/activity3.json",
1223 "type" => "Announce"
1224 }
1225
1226 :error = Transmogrifier.handle_incoming(data)
1227 end
1228 end
1229
1230 describe "reserialization" do
1231 test "successfully reserializes a message with inReplyTo == nil" do
1232 user = insert(:user)
1233
1234 message = %{
1235 "@context" => "https://www.w3.org/ns/activitystreams",
1236 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
1237 "cc" => [],
1238 "type" => "Create",
1239 "object" => %{
1240 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
1241 "cc" => [],
1242 "type" => "Note",
1243 "content" => "Hi",
1244 "inReplyTo" => nil,
1245 "attributedTo" => user.ap_id
1246 },
1247 "actor" => user.ap_id
1248 }
1249
1250 {:ok, activity} = Transmogrifier.handle_incoming(message)
1251
1252 {:ok, _} = Transmogrifier.prepare_outgoing(activity.data)
1253 end
1254
1255 test "successfully reserializes a message with AS2 objects in IR" do
1256 user = insert(:user)
1257
1258 message = %{
1259 "@context" => "https://www.w3.org/ns/activitystreams",
1260 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
1261 "cc" => [],
1262 "type" => "Create",
1263 "object" => %{
1264 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
1265 "cc" => [],
1266 "type" => "Note",
1267 "content" => "Hi",
1268 "inReplyTo" => nil,
1269 "attributedTo" => user.ap_id,
1270 "tag" => [
1271 %{"name" => "#2hu", "href" => "http://example.com/2hu", "type" => "Hashtag"},
1272 %{"name" => "Bob", "href" => "http://example.com/bob", "type" => "Mention"}
1273 ]
1274 },
1275 "actor" => user.ap_id
1276 }
1277
1278 {:ok, activity} = Transmogrifier.handle_incoming(message)
1279
1280 {:ok, _} = Transmogrifier.prepare_outgoing(activity.data)
1281 end
1282 end
1283
1284 test "Rewrites Answers to Notes" do
1285 user = insert(:user)
1286
1287 {:ok, poll_activity} =
1288 CommonAPI.post(user, %{
1289 "status" => "suya...",
1290 "poll" => %{"options" => ["suya", "suya.", "suya.."], "expires_in" => 10}
1291 })
1292
1293 poll_object = Object.normalize(poll_activity)
1294 # TODO: Replace with CommonAPI vote creation when implemented
1295 data =
1296 File.read!("test/fixtures/mastodon-vote.json")
1297 |> Poison.decode!()
1298 |> Kernel.put_in(["to"], user.ap_id)
1299 |> Kernel.put_in(["object", "inReplyTo"], poll_object.data["id"])
1300 |> Kernel.put_in(["object", "to"], user.ap_id)
1301
1302 {:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data)
1303 {:ok, data} = Transmogrifier.prepare_outgoing(activity.data)
1304
1305 assert data["object"]["type"] == "Note"
1306 end
1307
1308 describe "fix_explicit_addressing" do
1309 setup do
1310 user = insert(:user)
1311 [user: user]
1312 end
1313
1314 test "moves non-explicitly mentioned actors to cc", %{user: user} do
1315 explicitly_mentioned_actors = [
1316 "https://pleroma.gold/users/user1",
1317 "https://pleroma.gold/user2"
1318 ]
1319
1320 object = %{
1321 "actor" => user.ap_id,
1322 "to" => explicitly_mentioned_actors ++ ["https://social.beepboop.ga/users/dirb"],
1323 "cc" => [],
1324 "tag" =>
1325 Enum.map(explicitly_mentioned_actors, fn href ->
1326 %{"type" => "Mention", "href" => href}
1327 end)
1328 }
1329
1330 fixed_object = Transmogrifier.fix_explicit_addressing(object)
1331 assert Enum.all?(explicitly_mentioned_actors, &(&1 in fixed_object["to"]))
1332 refute "https://social.beepboop.ga/users/dirb" in fixed_object["to"]
1333 assert "https://social.beepboop.ga/users/dirb" in fixed_object["cc"]
1334 end
1335
1336 test "does not move actor's follower collection to cc", %{user: user} do
1337 object = %{
1338 "actor" => user.ap_id,
1339 "to" => [user.follower_address],
1340 "cc" => []
1341 }
1342
1343 fixed_object = Transmogrifier.fix_explicit_addressing(object)
1344 assert user.follower_address in fixed_object["to"]
1345 refute user.follower_address in fixed_object["cc"]
1346 end
1347
1348 test "removes recipient's follower collection from cc", %{user: user} do
1349 recipient = insert(:user)
1350
1351 object = %{
1352 "actor" => user.ap_id,
1353 "to" => [recipient.ap_id, "https://www.w3.org/ns/activitystreams#Public"],
1354 "cc" => [user.follower_address, recipient.follower_address]
1355 }
1356
1357 fixed_object = Transmogrifier.fix_explicit_addressing(object)
1358
1359 assert user.follower_address in fixed_object["cc"]
1360 refute recipient.follower_address in fixed_object["cc"]
1361 refute recipient.follower_address in fixed_object["to"]
1362 end
1363 end
1364
1365 test "update_following_followers_counters/1" do
1366 user1 =
1367 insert(:user,
1368 local: false,
1369 follower_address: "http://localhost:4001/users/masto_closed/followers",
1370 following_address: "http://localhost:4001/users/masto_closed/following"
1371 )
1372
1373 user2 =
1374 insert(:user,
1375 local: false,
1376 follower_address: "http://localhost:4001/users/fuser2/followers",
1377 following_address: "http://localhost:4001/users/fuser2/following"
1378 )
1379
1380 Transmogrifier.update_following_followers_counters(user1)
1381 Transmogrifier.update_following_followers_counters(user2)
1382
1383 %{follower_count: followers, following_count: following} = User.get_cached_user_info(user1)
1384 assert followers == 437
1385 assert following == 152
1386
1387 %{follower_count: followers, following_count: following} = User.get_cached_user_info(user2)
1388
1389 assert followers == 527
1390 assert following == 267
1391 end
1392 end