Add config identity_min_length and apply non-admin validation
This commit is contained in:
parent
f9ee3ef69d
commit
6b7082a194
|
@ -165,6 +165,7 @@ class Config(models.Model):
|
|||
signup_text: str = ""
|
||||
|
||||
post_length: int = 500
|
||||
identity_min_length: int = 2
|
||||
identity_max_per_user: int = 5
|
||||
identity_max_age: int = 24 * 60 * 60
|
||||
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
import pytest
|
||||
|
||||
from core.models import Config
|
||||
from users.models import Domain, Identity, User
|
||||
from users.views.identity import CreateIdentity
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_create_identity_form(client):
|
||||
""" """
|
||||
# Make a user
|
||||
user = User.objects.create(email="test@example.com")
|
||||
admin = User.objects.create(email="admin@example.com", admin=True)
|
||||
# Make a domain
|
||||
domain = Domain.objects.create(domain="example.com", local=True)
|
||||
domain.users.add(user)
|
||||
domain.users.add(admin)
|
||||
|
||||
# Test identity_min_length
|
||||
data = {
|
||||
"username": "a",
|
||||
"domain": domain.domain,
|
||||
"name": "The User",
|
||||
}
|
||||
|
||||
form = CreateIdentity.form_class(user=user, data=data)
|
||||
assert not form.is_valid()
|
||||
assert "username" in form.errors
|
||||
assert "value has at least" in form.errors["username"][0]
|
||||
|
||||
form = CreateIdentity.form_class(user=admin, data=data)
|
||||
assert form.errors == {}
|
||||
|
||||
# Test restricted_usernames
|
||||
data = {
|
||||
"username": "@root",
|
||||
"domain": domain.domain,
|
||||
"name": "The User",
|
||||
}
|
||||
|
||||
form = CreateIdentity.form_class(user=user, data=data)
|
||||
assert not form.is_valid()
|
||||
assert "username" in form.errors
|
||||
assert "restricted to administrators" in form.errors["username"][0]
|
||||
|
||||
form = CreateIdentity.form_class(user=admin, data=data)
|
||||
assert form.errors == {}
|
||||
|
||||
# Test valid chars
|
||||
data = {
|
||||
"username": "@someval!!!!",
|
||||
"domain": domain.domain,
|
||||
"name": "The User",
|
||||
}
|
||||
|
||||
for u in (user, admin):
|
||||
form = CreateIdentity.form_class(user=u, data=data)
|
||||
assert not form.is_valid()
|
||||
assert "username" in form.errors
|
||||
assert form.errors["username"][0].startswith("Only the letters")
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_identity_max_per_user(client):
|
||||
"""
|
||||
Ensures the webfinger and actor URLs are working properly
|
||||
"""
|
||||
# Make a user
|
||||
user = User.objects.create(email="test@example.com")
|
||||
# Make a domain
|
||||
domain = Domain.objects.create(domain="example.com", local=True)
|
||||
domain.users.add(user)
|
||||
# Make an identity for them
|
||||
for i in range(Config.system.identity_max_per_user):
|
||||
identity = Identity.objects.create(
|
||||
actor_uri=f"https://example.com/@test{i}@example.com/actor/",
|
||||
username=f"test{i}",
|
||||
domain=domain,
|
||||
name=f"Test User{i}",
|
||||
local=True,
|
||||
)
|
||||
identity.users.add(user)
|
||||
|
||||
data = {
|
||||
"username": "toomany",
|
||||
"domain": domain.domain,
|
||||
"name": "Too Many",
|
||||
}
|
||||
form = CreateIdentity.form_class(user=user, data=data)
|
||||
assert form.errors["__all__"][0].startswith("You are not allowed more than")
|
||||
|
||||
user.admin = True
|
||||
form = CreateIdentity.form_class(user=user, data=data)
|
||||
assert form.is_valid()
|
|
@ -54,6 +54,10 @@ class BasicSettings(AdminSettingsPage):
|
|||
"title": "Maximum Identities Per User",
|
||||
"help_text": "Non-admins will be blocked from creating more than this",
|
||||
},
|
||||
"identity_min_length": {
|
||||
"title": "Minimum Length For User Identities",
|
||||
"help_text": "Non-admins will be blocked from creating identities shorter than this",
|
||||
},
|
||||
"signup_allowed": {
|
||||
"title": "Signups Allowed",
|
||||
"help_text": "If signups are allowed at all",
|
||||
|
@ -84,5 +88,9 @@ class BasicSettings(AdminSettingsPage):
|
|||
],
|
||||
"Signups": ["signup_allowed", "signup_invite_only", "signup_text"],
|
||||
"Posts": ["post_length"],
|
||||
"Identities": ["identity_max_per_user", "restricted_usernames"],
|
||||
"Identities": [
|
||||
"identity_max_per_user",
|
||||
"identity_min_length",
|
||||
"restricted_usernames",
|
||||
],
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ import string
|
|||
|
||||
from django import forms
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.core import validators
|
||||
from django.http import Http404, JsonResponse
|
||||
from django.shortcuts import redirect
|
||||
from django.utils.decorators import method_decorator
|
||||
|
@ -144,10 +145,23 @@ class CreateIdentity(FormView):
|
|||
(domain.domain, domain.domain)
|
||||
for domain in Domain.available_for_user(user)
|
||||
]
|
||||
self.user = user
|
||||
|
||||
def clean_username(self):
|
||||
# Remove any leading @ and force it lowercase
|
||||
value = self.cleaned_data["username"].lstrip("@").lower()
|
||||
|
||||
if not self.user.admin:
|
||||
# Apply username min length
|
||||
limit = int(Config.system.identity_min_length)
|
||||
validators.MinLengthValidator(limit)(value)
|
||||
|
||||
# Apply username restrictions
|
||||
if value in Config.system.restricted_usernames.split():
|
||||
raise forms.ValidationError(
|
||||
"This username is restricted to administrators only."
|
||||
)
|
||||
|
||||
# Validate it's all ascii characters
|
||||
for character in value:
|
||||
if character not in string.ascii_letters + string.digits + "_-":
|
||||
|
@ -167,6 +181,14 @@ class CreateIdentity(FormView):
|
|||
):
|
||||
raise forms.ValidationError(f"{username}@{domain} is already taken")
|
||||
|
||||
if not self.user.admin and (
|
||||
Identity.objects.filter(users=self.user).count()
|
||||
>= Config.system.identity_max_per_user
|
||||
):
|
||||
raise forms.ValidationError(
|
||||
f"You are not allowed more than {Config.system.identity_max_per_user} identities"
|
||||
)
|
||||
|
||||
def get_form(self):
|
||||
form_class = self.get_form_class()
|
||||
return form_class(user=self.request.user, **self.get_form_kwargs())
|
||||
|
|
Loading…
Reference in New Issue