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