فهرست منبع

fix(api): switch User.email to case-insensitive CIText field, fixes #417

Peter Thomassen 4 سال پیش
والد
کامیت
fdde128695
3فایلهای تغییر یافته به همراه36 افزوده شده و 3 حذف شده
  1. 21 0
      api/desecapi/migrations/0007_email_citext.py
  2. 2 3
      api/desecapi/models.py
  3. 13 0
      test/e2e2/spec/test_api_user_mgmt.py

+ 21 - 0
api/desecapi/migrations/0007_email_citext.py

@@ -0,0 +1,21 @@
+# Generated by Django 3.1 on 2020-09-29 14:28
+
+import django.contrib.postgres.fields.citext
+from django.contrib.postgres.operations import CITextExtension
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('desecapi', '0006_cname_exclusivity'),
+    ]
+
+    operations = [
+        CITextExtension(),
+        migrations.AlterField(
+            model_name='user',
+            name='email',
+            field=django.contrib.postgres.fields.citext.CIEmailField(max_length=254, unique=True, verbose_name='email address'),
+        ),
+    ]

+ 2 - 3
api/desecapi/models.py

@@ -19,7 +19,7 @@ from django.conf import settings
 from django.contrib.auth.hashers import make_password
 from django.contrib.auth.models import BaseUserManager, AbstractBaseUser
 from django.contrib.postgres.constraints import ExclusionConstraint
-from django.contrib.postgres.fields import RangeOperators
+from django.contrib.postgres.fields import CIEmailField, RangeOperators
 from django.core.exceptions import ValidationError
 from django.core.mail import EmailMessage, get_connection
 from django.core.validators import RegexValidator
@@ -85,9 +85,8 @@ class MyUserManager(BaseUserManager):
 
 class User(ExportModelOperationsMixin('User'), AbstractBaseUser):
     id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
-    email = models.EmailField(
+    email = CIEmailField(
         verbose_name='email address',
-        max_length=191,
         unique=True,
     )
     is_active = models.BooleanField(default=True)

+ 13 - 0
test/e2e2/spec/test_api_user_mgmt.py

@@ -30,3 +30,16 @@ def test_register2(api_user: DeSECAPIV1Client):
     assert user["email"] == email_name + '@' + domain_part.lower()
     assert api_user.headers['Authorization'].startswith('Token ')
     assert len(api_user.headers['Authorization']) > len('Token ') + 10
+
+
+def test_register_login_email_case_variation(api_user: DeSECAPIV1Client, api_anon: DeSECAPIV1Client):
+    # Invert email casing
+    email2 = ''.join(l.lower() if l.isupper() else l.upper() for l in api_user.email)
+    password2 = "foobar13"
+
+    # Try registering an account (should always return success, even if address with any casing is taken)
+    assert api_anon.register(email2, password2)[1].json() == {"detail": "Welcome!"}
+
+    # Verify that login is possible regardless of email spelling, but only with the first user's password
+    assert api_anon.login(email2, password2).status_code == 403
+    assert "token" in api_anon.login(email2, api_user.password).json()