Merge pull request 'Federation: do not deliver to instances rejected by SimplePolicy' (#8021) from lambadalambda/pleroma:fix/federation-reject-instances into develop

Reviewed-on: https://git.pleroma.social/pleroma/pleroma/pulls/8021
This commit is contained in:
lain 2026-10-27 13:20:00 +00:00
commit c2bdfb6a34
11 changed files with 243 additions and 35 deletions

View file

@ -139,4 +139,37 @@ defmodule Pleroma.Web.ActivityPub.MRFTest do
type: :group
}
end
describe "instance_allowed?/1" do
setup do: clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.SimplePolicy])
setup do: clear_config([:mrf_simple, :reject], [{"rejected.example", "spam"}])
setup do: clear_config([:mrf_simple, :accept], [])
test "is false for hosts rejected by SimplePolicy, including subdomains" do
clear_config([:mrf_simple, :reject], [{"*.rejected.example", "spam"}])
refute MRF.instance_allowed?("rejected.example")
refute MRF.instance_allowed?("sub.rejected.example")
assert MRF.instance_allowed?("fine.example")
end
test "only allows accepted hosts when SimplePolicy has an accept list" do
clear_config([:mrf_simple, :accept], [{"friend.example", ""}])
assert MRF.instance_allowed?("friend.example")
refute MRF.instance_allowed?("stranger.example")
end
test "ignores the SimplePolicy lists when the policy is not enabled" do
clear_config([:mrf, :policies], [])
clear_config([:mrf_simple, :accept], [{"friend.example", ""}])
assert MRF.instance_allowed?("rejected.example")
assert MRF.instance_allowed?("stranger.example")
end
test "is false without a host" do
refute MRF.instance_allowed?(nil)
end
end
end

View file

@ -32,8 +32,26 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do
refute Publisher.should_federate?(nil, true)
end
test "it returns true when public is true" do
assert Publisher.should_federate?(false, true)
test "it returns true for public activities to quarantined instances" do
clear_config([:instance, :quarantined_instances], [{"quarantined.example", ""}])
assert Publisher.should_federate?("https://quarantined.example/inbox", true)
refute Publisher.should_federate?("https://quarantined.example/inbox", false)
end
test "it returns false for instances rejected by SimplePolicy, even for public activities" do
clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.SimplePolicy])
clear_config([:mrf_simple, :reject], [{"rejected.example", ""}])
refute Publisher.should_federate?("https://rejected.example/inbox", true)
refute Publisher.should_federate?("https://rejected.example/inbox", false)
assert Publisher.should_federate?("https://fine.example/inbox", true)
end
test "it returns false for inboxes without a host" do
clear_config([:instance, :quarantined_instances], [{"quarantined.example", ""}])
refute Publisher.should_federate?("inbox", false)
end
end
@ -204,6 +222,32 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do
)
end
test "doesn't publish a public activity to instances rejected by SimplePolicy" do
clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.SimplePolicy])
clear_config([:mrf_simple, :reject], [{"rejected.example", "spam"}])
actor = insert(:user)
for host <- ["rejected.example", "fine.example"] do
follower = insert(:user, local: false, inbox: "https://#{host}/users/nick/inbox")
{:ok, _, _} = Pleroma.User.follow(follower, actor)
end
actor = refresh_record(actor)
note_activity =
insert(:note_activity, user: actor, recipients: [@as_public, actor.follower_address])
assert :ok == Publisher.publish(actor, note_activity)
inboxes =
all_enqueued(worker: "Pleroma.Workers.PublisherWorker")
|> Enum.map(& &1.args["params"]["inbox"])
assert "https://fine.example/users/nick/inbox" in inboxes
refute "https://rejected.example/users/nick/inbox" in inboxes
end
test "Publishes a non-public activity to non-quarantined instances." do
Config.put([:instance, :quarantined_instances], [{"somedomain.com", "some reason"}])

View file

@ -0,0 +1,38 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Plugs.HTTPSignaturePlugMRFTest do
# Not async: the MRF settings are global config.
use Pleroma.Web.ConnCase
alias Pleroma.StaticStubbedConfigMock, as: ConfigMock
alias Pleroma.StubbedHTTPSignaturesMock, as: HTTPSignaturesMock
alias Pleroma.Web.Plugs.HTTPSignaturePlug
import Mox
import Phoenix.Controller, only: [put_format: 2]
import Plug.Conn
setup do: clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.SimplePolicy])
setup do: clear_config([:mrf_simple, :reject], [{"mastodon.example.org", "no reason"}])
defp signed_get(actor) do
ConfigMock
|> expect(:get, fn [:activitypub, :authorized_fetch_mode], false -> true end)
|> expect(:get, fn [:instance, :rejected_instances] -> [] end)
HTTPSignaturesMock
|> expect(:validate_conn, fn _ -> true end)
build_conn(:get, "/doesntmattter", %{"actor" => actor})
|> put_req_header("signature", "keyId=\"#{actor}#main-key")
|> put_format("activity+json")
|> HTTPSignaturePlug.call(%{})
end
test "rejects signed requests from instances rejected by SimplePolicy" do
assert signed_get("http://mastodon.example.org/users/admin").halted
refute signed_get("http://allowed.example.org/users/admin").halted
end
end

View file

@ -153,4 +153,38 @@ defmodule Pleroma.Workers.PublisherWorkerTest do
assert {:cancel, :unreachable} = PublisherWorker.perform(job)
end
end
describe "Blocked instances:" do
defp publish_one_job(inbox, activity) do
%Oban.Job{
args: %{
"op" => "publish_one",
"params" => %{"inbox" => inbox, "activity_id" => activity.id}
},
attempt: 1,
max_attempts: 5
}
end
test "cancels queued jobs to instances rejected by SimplePolicy" do
clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.SimplePolicy])
clear_config([:mrf_simple, :reject], [{"rejected.example", ""}])
{:ok, activity} = CommonAPI.post(insert(:user), %{status: "public"})
assert {:cancel, :rejected} =
PublisherWorker.perform(
publish_one_job("https://rejected.example/inbox", activity)
)
end
test "cancels queued private jobs to quarantined instances" do
clear_config([:instance, :quarantined_instances], [{"quarantined.example", ""}])
{:ok, activity} = CommonAPI.post(insert(:user), %{status: "hi", visibility: "private"})
assert {:cancel, :rejected} =
PublisherWorker.perform(
publish_one_job("https://quarantined.example/inbox", activity)
)
end
end
end