MRF / Dropping of incoming/outgoing messages based on allow-list

This commit is contained in:
Eliot Berriot 2019-06-20 10:27:07 +02:00
parent 371dc01205
commit 08262529ec
24 changed files with 897 additions and 89 deletions

View file

@ -1,5 +1,6 @@
import uuid
import logging
import urllib.parse
from django.core.cache import cache
from django.conf import settings
@ -122,32 +123,38 @@ def receive(activity, on_behalf_of):
from . import serializers
from . import tasks
from .routes import inbox
from funkwhale_api.moderation import mrf
logger.debug(
"[federation] Received activity from %s : %s", on_behalf_of.fid, activity
)
# we ensure the activity has the bare minimum structure before storing
# it in our database
serializer = serializers.BaseActivitySerializer(
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,
payload=activity,
):
payload, updated = mrf.inbox.apply(activity, sender_id=on_behalf_of.fid)
if not payload:
logger.info(
"[federation] Discarding activity due to instance policies %s",
"[federation] Discarding activity due to mrf %s",
serializer.validated_data.get("id"),
)
return
if not inbox.get_matching_handlers(payload):
# discard unhandlable activity
logger.debug(
"[federation] No matching route found for activity, discarding: %s", payload
)
return
try:
copy = serializer.save()
copy = serializer.save(payload=payload, type=payload["type"])
except IntegrityError:
logger.warning(
"[federation] Discarding already elivered activity %s",
"[federation] Discarding already delivered activity %s",
serializer.validated_data.get("id"),
)
return
@ -283,9 +290,19 @@ class OutboxRouter(Router):
and may yield data that should be persisted in the Activity model
for further delivery.
"""
from funkwhale_api.common import preferences
from . import models
from . import tasks
allow_list_enabled = preferences.get("moderation__allow_list_enabled")
allowed_domains = None
if allow_list_enabled:
allowed_domains = set(
models.Domain.objects.filter(allowed=True).values_list(
"name", flat=True
)
)
for route, handler in self.routes:
if not match_route(route, routing):
continue
@ -314,10 +331,10 @@ class OutboxRouter(Router):
a = models.Activity(**activity_data)
a.uuid = uuid.uuid4()
to_inbox_items, to_deliveries, new_to = prepare_deliveries_and_inbox_items(
to, "to"
to, "to", allowed_domains=allowed_domains
)
cc_inbox_items, cc_deliveries, new_cc = prepare_deliveries_and_inbox_items(
cc, "cc"
cc, "cc", allowed_domains=allowed_domains
)
if not any(
[to_inbox_items, to_deliveries, cc_inbox_items, cc_deliveries]
@ -374,7 +391,14 @@ def match_route(route, payload):
return True
def prepare_deliveries_and_inbox_items(recipient_list, type):
def is_allowed_url(url, allowed_domains):
return (
allowed_domains is None
or urllib.parse.urlparse(url).hostname in allowed_domains
)
def prepare_deliveries_and_inbox_items(recipient_list, type, allowed_domains=None):
"""
Given a list of recipients (
either actor instances, public adresses, a dictionnary with a "type" and "target"
@ -384,10 +408,12 @@ def prepare_deliveries_and_inbox_items(recipient_list, type):
"""
from . import models
if allowed_domains is not None:
allowed_domains = set(allowed_domains)
allowed_domains.add(settings.FEDERATION_HOSTNAME)
local_recipients = set()
remote_inbox_urls = set()
urls = []
for r in recipient_list:
if isinstance(r, models.Actor):
if r.is_local:
@ -432,7 +458,13 @@ def prepare_deliveries_and_inbox_items(recipient_list, type):
values = actors.values("shared_inbox_url", "inbox_url")
for v in values:
remote_inbox_urls.add(v["shared_inbox_url"] or v["inbox_url"])
deliveries = [models.Delivery(inbox_url=url) for url in remote_inbox_urls]
deliveries = [
models.Delivery(inbox_url=url)
for url in remote_inbox_urls
if is_allowed_url(url, allowed_domains)
]
urls = [url for url in urls if is_allowed_url(url, allowed_domains)]
inbox_items = [
models.InboxItem(actor=actor, type=type) for actor in local_recipients
]