From 798da28812b7af2e79e2c59896418192efcab543 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Tue, 19 Mar 2019 17:27:42 +0000 Subject: [PATCH 1/7] activitypub: transmogrifier: ensure as:Public activities are delivered to followers --- .../web/activity_pub/transmogrifier.ex | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 8e4bf7b47..7f3d8fd4b 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -128,13 +128,42 @@ def fix_explicit_addressing(object) do |> fix_explicit_addressing(explicit_mentions) end + # if as:Public is addressed, then make sure the followers collection is also addressed + # so that the activities will be delivered to local users. + def fix_implicit_addressing(%{"to" => to, "cc" => cc} = object, followers_collection) do + recipients = to ++ cc + + if followers_collection not in recipients do + cond do + "https://www.w3.org/ns/activitystreams#Public" in cc -> + to = to ++ [followers_collection] + Map.put(object, "to", to) + + "https://www.w3.org/ns/activitystreams#Public" in to -> + cc = cc ++ [followers_collection] + Map.put(object, "cc", cc) + + true -> + object + end + else + object + end + end + + def fix_implicit_addressing(object, _), do: object + def fix_addressing(object) do + %User{} = user = User.get_cached_by_ap_id(object["actor"]) + followers_collection = User.ap_followers(user) + object |> fix_addressing_list("to") |> fix_addressing_list("cc") |> fix_addressing_list("bto") |> fix_addressing_list("bcc") |> fix_explicit_addressing + |> fix_implicit_addressing(followers_collection) end def fix_actor(%{"attributedTo" => actor} = object) do From d487b753c3116e7a4261404b2357f337acc2d64d Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Tue, 19 Mar 2019 17:30:25 +0000 Subject: [PATCH 2/7] activitypub: transmogrifier: do not allow missing lists to be interpreted as nil --- lib/pleroma/web/activity_pub/transmogrifier.ex | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 7f3d8fd4b..9d536f7f5 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -86,11 +86,15 @@ def fix_object(object) do end def fix_addressing_list(map, field) do - if is_binary(map[field]) do - map - |> Map.put(field, [map[field]]) - else - map + cond do + is_binary(map[field]) -> + Map.put(map, field, [map[field]]) + + is_nil(map[field]) -> + Map.put(map, field, []) + + true -> + map end end From fd0aa58ee0e236fa25771965288a53990a145f75 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Tue, 19 Mar 2019 17:49:29 +0000 Subject: [PATCH 3/7] tests: add test for as:Public issues --- test/web/activity_pub/transmogrifier_test.exs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs index afb931934..6b263c3d7 100644 --- a/test/web/activity_pub/transmogrifier_test.exs +++ b/test/web/activity_pub/transmogrifier_test.exs @@ -335,6 +335,29 @@ test "it does not clobber the addressing on announce activities" do assert data["to"] == ["http://mastodon.example.org/users/admin/followers"] end + test "it ensures that as:Public activities make it to their followers collection" do + user = insert(:user) + + data = + File.read!("test/fixtures/mastodon-post-activity.json") + |> Poison.decode!() + |> Map.put("actor", user.ap_id) + |> Map.put("to", ["https://www.w3.org/ns/activitystreams#Public"]) + |> Map.put("cc", []) + + object = + data["object"] + |> Map.put("attributedTo", user.ap_id) + |> Map.put("to", ["https://www.w3.org/ns/activitystreams#Public"]) + |> Map.put("cc", []) + + data = Map.put(data, "object", object) + + {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) + + assert data["cc"] == [User.ap_followers(user)] + end + test "it works for incoming update activities" do data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!() From 455bb526f6a7ab1a85171cb9757ab2c523eaf39a Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Tue, 19 Mar 2019 17:53:40 +0000 Subject: [PATCH 4/7] test: add test for list sanitization --- test/web/activity_pub/transmogrifier_test.exs | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs index 6b263c3d7..50e8e40bd 100644 --- a/test/web/activity_pub/transmogrifier_test.exs +++ b/test/web/activity_pub/transmogrifier_test.exs @@ -358,6 +358,30 @@ test "it ensures that as:Public activities make it to their followers collection assert data["cc"] == [User.ap_followers(user)] end + test "it ensures that address fields become lists" do + user = insert(:user) + + data = + File.read!("test/fixtures/mastodon-post-activity.json") + |> Poison.decode!() + |> Map.put("actor", user.ap_id) + |> Map.put("to", nil) + |> Map.put("cc", nil) + + object = + data["object"] + |> Map.put("attributedTo", user.ap_id) + |> Map.put("to", nil) + |> Map.put("cc", nil) + + data = Map.put(data, "object", object) + + {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) + + assert !is_nil(data["to"]) + assert !is_nil(data["cc"]) + end + test "it works for incoming update activities" do data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!() From cd055983c3d066c9f08aa26b62d3ec6d4419cb7c Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Tue, 19 Mar 2019 18:04:57 +0000 Subject: [PATCH 5/7] transmogrifier: when determining followers collection URI, we may need to fetch the actor --- lib/pleroma/web/activity_pub/transmogrifier.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 9d536f7f5..4f663d01e 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -158,7 +158,7 @@ def fix_implicit_addressing(%{"to" => to, "cc" => cc} = object, followers_collec def fix_implicit_addressing(object, _), do: object def fix_addressing(object) do - %User{} = user = User.get_cached_by_ap_id(object["actor"]) + %User{} = user = User.get_or_fetch_by_ap_id(object["actor"]) followers_collection = User.ap_followers(user) object From 67ff8d9311d453220af1b84385281a077a3cb20e Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Tue, 19 Mar 2019 18:23:06 +0000 Subject: [PATCH 6/7] user: properly cope with actors which do not declare a followers collection --- lib/pleroma/user.ex | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index fb3bd121d..8df276ae0 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -104,9 +104,8 @@ def ap_id(%User{nickname: nickname}) do "#{Web.base_url()}/users/#{nickname}" end - def ap_followers(%User{} = user) do - "#{ap_id(user)}/followers" - end + def ap_followers(%User{follower_address: fa}) when is_binary(fa), do: fa + def ap_followers(%User{} = user), do: "#{ap_id(user)}/followers" def user_info(%User{} = user) do oneself = if user.local, do: 1, else: 0 From 1685e4258f452343c86d9dd3914076f101c8ed73 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Tue, 19 Mar 2019 18:39:33 +0000 Subject: [PATCH 7/7] transmogrifier: upgrade: when upgrading OStatus users to AP, ensure we always use the fake collection --- lib/pleroma/web/activity_pub/transmogrifier.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 4f663d01e..f733ae7e1 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -955,7 +955,8 @@ defp strip_internal_tags(%{"tag" => tags} = object) do defp strip_internal_tags(object), do: object defp user_upgrade_task(user) do - old_follower_address = User.ap_followers(user) + # we pass a fake user so that the followers collection is stripped away + old_follower_address = User.ap_followers(%User{nickname: user.nickname}) q = from(