MRF NoEmptyPolicy: Deny posts from local users if there is no content or only mentions.
Helps prevent accidental button mashes from submitting incomplete posts
This commit is contained in:
parent
d7262f7d22
commit
55a13fc360
|
@ -49,6 +49,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- Ability to set ActivityPub aliases for follower migration.
|
- Ability to set ActivityPub aliases for follower migration.
|
||||||
- Configurable background job limits for RichMedia (link previews) and MediaProxyWarmingPolicy
|
- Configurable background job limits for RichMedia (link previews) and MediaProxyWarmingPolicy
|
||||||
- Ability to define custom HTTP headers per each frontend
|
- Ability to define custom HTTP headers per each frontend
|
||||||
|
- MRF (`NoEmptyPolicy`): New MRF Policy which will deny empty statuses or statuses of only mentions from being created by local users
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>API Changes</summary>
|
<summary>API Changes</summary>
|
||||||
|
|
61
lib/pleroma/web/activity_pub/mrf/no_empty_policy.ex
Normal file
61
lib/pleroma/web/activity_pub/mrf/no_empty_policy.ex
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
# 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.NoEmptyPolicy do
|
||||||
|
@moduledoc "Filter local activities which have no content"
|
||||||
|
@behaviour Pleroma.Web.ActivityPub.MRF
|
||||||
|
|
||||||
|
alias Pleroma.Web
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def filter(%{"actor" => actor} = object) do
|
||||||
|
with true <- is_local?(actor),
|
||||||
|
true <- is_note?(object),
|
||||||
|
false <- has_attachment?(object),
|
||||||
|
true <- only_mentions?(object) do
|
||||||
|
{:reject, "[NoEmptyPolicy]"}
|
||||||
|
else
|
||||||
|
_ ->
|
||||||
|
{:ok, object}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def filter(object), do: {:ok, object}
|
||||||
|
|
||||||
|
defp is_local?(actor) do
|
||||||
|
if actor |> String.starts_with?("#{Web.base_url()}") do
|
||||||
|
true
|
||||||
|
else
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp has_attachment?(%{
|
||||||
|
"type" => "Create",
|
||||||
|
"object" => %{"type" => "Note", "attachment" => attachments}
|
||||||
|
})
|
||||||
|
when length(attachments) > 0,
|
||||||
|
do: true
|
||||||
|
|
||||||
|
defp has_attachment?(_), do: false
|
||||||
|
|
||||||
|
defp only_mentions?(%{"type" => "Create", "object" => %{"type" => "Note", "source" => source}}) do
|
||||||
|
non_mentions =
|
||||||
|
source |> String.split() |> Enum.filter(&(not String.starts_with?(&1, "@"))) |> length
|
||||||
|
|
||||||
|
if non_mentions > 0 do
|
||||||
|
false
|
||||||
|
else
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp only_mentions?(_), do: false
|
||||||
|
|
||||||
|
defp is_note?(%{"type" => "Create", "object" => %{"type" => "Note"}}), do: true
|
||||||
|
defp is_note?(_), do: false
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def describe, do: {:ok, %{}}
|
||||||
|
end
|
154
test/pleroma/web/activity_pub/mrf/no_empty_policy_test.exs
Normal file
154
test/pleroma/web/activity_pub/mrf/no_empty_policy_test.exs
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
# 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.NoEmptyPolicyTest do
|
||||||
|
use Pleroma.DataCase
|
||||||
|
alias Pleroma.Web.ActivityPub.MRF.NoEmptyPolicy
|
||||||
|
|
||||||
|
setup_all do: clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.NoEmptyPolicy])
|
||||||
|
|
||||||
|
test "Notes with content are exempt" do
|
||||||
|
message = %{
|
||||||
|
"actor" => "http://localhost:4001/users/testuser",
|
||||||
|
"cc" => ["http://localhost:4001/users/testuser/followers"],
|
||||||
|
"object" => %{
|
||||||
|
"actor" => "http://localhost:4001/users/testuser",
|
||||||
|
"attachment" => [],
|
||||||
|
"cc" => ["http://localhost:4001/users/testuser/followers"],
|
||||||
|
"source" => "this is a test post",
|
||||||
|
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
|
||||||
|
"type" => "Note"
|
||||||
|
},
|
||||||
|
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
|
||||||
|
"type" => "Create"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert NoEmptyPolicy.filter(message) == {:ok, message}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "Polls are exempt" do
|
||||||
|
message = %{
|
||||||
|
"actor" => "http://localhost:4001/users/testuser",
|
||||||
|
"cc" => ["http://localhost:4001/users/testuser/followers"],
|
||||||
|
"object" => %{
|
||||||
|
"actor" => "http://localhost:4001/users/testuser",
|
||||||
|
"attachment" => [],
|
||||||
|
"cc" => ["http://localhost:4001/users/testuser/followers"],
|
||||||
|
"oneOf" => [
|
||||||
|
%{
|
||||||
|
"name" => "chocolate",
|
||||||
|
"replies" => %{"totalItems" => 0, "type" => "Collection"},
|
||||||
|
"type" => "Note"
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
"name" => "vanilla",
|
||||||
|
"replies" => %{"totalItems" => 0, "type" => "Collection"},
|
||||||
|
"type" => "Note"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source" => "@user2",
|
||||||
|
"to" => [
|
||||||
|
"https://www.w3.org/ns/activitystreams#Public",
|
||||||
|
"http://localhost:4001/users/user2"
|
||||||
|
],
|
||||||
|
"type" => "Question"
|
||||||
|
},
|
||||||
|
"to" => [
|
||||||
|
"https://www.w3.org/ns/activitystreams#Public",
|
||||||
|
"http://localhost:4001/users/user2"
|
||||||
|
],
|
||||||
|
"type" => "Create"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert NoEmptyPolicy.filter(message) == {:ok, message}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "Notes with attachments are exempt" do
|
||||||
|
message = %{
|
||||||
|
"actor" => "http://localhost:4001/users/testuser",
|
||||||
|
"cc" => ["http://localhost:4001/users/testuser/followers"],
|
||||||
|
"object" => %{
|
||||||
|
"actor" => "http://localhost:4001/users/testuser",
|
||||||
|
"attachment" => [
|
||||||
|
%{
|
||||||
|
"actor" => "http://localhost:4001/users/testuser",
|
||||||
|
"mediaType" => "image/png",
|
||||||
|
"name" => "",
|
||||||
|
"type" => "Document",
|
||||||
|
"url" => [
|
||||||
|
%{
|
||||||
|
"href" =>
|
||||||
|
"http://localhost:4001/media/68ba231cf12e1382ce458f1979969f8ed5cc07ba198a02e653464abaf39bdb90.png",
|
||||||
|
"mediaType" => "image/png",
|
||||||
|
"type" => "Link"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"cc" => ["http://localhost:4001/users/testuser/followers"],
|
||||||
|
"source" => "@user2",
|
||||||
|
"to" => [
|
||||||
|
"https://www.w3.org/ns/activitystreams#Public",
|
||||||
|
"http://localhost:4001/users/user2"
|
||||||
|
],
|
||||||
|
"type" => "Note"
|
||||||
|
},
|
||||||
|
"to" => [
|
||||||
|
"https://www.w3.org/ns/activitystreams#Public",
|
||||||
|
"http://localhost:4001/users/user2"
|
||||||
|
],
|
||||||
|
"type" => "Create"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert NoEmptyPolicy.filter(message) == {:ok, message}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "Notes with only mentions are denied" do
|
||||||
|
message = %{
|
||||||
|
"actor" => "http://localhost:4001/users/testuser",
|
||||||
|
"cc" => ["http://localhost:4001/users/testuser/followers"],
|
||||||
|
"object" => %{
|
||||||
|
"actor" => "http://localhost:4001/users/testuser",
|
||||||
|
"attachment" => [],
|
||||||
|
"cc" => ["http://localhost:4001/users/testuser/followers"],
|
||||||
|
"source" => "@user2",
|
||||||
|
"to" => [
|
||||||
|
"https://www.w3.org/ns/activitystreams#Public",
|
||||||
|
"http://localhost:4001/users/user2"
|
||||||
|
],
|
||||||
|
"type" => "Note"
|
||||||
|
},
|
||||||
|
"to" => [
|
||||||
|
"https://www.w3.org/ns/activitystreams#Public",
|
||||||
|
"http://localhost:4001/users/user2"
|
||||||
|
],
|
||||||
|
"type" => "Create"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert NoEmptyPolicy.filter(message) == {:reject, "[NoEmptyPolicy]"}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "Notes with no content are denied" do
|
||||||
|
message = %{
|
||||||
|
"actor" => "http://localhost:4001/users/testuser",
|
||||||
|
"cc" => ["http://localhost:4001/users/testuser/followers"],
|
||||||
|
"object" => %{
|
||||||
|
"actor" => "http://localhost:4001/users/testuser",
|
||||||
|
"attachment" => [],
|
||||||
|
"cc" => ["http://localhost:4001/users/testuser/followers"],
|
||||||
|
"source" => "",
|
||||||
|
"to" => [
|
||||||
|
"https://www.w3.org/ns/activitystreams#Public"
|
||||||
|
],
|
||||||
|
"type" => "Note"
|
||||||
|
},
|
||||||
|
"to" => [
|
||||||
|
"https://www.w3.org/ns/activitystreams#Public"
|
||||||
|
],
|
||||||
|
"type" => "Create"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert NoEmptyPolicy.filter(message) == {:reject, "[NoEmptyPolicy]"}
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue