diff --git a/api/funkwhale_api/federation/activity.py b/api/funkwhale_api/federation/activity.py index fd397fe18..4141da795 100644 --- a/api/funkwhale_api/federation/activity.py +++ b/api/funkwhale_api/federation/activity.py @@ -121,6 +121,7 @@ def receive(activity, on_behalf_of): from . import models from . import serializers from . import tasks + from .routes import inbox # we ensure the activity has the bare minimum structure before storing # it in our database @@ -128,6 +129,10 @@ def receive(activity, on_behalf_of): data=activity, context={"actor": on_behalf_of, "local_recipients": True} ) serializer.is_valid(raise_exception=True) + if not inbox.get_matching_handlers(activity): + # discard unhandlable activity + return + if should_reject( fid=serializer.validated_data.get("id"), actor_id=serializer.validated_data["actor"].fid, diff --git a/api/tests/federation/test_activity.py b/api/tests/federation/test_activity.py index 15b063167..e195a7587 100644 --- a/api/tests/federation/test_activity.py +++ b/api/tests/federation/test_activity.py @@ -14,6 +14,9 @@ from funkwhale_api.federation import ( def test_receive_validates_basic_attributes_and_stores_activity(factories, now, mocker): + mocker.patch.object( + activity.InboxRouter, "get_matching_handlers", return_value=True + ) 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() @@ -48,6 +51,9 @@ def test_receive_validates_basic_attributes_and_stores_activity(factories, now, def test_receive_calls_should_reject(factories, now, mocker): should_reject = mocker.patch.object(activity, "should_reject", return_value=True) + mocker.patch.object( + activity.InboxRouter, "get_matching_handlers", return_value=True + ) local_to_actor = factories["users.User"]().create_actor() remote_actor = factories["federation.Actor"]() a = { @@ -65,6 +71,26 @@ def test_receive_calls_should_reject(factories, now, mocker): assert copy is None +def test_receive_skips_if_no_matching_route(factories, now, mocker): + get_matching_handlers = mocker.patch.object( + activity.InboxRouter, "get_matching_handlers", return_value=[] + ) + 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, remote_actor.fid], + } + + copy = activity.receive(activity=a, on_behalf_of=remote_actor) + get_matching_handlers.assert_called_once_with(a) + assert copy is None + assert models.Activity.objects.count() == 0 + + @pytest.mark.parametrize( "params, policy_kwargs, expected", [ diff --git a/changes/changelog.d/776.enhancement b/changes/changelog.d/776.enhancement new file mode 100644 index 000000000..4cdf48815 --- /dev/null +++ b/changes/changelog.d/776.enhancement @@ -0,0 +1 @@ +Don't store unhandled ActivityPub messages in database (#776)