diff --git a/api/funkwhale_api/federation/activity.py b/api/funkwhale_api/federation/activity.py index 17373479b..c13ef936b 100644 --- a/api/funkwhale_api/federation/activity.py +++ b/api/funkwhale_api/federation/activity.py @@ -481,7 +481,7 @@ class OutboxRouter(Router): ) for a in activities: - logger.info(f"[federation] OUtbox sending activity : {a.pk}") + logger.info(f"[federation] Outbox sending activity : {a.pk}") funkwhale_utils.on_commit(tasks.dispatch_outbox.delay, activity_id=a.pk) return activities diff --git a/api/funkwhale_api/federation/tasks.py b/api/funkwhale_api/federation/tasks.py index b4ad58e2d..31b4a6bcf 100644 --- a/api/funkwhale_api/federation/tasks.py +++ b/api/funkwhale_api/federation/tasks.py @@ -2,6 +2,7 @@ import datetime import json import logging import os +from urllib.parse import urlparse import requests from django.conf import settings @@ -145,6 +146,19 @@ def deliver_to_remote(delivery): # federation is disabled, we only deliver to local recipients return + # we check the domain is still reachable before attempting delivery + if ( + models.Domain.objects.get(name=urlparse(delivery.inbox_url).netloc).reachable + is False + ): + delivery.last_attempt_date = timezone.now() + delivery.attempts = F("attempts") + 1 + delivery.save(update_fields=["last_attempt_date", "attempts"]) + logger.info( + f"Skipping delivery to {delivery.inbox_url} as its domain is unreachable", + ) + return + actor = delivery.activity.actor logger.info("Preparing activity delivery to %s", delivery.inbox_url) auth = signing.get_auth(actor.private_key, actor.private_key_id) diff --git a/api/tests/federation/test_tasks.py b/api/tests/federation/test_tasks.py index ef48374b4..f6a9bb643 100644 --- a/api/tests/federation/test_tasks.py +++ b/api/tests/federation/test_tasks.py @@ -127,7 +127,12 @@ def test_dispatch_outbox_disabled_federation(factories, mocker, preferences): def test_deliver_to_remote_success_mark_as_delivered(factories, r_mock, now): - delivery = factories["federation.Delivery"]() + recipient = factories["federation.Actor"](domain__reachable=True) + activity = factories["federation.Activity"](actor__local=True, type=type) + activity.recipients.add(recipient) + delivery = factories["federation.Delivery"]( + activity=activity, inbox_url=recipient.fid + ) r_mock.post(delivery.inbox_url) tasks.deliver_to_remote(delivery_id=delivery.pk) @@ -145,7 +150,12 @@ def test_deliver_to_remote_success_mark_as_delivered(factories, r_mock, now): def test_deliver_to_remote_error(factories, r_mock, now): - delivery = factories["federation.Delivery"]() + recipient = factories["federation.Actor"](domain__reachable=True) + activity = factories["federation.Activity"](actor__local=True, type=type) + activity.recipients.add(recipient) + delivery = factories["federation.Delivery"]( + activity=activity, inbox_url=recipient.fid + ) r_mock.post(delivery.inbox_url, status_code=404) with pytest.raises(tasks.RequestException): @@ -158,6 +168,23 @@ def test_deliver_to_remote_error(factories, r_mock, now): assert delivery.last_attempt_date == now +def test_deliver_to_remote_filter_unreachable_domain(factories, now): + recipient = factories["federation.Actor"](domain__reachable=False) + activity = factories["federation.Activity"](actor__local=True, type=type) + activity.recipients.add(recipient) + delivery = factories["federation.Delivery"]( + activity=activity, inbox_url=recipient.fid + ) + + tasks.deliver_to_remote(delivery_id=delivery.pk) + + delivery.refresh_from_db() + + assert delivery.is_delivered is False + assert delivery.attempts == 1 + assert delivery.last_attempt_date == now + + def test_fetch_nodeinfo(factories, r_mock, now): wellknown_url = "https://test.test/.well-known/nodeinfo" nodeinfo_url = "https://test.test/nodeinfo" diff --git a/changes/changelog.d/2492.enhancement b/changes/changelog.d/2492.enhancement new file mode 100644 index 000000000..793446793 --- /dev/null +++ b/changes/changelog.d/2492.enhancement @@ -0,0 +1 @@ +fix(federation):only deliver activities to reachable domains (#2492)