1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
9 alias Pleroma.Object.Fetcher
11 alias Pleroma.Tests.ObanHelpers
13 alias Pleroma.Web.ActivityPub.ActivityPub
14 alias Pleroma.Web.ActivityPub.Transmogrifier
15 alias Pleroma.Web.AdminAPI.AccountView
16 alias Pleroma.Web.CommonAPI
17 alias Pleroma.Web.OStatus
18 alias Pleroma.Web.Websub.WebsubClientSubscription
21 import Pleroma.Factory
22 import ExUnit.CaptureLog
25 Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
29 clear_config([:instance, :max_remote_account_fields])
31 describe "handle_incoming" do
32 test "it ignores an incoming notice if we already have it" do
33 activity = insert(:note_activity)
36 File.read!("test/fixtures/mastodon-post-activity.json")
38 |> Map.put("object", Object.normalize(activity).data)
40 {:ok, returned_activity} = Transmogrifier.handle_incoming(data)
42 assert activity == returned_activity
45 test "it fetches replied-to activities if we don't have them" do
47 File.read!("test/fixtures/mastodon-post-activity.json")
52 |> Map.put("inReplyTo", "https://shitposter.club/notice/2827873")
54 data = Map.put(data, "object", object)
55 {:ok, returned_activity} = Transmogrifier.handle_incoming(data)
56 returned_object = Object.normalize(returned_activity, false)
59 Activity.get_create_by_object_ap_id(
60 "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"
63 assert returned_object.data["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873"
66 test "it does not fetch replied-to activities beyond max_replies_depth" do
68 File.read!("test/fixtures/mastodon-post-activity.json")
73 |> Map.put("inReplyTo", "https://shitposter.club/notice/2827873")
75 data = Map.put(data, "object", object)
77 with_mock Pleroma.Web.Federator,
78 allowed_incoming_reply_depth?: fn _ -> false end do
79 {:ok, returned_activity} = Transmogrifier.handle_incoming(data)
81 returned_object = Object.normalize(returned_activity, false)
83 refute Activity.get_create_by_object_ap_id(
84 "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"
87 assert returned_object.data["inReplyToAtomUri"] ==
88 "https://shitposter.club/notice/2827873"
92 test "it does not crash if the object in inReplyTo can't be fetched" do
94 File.read!("test/fixtures/mastodon-post-activity.json")
99 |> Map.put("inReplyTo", "https://404.site/whatever")
103 |> Map.put("object", object)
105 assert capture_log(fn ->
106 {:ok, _returned_activity} = Transmogrifier.handle_incoming(data)
107 end) =~ "[error] Couldn't fetch \"https://404.site/whatever\", error: nil"
110 test "it works for incoming notices" do
111 data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!()
113 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
116 "http://mastodon.example.org/users/admin/statuses/99512778738411822/activity"
118 assert data["context"] ==
119 "tag:mastodon.example.org,2018-02-12:objectId=20:objectType=Conversation"
121 assert data["to"] == ["https://www.w3.org/ns/activitystreams#Public"]
123 assert data["cc"] == [
124 "http://mastodon.example.org/users/admin/followers",
125 "http://localtesting.pleroma.lol/users/lain"
128 assert data["actor"] == "http://mastodon.example.org/users/admin"
130 object_data = Object.normalize(data["object"]).data
132 assert object_data["id"] ==
133 "http://mastodon.example.org/users/admin/statuses/99512778738411822"
135 assert object_data["to"] == ["https://www.w3.org/ns/activitystreams#Public"]
137 assert object_data["cc"] == [
138 "http://mastodon.example.org/users/admin/followers",
139 "http://localtesting.pleroma.lol/users/lain"
142 assert object_data["actor"] == "http://mastodon.example.org/users/admin"
143 assert object_data["attributedTo"] == "http://mastodon.example.org/users/admin"
145 assert object_data["context"] ==
146 "tag:mastodon.example.org,2018-02-12:objectId=20:objectType=Conversation"
148 assert object_data["sensitive"] == true
150 user = User.get_cached_by_ap_id(object_data["actor"])
152 assert user.info.note_count == 1
155 test "it works for incoming notices with hashtags" do
156 data = File.read!("test/fixtures/mastodon-post-activity-hashtag.json") |> Poison.decode!()
158 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
159 object = Object.normalize(data["object"])
161 assert Enum.at(object.data["tag"], 2) == "moo"
164 test "it works for incoming questions" do
165 data = File.read!("test/fixtures/mastodon-question-activity.json") |> Poison.decode!()
167 {:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data)
169 object = Object.normalize(activity)
171 assert Enum.all?(object.data["oneOf"], fn choice ->
174 "Everyone knows that!",
175 "25 char limit is dumb",
176 "I can't even fit a funny"
181 test "it works for incoming listens" do
183 "@context" => "https://www.w3.org/ns/activitystreams",
184 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
187 "id" => "http://mastodon.example.org/users/admin/listens/1234/activity",
188 "actor" => "http://mastodon.example.org/users/admin",
191 "id" => "http://mastodon.example.org/users/admin/listens/1234",
192 "attributedTo" => "http://mastodon.example.org/users/admin",
193 "title" => "lain radio episode 1",
195 "album" => "lain radio",
200 {:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data)
202 object = Object.normalize(activity)
204 assert object.data["title"] == "lain radio episode 1"
205 assert object.data["artist"] == "lain"
206 assert object.data["album"] == "lain radio"
207 assert object.data["length"] == 180_000
210 test "it rewrites Note votes to Answers and increments vote counters on question activities" do
214 CommonAPI.post(user, %{
215 "status" => "suya...",
216 "poll" => %{"options" => ["suya", "suya.", "suya.."], "expires_in" => 10}
219 object = Object.normalize(activity)
222 File.read!("test/fixtures/mastodon-vote.json")
224 |> Kernel.put_in(["to"], user.ap_id)
225 |> Kernel.put_in(["object", "inReplyTo"], object.data["id"])
226 |> Kernel.put_in(["object", "to"], user.ap_id)
228 {:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data)
229 answer_object = Object.normalize(activity)
230 assert answer_object.data["type"] == "Answer"
231 object = Object.get_by_ap_id(object.data["id"])
234 object.data["oneOf"],
236 %{"name" => "suya..", "replies" => %{"totalItems" => 1}} -> true
242 test "it works for incoming notices with contentMap" do
244 File.read!("test/fixtures/mastodon-post-activity-contentmap.json") |> Poison.decode!()
246 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
247 object = Object.normalize(data["object"])
249 assert object.data["content"] ==
250 "<p><span class=\"h-card\"><a href=\"http://localtesting.pleroma.lol/users/lain\" class=\"u-url mention\">@<span>lain</span></a></span></p>"
253 test "it works for incoming notices with to/cc not being an array (kroeg)" do
254 data = File.read!("test/fixtures/kroeg-post-activity.json") |> Poison.decode!()
256 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
257 object = Object.normalize(data["object"])
259 assert object.data["content"] ==
260 "<p>henlo from my Psion netBook</p><p>message sent from my Psion netBook</p>"
263 test "it works for incoming announces with actor being inlined (kroeg)" do
264 data = File.read!("test/fixtures/kroeg-announce-with-inline-actor.json") |> Poison.decode!()
266 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
268 assert data["actor"] == "https://puckipedia.com/"
271 test "it works for incoming notices with tag not being an array (kroeg)" do
272 data = File.read!("test/fixtures/kroeg-array-less-emoji.json") |> Poison.decode!()
274 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
275 object = Object.normalize(data["object"])
277 assert object.data["emoji"] == %{
278 "icon_e_smile" => "https://puckipedia.com/forum/images/smilies/icon_e_smile.png"
281 data = File.read!("test/fixtures/kroeg-array-less-hashtag.json") |> Poison.decode!()
283 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
284 object = Object.normalize(data["object"])
286 assert "test" in object.data["tag"]
289 test "it works for incoming notices with url not being a string (prismo)" do
290 data = File.read!("test/fixtures/prismo-url-map.json") |> Poison.decode!()
292 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
293 object = Object.normalize(data["object"])
295 assert object.data["url"] == "https://prismo.news/posts/83"
298 test "it cleans up incoming notices which are not really DMs" do
300 other_user = insert(:user)
302 to = [user.ap_id, other_user.ap_id]
305 File.read!("test/fixtures/mastodon-post-activity.json")
315 data = Map.put(data, "object", object)
317 {:ok, %Activity{data: data, local: false} = activity} = Transmogrifier.handle_incoming(data)
319 assert data["to"] == []
320 assert data["cc"] == to
322 object_data = Object.normalize(activity).data
324 assert object_data["to"] == []
325 assert object_data["cc"] == to
328 test "it works for incoming likes" do
330 {:ok, activity} = CommonAPI.post(user, %{"status" => "hello"})
333 File.read!("test/fixtures/mastodon-like.json")
335 |> Map.put("object", activity.data["object"])
337 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
339 assert data["actor"] == "http://mastodon.example.org/users/admin"
340 assert data["type"] == "Like"
341 assert data["id"] == "http://mastodon.example.org/users/admin#likes/2"
342 assert data["object"] == activity.data["object"]
345 test "it returns an error for incoming unlikes wihout a like activity" do
347 {:ok, activity} = CommonAPI.post(user, %{"status" => "leave a like pls"})
350 File.read!("test/fixtures/mastodon-undo-like.json")
352 |> Map.put("object", activity.data["object"])
354 assert Transmogrifier.handle_incoming(data) == :error
357 test "it works for incoming unlikes with an existing like activity" do
359 {:ok, activity} = CommonAPI.post(user, %{"status" => "leave a like pls"})
362 File.read!("test/fixtures/mastodon-like.json")
364 |> Map.put("object", activity.data["object"])
366 {:ok, %Activity{data: like_data, local: false}} = Transmogrifier.handle_incoming(like_data)
369 File.read!("test/fixtures/mastodon-undo-like.json")
371 |> Map.put("object", like_data)
372 |> Map.put("actor", like_data["actor"])
374 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
376 assert data["actor"] == "http://mastodon.example.org/users/admin"
377 assert data["type"] == "Undo"
378 assert data["id"] == "http://mastodon.example.org/users/admin#likes/2/undo"
379 assert data["object"]["id"] == "http://mastodon.example.org/users/admin#likes/2"
382 test "it works for incoming unlikes with an existing like activity and a compact object" do
384 {:ok, activity} = CommonAPI.post(user, %{"status" => "leave a like pls"})
387 File.read!("test/fixtures/mastodon-like.json")
389 |> Map.put("object", activity.data["object"])
391 {:ok, %Activity{data: like_data, local: false}} = Transmogrifier.handle_incoming(like_data)
394 File.read!("test/fixtures/mastodon-undo-like.json")
396 |> Map.put("object", like_data["id"])
397 |> Map.put("actor", like_data["actor"])
399 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
401 assert data["actor"] == "http://mastodon.example.org/users/admin"
402 assert data["type"] == "Undo"
403 assert data["id"] == "http://mastodon.example.org/users/admin#likes/2/undo"
404 assert data["object"]["id"] == "http://mastodon.example.org/users/admin#likes/2"
407 test "it works for incoming announces" do
408 data = File.read!("test/fixtures/mastodon-announce.json") |> Poison.decode!()
410 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
412 assert data["actor"] == "http://mastodon.example.org/users/admin"
413 assert data["type"] == "Announce"
416 "http://mastodon.example.org/users/admin/statuses/99542391527669785/activity"
418 assert data["object"] ==
419 "http://mastodon.example.org/users/admin/statuses/99541947525187367"
421 assert Activity.get_create_by_object_ap_id(data["object"])
424 test "it works for incoming announces with an existing activity" do
426 {:ok, activity} = CommonAPI.post(user, %{"status" => "hey"})
429 File.read!("test/fixtures/mastodon-announce.json")
431 |> Map.put("object", activity.data["object"])
433 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
435 assert data["actor"] == "http://mastodon.example.org/users/admin"
436 assert data["type"] == "Announce"
439 "http://mastodon.example.org/users/admin/statuses/99542391527669785/activity"
441 assert data["object"] == activity.data["object"]
443 assert Activity.get_create_by_object_ap_id(data["object"]).id == activity.id
446 test "it works for incoming announces with an inlined activity" do
448 File.read!("test/fixtures/mastodon-announce-private.json")
451 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
453 assert data["actor"] == "http://mastodon.example.org/users/admin"
454 assert data["type"] == "Announce"
457 "http://mastodon.example.org/users/admin/statuses/99542391527669785/activity"
459 object = Object.normalize(data["object"])
461 assert object.data["id"] == "http://mastodon.example.org/@admin/99541947525187368"
462 assert object.data["content"] == "this is a private toot"
465 test "it rejects incoming announces with an inlined activity from another origin" do
467 File.read!("test/fixtures/bogus-mastodon-announce.json")
470 assert :error = Transmogrifier.handle_incoming(data)
473 test "it does not clobber the addressing on announce activities" do
475 {:ok, activity} = CommonAPI.post(user, %{"status" => "hey"})
478 File.read!("test/fixtures/mastodon-announce.json")
480 |> Map.put("object", Object.normalize(activity).data["id"])
481 |> Map.put("to", ["http://mastodon.example.org/users/admin/followers"])
484 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
486 assert data["to"] == ["http://mastodon.example.org/users/admin/followers"]
489 test "it ensures that as:Public activities make it to their followers collection" do
493 File.read!("test/fixtures/mastodon-post-activity.json")
495 |> Map.put("actor", user.ap_id)
496 |> Map.put("to", ["https://www.w3.org/ns/activitystreams#Public"])
501 |> Map.put("attributedTo", user.ap_id)
502 |> Map.put("to", ["https://www.w3.org/ns/activitystreams#Public"])
504 |> Map.put("id", user.ap_id <> "/activities/12345678")
506 data = Map.put(data, "object", object)
508 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
510 assert data["cc"] == [User.ap_followers(user)]
513 test "it ensures that address fields become lists" do
517 File.read!("test/fixtures/mastodon-post-activity.json")
519 |> Map.put("actor", user.ap_id)
520 |> Map.put("to", nil)
521 |> Map.put("cc", nil)
525 |> Map.put("attributedTo", user.ap_id)
526 |> Map.put("to", nil)
527 |> Map.put("cc", nil)
528 |> Map.put("id", user.ap_id <> "/activities/12345678")
530 data = Map.put(data, "object", object)
532 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
534 assert !is_nil(data["to"])
535 assert !is_nil(data["cc"])
538 test "it strips internal likes" do
540 File.read!("test/fixtures/mastodon-post-activity.json")
545 "http://mastodon.example.org/objects/dbdbc507-52c8-490d-9b7c-1e1d52e5c132/likes?page=1",
546 "id" => "http://mastodon.example.org/objects/dbdbc507-52c8-490d-9b7c-1e1d52e5c132/likes",
548 "type" => "OrderedCollection"
551 object = Map.put(data["object"], "likes", likes)
552 data = Map.put(data, "object", object)
554 {:ok, %Activity{object: object}} = Transmogrifier.handle_incoming(data)
556 refute Map.has_key?(object.data, "likes")
559 test "it works for incoming update activities" do
560 data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!()
562 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
563 update_data = File.read!("test/fixtures/mastodon-update.json") |> Poison.decode!()
566 update_data["object"]
567 |> Map.put("actor", data["actor"])
568 |> Map.put("id", data["actor"])
572 |> Map.put("actor", data["actor"])
573 |> Map.put("object", object)
575 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(update_data)
577 assert data["id"] == update_data["id"]
579 user = User.get_cached_by_ap_id(data["actor"])
580 assert user.name == "gargle"
582 assert user.avatar["url"] == [
585 "https://cd.niu.moe/accounts/avatars/000/033/323/original/fd7f8ae0b3ffedc9.jpeg"
589 assert user.info.banner["url"] == [
592 "https://cd.niu.moe/accounts/headers/000/033/323/original/850b3448fa5fd477.png"
596 assert user.bio == "<p>Some bio</p>"
599 test "it works with custom profile fields" do
601 "test/fixtures/mastodon-post-activity.json"
604 |> Transmogrifier.handle_incoming()
606 user = User.get_cached_by_ap_id(activity.actor)
608 assert User.Info.fields(user.info) == [
609 %{"name" => "foo", "value" => "bar"},
610 %{"name" => "foo1", "value" => "bar1"}
613 update_data = File.read!("test/fixtures/mastodon-update.json") |> Poison.decode!()
616 update_data["object"]
617 |> Map.put("actor", user.ap_id)
618 |> Map.put("id", user.ap_id)
622 |> Map.put("actor", user.ap_id)
623 |> Map.put("object", object)
625 {:ok, _update_activity} = Transmogrifier.handle_incoming(update_data)
627 user = User.get_cached_by_ap_id(user.ap_id)
629 assert User.Info.fields(user.info) == [
630 %{"name" => "foo", "value" => "updated"},
631 %{"name" => "foo1", "value" => "updated"}
634 Pleroma.Config.put([:instance, :max_remote_account_fields], 2)
637 put_in(update_data, ["object", "attachment"], [
638 %{"name" => "foo", "type" => "PropertyValue", "value" => "bar"},
639 %{"name" => "foo11", "type" => "PropertyValue", "value" => "bar11"},
640 %{"name" => "foo22", "type" => "PropertyValue", "value" => "bar22"}
643 {:ok, _} = Transmogrifier.handle_incoming(update_data)
645 user = User.get_cached_by_ap_id(user.ap_id)
647 assert User.Info.fields(user.info) == [
648 %{"name" => "foo", "value" => "updated"},
649 %{"name" => "foo1", "value" => "updated"}
652 update_data = put_in(update_data, ["object", "attachment"], [])
654 {:ok, _} = Transmogrifier.handle_incoming(update_data)
656 user = User.get_cached_by_ap_id(user.ap_id)
658 assert User.Info.fields(user.info) == []
661 test "it works for incoming update activities which lock the account" do
662 data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!()
664 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
665 update_data = File.read!("test/fixtures/mastodon-update.json") |> Poison.decode!()
668 update_data["object"]
669 |> Map.put("actor", data["actor"])
670 |> Map.put("id", data["actor"])
671 |> Map.put("manuallyApprovesFollowers", true)
675 |> Map.put("actor", data["actor"])
676 |> Map.put("object", object)
678 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(update_data)
680 user = User.get_cached_by_ap_id(data["actor"])
681 assert user.info.locked == true
684 test "it works for incoming deletes" do
685 activity = insert(:note_activity)
686 deleting_user = insert(:user)
689 File.read!("test/fixtures/mastodon-delete.json")
694 |> Map.put("id", activity.data["object"])
698 |> Map.put("object", object)
699 |> Map.put("actor", deleting_user.ap_id)
701 {:ok, %Activity{actor: actor, local: false, data: %{"id" => id}}} =
702 Transmogrifier.handle_incoming(data)
704 assert id == data["id"]
705 refute Activity.get_by_id(activity.id)
706 assert actor == deleting_user.ap_id
709 test "it fails for incoming deletes with spoofed origin" do
710 activity = insert(:note_activity)
713 File.read!("test/fixtures/mastodon-delete.json")
718 |> Map.put("id", activity.data["object"])
722 |> Map.put("object", object)
724 assert capture_log(fn ->
725 :error = Transmogrifier.handle_incoming(data)
727 "[error] Could not decode user at fetch http://mastodon.example.org/users/gargron, {:error, {:error, :nxdomain}}"
729 assert Activity.get_by_id(activity.id)
732 test "it works for incoming user deletes" do
733 %{ap_id: ap_id} = insert(:user, ap_id: "http://mastodon.example.org/users/admin")
736 File.read!("test/fixtures/mastodon-delete-user.json")
739 {:ok, _} = Transmogrifier.handle_incoming(data)
740 ObanHelpers.perform_all()
742 refute User.get_cached_by_ap_id(ap_id)
745 test "it fails for incoming user deletes with spoofed origin" do
746 %{ap_id: ap_id} = insert(:user)
749 File.read!("test/fixtures/mastodon-delete-user.json")
751 |> Map.put("actor", ap_id)
753 assert :error == Transmogrifier.handle_incoming(data)
754 assert User.get_cached_by_ap_id(ap_id)
757 test "it works for incoming unannounces with an existing notice" do
759 {:ok, activity} = CommonAPI.post(user, %{"status" => "hey"})
762 File.read!("test/fixtures/mastodon-announce.json")
764 |> Map.put("object", activity.data["object"])
766 {:ok, %Activity{data: announce_data, local: false}} =
767 Transmogrifier.handle_incoming(announce_data)
770 File.read!("test/fixtures/mastodon-undo-announce.json")
772 |> Map.put("object", announce_data)
773 |> Map.put("actor", announce_data["actor"])
775 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
777 assert data["type"] == "Undo"
778 assert object_data = data["object"]
779 assert object_data["type"] == "Announce"
780 assert object_data["object"] == activity.data["object"]
782 assert object_data["id"] ==
783 "http://mastodon.example.org/users/admin/statuses/99542391527669785/activity"
786 test "it works for incomming unfollows with an existing follow" do
790 File.read!("test/fixtures/mastodon-follow-activity.json")
792 |> Map.put("object", user.ap_id)
794 {:ok, %Activity{data: _, local: false}} = Transmogrifier.handle_incoming(follow_data)
797 File.read!("test/fixtures/mastodon-unfollow-activity.json")
799 |> Map.put("object", follow_data)
801 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
803 assert data["type"] == "Undo"
804 assert data["object"]["type"] == "Follow"
805 assert data["object"]["object"] == user.ap_id
806 assert data["actor"] == "http://mastodon.example.org/users/admin"
808 refute User.following?(User.get_cached_by_ap_id(data["actor"]), user)
811 test "it works for incoming blocks" do
815 File.read!("test/fixtures/mastodon-block-activity.json")
817 |> Map.put("object", user.ap_id)
819 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
821 assert data["type"] == "Block"
822 assert data["object"] == user.ap_id
823 assert data["actor"] == "http://mastodon.example.org/users/admin"
825 blocker = User.get_cached_by_ap_id(data["actor"])
827 assert User.blocks?(blocker, user)
830 test "incoming blocks successfully tear down any follow relationship" do
831 blocker = insert(:user)
832 blocked = insert(:user)
835 File.read!("test/fixtures/mastodon-block-activity.json")
837 |> Map.put("object", blocked.ap_id)
838 |> Map.put("actor", blocker.ap_id)
840 {:ok, blocker} = User.follow(blocker, blocked)
841 {:ok, blocked} = User.follow(blocked, blocker)
843 assert User.following?(blocker, blocked)
844 assert User.following?(blocked, blocker)
846 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
848 assert data["type"] == "Block"
849 assert data["object"] == blocked.ap_id
850 assert data["actor"] == blocker.ap_id
852 blocker = User.get_cached_by_ap_id(data["actor"])
853 blocked = User.get_cached_by_ap_id(data["object"])
855 assert User.blocks?(blocker, blocked)
857 refute User.following?(blocker, blocked)
858 refute User.following?(blocked, blocker)
861 test "it works for incoming unblocks with an existing block" do
865 File.read!("test/fixtures/mastodon-block-activity.json")
867 |> Map.put("object", user.ap_id)
869 {:ok, %Activity{data: _, local: false}} = Transmogrifier.handle_incoming(block_data)
872 File.read!("test/fixtures/mastodon-unblock-activity.json")
874 |> Map.put("object", block_data)
876 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
877 assert data["type"] == "Undo"
878 assert data["object"]["type"] == "Block"
879 assert data["object"]["object"] == user.ap_id
880 assert data["actor"] == "http://mastodon.example.org/users/admin"
882 blocker = User.get_cached_by_ap_id(data["actor"])
884 refute User.blocks?(blocker, user)
887 test "it works for incoming accepts which were pre-accepted" do
888 follower = insert(:user)
889 followed = insert(:user)
891 {:ok, follower} = User.follow(follower, followed)
892 assert User.following?(follower, followed) == true
894 {:ok, follow_activity} = ActivityPub.follow(follower, followed)
897 File.read!("test/fixtures/mastodon-accept-activity.json")
899 |> Map.put("actor", followed.ap_id)
902 accept_data["object"]
903 |> Map.put("actor", follower.ap_id)
904 |> Map.put("id", follow_activity.data["id"])
906 accept_data = Map.put(accept_data, "object", object)
908 {:ok, activity} = Transmogrifier.handle_incoming(accept_data)
909 refute activity.local
911 assert activity.data["object"] == follow_activity.data["id"]
913 assert activity.data["id"] == accept_data["id"]
915 follower = User.get_cached_by_id(follower.id)
917 assert User.following?(follower, followed) == true
920 test "it works for incoming accepts which were orphaned" do
921 follower = insert(:user)
922 followed = insert(:user, %{info: %User.Info{locked: true}})
924 {:ok, follow_activity} = ActivityPub.follow(follower, followed)
927 File.read!("test/fixtures/mastodon-accept-activity.json")
929 |> Map.put("actor", followed.ap_id)
932 Map.put(accept_data, "object", Map.put(accept_data["object"], "actor", follower.ap_id))
934 {:ok, activity} = Transmogrifier.handle_incoming(accept_data)
935 assert activity.data["object"] == follow_activity.data["id"]
937 follower = User.get_cached_by_id(follower.id)
939 assert User.following?(follower, followed) == true
942 test "it works for incoming accepts which are referenced by IRI only" do
943 follower = insert(:user)
944 followed = insert(:user, %{info: %User.Info{locked: true}})
946 {:ok, follow_activity} = ActivityPub.follow(follower, followed)
949 File.read!("test/fixtures/mastodon-accept-activity.json")
951 |> Map.put("actor", followed.ap_id)
952 |> Map.put("object", follow_activity.data["id"])
954 {:ok, activity} = Transmogrifier.handle_incoming(accept_data)
955 assert activity.data["object"] == follow_activity.data["id"]
957 follower = User.get_cached_by_id(follower.id)
959 assert User.following?(follower, followed) == true
962 test "it fails for incoming accepts which cannot be correlated" do
963 follower = insert(:user)
964 followed = insert(:user, %{info: %User.Info{locked: true}})
967 File.read!("test/fixtures/mastodon-accept-activity.json")
969 |> Map.put("actor", followed.ap_id)
972 Map.put(accept_data, "object", Map.put(accept_data["object"], "actor", follower.ap_id))
974 :error = Transmogrifier.handle_incoming(accept_data)
976 follower = User.get_cached_by_id(follower.id)
978 refute User.following?(follower, followed) == true
981 test "it fails for incoming rejects which cannot be correlated" do
982 follower = insert(:user)
983 followed = insert(:user, %{info: %User.Info{locked: true}})
986 File.read!("test/fixtures/mastodon-reject-activity.json")
988 |> Map.put("actor", followed.ap_id)
991 Map.put(accept_data, "object", Map.put(accept_data["object"], "actor", follower.ap_id))
993 :error = Transmogrifier.handle_incoming(accept_data)
995 follower = User.get_cached_by_id(follower.id)
997 refute User.following?(follower, followed) == true
1000 test "it works for incoming rejects which are orphaned" do
1001 follower = insert(:user)
1002 followed = insert(:user, %{info: %User.Info{locked: true}})
1004 {:ok, follower} = User.follow(follower, followed)
1005 {:ok, _follow_activity} = ActivityPub.follow(follower, followed)
1007 assert User.following?(follower, followed) == true
1010 File.read!("test/fixtures/mastodon-reject-activity.json")
1012 |> Map.put("actor", followed.ap_id)
1015 Map.put(reject_data, "object", Map.put(reject_data["object"], "actor", follower.ap_id))
1017 {:ok, activity} = Transmogrifier.handle_incoming(reject_data)
1018 refute activity.local
1019 assert activity.data["id"] == reject_data["id"]
1021 follower = User.get_cached_by_id(follower.id)
1023 assert User.following?(follower, followed) == false
1026 test "it works for incoming rejects which are referenced by IRI only" do
1027 follower = insert(:user)
1028 followed = insert(:user, %{info: %User.Info{locked: true}})
1030 {:ok, follower} = User.follow(follower, followed)
1031 {:ok, follow_activity} = ActivityPub.follow(follower, followed)
1033 assert User.following?(follower, followed) == true
1036 File.read!("test/fixtures/mastodon-reject-activity.json")
1038 |> Map.put("actor", followed.ap_id)
1039 |> Map.put("object", follow_activity.data["id"])
1041 {:ok, %Activity{data: _}} = Transmogrifier.handle_incoming(reject_data)
1043 follower = User.get_cached_by_id(follower.id)
1045 assert User.following?(follower, followed) == false
1048 test "it rejects activities without a valid ID" do
1049 user = insert(:user)
1052 File.read!("test/fixtures/mastodon-follow-activity.json")
1054 |> Map.put("object", user.ap_id)
1055 |> Map.put("id", "")
1057 :error = Transmogrifier.handle_incoming(data)
1060 test "it remaps video URLs as attachments if necessary" do
1062 Fetcher.fetch_object_from_id(
1063 "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3"
1068 "mediaType" => "video/mp4",
1070 "https://peertube.moe/static/webseed/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-480.mp4",
1071 "mimeType" => "video/mp4",
1072 "size" => 5_015_880,
1076 "https://peertube.moe/static/webseed/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-480.mp4",
1077 "mediaType" => "video/mp4",
1084 assert object.data["url"] ==
1085 "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3"
1087 assert object.data["attachment"] == [attachment]
1090 test "it accepts Flag activities" do
1091 user = insert(:user)
1092 other_user = insert(:user)
1094 {:ok, activity} = CommonAPI.post(user, %{"status" => "test post"})
1095 object = Object.normalize(activity)
1099 "id" => activity.data["id"],
1100 "content" => "test post",
1101 "published" => object.data["published"],
1102 "actor" => AccountView.render("show.json", %{user: user})
1106 "@context" => "https://www.w3.org/ns/activitystreams",
1107 "cc" => [user.ap_id],
1108 "object" => [user.ap_id, activity],
1110 "content" => "blocked AND reported!!!",
1111 "actor" => other_user.ap_id
1114 assert {:ok, activity} = Transmogrifier.handle_incoming(message)
1116 assert activity.data["object"] == [user.ap_id, note_obj]
1117 assert activity.data["content"] == "blocked AND reported!!!"
1118 assert activity.data["actor"] == other_user.ap_id
1119 assert activity.data["cc"] == [user.ap_id]
1123 describe "prepare outgoing" do
1124 test "it inlines private announced objects" do
1125 user = insert(:user)
1127 {:ok, activity} = CommonAPI.post(user, %{"status" => "hey", "visibility" => "private"})
1129 {:ok, announce_activity, _} = CommonAPI.repeat(activity.id, user)
1131 {:ok, modified} = Transmogrifier.prepare_outgoing(announce_activity.data)
1133 assert modified["object"]["content"] == "hey"
1134 assert modified["object"]["actor"] == modified["object"]["attributedTo"]
1137 test "it turns mentions into tags" do
1138 user = insert(:user)
1139 other_user = insert(:user)
1142 CommonAPI.post(user, %{"status" => "hey, @#{other_user.nickname}, how are ya? #2hu"})
1144 {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
1145 object = modified["object"]
1147 expected_mention = %{
1148 "href" => other_user.ap_id,
1149 "name" => "@#{other_user.nickname}",
1154 "href" => Pleroma.Web.Endpoint.url() <> "/tags/2hu",
1155 "type" => "Hashtag",
1159 assert Enum.member?(object["tag"], expected_tag)
1160 assert Enum.member?(object["tag"], expected_mention)
1163 test "it adds the sensitive property" do
1164 user = insert(:user)
1166 {:ok, activity} = CommonAPI.post(user, %{"status" => "#nsfw hey"})
1167 {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
1169 assert modified["object"]["sensitive"]
1172 test "it adds the json-ld context and the conversation property" do
1173 user = insert(:user)
1175 {:ok, activity} = CommonAPI.post(user, %{"status" => "hey"})
1176 {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
1178 assert modified["@context"] ==
1179 Pleroma.Web.ActivityPub.Utils.make_json_ld_header()["@context"]
1181 assert modified["object"]["conversation"] == modified["context"]
1184 test "it sets the 'attributedTo' property to the actor of the object if it doesn't have one" do
1185 user = insert(:user)
1187 {:ok, activity} = CommonAPI.post(user, %{"status" => "hey"})
1188 {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
1190 assert modified["object"]["actor"] == modified["object"]["attributedTo"]
1193 test "it translates ostatus IDs to external URLs" do
1194 incoming = File.read!("test/fixtures/incoming_note_activity.xml")
1195 {:ok, [referent_activity]} = OStatus.handle_incoming(incoming)
1197 user = insert(:user)
1199 {:ok, activity, _} = CommonAPI.favorite(referent_activity.id, user)
1200 {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
1202 assert modified["object"] == "http://gs.example.org:4040/index.php/notice/29"
1205 test "it translates ostatus reply_to IDs to external URLs" do
1206 incoming = File.read!("test/fixtures/incoming_note_activity.xml")
1207 {:ok, [referred_activity]} = OStatus.handle_incoming(incoming)
1209 user = insert(:user)
1212 CommonAPI.post(user, %{"status" => "HI!", "in_reply_to_status_id" => referred_activity.id})
1214 {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
1216 assert modified["object"]["inReplyTo"] == "http://gs.example.org:4040/index.php/notice/29"
1219 test "it strips internal hashtag data" do
1220 user = insert(:user)
1222 {:ok, activity} = CommonAPI.post(user, %{"status" => "#2hu"})
1225 "href" => Pleroma.Web.Endpoint.url() <> "/tags/2hu",
1226 "type" => "Hashtag",
1230 {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
1232 assert modified["object"]["tag"] == [expected_tag]
1235 test "it strips internal fields" do
1236 user = insert(:user)
1238 {:ok, activity} = CommonAPI.post(user, %{"status" => "#2hu :firefox:"})
1240 {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
1242 assert length(modified["object"]["tag"]) == 2
1244 assert is_nil(modified["object"]["emoji"])
1245 assert is_nil(modified["object"]["like_count"])
1246 assert is_nil(modified["object"]["announcements"])
1247 assert is_nil(modified["object"]["announcement_count"])
1248 assert is_nil(modified["object"]["context_id"])
1251 test "it strips internal fields of article" do
1252 activity = insert(:article_activity)
1254 {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
1256 assert length(modified["object"]["tag"]) == 2
1258 assert is_nil(modified["object"]["emoji"])
1259 assert is_nil(modified["object"]["like_count"])
1260 assert is_nil(modified["object"]["announcements"])
1261 assert is_nil(modified["object"]["announcement_count"])
1262 assert is_nil(modified["object"]["context_id"])
1263 assert is_nil(modified["object"]["likes"])
1266 test "the directMessage flag is present" do
1267 user = insert(:user)
1268 other_user = insert(:user)
1270 {:ok, activity} = CommonAPI.post(user, %{"status" => "2hu :moominmamma:"})
1272 {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
1274 assert modified["directMessage"] == false
1277 CommonAPI.post(user, %{"status" => "@#{other_user.nickname} :moominmamma:"})
1279 {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
1281 assert modified["directMessage"] == false
1284 CommonAPI.post(user, %{
1285 "status" => "@#{other_user.nickname} :moominmamma:",
1286 "visibility" => "direct"
1289 {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
1291 assert modified["directMessage"] == true
1294 test "it strips BCC field" do
1295 user = insert(:user)
1296 {:ok, list} = Pleroma.List.create("foo", user)
1299 CommonAPI.post(user, %{"status" => "foobar", "visibility" => "list:#{list.id}"})
1301 {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
1303 assert is_nil(modified["bcc"])
1306 test "it can handle Listen activities" do
1307 listen_activity = insert(:listen)
1309 {:ok, modified} = Transmogrifier.prepare_outgoing(listen_activity.data)
1311 assert modified["type"] == "Listen"
1313 user = insert(:user)
1315 {:ok, activity} = CommonAPI.listen(user, %{"title" => "lain radio episode 1"})
1317 {:ok, _modified} = Transmogrifier.prepare_outgoing(activity.data)
1321 describe "user upgrade" do
1322 test "it upgrades a user to activitypub" do
1325 nickname: "rye@niu.moe",
1327 ap_id: "https://niu.moe/users/rye",
1328 follower_address: User.ap_followers(%User{nickname: "rye@niu.moe"})
1331 user_two = insert(:user, %{following: [user.follower_address]})
1333 {:ok, activity} = CommonAPI.post(user, %{"status" => "test"})
1334 {:ok, unrelated_activity} = CommonAPI.post(user_two, %{"status" => "test"})
1335 assert "http://localhost:4001/users/rye@niu.moe/followers" in activity.recipients
1337 user = User.get_cached_by_id(user.id)
1338 assert user.info.note_count == 1
1340 {:ok, user} = Transmogrifier.upgrade_user_from_ap_id("https://niu.moe/users/rye")
1341 ObanHelpers.perform_all()
1343 assert user.info.ap_enabled
1344 assert user.info.note_count == 1
1345 assert user.follower_address == "https://niu.moe/users/rye/followers"
1346 assert user.following_address == "https://niu.moe/users/rye/following"
1348 user = User.get_cached_by_id(user.id)
1349 assert user.info.note_count == 1
1351 activity = Activity.get_by_id(activity.id)
1352 assert user.follower_address in activity.recipients
1358 "https://cdn.niu.moe/accounts/avatars/000/033/323/original/fd7f8ae0b3ffedc9.jpeg"
1367 "https://cdn.niu.moe/accounts/headers/000/033/323/original/850b3448fa5fd477.png"
1370 } = user.info.banner
1372 refute "..." in activity.recipients
1374 unrelated_activity = Activity.get_by_id(unrelated_activity.id)
1375 refute user.follower_address in unrelated_activity.recipients
1377 user_two = User.get_cached_by_id(user_two.id)
1378 assert user.follower_address in user_two.following
1379 refute "..." in user_two.following
1383 describe "maybe_retire_websub" do
1384 test "it deletes all websub client subscripitions with the user as topic" do
1385 subscription = %WebsubClientSubscription{topic: "https://niu.moe/users/rye.atom"}
1386 {:ok, ws} = Repo.insert(subscription)
1388 subscription = %WebsubClientSubscription{topic: "https://niu.moe/users/pasty.atom"}
1389 {:ok, ws2} = Repo.insert(subscription)
1391 Transmogrifier.maybe_retire_websub("https://niu.moe/users/rye")
1393 refute Repo.get(WebsubClientSubscription, ws.id)
1394 assert Repo.get(WebsubClientSubscription, ws2.id)
1398 describe "actor rewriting" do
1399 test "it fixes the actor URL property to be a proper URI" do
1401 "url" => %{"href" => "http://example.com"}
1404 rewritten = Transmogrifier.maybe_fix_user_object(data)
1405 assert rewritten["url"] == "http://example.com"
1409 describe "actor origin containment" do
1410 test "it rejects activities which reference objects with bogus origins" do
1412 "@context" => "https://www.w3.org/ns/activitystreams",
1413 "id" => "http://mastodon.example.org/users/admin/activities/1234",
1414 "actor" => "http://mastodon.example.org/users/admin",
1415 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
1416 "object" => "https://info.pleroma.site/activity.json",
1417 "type" => "Announce"
1420 :error = Transmogrifier.handle_incoming(data)
1423 test "it rejects activities which reference objects that have an incorrect attribution (variant 1)" do
1425 "@context" => "https://www.w3.org/ns/activitystreams",
1426 "id" => "http://mastodon.example.org/users/admin/activities/1234",
1427 "actor" => "http://mastodon.example.org/users/admin",
1428 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
1429 "object" => "https://info.pleroma.site/activity2.json",
1430 "type" => "Announce"
1433 :error = Transmogrifier.handle_incoming(data)
1436 test "it rejects activities which reference objects that have an incorrect attribution (variant 2)" do
1438 "@context" => "https://www.w3.org/ns/activitystreams",
1439 "id" => "http://mastodon.example.org/users/admin/activities/1234",
1440 "actor" => "http://mastodon.example.org/users/admin",
1441 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
1442 "object" => "https://info.pleroma.site/activity3.json",
1443 "type" => "Announce"
1446 :error = Transmogrifier.handle_incoming(data)
1450 describe "reserialization" do
1451 test "successfully reserializes a message with inReplyTo == nil" do
1452 user = insert(:user)
1455 "@context" => "https://www.w3.org/ns/activitystreams",
1456 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
1460 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
1465 "attributedTo" => user.ap_id
1467 "actor" => user.ap_id
1470 {:ok, activity} = Transmogrifier.handle_incoming(message)
1472 {:ok, _} = Transmogrifier.prepare_outgoing(activity.data)
1475 test "successfully reserializes a message with AS2 objects in IR" do
1476 user = insert(:user)
1479 "@context" => "https://www.w3.org/ns/activitystreams",
1480 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
1484 "to" => ["https://www.w3.org/ns/activitystreams#Public"],
1489 "attributedTo" => user.ap_id,
1491 %{"name" => "#2hu", "href" => "http://example.com/2hu", "type" => "Hashtag"},
1492 %{"name" => "Bob", "href" => "http://example.com/bob", "type" => "Mention"}
1495 "actor" => user.ap_id
1498 {:ok, activity} = Transmogrifier.handle_incoming(message)
1500 {:ok, _} = Transmogrifier.prepare_outgoing(activity.data)
1504 test "Rewrites Answers to Notes" do
1505 user = insert(:user)
1507 {:ok, poll_activity} =
1508 CommonAPI.post(user, %{
1509 "status" => "suya...",
1510 "poll" => %{"options" => ["suya", "suya.", "suya.."], "expires_in" => 10}
1513 poll_object = Object.normalize(poll_activity)
1514 # TODO: Replace with CommonAPI vote creation when implemented
1516 File.read!("test/fixtures/mastodon-vote.json")
1518 |> Kernel.put_in(["to"], user.ap_id)
1519 |> Kernel.put_in(["object", "inReplyTo"], poll_object.data["id"])
1520 |> Kernel.put_in(["object", "to"], user.ap_id)
1522 {:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data)
1523 {:ok, data} = Transmogrifier.prepare_outgoing(activity.data)
1525 assert data["object"]["type"] == "Note"
1528 describe "fix_explicit_addressing" do
1530 user = insert(:user)
1534 test "moves non-explicitly mentioned actors to cc", %{user: user} do
1535 explicitly_mentioned_actors = [
1536 "https://pleroma.gold/users/user1",
1537 "https://pleroma.gold/user2"
1541 "actor" => user.ap_id,
1542 "to" => explicitly_mentioned_actors ++ ["https://social.beepboop.ga/users/dirb"],
1545 Enum.map(explicitly_mentioned_actors, fn href ->
1546 %{"type" => "Mention", "href" => href}
1550 fixed_object = Transmogrifier.fix_explicit_addressing(object)
1551 assert Enum.all?(explicitly_mentioned_actors, &(&1 in fixed_object["to"]))
1552 refute "https://social.beepboop.ga/users/dirb" in fixed_object["to"]
1553 assert "https://social.beepboop.ga/users/dirb" in fixed_object["cc"]
1556 test "does not move actor's follower collection to cc", %{user: user} do
1558 "actor" => user.ap_id,
1559 "to" => [user.follower_address],
1563 fixed_object = Transmogrifier.fix_explicit_addressing(object)
1564 assert user.follower_address in fixed_object["to"]
1565 refute user.follower_address in fixed_object["cc"]
1568 test "removes recipient's follower collection from cc", %{user: user} do
1569 recipient = insert(:user)
1572 "actor" => user.ap_id,
1573 "to" => [recipient.ap_id, "https://www.w3.org/ns/activitystreams#Public"],
1574 "cc" => [user.follower_address, recipient.follower_address]
1577 fixed_object = Transmogrifier.fix_explicit_addressing(object)
1579 assert user.follower_address in fixed_object["cc"]
1580 refute recipient.follower_address in fixed_object["cc"]
1581 refute recipient.follower_address in fixed_object["to"]
1585 describe "fix_summary/1" do
1586 test "returns fixed object" do
1587 assert Transmogrifier.fix_summary(%{"summary" => nil}) == %{"summary" => ""}
1588 assert Transmogrifier.fix_summary(%{"summary" => "ok"}) == %{"summary" => "ok"}
1589 assert Transmogrifier.fix_summary(%{}) == %{"summary" => ""}
1593 describe "fix_in_reply_to/2" do
1594 clear_config([:instance, :federation_incoming_replies_max_depth])
1597 data = Poison.decode!(File.read!("test/fixtures/mastodon-post-activity.json"))
1601 test "returns not modified object when hasn't containts inReplyTo field", %{data: data} do
1602 assert Transmogrifier.fix_in_reply_to(data) == data
1605 test "returns object with inReplyToAtomUri when denied incoming reply", %{data: data} do
1606 Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 0)
1609 Map.put(data["object"], "inReplyTo", "https://shitposter.club/notice/2827873")
1611 modified_object = Transmogrifier.fix_in_reply_to(object_with_reply)
1612 assert modified_object["inReplyTo"] == "https://shitposter.club/notice/2827873"
1613 assert modified_object["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873"
1616 Map.put(data["object"], "inReplyTo", %{"id" => "https://shitposter.club/notice/2827873"})
1618 modified_object = Transmogrifier.fix_in_reply_to(object_with_reply)
1619 assert modified_object["inReplyTo"] == %{"id" => "https://shitposter.club/notice/2827873"}
1620 assert modified_object["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873"
1623 Map.put(data["object"], "inReplyTo", ["https://shitposter.club/notice/2827873"])
1625 modified_object = Transmogrifier.fix_in_reply_to(object_with_reply)
1626 assert modified_object["inReplyTo"] == ["https://shitposter.club/notice/2827873"]
1627 assert modified_object["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873"
1629 object_with_reply = Map.put(data["object"], "inReplyTo", [])
1630 modified_object = Transmogrifier.fix_in_reply_to(object_with_reply)
1631 assert modified_object["inReplyTo"] == []
1632 assert modified_object["inReplyToAtomUri"] == ""
1635 test "returns modified object when allowed incoming reply", %{data: data} do
1640 "https://shitposter.club/notice/2827873"
1643 Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 5)
1644 modified_object = Transmogrifier.fix_in_reply_to(object_with_reply)
1646 assert modified_object["inReplyTo"] ==
1647 "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"
1649 assert modified_object["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873"
1651 assert modified_object["conversation"] ==
1652 "tag:shitposter.club,2017-05-05:objectType=thread:nonce=3c16e9c2681f6d26"
1654 assert modified_object["context"] ==
1655 "tag:shitposter.club,2017-05-05:objectType=thread:nonce=3c16e9c2681f6d26"
1659 describe "fix_url/1" do
1660 test "fixes data for object when url is map" do
1664 "mimeType" => "video/mp4",
1665 "href" => "https://peede8d-46fb-ad81-2d4c2d1630e3-480.mp4"
1669 assert Transmogrifier.fix_url(object) == %{
1670 "url" => "https://peede8d-46fb-ad81-2d4c2d1630e3-480.mp4"
1674 test "fixes data for video object" do
1680 "mimeType" => "video/mp4",
1681 "href" => "https://peede8d-46fb-ad81-2d4c2d1630e3-480.mp4"
1685 "mimeType" => "video/mp4",
1686 "href" => "https://peertube46fb-ad81-2d4c2d1630e3-240.mp4"
1690 "mimeType" => "text/html",
1691 "href" => "https://peertube.-2d4c2d1630e3"
1695 "mimeType" => "text/html",
1696 "href" => "https://peertube.-2d4c2d16377-42"
1701 assert Transmogrifier.fix_url(object) == %{
1704 "href" => "https://peede8d-46fb-ad81-2d4c2d1630e3-480.mp4",
1705 "mimeType" => "video/mp4",
1710 "url" => "https://peertube.-2d4c2d1630e3"
1714 test "fixes url for not Video object" do
1720 "mimeType" => "text/html",
1721 "href" => "https://peertube.-2d4c2d1630e3"
1725 "mimeType" => "text/html",
1726 "href" => "https://peertube.-2d4c2d16377-42"
1731 assert Transmogrifier.fix_url(object) == %{
1733 "url" => "https://peertube.-2d4c2d1630e3"
1736 assert Transmogrifier.fix_url(%{"type" => "Text", "url" => []}) == %{
1742 test "retunrs not modified object" do
1743 assert Transmogrifier.fix_url(%{"type" => "Text"}) == %{"type" => "Text"}
1747 describe "get_obj_helper/2" do
1748 test "returns nil when cannot normalize object" do
1749 refute Transmogrifier.get_obj_helper("test-obj-id")
1752 test "returns {:ok, %Object{}} for success case" do
1753 assert {:ok, %Object{}} =
1754 Transmogrifier.get_obj_helper("https://shitposter.club/notice/2827873")
1758 describe "fix_attachments/1" do
1759 test "returns not modified object" do
1760 data = Poison.decode!(File.read!("test/fixtures/mastodon-post-activity.json"))
1761 assert Transmogrifier.fix_attachments(data) == data
1764 test "returns modified object when attachment is map" do
1765 assert Transmogrifier.fix_attachments(%{
1767 "mediaType" => "video/mp4",
1768 "url" => "https://peertube.moe/stat-480.mp4"
1773 "mediaType" => "video/mp4",
1776 "href" => "https://peertube.moe/stat-480.mp4",
1777 "mediaType" => "video/mp4",
1786 test "returns modified object when attachment is list" do
1787 assert Transmogrifier.fix_attachments(%{
1789 %{"mediaType" => "video/mp4", "url" => "https://pe.er/stat-480.mp4"},
1790 %{"mimeType" => "video/mp4", "href" => "https://pe.er/stat-480.mp4"}
1795 "mediaType" => "video/mp4",
1798 "href" => "https://pe.er/stat-480.mp4",
1799 "mediaType" => "video/mp4",
1805 "href" => "https://pe.er/stat-480.mp4",
1806 "mediaType" => "video/mp4",
1807 "mimeType" => "video/mp4",
1810 "href" => "https://pe.er/stat-480.mp4",
1811 "mediaType" => "video/mp4",
1821 describe "fix_emoji/1" do
1822 test "returns not modified object when object not contains tags" do
1823 data = Poison.decode!(File.read!("test/fixtures/mastodon-post-activity.json"))
1824 assert Transmogrifier.fix_emoji(data) == data
1827 test "returns object with emoji when object contains list tags" do
1828 assert Transmogrifier.fix_emoji(%{
1830 %{"type" => "Emoji", "name" => ":bib:", "icon" => %{"url" => "/test"}},
1831 %{"type" => "Hashtag"}
1834 "emoji" => %{"bib" => "/test"},
1836 %{"icon" => %{"url" => "/test"}, "name" => ":bib:", "type" => "Emoji"},
1837 %{"type" => "Hashtag"}
1842 test "returns object with emoji when object contains map tag" do
1843 assert Transmogrifier.fix_emoji(%{
1844 "tag" => %{"type" => "Emoji", "name" => ":bib:", "icon" => %{"url" => "/test"}}
1846 "emoji" => %{"bib" => "/test"},
1847 "tag" => %{"icon" => %{"url" => "/test"}, "name" => ":bib:", "type" => "Emoji"}