1f863f0a36
Objects who got updated would just pass through several of the MRF policies, undoing moderation in some situations. In the relevant cases we now check not only for Create activities, but also Update activities. I checked which ones checked explicitly on type Create using `grep '"type" => "Create"' lib/pleroma/web/activity_pub/mrf/*`. The following from that list have not been changed: * lib/pleroma/web/activity_pub/mrf/follow_bot_policy.ex * Not relevant for moderation * lib/pleroma/web/activity_pub/mrf/keyword_policy.ex * Already had a test for Update * lib/pleroma/web/activity_pub/mrf/object_age_policy.ex * In practice only relevant when fetching old objects (e.g. through Like or Announce). These are always wrapped in a Create. * lib/pleroma/web/activity_pub/mrf/reject_non_public.ex * We don't allow changing scope with Update, so not relevant here
635 lines
20 KiB
Elixir
635 lines
20 KiB
Elixir
# Pleroma: A lightweight social networking server
|
|
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
|
# SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
|
use Pleroma.DataCase
|
|
import Pleroma.Factory
|
|
alias Pleroma.Web.ActivityPub.MRF.SimplePolicy
|
|
alias Pleroma.Web.CommonAPI
|
|
|
|
setup do:
|
|
clear_config(:mrf_simple,
|
|
media_removal: [],
|
|
media_nsfw: [],
|
|
federated_timeline_removal: [],
|
|
report_removal: [],
|
|
reject: [],
|
|
followers_only: [],
|
|
accept: [],
|
|
avatar_removal: [],
|
|
banner_removal: [],
|
|
reject_deletes: []
|
|
)
|
|
|
|
describe "when :media_removal" do
|
|
test "is empty" do
|
|
clear_config([:mrf_simple, :media_removal], [])
|
|
media_message = build_media_message()
|
|
media_update_message = build_media_update_message()
|
|
local_message = build_local_message()
|
|
|
|
assert SimplePolicy.filter(media_message) == {:ok, media_message}
|
|
assert SimplePolicy.filter(media_update_message) == {:ok, media_update_message}
|
|
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
|
end
|
|
|
|
test "has a matching host" do
|
|
clear_config([:mrf_simple, :media_removal], [{"remote.instance", "Some reason"}])
|
|
media_message = build_media_message()
|
|
media_update_message = build_media_update_message()
|
|
local_message = build_local_message()
|
|
|
|
assert SimplePolicy.filter(media_message) ==
|
|
{:ok,
|
|
media_message
|
|
|> Map.put("object", Map.delete(media_message["object"], "attachment"))}
|
|
|
|
assert SimplePolicy.filter(media_update_message) ==
|
|
{:ok,
|
|
media_update_message
|
|
|> Map.put("object", Map.delete(media_update_message["object"], "attachment"))}
|
|
|
|
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
|
end
|
|
|
|
test "match with wildcard domain" do
|
|
clear_config([:mrf_simple, :media_removal], [{"*.remote.instance", "Whatever reason"}])
|
|
media_message = build_media_message()
|
|
media_update_message = build_media_update_message()
|
|
local_message = build_local_message()
|
|
|
|
assert SimplePolicy.filter(media_message) ==
|
|
{:ok,
|
|
media_message
|
|
|> Map.put("object", Map.delete(media_message["object"], "attachment"))}
|
|
|
|
assert SimplePolicy.filter(media_update_message) ==
|
|
{:ok,
|
|
media_update_message
|
|
|> Map.put("object", Map.delete(media_update_message["object"], "attachment"))}
|
|
|
|
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
|
end
|
|
end
|
|
|
|
describe "when :media_nsfw" do
|
|
test "is empty" do
|
|
clear_config([:mrf_simple, :media_nsfw], [])
|
|
media_message = build_media_message()
|
|
media_update_message = build_media_update_message()
|
|
local_message = build_local_message()
|
|
|
|
assert SimplePolicy.filter(media_message) == {:ok, media_message}
|
|
assert SimplePolicy.filter(media_update_message) == {:ok, media_update_message}
|
|
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
|
end
|
|
|
|
test "has a matching host" do
|
|
clear_config([:mrf_simple, :media_nsfw], [{"remote.instance", "Whetever"}])
|
|
media_message = build_media_message()
|
|
media_update_message = build_media_update_message()
|
|
local_message = build_local_message()
|
|
|
|
assert SimplePolicy.filter(media_message) ==
|
|
{:ok, put_in(media_message, ["object", "sensitive"], true)}
|
|
|
|
assert SimplePolicy.filter(media_update_message) ==
|
|
{:ok, put_in(media_update_message, ["object", "sensitive"], true)}
|
|
|
|
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
|
end
|
|
|
|
test "match with wildcard domain" do
|
|
clear_config([:mrf_simple, :media_nsfw], [{"*.remote.instance", "yeah yeah"}])
|
|
media_message = build_media_message()
|
|
media_update_message = build_media_update_message()
|
|
local_message = build_local_message()
|
|
|
|
assert SimplePolicy.filter(media_message) ==
|
|
{:ok, put_in(media_message, ["object", "sensitive"], true)}
|
|
|
|
assert SimplePolicy.filter(media_update_message) ==
|
|
{:ok, put_in(media_update_message, ["object", "sensitive"], true)}
|
|
|
|
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
|
end
|
|
end
|
|
|
|
defp build_media_message do
|
|
%{
|
|
"actor" => "https://remote.instance/users/bob",
|
|
"type" => "Create",
|
|
"object" => %{
|
|
"attachment" => [%{}],
|
|
"tag" => ["foo"],
|
|
"sensitive" => false
|
|
}
|
|
}
|
|
end
|
|
|
|
defp build_media_update_message do
|
|
%{
|
|
"actor" => "https://remote.instance/users/bob",
|
|
"type" => "Update",
|
|
"object" => %{
|
|
"attachment" => [%{}],
|
|
"tag" => ["foo"],
|
|
"sensitive" => false
|
|
}
|
|
}
|
|
end
|
|
|
|
describe "when :report_removal" do
|
|
test "is empty" do
|
|
clear_config([:mrf_simple, :report_removal], [])
|
|
report_message = build_report_message()
|
|
local_message = build_local_message()
|
|
|
|
assert SimplePolicy.filter(report_message) == {:ok, report_message}
|
|
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
|
end
|
|
|
|
test "has a matching host" do
|
|
clear_config([:mrf_simple, :report_removal], [{"remote.instance", "muh"}])
|
|
report_message = build_report_message()
|
|
local_message = build_local_message()
|
|
|
|
assert {:reject, _} = SimplePolicy.filter(report_message)
|
|
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
|
end
|
|
|
|
test "match with wildcard domain" do
|
|
clear_config([:mrf_simple, :report_removal], [{"*.remote.instance", "suya"}])
|
|
report_message = build_report_message()
|
|
local_message = build_local_message()
|
|
|
|
assert {:reject, _} = SimplePolicy.filter(report_message)
|
|
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
|
end
|
|
end
|
|
|
|
defp build_report_message do
|
|
%{
|
|
"actor" => "https://remote.instance/users/bob",
|
|
"type" => "Flag"
|
|
}
|
|
end
|
|
|
|
describe "when :federated_timeline_removal" do
|
|
test "is empty" do
|
|
clear_config([:mrf_simple, :federated_timeline_removal], [])
|
|
{_, ftl_message} = build_ftl_actor_and_message()
|
|
local_message = build_local_message()
|
|
|
|
assert SimplePolicy.filter(ftl_message) == {:ok, ftl_message}
|
|
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
|
end
|
|
|
|
test "has a matching host" do
|
|
{actor, ftl_message} = build_ftl_actor_and_message()
|
|
|
|
ftl_message_actor_host =
|
|
ftl_message
|
|
|> Map.fetch!("actor")
|
|
|> URI.parse()
|
|
|> Map.fetch!(:host)
|
|
|
|
clear_config([:mrf_simple, :federated_timeline_removal], [{ftl_message_actor_host, "uwu"}])
|
|
local_message = build_local_message()
|
|
|
|
assert {:ok, ftl_message} = SimplePolicy.filter(ftl_message)
|
|
assert actor.follower_address in ftl_message["to"]
|
|
refute actor.follower_address in ftl_message["cc"]
|
|
refute "https://www.w3.org/ns/activitystreams#Public" in ftl_message["to"]
|
|
assert "https://www.w3.org/ns/activitystreams#Public" in ftl_message["cc"]
|
|
|
|
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
|
end
|
|
|
|
test "match with wildcard domain" do
|
|
{actor, ftl_message} = build_ftl_actor_and_message()
|
|
|
|
ftl_message_actor_host =
|
|
ftl_message
|
|
|> Map.fetch!("actor")
|
|
|> URI.parse()
|
|
|> Map.fetch!(:host)
|
|
|
|
clear_config([:mrf_simple, :federated_timeline_removal], [
|
|
{"*." <> ftl_message_actor_host, "owo"}
|
|
])
|
|
|
|
local_message = build_local_message()
|
|
|
|
assert {:ok, ftl_message} = SimplePolicy.filter(ftl_message)
|
|
assert actor.follower_address in ftl_message["to"]
|
|
refute actor.follower_address in ftl_message["cc"]
|
|
refute "https://www.w3.org/ns/activitystreams#Public" in ftl_message["to"]
|
|
assert "https://www.w3.org/ns/activitystreams#Public" in ftl_message["cc"]
|
|
|
|
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
|
end
|
|
|
|
test "has a matching host but only as:Public in to" do
|
|
{_actor, ftl_message} = build_ftl_actor_and_message()
|
|
|
|
ftl_message_actor_host =
|
|
ftl_message
|
|
|> Map.fetch!("actor")
|
|
|> URI.parse()
|
|
|> Map.fetch!(:host)
|
|
|
|
ftl_message = Map.put(ftl_message, "cc", [])
|
|
|
|
clear_config([:mrf_simple, :federated_timeline_removal], [
|
|
{ftl_message_actor_host, "spiderwaifu goes 88w88"}
|
|
])
|
|
|
|
assert {:ok, ftl_message} = SimplePolicy.filter(ftl_message)
|
|
refute "https://www.w3.org/ns/activitystreams#Public" in ftl_message["to"]
|
|
assert "https://www.w3.org/ns/activitystreams#Public" in ftl_message["cc"]
|
|
end
|
|
end
|
|
|
|
describe "describe/1" do
|
|
test "returns a description of the policy" do
|
|
clear_config([:mrf_simple, :reject], [
|
|
{"remote.instance", "did not give my catboy a burg"}
|
|
])
|
|
|
|
assert {:ok, %{mrf_simple: %{reject: ["remote.instance"]}}} = SimplePolicy.describe()
|
|
end
|
|
|
|
test "excludes domains listed in :transparency_exclusions" do
|
|
clear_config([:mrf, :transparency_exclusions], [{"remote.instance", ":("}])
|
|
|
|
clear_config([:mrf_simple, :reject], [
|
|
{"remote.instance", "did not give my catboy a burg"}
|
|
])
|
|
|
|
{:ok, description} = SimplePolicy.describe()
|
|
assert %{mrf_simple: %{reject: []}} = description
|
|
assert description[:mrf_simple_info][:reject] == nil
|
|
end
|
|
|
|
test "obfuscates domains listed in :transparency_obfuscate_domains" do
|
|
clear_config([:mrf, :transparency_obfuscate_domains], ["remote.instance", "a.b"])
|
|
|
|
clear_config([:mrf_simple, :reject], [
|
|
{"remote.instance", "did not give my catboy a burg"},
|
|
{"a.b", "spam-poked me on facebook in 2006"}
|
|
])
|
|
|
|
assert {:ok,
|
|
%{
|
|
mrf_simple: %{reject: ["rem***.*****nce", "a.b"]},
|
|
mrf_simple_info: %{reject: %{"rem***.*****nce" => %{}}}
|
|
}} = SimplePolicy.describe()
|
|
end
|
|
end
|
|
|
|
defp build_ftl_actor_and_message do
|
|
actor = insert(:user)
|
|
|
|
{actor,
|
|
%{
|
|
"actor" => actor.ap_id,
|
|
"to" => ["https://www.w3.org/ns/activitystreams#Public", "http://foo.bar/baz"],
|
|
"cc" => [actor.follower_address, "http://foo.bar/qux"]
|
|
}}
|
|
end
|
|
|
|
describe "when :reject" do
|
|
test "is empty" do
|
|
clear_config([:mrf_simple, :reject], [])
|
|
|
|
remote_message = build_remote_message()
|
|
|
|
assert SimplePolicy.filter(remote_message) == {:ok, remote_message}
|
|
end
|
|
|
|
test "activity has a matching host" do
|
|
clear_config([:mrf_simple, :reject], [{"remote.instance", ""}])
|
|
|
|
remote_message = build_remote_message()
|
|
|
|
assert {:reject, _} = SimplePolicy.filter(remote_message)
|
|
end
|
|
|
|
test "activity matches with wildcard domain" do
|
|
clear_config([:mrf_simple, :reject], [{"*.remote.instance", ""}])
|
|
|
|
remote_message = build_remote_message()
|
|
|
|
assert {:reject, _} = SimplePolicy.filter(remote_message)
|
|
end
|
|
|
|
test "actor has a matching host" do
|
|
clear_config([:mrf_simple, :reject], [{"remote.instance", ""}])
|
|
|
|
remote_user = build_remote_user()
|
|
|
|
assert {:reject, _} = SimplePolicy.filter(remote_user)
|
|
end
|
|
|
|
test "reject Announce when object would be rejected" do
|
|
clear_config([:mrf_simple, :reject], [{"blocked.tld", ""}])
|
|
|
|
announce = %{
|
|
"type" => "Announce",
|
|
"actor" => "https://okay.tld/users/alice",
|
|
"object" => %{"type" => "Note", "actor" => "https://blocked.tld/users/bob"}
|
|
}
|
|
|
|
assert {:reject, _} = SimplePolicy.filter(announce)
|
|
end
|
|
|
|
test "reject by URI object" do
|
|
clear_config([:mrf_simple, :reject], [{"blocked.tld", ""}])
|
|
|
|
announce = %{
|
|
"type" => "Announce",
|
|
"actor" => "https://okay.tld/users/alice",
|
|
"object" => "https://blocked.tld/activities/1"
|
|
}
|
|
|
|
assert {:reject, _} = SimplePolicy.filter(announce)
|
|
end
|
|
end
|
|
|
|
describe "when :followers_only" do
|
|
test "is empty" do
|
|
clear_config([:mrf_simple, :followers_only], [])
|
|
{_, ftl_message} = build_ftl_actor_and_message()
|
|
local_message = build_local_message()
|
|
|
|
assert SimplePolicy.filter(ftl_message) == {:ok, ftl_message}
|
|
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
|
end
|
|
|
|
test "has a matching host" do
|
|
actor = insert(:user)
|
|
following_user = insert(:user)
|
|
non_following_user = insert(:user)
|
|
|
|
{:ok, _, _, _} = CommonAPI.follow(following_user, actor)
|
|
|
|
activity = %{
|
|
"actor" => actor.ap_id,
|
|
"to" => [
|
|
"https://www.w3.org/ns/activitystreams#Public",
|
|
following_user.ap_id,
|
|
non_following_user.ap_id
|
|
],
|
|
"cc" => [actor.follower_address, "http://foo.bar/qux"]
|
|
}
|
|
|
|
dm_activity = %{
|
|
"actor" => actor.ap_id,
|
|
"to" => [
|
|
following_user.ap_id,
|
|
non_following_user.ap_id
|
|
],
|
|
"cc" => []
|
|
}
|
|
|
|
actor_domain =
|
|
activity
|
|
|> Map.fetch!("actor")
|
|
|> URI.parse()
|
|
|> Map.fetch!(:host)
|
|
|
|
clear_config([:mrf_simple, :followers_only], [{actor_domain, ""}])
|
|
|
|
assert {:ok, new_activity} = SimplePolicy.filter(activity)
|
|
assert actor.follower_address in new_activity["cc"]
|
|
assert following_user.ap_id in new_activity["to"]
|
|
refute "https://www.w3.org/ns/activitystreams#Public" in new_activity["to"]
|
|
refute "https://www.w3.org/ns/activitystreams#Public" in new_activity["cc"]
|
|
refute non_following_user.ap_id in new_activity["to"]
|
|
refute non_following_user.ap_id in new_activity["cc"]
|
|
|
|
assert {:ok, new_dm_activity} = SimplePolicy.filter(dm_activity)
|
|
assert new_dm_activity["to"] == [following_user.ap_id]
|
|
assert new_dm_activity["cc"] == []
|
|
end
|
|
end
|
|
|
|
describe "when :accept" do
|
|
test "is empty" do
|
|
clear_config([:mrf_simple, :accept], [])
|
|
|
|
local_message = build_local_message()
|
|
remote_message = build_remote_message()
|
|
|
|
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
|
assert SimplePolicy.filter(remote_message) == {:ok, remote_message}
|
|
end
|
|
|
|
test "is not empty but activity doesn't have a matching host" do
|
|
clear_config([:mrf_simple, :accept], [{"non.matching.remote", ""}])
|
|
|
|
local_message = build_local_message()
|
|
remote_message = build_remote_message()
|
|
|
|
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
|
assert {:reject, _} = SimplePolicy.filter(remote_message)
|
|
end
|
|
|
|
test "activity has a matching host" do
|
|
clear_config([:mrf_simple, :accept], [{"remote.instance", ""}])
|
|
|
|
local_message = build_local_message()
|
|
remote_message = build_remote_message()
|
|
|
|
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
|
assert SimplePolicy.filter(remote_message) == {:ok, remote_message}
|
|
end
|
|
|
|
test "activity matches with wildcard domain" do
|
|
clear_config([:mrf_simple, :accept], [{"*.remote.instance", ""}])
|
|
|
|
local_message = build_local_message()
|
|
remote_message = build_remote_message()
|
|
|
|
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
|
assert SimplePolicy.filter(remote_message) == {:ok, remote_message}
|
|
end
|
|
|
|
test "actor has a matching host" do
|
|
clear_config([:mrf_simple, :accept], [{"remote.instance", ""}])
|
|
|
|
remote_user = build_remote_user()
|
|
|
|
assert SimplePolicy.filter(remote_user) == {:ok, remote_user}
|
|
end
|
|
end
|
|
|
|
describe "when :avatar_removal" do
|
|
test "is empty" do
|
|
clear_config([:mrf_simple, :avatar_removal], [])
|
|
|
|
remote_user = build_remote_user()
|
|
|
|
assert SimplePolicy.filter(remote_user) == {:ok, remote_user}
|
|
end
|
|
|
|
test "is not empty but it doesn't have a matching host" do
|
|
clear_config([:mrf_simple, :avatar_removal], [{"non.matching.remote", ""}])
|
|
|
|
remote_user = build_remote_user()
|
|
|
|
assert SimplePolicy.filter(remote_user) == {:ok, remote_user}
|
|
end
|
|
|
|
test "has a matching host" do
|
|
clear_config([:mrf_simple, :avatar_removal], [{"remote.instance", ""}])
|
|
|
|
remote_user = build_remote_user()
|
|
{:ok, filtered} = SimplePolicy.filter(remote_user)
|
|
|
|
refute filtered["icon"]
|
|
end
|
|
|
|
test "match with wildcard domain" do
|
|
clear_config([:mrf_simple, :avatar_removal], [{"*.remote.instance", ""}])
|
|
|
|
remote_user = build_remote_user()
|
|
{:ok, filtered} = SimplePolicy.filter(remote_user)
|
|
|
|
refute filtered["icon"]
|
|
end
|
|
end
|
|
|
|
describe "when :banner_removal" do
|
|
test "is empty" do
|
|
clear_config([:mrf_simple, :banner_removal], [])
|
|
|
|
remote_user = build_remote_user()
|
|
|
|
assert SimplePolicy.filter(remote_user) == {:ok, remote_user}
|
|
end
|
|
|
|
test "is not empty but it doesn't have a matching host" do
|
|
clear_config([:mrf_simple, :banner_removal], [{"non.matching.remote", ""}])
|
|
|
|
remote_user = build_remote_user()
|
|
|
|
assert SimplePolicy.filter(remote_user) == {:ok, remote_user}
|
|
end
|
|
|
|
test "has a matching host" do
|
|
clear_config([:mrf_simple, :banner_removal], [{"remote.instance", ""}])
|
|
|
|
remote_user = build_remote_user()
|
|
{:ok, filtered} = SimplePolicy.filter(remote_user)
|
|
|
|
refute filtered["image"]
|
|
end
|
|
|
|
test "match with wildcard domain" do
|
|
clear_config([:mrf_simple, :banner_removal], [{"*.remote.instance", ""}])
|
|
|
|
remote_user = build_remote_user()
|
|
{:ok, filtered} = SimplePolicy.filter(remote_user)
|
|
|
|
refute filtered["image"]
|
|
end
|
|
end
|
|
|
|
describe "when :reject_deletes is empty" do
|
|
setup do: clear_config([:mrf_simple, :reject_deletes], [])
|
|
|
|
test "it accepts deletions even from rejected servers" do
|
|
clear_config([:mrf_simple, :reject], [{"remote.instance", ""}])
|
|
|
|
deletion_message = build_remote_deletion_message()
|
|
|
|
assert SimplePolicy.filter(deletion_message) == {:ok, deletion_message}
|
|
end
|
|
|
|
test "it accepts deletions even from non-whitelisted servers" do
|
|
clear_config([:mrf_simple, :accept], [{"non.matching.remote", ""}])
|
|
|
|
deletion_message = build_remote_deletion_message()
|
|
|
|
assert SimplePolicy.filter(deletion_message) == {:ok, deletion_message}
|
|
end
|
|
end
|
|
|
|
describe "when :reject_deletes is not empty but it doesn't have a matching host" do
|
|
setup do: clear_config([:mrf_simple, :reject_deletes], [{"non.matching.remote", ""}])
|
|
|
|
test "it accepts deletions even from rejected servers" do
|
|
clear_config([:mrf_simple, :reject], [{"remote.instance", ""}])
|
|
|
|
deletion_message = build_remote_deletion_message()
|
|
|
|
assert SimplePolicy.filter(deletion_message) == {:ok, deletion_message}
|
|
end
|
|
|
|
test "it accepts deletions even from non-whitelisted servers" do
|
|
clear_config([:mrf_simple, :accept], [{"non.matching.remote", ""}])
|
|
|
|
deletion_message = build_remote_deletion_message()
|
|
|
|
assert SimplePolicy.filter(deletion_message) == {:ok, deletion_message}
|
|
end
|
|
end
|
|
|
|
describe "when :reject_deletes has a matching host" do
|
|
setup do: clear_config([:mrf_simple, :reject_deletes], [{"remote.instance", ""}])
|
|
|
|
test "it rejects the deletion" do
|
|
deletion_message = build_remote_deletion_message()
|
|
|
|
assert {:reject, _} = SimplePolicy.filter(deletion_message)
|
|
end
|
|
end
|
|
|
|
describe "when :reject_deletes match with wildcard domain" do
|
|
setup do: clear_config([:mrf_simple, :reject_deletes], [{"*.remote.instance", ""}])
|
|
|
|
test "it rejects the deletion" do
|
|
deletion_message = build_remote_deletion_message()
|
|
|
|
assert {:reject, _} = SimplePolicy.filter(deletion_message)
|
|
end
|
|
end
|
|
|
|
defp build_local_message do
|
|
%{
|
|
"actor" => "#{Pleroma.Web.Endpoint.url()}/users/alice",
|
|
"to" => [],
|
|
"cc" => []
|
|
}
|
|
end
|
|
|
|
defp build_remote_message do
|
|
%{"actor" => "https://remote.instance/users/bob"}
|
|
end
|
|
|
|
defp build_remote_user do
|
|
%{
|
|
"id" => "https://remote.instance/users/bob",
|
|
"icon" => %{
|
|
"url" => "http://example.com/image.jpg",
|
|
"type" => "Image"
|
|
},
|
|
"image" => %{
|
|
"url" => "http://example.com/image.jpg",
|
|
"type" => "Image"
|
|
},
|
|
"type" => "Person"
|
|
}
|
|
end
|
|
|
|
defp build_remote_deletion_message do
|
|
%{
|
|
"type" => "Delete",
|
|
"actor" => "https://remote.instance/users/bob"
|
|
}
|
|
end
|
|
end
|