From 2b2b64f0a7251abd2e7b5655dbb9eb5ba48bfa27 Mon Sep 17 00:00:00 2001
From: Eliot Berriot <contact@eliotberriot.com>
Date: Mon, 17 Jun 2019 08:48:05 +0200
Subject: [PATCH] Model / settings for allow-listing
---
api/funkwhale_api/federation/admin.py | 3 ++-
.../migrations/0019_auto_20190611_0851.py | 19 ++++++++++++++
api/funkwhale_api/federation/models.py | 3 +++
api/funkwhale_api/manage/serializers.py | 6 +++++
api/funkwhale_api/manage/views.py | 8 ++++++
.../dynamic_preferences_registry.py | 26 +++++++++++++++++++
api/tests/manage/test_serializers.py | 1 +
api/tests/manage/test_views.py | 25 ++++++++++++++++++
8 files changed, 90 insertions(+), 1 deletion(-)
create mode 100644 api/funkwhale_api/federation/migrations/0019_auto_20190611_0851.py
create mode 100644 api/funkwhale_api/moderation/dynamic_preferences_registry.py
diff --git a/api/funkwhale_api/federation/admin.py b/api/funkwhale_api/federation/admin.py
index 263af80cb..40f7b4f69 100644
--- a/api/funkwhale_api/federation/admin.py
+++ b/api/funkwhale_api/federation/admin.py
@@ -26,7 +26,8 @@ redeliver_activities.short_description = "Redeliver"
@admin.register(models.Domain)
class DomainAdmin(admin.ModelAdmin):
- list_display = ["name", "creation_date"]
+ list_display = ["name", "allowed", "creation_date"]
+ list_filter = ["allowed"]
search_fields = ["name"]
diff --git a/api/funkwhale_api/federation/migrations/0019_auto_20190611_0851.py b/api/funkwhale_api/federation/migrations/0019_auto_20190611_0851.py
new file mode 100644
index 000000000..4ae5e31fb
--- /dev/null
+++ b/api/funkwhale_api/federation/migrations/0019_auto_20190611_0851.py
@@ -0,0 +1,19 @@
+# Generated by Django 2.2.2 on 2019-06-11 08:51
+
+import django.contrib.postgres.fields.jsonb
+import django.core.serializers.json
+from django.db import migrations, models
+import funkwhale_api.federation.models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [("federation", "0018_fetch")]
+
+ operations = [
+ migrations.AddField(
+ model_name="domain",
+ name="allowed",
+ field=models.BooleanField(default=None, null=True),
+ )
+ ]
diff --git a/api/funkwhale_api/federation/models.py b/api/funkwhale_api/federation/models.py
index d530c62df..df81cd500 100644
--- a/api/funkwhale_api/federation/models.py
+++ b/api/funkwhale_api/federation/models.py
@@ -118,6 +118,9 @@ class Domain(models.Model):
null=True,
blank=True,
)
+ # are interactions with this domain allowed (only applies when allow-listing is on)
+ allowed = models.BooleanField(default=None, null=True)
+
objects = DomainQuerySet.as_manager()
def __str__(self):
diff --git a/api/funkwhale_api/manage/serializers.py b/api/funkwhale_api/manage/serializers.py
index add9364e8..25f8c01db 100644
--- a/api/funkwhale_api/manage/serializers.py
+++ b/api/funkwhale_api/manage/serializers.py
@@ -130,6 +130,7 @@ class ManageDomainSerializer(serializers.ModelSerializer):
"nodeinfo",
"nodeinfo_fetch_date",
"instance_policy",
+ "allowed",
]
read_only_fields = [
"creation_date",
@@ -145,6 +146,11 @@ class ManageDomainSerializer(serializers.ModelSerializer):
return getattr(o, "outbox_activities_count", 0)
+class ManageDomainUpdateSerializer(ManageDomainSerializer):
+ class Meta(ManageDomainSerializer.Meta):
+ read_only_fields = ["name"] + ManageDomainSerializer.Meta.read_only_fields
+
+
class ManageDomainActionSerializer(common_serializers.ActionSerializer):
actions = [common_serializers.Action("purge", allow_all=False)]
filterset_class = filters.ManageDomainFilterSet
diff --git a/api/funkwhale_api/manage/views.py b/api/funkwhale_api/manage/views.py
index 83981116c..fb9ceabc5 100644
--- a/api/funkwhale_api/manage/views.py
+++ b/api/funkwhale_api/manage/views.py
@@ -339,6 +339,7 @@ class ManageDomainViewSet(
mixins.CreateModelMixin,
mixins.ListModelMixin,
mixins.RetrieveModelMixin,
+ mixins.UpdateModelMixin,
viewsets.GenericViewSet,
):
lookup_value_regex = r"[a-zA-Z0-9\-\.]+"
@@ -361,6 +362,13 @@ class ManageDomainViewSet(
"instance_policy",
]
+ def get_serializer_class(self):
+ if self.action in ["update", "partial_update"]:
+ # A dedicated serializer for update
+ # to ensure domain name can't be changed
+ return serializers.ManageDomainUpdateSerializer
+ return super().get_serializer_class()
+
def perform_create(self, serializer):
domain = serializer.save()
federation_tasks.update_domain_nodeinfo(domain_name=domain.name)
diff --git a/api/funkwhale_api/moderation/dynamic_preferences_registry.py b/api/funkwhale_api/moderation/dynamic_preferences_registry.py
new file mode 100644
index 000000000..ff4201b57
--- /dev/null
+++ b/api/funkwhale_api/moderation/dynamic_preferences_registry.py
@@ -0,0 +1,26 @@
+from dynamic_preferences import types
+from dynamic_preferences.registries import global_preferences_registry
+
+moderation = types.Section("Moderation")
+
+
+@global_preferences_registry.register
+class AllowListEnabled(types.BooleanPreference):
+ section = moderation
+ name = "allow_list_enabled"
+ verbose_name = "Enable allow-listing"
+ help_text = "If enabled, only interactions with explicitely allowed domains will be authorized."
+ default = False
+
+
+@global_preferences_registry.register
+class AllowListPublic(types.BooleanPreference):
+ section = moderation
+ name = "allow_list_public"
+ verbose_name = "Publish your allowed-domains list"
+ help_text = (
+ "If enabled, everyone will be able to retrieve the list of domains you allowed. ",
+ "This is useful on open setups, to help people decide if they want to join your pod, or to "
+ "make your moderation policy public.",
+ )
+ default = False
diff --git a/api/tests/manage/test_serializers.py b/api/tests/manage/test_serializers.py
index 65c75c2c3..cfbb17517 100644
--- a/api/tests/manage/test_serializers.py
+++ b/api/tests/manage/test_serializers.py
@@ -51,6 +51,7 @@ def test_manage_domain_serializer(factories, now):
"nodeinfo": {},
"nodeinfo_fetch_date": None,
"instance_policy": None,
+ "allowed": None,
}
s = serializers.ManageDomainSerializer(domain)
diff --git a/api/tests/manage/test_views.py b/api/tests/manage/test_views.py
index e3d136a0e..72394052c 100644
--- a/api/tests/manage/test_views.py
+++ b/api/tests/manage/test_views.py
@@ -73,6 +73,31 @@ def test_domain_create(superuser_api_client, mocker):
update_domain_nodeinfo.assert_called_once_with(domain_name="test.federation")
+def test_domain_update_allowed(superuser_api_client, factories):
+ domain = factories["federation.Domain"]()
+ url = reverse("api:v1:manage:federation:domains-detail", kwargs={"pk": domain.name})
+ response = superuser_api_client.put(url, {"allowed": True})
+
+ assert response.status_code == 200
+ domain.refresh_from_db()
+ assert domain.allowed is True
+
+
+def test_domain_update_cannot_change_name(superuser_api_client, factories):
+ domain = factories["federation.Domain"]()
+ old_name = domain.name
+ url = reverse("api:v1:manage:federation:domains-detail", kwargs={"pk": old_name})
+ response = superuser_api_client.put(url, {"name": "something.else"})
+
+ domain.refresh_from_db()
+
+ assert response.status_code == 200
+ assert domain.name == old_name
+ # changing the pk of a model and saving results in a new DB entry in django,
+ # so we check that no other entry was created
+ assert domain.__class__.objects.count() == 1
+
+
def test_domain_nodeinfo(factories, superuser_api_client, mocker):
domain = factories["federation.Domain"]()
url = reverse(
--
GitLab