From 2b2b64f0a7251abd2e7b5655dbb9eb5ba48bfa27 Mon Sep 17 00:00:00 2001 From: Eliot Berriot 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(