mirror of
https://git.pleroma.social/pleroma/pleroma.git
synced 2025-01-03 13:58:41 +00:00
Added MRF.QuietReply which prevents replies to public posts from being published to the timelines
This commit is contained in:
parent
540e62c5fc
commit
a0af6cba09
4 changed files with 169 additions and 6 deletions
1
changelog.d/mrf-quietreply.add
Normal file
1
changelog.d/mrf-quietreply.add
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Added MRF.QuietReply which prevents replies to public posts from being published to the timelines
|
55
lib/pleroma/web/activity_pub/mrf/quiet_reply.ex
Normal file
55
lib/pleroma/web/activity_pub/mrf/quiet_reply.ex
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2023 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.ActivityPub.MRF.QuietReply do
|
||||||
|
require Pleroma.Constants
|
||||||
|
|
||||||
|
alias Pleroma.User
|
||||||
|
|
||||||
|
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def history_awareness, do: :auto
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def filter(
|
||||||
|
%{
|
||||||
|
"type" => "Create",
|
||||||
|
"object" => %{
|
||||||
|
"actor" => actor,
|
||||||
|
"type" => "Note",
|
||||||
|
"to" => to,
|
||||||
|
"cc" => cc,
|
||||||
|
"inReplyTo" => in_reply_to
|
||||||
|
}
|
||||||
|
} = object
|
||||||
|
) do
|
||||||
|
with true <- is_binary(in_reply_to),
|
||||||
|
false <- match?([], cc),
|
||||||
|
%User{follower_address: followers_collection, local: true} <-
|
||||||
|
User.get_by_ap_id(actor) do
|
||||||
|
updated_to =
|
||||||
|
to
|
||||||
|
|> Kernel.++([followers_collection])
|
||||||
|
|> Kernel.--([Pleroma.Constants.as_public()])
|
||||||
|
|
||||||
|
updated_cc = [Pleroma.Constants.as_public()]
|
||||||
|
|
||||||
|
updated_object =
|
||||||
|
object
|
||||||
|
|> put_in(["object", "to"], updated_to)
|
||||||
|
|> put_in(["object", "cc"], updated_cc)
|
||||||
|
|
||||||
|
{:ok, updated_object}
|
||||||
|
else
|
||||||
|
_ -> {:ok, object}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def filter(object), do: {:ok, object}
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def describe, do: {:ok, %{}}
|
||||||
|
end
|
103
test/pleroma/web/activity_pub/mrf/quiet_reply_test.exs
Normal file
103
test/pleroma/web/activity_pub/mrf/quiet_reply_test.exs
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.ActivityPub.MRF.QuietReplyTest do
|
||||||
|
use Pleroma.DataCase
|
||||||
|
import Pleroma.Factory
|
||||||
|
|
||||||
|
require Pleroma.Constants
|
||||||
|
|
||||||
|
alias Pleroma.Object
|
||||||
|
alias Pleroma.Web.ActivityPub.MRF.QuietReply
|
||||||
|
alias Pleroma.Web.CommonAPI
|
||||||
|
|
||||||
|
test "replying to public post is forced to be quiet" do
|
||||||
|
batman = insert(:user, nickname: "batman")
|
||||||
|
robin = insert(:user, nickname: "robin")
|
||||||
|
|
||||||
|
{:ok, post} = CommonAPI.post(batman, %{status: "To the Batmobile!"})
|
||||||
|
|
||||||
|
reply = %{
|
||||||
|
"type" => "Create",
|
||||||
|
"actor" => robin.ap_id,
|
||||||
|
"object" => %{
|
||||||
|
"type" => "Note",
|
||||||
|
"actor" => robin.ap_id,
|
||||||
|
"content" => "@batman Wait up, I forgot my spandex!",
|
||||||
|
"to" => [
|
||||||
|
batman.ap_id,
|
||||||
|
Pleroma.Constants.as_public()
|
||||||
|
],
|
||||||
|
"cc" => [robin.follower_address],
|
||||||
|
"inReplyTo" => Object.normalize(post).data["id"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expected_to = [batman.ap_id, robin.follower_address]
|
||||||
|
expected_cc = [Pleroma.Constants.as_public()]
|
||||||
|
|
||||||
|
assert {:ok, filtered} = QuietReply.filter(reply)
|
||||||
|
|
||||||
|
assert expected_to == filtered["object"]["to"]
|
||||||
|
assert expected_cc == filtered["object"]["cc"]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "replying direct is unmodified" do
|
||||||
|
batman = insert(:user, nickname: "batman")
|
||||||
|
robin = insert(:user, nickname: "robin")
|
||||||
|
|
||||||
|
{:ok, post} = CommonAPI.post(batman, %{status: "To the Batmobile!"})
|
||||||
|
|
||||||
|
reply = %{
|
||||||
|
"type" => "Create",
|
||||||
|
"actor" => robin.ap_id,
|
||||||
|
"object" => %{
|
||||||
|
"type" => "Note",
|
||||||
|
"actor" => robin.ap_id,
|
||||||
|
"content" => "@batman Wait up, I forgot my spandex!",
|
||||||
|
"to" => [batman.ap_id],
|
||||||
|
"cc" => [],
|
||||||
|
"inReplyTo" => Object.normalize(post).data["id"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert {:ok, filtered} = QuietReply.filter(reply)
|
||||||
|
|
||||||
|
assert match?(^filtered, reply)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "replying followers-only is unmodified" do
|
||||||
|
batman = insert(:user, nickname: "batman")
|
||||||
|
robin = insert(:user, nickname: "robin")
|
||||||
|
|
||||||
|
{:ok, post} = CommonAPI.post(batman, %{status: "To the Batmobile!"})
|
||||||
|
|
||||||
|
reply = %{
|
||||||
|
"type" => "Create",
|
||||||
|
"actor" => robin.ap_id,
|
||||||
|
"object" => %{
|
||||||
|
"type" => "Note",
|
||||||
|
"actor" => robin.ap_id,
|
||||||
|
"content" => "@batman Wait up, I forgot my spandex!",
|
||||||
|
"to" => [batman.ap_id, robin.follower_address],
|
||||||
|
"cc" => [],
|
||||||
|
"inReplyTo" => Object.normalize(post).data["id"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert {:ok, filtered} = QuietReply.filter(reply)
|
||||||
|
|
||||||
|
assert match?(^filtered, reply)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "non-reply posts are unmodified" do
|
||||||
|
batman = insert(:user, nickname: "batman")
|
||||||
|
|
||||||
|
{:ok, post} = CommonAPI.post(batman, %{status: "To the Batmobile!"})
|
||||||
|
|
||||||
|
assert {:ok, filtered} = QuietReply.filter(post)
|
||||||
|
|
||||||
|
assert match?(^filtered, post)
|
||||||
|
end
|
||||||
|
end
|
|
@ -53,6 +53,15 @@ defmodule Pleroma.Factory do
|
||||||
keys: pem
|
keys: pem
|
||||||
}
|
}
|
||||||
|
|
||||||
|
attrs = Map.delete(attrs, :domain)
|
||||||
|
|
||||||
|
user
|
||||||
|
|> Map.put(:raw_bio, user.bio)
|
||||||
|
|> merge_attributes(attrs)
|
||||||
|
|> user_urls(attrs)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp user_urls(user, attrs) do
|
||||||
urls =
|
urls =
|
||||||
if attrs[:local] == false do
|
if attrs[:local] == false do
|
||||||
base_domain = attrs[:domain] || Enum.random(["domain1.com", "domain2.com", "domain3.com"])
|
base_domain = attrs[:domain] || Enum.random(["domain1.com", "domain2.com", "domain3.com"])
|
||||||
|
@ -75,12 +84,7 @@ defmodule Pleroma.Factory do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
attrs = Map.delete(attrs, :domain)
|
Map.merge(user, urls)
|
||||||
|
|
||||||
user
|
|
||||||
|> Map.put(:raw_bio, user.bio)
|
|
||||||
|> Map.merge(urls)
|
|
||||||
|> merge_attributes(attrs)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def user_relationship_factory(attrs \\ %{}) do
|
def user_relationship_factory(attrs \\ %{}) do
|
||||||
|
|
Loading…
Reference in a new issue