Fix create processing in direct message disabled

This commit is contained in:
FloatingGhost 2023-05-23 13:16:20 +01:00
parent ab34680554
commit 037f881187
12 changed files with 111 additions and 25 deletions

View file

@ -6,8 +6,17 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## Unreleased ## Unreleased
## Added
- Custom options for users to accept/reject private messages
- options: everybody, nobody, people\_i\_follow
- MRF to reject notes from accounts newer than a given age
- this will have the side-effect of rejecting legitimate messages if your
post gets boosted outside of your local bubble and people your instance
does not know about reply to it.
## Fixed ## Fixed
- Support for `streams` public key URIs - Support for `streams` public key URIs
- Bookmarks are cleaned up on DB prune now
## 2023.04 ## 2023.04

View file

@ -418,6 +418,8 @@
config :pleroma, :mrf_follow_bot, follower_nickname: nil config :pleroma, :mrf_follow_bot, follower_nickname: nil
config :pleroma, :mrf_reject_newly_created_account_notes, age: 86_400
config :pleroma, :rich_media, config :pleroma, :rich_media,
enabled: true, enabled: true,
ignore_hosts: [], ignore_hosts: [],

View file

@ -160,7 +160,8 @@ defmodule Pleroma.User do
field(:status_ttl_days, :integer, default: nil) field(:status_ttl_days, :integer, default: nil)
field(:accepts_direct_messages_from, Ecto.Enum, field(:accepts_direct_messages_from, Ecto.Enum,
values: [:everybody, :people_i_follow, :nobody] values: [:everybody, :people_i_follow, :nobody],
default: :everybody
) )
embeds_one( embeds_one(

View file

@ -12,7 +12,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.DirectMessageDisabledPolicy do
@impl true @impl true
def filter( def filter(
%{ %{
"type" => "Note", "type" => "Create",
"actor" => actor "actor" => actor
} = activity } = activity
) do ) do
@ -24,9 +24,13 @@ def filter(
should_filter?(sender, recv) should_filter?(sender, recv)
end) end)
{:ok, Map.put(activity, :to, new_to)} {:ok,
activity
|> Map.put("to", new_to)
|> maybe_replace_object_to(new_to)}
else else
_ -> {:ok, activity} _ ->
{:ok, activity}
end end
end end
@ -43,4 +47,10 @@ defp should_filter?(sender, receiver_ap_id) do
_ -> false _ -> false
end end
end end
defp maybe_replace_object_to(%{"object" => %{"to" => _}} = activity, to) do
Kernel.put_in(activity, ["object", "to"], to)
end
defp maybe_replace_object_to(other, _), do: other
end end

View file

@ -16,9 +16,9 @@ def filter(
when type in ["Note", "Create"] do when type in ["Note", "Create"] do
min_age = Pleroma.Config.get([:mrf_reject_newly_created_account_notes, :age]) min_age = Pleroma.Config.get([:mrf_reject_newly_created_account_notes, :age])
with %User{} = user <- Pleroma.User.get_cached_by_ap_id(actor), with %User{local: false} = user <- Pleroma.User.get_cached_by_ap_id(actor),
true <- Timex.diff(Timex.now(), user.inserted_at, :seconds) < min_age do true <- Timex.diff(Timex.now(), user.inserted_at, :seconds) < min_age do
{:reject, "Account created too recently"} {:reject, "[RejectNewlyCreatedAccountNotesPolicy] Account created too recently"}
else else
_ -> {:ok, activity} _ -> {:ok, activity}
end end

View file

@ -717,8 +717,7 @@ defp update_credentials_request do
"people_i_follow" "people_i_follow"
], ],
nullable: true, nullable: true,
description: description: "Who to accept DMs from"
"Who to accept DMs from"
} }
}, },
example: %{ example: %{

View file

@ -191,7 +191,7 @@ def update_credentials(%{assigns: %{user: user}, body_params: params} = conn, _p
:show_role, :show_role,
:skip_thread_containment, :skip_thread_containment,
:allow_following_move, :allow_following_move,
:also_known_as, :also_known_as
] ]
|> Enum.reduce(%{}, fn key, acc -> |> Enum.reduce(%{}, fn key, acc ->
Maps.put_if_present(acc, key, params[key], &{:ok, Params.truthy_param?(&1)}) Maps.put_if_present(acc, key, params[key], &{:ok, Params.truthy_param?(&1)})

View file

@ -8,7 +8,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.DirectMessageDisabledPolicyTest do
describe "strips recipients" do describe "strips recipients" do
test "when the user denies the direct message" do test "when the user denies the direct message" do
sender = insert(:user) sender = insert(:user)
recipient = insert(:user, %{accepts_direct_messages_from_not_followed: false}) recipient = insert(:user, %{accepts_direct_messages_from: :nobody})
refute User.accepts_direct_messages?(recipient, sender) refute User.accepts_direct_messages?(recipient, sender)
@ -16,15 +16,15 @@ test "when the user denies the direct message" do
"actor" => sender.ap_id, "actor" => sender.ap_id,
"to" => [recipient.ap_id], "to" => [recipient.ap_id],
"cc" => [], "cc" => [],
"type" => "Note" "type" => "Create"
} }
assert {:ok, %{to: []}} = DirectMessageDisabledPolicy.filter(message) assert {:ok, %{"to" => []}} = DirectMessageDisabledPolicy.filter(message)
end end
test "when the user does not deny the direct message" do test "when the user does not deny the direct message" do
sender = insert(:user) sender = insert(:user)
recipient = insert(:user, %{accepts_direct_messages_from_not_followed: true}) recipient = insert(:user, %{accepts_direct_messages_from: :everybody})
assert User.accepts_direct_messages?(recipient, sender) assert User.accepts_direct_messages?(recipient, sender)
@ -32,11 +32,11 @@ test "when the user does not deny the direct message" do
"actor" => sender.ap_id, "actor" => sender.ap_id,
"to" => [recipient.ap_id], "to" => [recipient.ap_id],
"cc" => [], "cc" => [],
"type" => "Note" "type" => "Create"
} }
assert {:ok, message} = DirectMessageDisabledPolicy.filter(message) assert {:ok, message} = DirectMessageDisabledPolicy.filter(message)
assert message.to == [recipient.ap_id] assert message["to"] == [recipient.ap_id]
end end
end end
end end

View file

@ -0,0 +1,45 @@
defmodule Pleroma.Web.ActivityPub.MRF.RejectNewlyCreatedAccountNotesPolicyTest do
use Pleroma.DataCase
import Pleroma.Factory
alias Pleroma.Web.ActivityPub.MRF.RejectNewlyCreatedAccountNotesPolicy
describe "reject notes from new accounts" do
test "rejects notes from accounts created more recently than `age`" do
clear_config([:mrf_reject_newly_created_account_notes, :age], 86_400)
sender = insert(:user, %{inserted_at: Timex.now(), local: false})
message = %{
"actor" => sender.ap_id,
"type" => "Create"
}
assert {:reject, _} = RejectNewlyCreatedAccountNotesPolicy.filter(message)
end
test "does not reject notes from accounts created longer ago" do
clear_config([:mrf_reject_newly_created_account_notes, :age], 86_400)
a_day_ago = Timex.shift(Timex.now(), days: -1)
sender = insert(:user, %{inserted_at: a_day_ago, local: false})
message = %{
"actor" => sender.ap_id,
"type" => "Create"
}
assert {:ok, _} = RejectNewlyCreatedAccountNotesPolicy.filter(message)
end
test "does not affect local users" do
clear_config([:mrf_reject_newly_created_account_notes, :age], 86_400)
sender = insert(:user, %{inserted_at: Timex.now(), local: true})
message = %{
"actor" => sender.ap_id,
"type" => "Create"
}
assert {:ok, _} = RejectNewlyCreatedAccountNotesPolicy.filter(message)
end
end
end

View file

@ -102,7 +102,13 @@ test "it works as expected with noop policy" do
clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.NoOpPolicy]) clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.NoOpPolicy])
expected = %{ expected = %{
mrf_policies: ["NoOpPolicy", "HashtagPolicy", "InlineQuotePolicy", "NormalizeMarkup"], mrf_policies: [
"NoOpPolicy",
"HashtagPolicy",
"InlineQuotePolicy",
"NormalizeMarkup",
"DirectMessageDisabledPolicy"
],
mrf_hashtag: %{ mrf_hashtag: %{
federated_timeline_removal: [], federated_timeline_removal: [],
reject: [], reject: [],
@ -118,7 +124,13 @@ test "it works as expected with mock policy" do
clear_config([:mrf, :policies], [MRFModuleMock]) clear_config([:mrf, :policies], [MRFModuleMock])
expected = %{ expected = %{
mrf_policies: ["MRFModuleMock", "HashtagPolicy", "InlineQuotePolicy", "NormalizeMarkup"], mrf_policies: [
"MRFModuleMock",
"HashtagPolicy",
"InlineQuotePolicy",
"NormalizeMarkup",
"DirectMessageDisabledPolicy"
],
mrf_module_mock: "some config data", mrf_module_mock: "some config data",
mrf_hashtag: %{ mrf_hashtag: %{
federated_timeline_removal: [], federated_timeline_removal: [],

View file

@ -316,7 +316,7 @@ test "it strips internal reactions" do
test "it correctly processes messages with non-array to field" do test "it correctly processes messages with non-array to field" do
data = data =
File.read!("test/fixtures/mastodon-post-activity.json") File.read!("test/fixtures/mastodon-post-activity.json")
|> Poison.decode!() |> Jason.decode!()
|> Map.put("to", "https://www.w3.org/ns/activitystreams#Public") |> Map.put("to", "https://www.w3.org/ns/activitystreams#Public")
|> put_in(["object", "to"], "https://www.w3.org/ns/activitystreams#Public") |> put_in(["object", "to"], "https://www.w3.org/ns/activitystreams#Public")
@ -333,7 +333,7 @@ test "it correctly processes messages with non-array to field" do
test "it correctly processes messages with non-array cc field" do test "it correctly processes messages with non-array cc field" do
data = data =
File.read!("test/fixtures/mastodon-post-activity.json") File.read!("test/fixtures/mastodon-post-activity.json")
|> Poison.decode!() |> Jason.decode!()
|> Map.put("cc", "http://mastodon.example.org/users/admin/followers") |> Map.put("cc", "http://mastodon.example.org/users/admin/followers")
|> put_in(["object", "cc"], "http://mastodon.example.org/users/admin/followers") |> put_in(["object", "cc"], "http://mastodon.example.org/users/admin/followers")
@ -346,7 +346,7 @@ test "it correctly processes messages with non-array cc field" do
test "it correctly processes messages with weirdness in address fields" do test "it correctly processes messages with weirdness in address fields" do
data = data =
File.read!("test/fixtures/mastodon-post-activity.json") File.read!("test/fixtures/mastodon-post-activity.json")
|> Poison.decode!() |> Jason.decode!()
|> Map.put("cc", ["http://mastodon.example.org/users/admin/followers", ["¿"]]) |> Map.put("cc", ["http://mastodon.example.org/users/admin/followers", ["¿"]])
|> put_in(["object", "cc"], ["http://mastodon.example.org/users/admin/followers", ["¿"]]) |> put_in(["object", "cc"], ["http://mastodon.example.org/users/admin/followers", ["¿"]])
@ -412,7 +412,7 @@ test "does NOT schedule background fetching of `replies` beyond max thread depth
activity = activity =
File.read!("test/fixtures/mastodon-post-activity.json") File.read!("test/fixtures/mastodon-post-activity.json")
|> Poison.decode!() |> Jason.decode!()
|> Kernel.put_in(["object", "replies"], replies) |> Kernel.put_in(["object", "replies"], replies)
%{activity: activity} %{activity: activity}

View file

@ -735,7 +735,9 @@ test "actor_type field has a higher priority than bot", %{conn: conn} do
test "changing to :everybody", %{conn: conn} do test "changing to :everybody", %{conn: conn} do
account = account =
conn conn
|> patch("/api/v1/accounts/update_credentials", %{accepts_direct_messages_from: "everybody"}) |> patch("/api/v1/accounts/update_credentials", %{
accepts_direct_messages_from: "everybody"
})
|> json_response_and_validate_schema(200) |> json_response_and_validate_schema(200)
assert account["accepts_direct_messages_from"] assert account["accepts_direct_messages_from"]
@ -757,17 +759,23 @@ test "changing to :nobody", %{conn: conn} do
test "changing to :people_i_follow", %{conn: conn} do test "changing to :people_i_follow", %{conn: conn} do
account = account =
conn conn
|> patch("/api/v1/accounts/update_credentials", %{accepts_direct_messages_from: "people_i_follow"}) |> patch("/api/v1/accounts/update_credentials", %{
accepts_direct_messages_from: "people_i_follow"
})
|> json_response_and_validate_schema(200) |> json_response_and_validate_schema(200)
assert account["accepts_direct_messages_from"] assert account["accepts_direct_messages_from"]
assert account["accepts_direct_messages_from"] == "people_i_follow" assert account["accepts_direct_messages_from"] == "people_i_follow"
assert Pleroma.User.get_by_ap_id(account["url"]).accepts_direct_messages_from == :people_i_follow
assert Pleroma.User.get_by_ap_id(account["url"]).accepts_direct_messages_from ==
:people_i_follow
end end
test "changing to an unsupported value", %{conn: conn} do test "changing to an unsupported value", %{conn: conn} do
conn conn
|> patch("/api/v1/accounts/update_credentials", %{accepts_direct_messages_from: "unsupported"}) |> patch("/api/v1/accounts/update_credentials", %{
accepts_direct_messages_from: "unsupported"
})
|> json_response(400) |> json_response(400)
end end
end end