mirror of
https://code.eliotberriot.com/funkwhale/funkwhale.git
synced 2025-10-06 02:40:00 +02:00
MRF / Dropping of incoming/outgoing messages based on allow-list
This commit is contained in:
parent
371dc01205
commit
08262529ec
24 changed files with 897 additions and 89 deletions
|
@ -13,10 +13,13 @@ from funkwhale_api.federation import (
|
|||
)
|
||||
|
||||
|
||||
def test_receive_validates_basic_attributes_and_stores_activity(factories, now, mocker):
|
||||
def test_receive_validates_basic_attributes_and_stores_activity(
|
||||
mrf_inbox_registry, factories, now, mocker
|
||||
):
|
||||
mocker.patch.object(
|
||||
activity.InboxRouter, "get_matching_handlers", return_value=True
|
||||
)
|
||||
mrf_inbox_registry_apply = mocker.spy(mrf_inbox_registry, "apply")
|
||||
mocked_dispatch = mocker.patch("funkwhale_api.common.utils.on_commit")
|
||||
local_to_actor = factories["users.User"]().create_actor()
|
||||
local_cc_actor = factories["users.User"]().create_actor()
|
||||
|
@ -31,6 +34,7 @@ def test_receive_validates_basic_attributes_and_stores_activity(factories, now,
|
|||
}
|
||||
|
||||
copy = activity.receive(activity=a, on_behalf_of=remote_actor)
|
||||
mrf_inbox_registry_apply.assert_called_once_with(a, sender_id=a["actor"])
|
||||
|
||||
assert copy.payload == a
|
||||
assert copy.creation_date >= now
|
||||
|
@ -49,6 +53,63 @@ def test_receive_validates_basic_attributes_and_stores_activity(factories, now,
|
|||
assert ii.is_read is False
|
||||
|
||||
|
||||
def test_receive_uses_mrf_returned_payload(mrf_inbox_registry, factories, now, mocker):
|
||||
mocker.patch.object(
|
||||
activity.InboxRouter, "get_matching_handlers", return_value=True
|
||||
)
|
||||
|
||||
def patched_apply(payload, **kwargs):
|
||||
payload["type"] = "SomethingElse"
|
||||
return payload, True
|
||||
|
||||
mrf_inbox_registry_apply = mocker.patch.object(
|
||||
mrf_inbox_registry, "apply", side_effect=patched_apply
|
||||
)
|
||||
mocked_dispatch = mocker.patch("funkwhale_api.common.utils.on_commit")
|
||||
local_to_actor = factories["users.User"]().create_actor()
|
||||
remote_actor = factories["federation.Actor"]()
|
||||
a = {
|
||||
"@context": [],
|
||||
"actor": remote_actor.fid,
|
||||
"type": "Noop",
|
||||
"id": "https://test.activity",
|
||||
"to": [local_to_actor.fid],
|
||||
}
|
||||
|
||||
copy = activity.receive(activity=a, on_behalf_of=remote_actor)
|
||||
mrf_inbox_registry_apply.assert_called_once_with(a, sender_id=a["actor"])
|
||||
|
||||
expected = a.copy()
|
||||
expected["type"] = "SomethingElse"
|
||||
assert copy.payload == expected
|
||||
assert copy.creation_date >= now
|
||||
assert copy.actor == remote_actor
|
||||
assert copy.fid == a["id"]
|
||||
assert copy.type == "SomethingElse"
|
||||
mocked_dispatch.assert_called_once_with(
|
||||
tasks.dispatch_inbox.delay, activity_id=copy.pk
|
||||
)
|
||||
|
||||
|
||||
def test_receive_mrf_skip(mrf_inbox_registry, factories, now, mocker):
|
||||
mocker.patch.object(
|
||||
activity.InboxRouter, "get_matching_handlers", return_value=True
|
||||
)
|
||||
mocker.patch.object(mrf_inbox_registry, "apply", return_value=(None, False))
|
||||
local_to_actor = factories["users.User"]().create_actor()
|
||||
remote_actor = factories["federation.Actor"]()
|
||||
a = {
|
||||
"@context": [],
|
||||
"actor": remote_actor.fid,
|
||||
"type": "Noop",
|
||||
"id": "https://test.activity",
|
||||
"to": [local_to_actor.fid],
|
||||
}
|
||||
|
||||
copy = activity.receive(activity=a, on_behalf_of=remote_actor)
|
||||
assert copy is None
|
||||
|
||||
|
||||
def test_receive_calls_should_reject(factories, now, mocker):
|
||||
should_reject = mocker.patch.object(activity, "should_reject", return_value=True)
|
||||
mocker.patch.object(
|
||||
|
@ -287,7 +348,7 @@ def test_route_matching(route, payload, expected):
|
|||
assert activity.match_route(route, payload) is expected
|
||||
|
||||
|
||||
def test_outbox_router_dispatch(mocker, factories, now):
|
||||
def test_outbox_router_dispatch(mocker, factories, preferences, now):
|
||||
router = activity.OutboxRouter()
|
||||
actor = factories["federation.Actor"]()
|
||||
r1 = factories["federation.Actor"]()
|
||||
|
@ -331,7 +392,39 @@ def test_outbox_router_dispatch(mocker, factories, now):
|
|||
assert delivery.is_delivered is False
|
||||
|
||||
|
||||
def test_prepare_deliveries_and_inbox_items(factories):
|
||||
def test_outbox_router_dispatch_allow_list(mocker, factories, preferences, now):
|
||||
preferences["moderation__allow_list_enabled"] = True
|
||||
router = activity.OutboxRouter()
|
||||
actor = factories["federation.Actor"]()
|
||||
r1 = factories["federation.Actor"](domain__allowed=True)
|
||||
r2 = factories["federation.Actor"]()
|
||||
prepare_deliveries_and_inbox_items = mocker.spy(
|
||||
activity, "prepare_deliveries_and_inbox_items"
|
||||
)
|
||||
|
||||
def handler(context):
|
||||
yield {
|
||||
"payload": {
|
||||
"type": "Noop",
|
||||
"actor": actor.fid,
|
||||
"summary": context["summary"],
|
||||
"to": [r1],
|
||||
"cc": [r2],
|
||||
},
|
||||
"actor": actor,
|
||||
}
|
||||
|
||||
router.connect({"type": "Noop"}, handler)
|
||||
router.dispatch({"type": "Noop"}, {"summary": "hello"})
|
||||
prepare_deliveries_and_inbox_items.assert_any_call(
|
||||
[r1], "to", allowed_domains=set([r1.domain_id])
|
||||
)
|
||||
prepare_deliveries_and_inbox_items.assert_any_call(
|
||||
[r2], "cc", allowed_domains=set([r1.domain_id])
|
||||
)
|
||||
|
||||
|
||||
def test_prepare_deliveries_and_inbox_items(factories, preferences):
|
||||
local_actor1 = factories["federation.Actor"](
|
||||
local=True, shared_inbox_url="https://testlocal.inbox"
|
||||
)
|
||||
|
@ -385,7 +478,7 @@ def test_prepare_deliveries_and_inbox_items(factories):
|
|||
]
|
||||
|
||||
inbox_items, deliveries, urls = activity.prepare_deliveries_and_inbox_items(
|
||||
recipients, "to"
|
||||
recipients, "to", allowed_domains=None
|
||||
)
|
||||
expected_inbox_items = sorted(
|
||||
[
|
||||
|
@ -436,6 +529,32 @@ def test_prepare_deliveries_and_inbox_items(factories):
|
|||
assert inbox_item.type == "to"
|
||||
|
||||
|
||||
def test_prepare_deliveries_and_inbox_items_allow_list(factories, preferences):
|
||||
preferences["moderation__allow_list_enabled"] = True
|
||||
remote_actor1 = factories["federation.Actor"](domain__allowed=True)
|
||||
remote_actor2 = factories["federation.Actor"](domain__allowed=False)
|
||||
|
||||
recipients = [remote_actor1, remote_actor2]
|
||||
|
||||
inbox_items, deliveries, urls = activity.prepare_deliveries_and_inbox_items(
|
||||
recipients, "to", allowed_domains=set([remote_actor1.domain_id])
|
||||
)
|
||||
expected_inbox_items = []
|
||||
|
||||
expected_deliveries = [models.Delivery(inbox_url=remote_actor1.inbox_url)]
|
||||
|
||||
expected_urls = [remote_actor1.fid]
|
||||
|
||||
assert urls == expected_urls
|
||||
assert len(expected_inbox_items) == len(inbox_items)
|
||||
assert len(expected_deliveries) == len(deliveries)
|
||||
|
||||
for delivery, expected_delivery in zip(
|
||||
sorted(deliveries, key=lambda v: v.inbox_url), expected_deliveries
|
||||
):
|
||||
assert delivery.inbox_url == expected_delivery.inbox_url
|
||||
|
||||
|
||||
def test_prepare_deliveries_and_inbox_items_instances_with_followers(factories):
|
||||
|
||||
domain1 = factories["federation.Domain"](with_service_actor=True)
|
||||
|
@ -460,7 +579,7 @@ def test_prepare_deliveries_and_inbox_items_instances_with_followers(factories):
|
|||
recipients = [activity.PUBLIC_ADDRESS, {"type": "instances_with_followers"}]
|
||||
|
||||
inbox_items, deliveries, urls = activity.prepare_deliveries_and_inbox_items(
|
||||
recipients, "to"
|
||||
recipients, "to", allowed_domains=None
|
||||
)
|
||||
|
||||
expected_deliveries = sorted(
|
||||
|
@ -483,6 +602,20 @@ def test_prepare_deliveries_and_inbox_items_instances_with_followers(factories):
|
|||
assert delivery.inbox_url == expected_delivery.inbox_url
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"url, allowed_domains, expected",
|
||||
[
|
||||
("https://domain.example/test", None, True),
|
||||
("https://domain.example/test", [], False),
|
||||
("https://allowed.example/test", ["allowed.example"], True),
|
||||
("https://domain.example/test", ["allowed.example"], False),
|
||||
("https://social.allowed.example/test", ["allowed.example"], False),
|
||||
],
|
||||
)
|
||||
def test_is_allowed_url(url, allowed_domains, expected):
|
||||
assert activity.is_allowed_url(url, allowed_domains) is expected
|
||||
|
||||
|
||||
def test_should_rotate_actor_key(settings, cache, now):
|
||||
actor_id = 42
|
||||
settings.ACTOR_KEY_ROTATION_DELAY = 10
|
||||
|
@ -507,7 +640,9 @@ def test_schedule_key_rotation(cache, mocker):
|
|||
assert cache.get(activity.ACTOR_KEY_ROTATION_LOCK_CACHE_KEY.format(actor_id), True)
|
||||
|
||||
|
||||
def test_outbox_dispatch_rotate_key_on_delete(mocker, factories, cache, settings):
|
||||
def test_outbox_dispatch_rotate_key_on_delete(
|
||||
mocker, factories, cache, settings, preferences
|
||||
):
|
||||
router = activity.OutboxRouter()
|
||||
actor = factories["federation.Actor"]()
|
||||
r1 = factories["federation.Actor"]()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue