Model / settings for allow-listing
This commit is contained in:
parent
1a52dfcc1d
commit
2b2b64f0a7
|
@ -26,7 +26,8 @@ redeliver_activities.short_description = "Redeliver"
|
||||||
|
|
||||||
@admin.register(models.Domain)
|
@admin.register(models.Domain)
|
||||||
class DomainAdmin(admin.ModelAdmin):
|
class DomainAdmin(admin.ModelAdmin):
|
||||||
list_display = ["name", "creation_date"]
|
list_display = ["name", "allowed", "creation_date"]
|
||||||
|
list_filter = ["allowed"]
|
||||||
search_fields = ["name"]
|
search_fields = ["name"]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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),
|
||||||
|
)
|
||||||
|
]
|
|
@ -118,6 +118,9 @@ class Domain(models.Model):
|
||||||
null=True,
|
null=True,
|
||||||
blank=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()
|
objects = DomainQuerySet.as_manager()
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
|
|
@ -130,6 +130,7 @@ class ManageDomainSerializer(serializers.ModelSerializer):
|
||||||
"nodeinfo",
|
"nodeinfo",
|
||||||
"nodeinfo_fetch_date",
|
"nodeinfo_fetch_date",
|
||||||
"instance_policy",
|
"instance_policy",
|
||||||
|
"allowed",
|
||||||
]
|
]
|
||||||
read_only_fields = [
|
read_only_fields = [
|
||||||
"creation_date",
|
"creation_date",
|
||||||
|
@ -145,6 +146,11 @@ class ManageDomainSerializer(serializers.ModelSerializer):
|
||||||
return getattr(o, "outbox_activities_count", 0)
|
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):
|
class ManageDomainActionSerializer(common_serializers.ActionSerializer):
|
||||||
actions = [common_serializers.Action("purge", allow_all=False)]
|
actions = [common_serializers.Action("purge", allow_all=False)]
|
||||||
filterset_class = filters.ManageDomainFilterSet
|
filterset_class = filters.ManageDomainFilterSet
|
||||||
|
|
|
@ -339,6 +339,7 @@ class ManageDomainViewSet(
|
||||||
mixins.CreateModelMixin,
|
mixins.CreateModelMixin,
|
||||||
mixins.ListModelMixin,
|
mixins.ListModelMixin,
|
||||||
mixins.RetrieveModelMixin,
|
mixins.RetrieveModelMixin,
|
||||||
|
mixins.UpdateModelMixin,
|
||||||
viewsets.GenericViewSet,
|
viewsets.GenericViewSet,
|
||||||
):
|
):
|
||||||
lookup_value_regex = r"[a-zA-Z0-9\-\.]+"
|
lookup_value_regex = r"[a-zA-Z0-9\-\.]+"
|
||||||
|
@ -361,6 +362,13 @@ class ManageDomainViewSet(
|
||||||
"instance_policy",
|
"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):
|
def perform_create(self, serializer):
|
||||||
domain = serializer.save()
|
domain = serializer.save()
|
||||||
federation_tasks.update_domain_nodeinfo(domain_name=domain.name)
|
federation_tasks.update_domain_nodeinfo(domain_name=domain.name)
|
||||||
|
|
|
@ -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
|
|
@ -51,6 +51,7 @@ def test_manage_domain_serializer(factories, now):
|
||||||
"nodeinfo": {},
|
"nodeinfo": {},
|
||||||
"nodeinfo_fetch_date": None,
|
"nodeinfo_fetch_date": None,
|
||||||
"instance_policy": None,
|
"instance_policy": None,
|
||||||
|
"allowed": None,
|
||||||
}
|
}
|
||||||
s = serializers.ManageDomainSerializer(domain)
|
s = serializers.ManageDomainSerializer(domain)
|
||||||
|
|
||||||
|
|
|
@ -73,6 +73,31 @@ def test_domain_create(superuser_api_client, mocker):
|
||||||
update_domain_nodeinfo.assert_called_once_with(domain_name="test.federation")
|
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):
|
def test_domain_nodeinfo(factories, superuser_api_client, mocker):
|
||||||
domain = factories["federation.Domain"]()
|
domain = factories["federation.Domain"]()
|
||||||
url = reverse(
|
url = reverse(
|
||||||
|
|
Loading…
Reference in New Issue