formatting
[akkoma] / test / web / activity_pub / transmogrifier_test.exs
1 defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
2 use Pleroma.DataCase
3 alias Pleroma.Web.ActivityPub.Transmogrifier
4 alias Pleroma.Web.ActivityPub.Utils
5 alias Pleroma.Web.ActivityPub.ActivityPub
6 alias Pleroma.Web.OStatus
7 alias Pleroma.{Activity, Object}
8 alias Pleroma.User
9 alias Pleroma.Repo
10 alias Pleroma.Web.Websub.WebsubClientSubscription
11
12 import Pleroma.Factory
13 alias Pleroma.Web.CommonAPI
14
15 describe "handle_incoming" do
16 test "it ignores an incoming notice if we already have it" do
17 activity = insert(:note_activity)
18
19 data =
20 File.read!("test/fixtures/mastodon-post-activity.json")
21 |> Poison.decode!()
22 |> Map.put("object", activity.data["object"])
23
24 {:ok, returned_activity} = Transmogrifier.handle_incoming(data)
25
26 assert activity == returned_activity
27 end
28
29 test "it fetches replied-to activities if we don't have them" do
30 data =
31 File.read!("test/fixtures/mastodon-post-activity.json")
32 |> Poison.decode!()
33
34 object =
35 data["object"]
36 |> Map.put("inReplyTo", "https://shitposter.club/notice/2827873")
37
38 data =
39 data
40 |> Map.put("object", object)
41
42 {:ok, returned_activity} = Transmogrifier.handle_incoming(data)
43 returned_object = Object.normalize(returned_activity.data["object"])
44
45 assert activity =
46 Activity.get_create_activity_by_object_ap_id(
47 "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"
48 )
49
50 assert returned_object.data["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873"
51
52 assert returned_object.data["inReplyToStatusId"] == activity.id
53 end
54
55 test "it works for incoming notices" do
56 data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!()
57
58 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
59
60 assert data["id"] ==
61 "http://mastodon.example.org/users/admin/statuses/99512778738411822/activity"
62
63 assert data["context"] ==
64 "tag:mastodon.example.org,2018-02-12:objectId=20:objectType=Conversation"
65
66 assert data["to"] == ["https://www.w3.org/ns/activitystreams#Public"]
67
68 assert data["cc"] == [
69 "http://mastodon.example.org/users/admin/followers",
70 "http://localtesting.pleroma.lol/users/lain"
71 ]
72
73 assert data["actor"] == "http://mastodon.example.org/users/admin"
74
75 object = Object.normalize(data["object"]).data
76 assert object["id"] == "http://mastodon.example.org/users/admin/statuses/99512778738411822"
77
78 assert object["to"] == ["https://www.w3.org/ns/activitystreams#Public"]
79
80 assert object["cc"] == [
81 "http://mastodon.example.org/users/admin/followers",
82 "http://localtesting.pleroma.lol/users/lain"
83 ]
84
85 assert object["actor"] == "http://mastodon.example.org/users/admin"
86 assert object["attributedTo"] == "http://mastodon.example.org/users/admin"
87
88 assert object["context"] ==
89 "tag:mastodon.example.org,2018-02-12:objectId=20:objectType=Conversation"
90
91 assert object["sensitive"] == true
92
93 user = User.get_by_ap_id(object["actor"])
94
95 assert user.info.note_count == 1
96 end
97
98 test "it works for incoming notices with hashtags" do
99 data = File.read!("test/fixtures/mastodon-post-activity-hashtag.json") |> Poison.decode!()
100
101 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
102 object = Object.normalize(data["object"])
103
104 assert Enum.at(object.data["tag"], 2) == "moo"
105 end
106
107 test "it works for incoming notices with contentMap" do
108 data =
109 File.read!("test/fixtures/mastodon-post-activity-contentmap.json") |> Poison.decode!()
110
111 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
112 object = Object.normalize(data["object"])
113
114 assert object.data["content"] ==
115 "<p><span class=\"h-card\"><a href=\"http://localtesting.pleroma.lol/users/lain\" class=\"u-url mention\">@<span>lain</span></a></span></p>"
116 end
117
118 test "it works for incoming notices with to/cc not being an array (kroeg)" do
119 data = File.read!("test/fixtures/kroeg-post-activity.json") |> Poison.decode!()
120
121 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
122 object = Object.normalize(data["object"])
123
124 assert object.data["content"] ==
125 "<p>henlo from my Psion netBook</p><p>message sent from my Psion netBook</p>"
126 end
127
128 test "it works for incoming announces with actor being inlined (kroeg)" do
129 data = File.read!("test/fixtures/kroeg-announce-with-inline-actor.json") |> Poison.decode!()
130
131 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
132
133 assert data["actor"] == "https://puckipedia.com/"
134 end
135
136 test "it works for incoming notices with tag not being an array (kroeg)" do
137 data = File.read!("test/fixtures/kroeg-array-less-emoji.json") |> Poison.decode!()
138
139 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
140 object = Object.normalize(data["object"])
141
142 assert object.data["emoji"] == %{
143 "icon_e_smile" => "https://puckipedia.com/forum/images/smilies/icon_e_smile.png"
144 }
145
146 data = File.read!("test/fixtures/kroeg-array-less-hashtag.json") |> Poison.decode!()
147
148 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
149 object = Object.normalize(data["object"])
150
151 assert "test" in object.data["tag"]
152 end
153
154 test "it works for incoming notices with url not being a string (prismo)" do
155 data = File.read!("test/fixtures/prismo-url-map.json") |> Poison.decode!()
156
157 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
158 object = Object.normalize(data["object"])
159
160 assert object.data["url"] == "https://prismo.news/posts/83"
161 end
162
163 test "it works for incoming follow requests" do
164 user = insert(:user)
165
166 data =
167 File.read!("test/fixtures/mastodon-follow-activity.json")
168 |> Poison.decode!()
169 |> Map.put("object", user.ap_id)
170
171 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
172
173 assert data["actor"] == "http://mastodon.example.org/users/admin"
174 assert data["type"] == "Follow"
175 assert data["id"] == "http://mastodon.example.org/users/admin#follows/2"
176 assert User.following?(User.get_by_ap_id(data["actor"]), user)
177 end
178
179 test "it works for incoming follow requests from hubzilla" do
180 user = insert(:user)
181
182 data =
183 File.read!("test/fixtures/hubzilla-follow-activity.json")
184 |> Poison.decode!()
185 |> Map.put("object", user.ap_id)
186 |> Utils.normalize_params()
187
188 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
189
190 assert data["actor"] == "https://hubzilla.example.org/channel/kaniini"
191 assert data["type"] == "Follow"
192 assert data["id"] == "https://hubzilla.example.org/channel/kaniini#follows/2"
193 assert User.following?(User.get_by_ap_id(data["actor"]), user)
194 end
195
196 test "it works for incoming likes" do
197 user = insert(:user)
198 {:ok, activity} = CommonAPI.post(user, %{"status" => "hello"})
199
200 data =
201 File.read!("test/fixtures/mastodon-like.json")
202 |> Poison.decode!()
203 |> Map.put("object", activity.data["object"])
204
205 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
206
207 assert data["actor"] == "http://mastodon.example.org/users/admin"
208 assert data["type"] == "Like"
209 assert data["id"] == "http://mastodon.example.org/users/admin#likes/2"
210 assert data["object"] == activity.data["object"]
211 end
212
213 test "it returns an error for incoming unlikes wihout a like activity" do
214 user = insert(:user)
215 {:ok, activity} = CommonAPI.post(user, %{"status" => "leave a like pls"})
216
217 data =
218 File.read!("test/fixtures/mastodon-undo-like.json")
219 |> Poison.decode!()
220 |> Map.put("object", activity.data["object"])
221
222 assert Transmogrifier.handle_incoming(data) == :error
223 end
224
225 test "it works for incoming unlikes with an existing like activity" do
226 user = insert(:user)
227 {:ok, activity} = CommonAPI.post(user, %{"status" => "leave a like pls"})
228
229 like_data =
230 File.read!("test/fixtures/mastodon-like.json")
231 |> Poison.decode!()
232 |> Map.put("object", activity.data["object"])
233
234 {:ok, %Activity{data: like_data, local: false}} = Transmogrifier.handle_incoming(like_data)
235
236 data =
237 File.read!("test/fixtures/mastodon-undo-like.json")
238 |> Poison.decode!()
239 |> Map.put("object", like_data)
240 |> Map.put("actor", like_data["actor"])
241
242 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
243
244 assert data["actor"] == "http://mastodon.example.org/users/admin"
245 assert data["type"] == "Undo"
246 assert data["id"] == "http://mastodon.example.org/users/admin#likes/2/undo"
247 assert data["object"]["id"] == "http://mastodon.example.org/users/admin#likes/2"
248 end
249
250 test "it works for incoming announces" do
251 data = File.read!("test/fixtures/mastodon-announce.json") |> Poison.decode!()
252
253 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
254
255 assert data["actor"] == "http://mastodon.example.org/users/admin"
256 assert data["type"] == "Announce"
257
258 assert data["id"] ==
259 "http://mastodon.example.org/users/admin/statuses/99542391527669785/activity"
260
261 assert data["object"] ==
262 "http://mastodon.example.org/users/admin/statuses/99541947525187367"
263
264 assert Activity.get_create_activity_by_object_ap_id(data["object"])
265 end
266
267 test "it works for incoming announces with an existing activity" do
268 user = insert(:user)
269 {:ok, activity} = CommonAPI.post(user, %{"status" => "hey"})
270
271 data =
272 File.read!("test/fixtures/mastodon-announce.json")
273 |> Poison.decode!()
274 |> Map.put("object", activity.data["object"])
275
276 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
277
278 assert data["actor"] == "http://mastodon.example.org/users/admin"
279 assert data["type"] == "Announce"
280
281 assert data["id"] ==
282 "http://mastodon.example.org/users/admin/statuses/99542391527669785/activity"
283
284 assert data["object"] == activity.data["object"]
285
286 assert Activity.get_create_activity_by_object_ap_id(data["object"]).id == activity.id
287 end
288
289 test "it works for incoming update activities" do
290 data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!()
291
292 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
293 update_data = File.read!("test/fixtures/mastodon-update.json") |> Poison.decode!()
294
295 object =
296 update_data["object"]
297 |> Map.put("actor", data["actor"])
298 |> Map.put("id", data["actor"])
299
300 update_data =
301 update_data
302 |> Map.put("actor", data["actor"])
303 |> Map.put("object", object)
304
305 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(update_data)
306
307 user = User.get_cached_by_ap_id(data["actor"])
308 assert user.name == "gargle"
309
310 assert user.avatar["url"] == [
311 %{
312 "href" =>
313 "https://cd.niu.moe/accounts/avatars/000/033/323/original/fd7f8ae0b3ffedc9.jpeg"
314 }
315 ]
316
317 assert user.info.banner["url"] == [
318 %{
319 "href" =>
320 "https://cd.niu.moe/accounts/headers/000/033/323/original/850b3448fa5fd477.png"
321 }
322 ]
323
324 assert user.bio == "<p>Some bio</p>"
325 end
326
327 test "it works for incoming update activities which lock the account" do
328 data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!()
329
330 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
331 update_data = File.read!("test/fixtures/mastodon-update.json") |> Poison.decode!()
332
333 object =
334 update_data["object"]
335 |> Map.put("actor", data["actor"])
336 |> Map.put("id", data["actor"])
337 |> Map.put("manuallyApprovesFollowers", true)
338
339 update_data =
340 update_data
341 |> Map.put("actor", data["actor"])
342 |> Map.put("object", object)
343
344 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(update_data)
345
346 user = User.get_cached_by_ap_id(data["actor"])
347 assert user.info.locked == true
348 end
349
350 test "it works for incoming deletes" do
351 activity = insert(:note_activity)
352
353 data =
354 File.read!("test/fixtures/mastodon-delete.json")
355 |> Poison.decode!()
356
357 object =
358 data["object"]
359 |> Map.put("id", activity.data["object"])
360
361 data =
362 data
363 |> Map.put("object", object)
364 |> Map.put("actor", activity.data["actor"])
365
366 {:ok, %Activity{local: false}} = Transmogrifier.handle_incoming(data)
367
368 refute Repo.get(Activity, activity.id)
369 end
370
371 test "it fails for incoming deletes with spoofed origin" do
372 activity = insert(:note_activity)
373
374 data =
375 File.read!("test/fixtures/mastodon-delete.json")
376 |> Poison.decode!()
377
378 object =
379 data["object"]
380 |> Map.put("id", activity.data["object"])
381
382 data =
383 data
384 |> Map.put("object", object)
385
386 :error = Transmogrifier.handle_incoming(data)
387
388 assert Repo.get(Activity, activity.id)
389 end
390
391 test "it works for incoming unannounces with an existing notice" do
392 user = insert(:user)
393 {:ok, activity} = CommonAPI.post(user, %{"status" => "hey"})
394
395 announce_data =
396 File.read!("test/fixtures/mastodon-announce.json")
397 |> Poison.decode!()
398 |> Map.put("object", activity.data["object"])
399
400 {:ok, %Activity{data: announce_data, local: false}} =
401 Transmogrifier.handle_incoming(announce_data)
402
403 data =
404 File.read!("test/fixtures/mastodon-undo-announce.json")
405 |> Poison.decode!()
406 |> Map.put("object", announce_data)
407 |> Map.put("actor", announce_data["actor"])
408
409 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
410
411 assert data["type"] == "Undo"
412 assert data["object"]["type"] == "Announce"
413 assert data["object"]["object"] == activity.data["object"]
414
415 assert data["object"]["id"] ==
416 "http://mastodon.example.org/users/admin/statuses/99542391527669785/activity"
417 end
418
419 test "it works for incomming unfollows with an existing follow" do
420 user = insert(:user)
421
422 follow_data =
423 File.read!("test/fixtures/mastodon-follow-activity.json")
424 |> Poison.decode!()
425 |> Map.put("object", user.ap_id)
426
427 {:ok, %Activity{data: _, local: false}} = Transmogrifier.handle_incoming(follow_data)
428
429 data =
430 File.read!("test/fixtures/mastodon-unfollow-activity.json")
431 |> Poison.decode!()
432 |> Map.put("object", follow_data)
433
434 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
435
436 assert data["type"] == "Undo"
437 assert data["object"]["type"] == "Follow"
438 assert data["object"]["object"] == user.ap_id
439 assert data["actor"] == "http://mastodon.example.org/users/admin"
440
441 refute User.following?(User.get_by_ap_id(data["actor"]), user)
442 end
443
444 test "it works for incoming blocks" do
445 user = insert(:user)
446
447 data =
448 File.read!("test/fixtures/mastodon-block-activity.json")
449 |> Poison.decode!()
450 |> Map.put("object", user.ap_id)
451
452 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
453
454 assert data["type"] == "Block"
455 assert data["object"] == user.ap_id
456 assert data["actor"] == "http://mastodon.example.org/users/admin"
457
458 blocker = User.get_by_ap_id(data["actor"])
459
460 assert User.blocks?(blocker, user)
461 end
462
463 test "incoming blocks successfully tear down any follow relationship" do
464 blocker = insert(:user)
465 blocked = insert(:user)
466
467 data =
468 File.read!("test/fixtures/mastodon-block-activity.json")
469 |> Poison.decode!()
470 |> Map.put("object", blocked.ap_id)
471 |> Map.put("actor", blocker.ap_id)
472
473 {:ok, blocker} = User.follow(blocker, blocked)
474 {:ok, blocked} = User.follow(blocked, blocker)
475
476 assert User.following?(blocker, blocked)
477 assert User.following?(blocked, blocker)
478
479 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
480
481 assert data["type"] == "Block"
482 assert data["object"] == blocked.ap_id
483 assert data["actor"] == blocker.ap_id
484
485 blocker = User.get_by_ap_id(data["actor"])
486 blocked = User.get_by_ap_id(data["object"])
487
488 assert User.blocks?(blocker, blocked)
489
490 refute User.following?(blocker, blocked)
491 refute User.following?(blocked, blocker)
492 end
493
494 test "it works for incoming unblocks with an existing block" do
495 user = insert(:user)
496
497 block_data =
498 File.read!("test/fixtures/mastodon-block-activity.json")
499 |> Poison.decode!()
500 |> Map.put("object", user.ap_id)
501
502 {:ok, %Activity{data: _, local: false}} = Transmogrifier.handle_incoming(block_data)
503
504 data =
505 File.read!("test/fixtures/mastodon-unblock-activity.json")
506 |> Poison.decode!()
507 |> Map.put("object", block_data)
508
509 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
510 assert data["type"] == "Undo"
511 assert data["object"]["type"] == "Block"
512 assert data["object"]["object"] == user.ap_id
513 assert data["actor"] == "http://mastodon.example.org/users/admin"
514
515 blocker = User.get_by_ap_id(data["actor"])
516
517 refute User.blocks?(blocker, user)
518 end
519
520 test "it works for incoming accepts which were pre-accepted" do
521 follower = insert(:user)
522 followed = insert(:user)
523
524 {:ok, follower} = User.follow(follower, followed)
525 assert User.following?(follower, followed) == true
526
527 {:ok, follow_activity} = ActivityPub.follow(follower, followed)
528
529 accept_data =
530 File.read!("test/fixtures/mastodon-accept-activity.json")
531 |> Poison.decode!()
532 |> Map.put("actor", followed.ap_id)
533
534 object =
535 accept_data["object"]
536 |> Map.put("actor", follower.ap_id)
537 |> Map.put("id", follow_activity.data["id"])
538
539 accept_data = Map.put(accept_data, "object", object)
540
541 {:ok, activity} = Transmogrifier.handle_incoming(accept_data)
542 refute activity.local
543
544 assert activity.data["object"] == follow_activity.data["id"]
545
546 follower = Repo.get(User, follower.id)
547
548 assert User.following?(follower, followed) == true
549 end
550
551 test "it works for incoming accepts which were orphaned" do
552 follower = insert(:user)
553 followed = insert(:user, %{info: %User.Info{locked: true}})
554
555 {:ok, follow_activity} = ActivityPub.follow(follower, followed)
556
557 accept_data =
558 File.read!("test/fixtures/mastodon-accept-activity.json")
559 |> Poison.decode!()
560 |> Map.put("actor", followed.ap_id)
561
562 accept_data =
563 Map.put(accept_data, "object", Map.put(accept_data["object"], "actor", follower.ap_id))
564
565 {:ok, activity} = Transmogrifier.handle_incoming(accept_data)
566 assert activity.data["object"] == follow_activity.data["id"]
567
568 follower = Repo.get(User, follower.id)
569
570 assert User.following?(follower, followed) == true
571 end
572
573 test "it works for incoming accepts which are referenced by IRI only" do
574 follower = insert(:user)
575 followed = insert(:user, %{info: %User.Info{locked: true}})
576
577 {:ok, follow_activity} = ActivityPub.follow(follower, followed)
578
579 accept_data =
580 File.read!("test/fixtures/mastodon-accept-activity.json")
581 |> Poison.decode!()
582 |> Map.put("actor", followed.ap_id)
583 |> Map.put("object", follow_activity.data["id"])
584
585 {:ok, activity} = Transmogrifier.handle_incoming(accept_data)
586 assert activity.data["object"] == follow_activity.data["id"]
587
588 follower = Repo.get(User, follower.id)
589
590 assert User.following?(follower, followed) == true
591 end
592
593 test "it fails for incoming accepts which cannot be correlated" do
594 follower = insert(:user)
595 followed = insert(:user, %{info: %User.Info{locked: true}})
596
597 accept_data =
598 File.read!("test/fixtures/mastodon-accept-activity.json")
599 |> Poison.decode!()
600 |> Map.put("actor", followed.ap_id)
601
602 accept_data =
603 Map.put(accept_data, "object", Map.put(accept_data["object"], "actor", follower.ap_id))
604
605 :error = Transmogrifier.handle_incoming(accept_data)
606
607 follower = Repo.get(User, follower.id)
608
609 refute User.following?(follower, followed) == true
610 end
611
612 test "it fails for incoming rejects which cannot be correlated" do
613 follower = insert(:user)
614 followed = insert(:user, %{info: %User.Info{locked: true}})
615
616 accept_data =
617 File.read!("test/fixtures/mastodon-reject-activity.json")
618 |> Poison.decode!()
619 |> Map.put("actor", followed.ap_id)
620
621 accept_data =
622 Map.put(accept_data, "object", Map.put(accept_data["object"], "actor", follower.ap_id))
623
624 :error = Transmogrifier.handle_incoming(accept_data)
625
626 follower = Repo.get(User, follower.id)
627
628 refute User.following?(follower, followed) == true
629 end
630
631 test "it works for incoming rejects which are orphaned" do
632 follower = insert(:user)
633 followed = insert(:user, %{info: %User.Info{locked: true}})
634
635 {:ok, follower} = User.follow(follower, followed)
636 {:ok, _follow_activity} = ActivityPub.follow(follower, followed)
637
638 assert User.following?(follower, followed) == true
639
640 reject_data =
641 File.read!("test/fixtures/mastodon-reject-activity.json")
642 |> Poison.decode!()
643 |> Map.put("actor", followed.ap_id)
644
645 reject_data =
646 Map.put(reject_data, "object", Map.put(reject_data["object"], "actor", follower.ap_id))
647
648 {:ok, activity} = Transmogrifier.handle_incoming(reject_data)
649 refute activity.local
650
651 follower = Repo.get(User, follower.id)
652
653 assert User.following?(follower, followed) == false
654 end
655
656 test "it works for incoming rejects which are referenced by IRI only" do
657 follower = insert(:user)
658 followed = insert(:user, %{info: %User.Info{locked: true}})
659
660 {:ok, follower} = User.follow(follower, followed)
661 {:ok, follow_activity} = ActivityPub.follow(follower, followed)
662
663 assert User.following?(follower, followed) == true
664
665 reject_data =
666 File.read!("test/fixtures/mastodon-reject-activity.json")
667 |> Poison.decode!()
668 |> Map.put("actor", followed.ap_id)
669 |> Map.put("object", follow_activity.data["id"])
670
671 {:ok, %Activity{data: _}} = Transmogrifier.handle_incoming(reject_data)
672
673 follower = Repo.get(User, follower.id)
674
675 assert User.following?(follower, followed) == false
676 end
677
678 test "it rejects activities without a valid ID" do
679 user = insert(:user)
680
681 data =
682 File.read!("test/fixtures/mastodon-follow-activity.json")
683 |> Poison.decode!()
684 |> Map.put("object", user.ap_id)
685 |> Map.put("id", "")
686
687 :error = Transmogrifier.handle_incoming(data)
688 end
689 end
690
691 describe "prepare outgoing" do
692 test "it turns mentions into tags" do
693 user = insert(:user)
694 other_user = insert(:user)
695
696 {:ok, activity} =
697 CommonAPI.post(user, %{"status" => "hey, @#{other_user.nickname}, how are ya? #2hu"})
698
699 {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
700 object = modified["object"]
701
702 expected_mention = %{
703 "href" => other_user.ap_id,
704 "name" => "@#{other_user.nickname}",
705 "type" => "Mention"
706 }
707
708 expected_tag = %{
709 "href" => Pleroma.Web.Endpoint.url() <> "/tags/2hu",
710 "type" => "Hashtag",
711 "name" => "#2hu"
712 }
713
714 assert Enum.member?(object["tag"], expected_tag)
715 assert Enum.member?(object["tag"], expected_mention)
716 end
717
718 test "it adds the sensitive property" do
719 user = insert(:user)
720
721 {:ok, activity} = CommonAPI.post(user, %{"status" => "#nsfw hey"})
722 {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
723
724 assert modified["object"]["sensitive"]
725 end
726
727 test "it adds the json-ld context and the conversation property" do
728 user = insert(:user)
729
730 {:ok, activity} = CommonAPI.post(user, %{"status" => "hey"})
731 {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
732
733 assert modified["@context"] ==
734 Pleroma.Web.ActivityPub.Utils.make_json_ld_header()["@context"]
735
736 assert modified["object"]["conversation"] == modified["context"]
737 end
738
739 test "it sets the 'attributedTo' property to the actor of the object if it doesn't have one" do
740 user = insert(:user)
741
742 {:ok, activity} = CommonAPI.post(user, %{"status" => "hey"})
743 {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
744
745 assert modified["object"]["actor"] == modified["object"]["attributedTo"]
746 end
747
748 test "it translates ostatus IDs to external URLs" do
749 incoming = File.read!("test/fixtures/incoming_note_activity.xml")
750 {:ok, [referent_activity]} = OStatus.handle_incoming(incoming)
751
752 user = insert(:user)
753
754 {:ok, activity, _} = CommonAPI.favorite(referent_activity.id, user)
755 {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
756
757 assert modified["object"] == "http://gs.example.org:4040/index.php/notice/29"
758 end
759
760 test "it translates ostatus reply_to IDs to external URLs" do
761 incoming = File.read!("test/fixtures/incoming_note_activity.xml")
762 {:ok, [referred_activity]} = OStatus.handle_incoming(incoming)
763
764 user = insert(:user)
765
766 {:ok, activity} =
767 CommonAPI.post(user, %{"status" => "HI!", "in_reply_to_status_id" => referred_activity.id})
768
769 {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
770
771 assert modified["object"]["inReplyTo"] == "http://gs.example.org:4040/index.php/notice/29"
772 end
773
774 test "it strips internal hashtag data" do
775 user = insert(:user)
776
777 {:ok, activity} = CommonAPI.post(user, %{"status" => "#2hu"})
778
779 expected_tag = %{
780 "href" => Pleroma.Web.Endpoint.url() <> "/tags/2hu",
781 "type" => "Hashtag",
782 "name" => "#2hu"
783 }
784
785 {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
786
787 assert modified["object"]["tag"] == [expected_tag]
788 end
789
790 test "it strips internal fields" do
791 user = insert(:user)
792
793 {:ok, activity} = CommonAPI.post(user, %{"status" => "#2hu :moominmamma:"})
794
795 {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
796
797 assert length(modified["object"]["tag"]) == 2
798
799 assert is_nil(modified["object"]["emoji"])
800 assert is_nil(modified["object"]["likes"])
801 assert is_nil(modified["object"]["like_count"])
802 assert is_nil(modified["object"]["announcements"])
803 assert is_nil(modified["object"]["announcement_count"])
804 assert is_nil(modified["object"]["context_id"])
805 end
806 end
807
808 describe "user upgrade" do
809 test "it upgrades a user to activitypub" do
810 user =
811 insert(:user, %{
812 nickname: "rye@niu.moe",
813 local: false,
814 ap_id: "https://niu.moe/users/rye",
815 follower_address: User.ap_followers(%User{nickname: "rye@niu.moe"})
816 })
817
818 user_two = insert(:user, %{following: [user.follower_address]})
819
820 {:ok, activity} = CommonAPI.post(user, %{"status" => "test"})
821 {:ok, unrelated_activity} = CommonAPI.post(user_two, %{"status" => "test"})
822 assert "http://localhost:4001/users/rye@niu.moe/followers" in activity.recipients
823
824 user = Repo.get(User, user.id)
825 assert user.info.note_count == 1
826
827 {:ok, user} = Transmogrifier.upgrade_user_from_ap_id("https://niu.moe/users/rye")
828 assert user.info.ap_enabled
829 assert user.info.note_count == 1
830 assert user.follower_address == "https://niu.moe/users/rye/followers"
831
832 # Wait for the background task
833 :timer.sleep(1000)
834
835 user = Repo.get(User, user.id)
836 assert user.info.note_count == 1
837
838 activity = Repo.get(Activity, activity.id)
839 assert user.follower_address in activity.recipients
840
841 assert %{
842 "url" => [
843 %{
844 "href" =>
845 "https://cdn.niu.moe/accounts/avatars/000/033/323/original/fd7f8ae0b3ffedc9.jpeg"
846 }
847 ]
848 } = user.avatar
849
850 assert %{
851 "url" => [
852 %{
853 "href" =>
854 "https://cdn.niu.moe/accounts/headers/000/033/323/original/850b3448fa5fd477.png"
855 }
856 ]
857 } = user.info.banner
858
859 refute "..." in activity.recipients
860
861 unrelated_activity = Repo.get(Activity, unrelated_activity.id)
862 refute user.follower_address in unrelated_activity.recipients
863
864 user_two = Repo.get(User, user_two.id)
865 assert user.follower_address in user_two.following
866 refute "..." in user_two.following
867 end
868 end
869
870 describe "maybe_retire_websub" do
871 test "it deletes all websub client subscripitions with the user as topic" do
872 subscription = %WebsubClientSubscription{topic: "https://niu.moe/users/rye.atom"}
873 {:ok, ws} = Repo.insert(subscription)
874
875 subscription = %WebsubClientSubscription{topic: "https://niu.moe/users/pasty.atom"}
876 {:ok, ws2} = Repo.insert(subscription)
877
878 Transmogrifier.maybe_retire_websub("https://niu.moe/users/rye")
879
880 refute Repo.get(WebsubClientSubscription, ws.id)
881 assert Repo.get(WebsubClientSubscription, ws2.id)
882 end
883 end
884
885 describe "actor rewriting" do
886 test "it fixes the actor URL property to be a proper URI" do
887 data = %{
888 "url" => %{"href" => "http://example.com"}
889 }
890
891 rewritten = Transmogrifier.maybe_fix_user_object(data)
892 assert rewritten["url"] == "http://example.com"
893 end
894 end
895
896 describe "actor origin containment" do
897 test "it rejects activities which reference objects with bogus origins" do
898 data = %{
899 "@context" => "https://www.w3.org/ns/activitystreams",
900 "id" => "http://mastodon.example.org/users/admin/activities/1234",
901 "actor" => "http://mastodon.example.org/users/admin",
902 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
903 "object" => "https://info.pleroma.site/activity.json",
904 "type" => "Announce"
905 }
906
907 :error = Transmogrifier.handle_incoming(data)
908 end
909
910 test "it rejects activities which reference objects that have an incorrect attribution (variant 1)" do
911 data = %{
912 "@context" => "https://www.w3.org/ns/activitystreams",
913 "id" => "http://mastodon.example.org/users/admin/activities/1234",
914 "actor" => "http://mastodon.example.org/users/admin",
915 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
916 "object" => "https://info.pleroma.site/activity2.json",
917 "type" => "Announce"
918 }
919
920 :error = Transmogrifier.handle_incoming(data)
921 end
922
923 test "it rejects activities which reference objects that have an incorrect attribution (variant 2)" do
924 data = %{
925 "@context" => "https://www.w3.org/ns/activitystreams",
926 "id" => "http://mastodon.example.org/users/admin/activities/1234",
927 "actor" => "http://mastodon.example.org/users/admin",
928 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
929 "object" => "https://info.pleroma.site/activity3.json",
930 "type" => "Announce"
931 }
932
933 :error = Transmogrifier.handle_incoming(data)
934 end
935 end
936 end