Skip to content

Commit 14f51a2

Browse files
authored
Merge pull request #525 from MerginMaps/validate_email_domain
Disallow non-ASCII in email domain
2 parents 16aeab3 + caed4df commit 14f51a2

2 files changed

Lines changed: 21 additions & 10 deletions

File tree

server/mergin/auth/forms.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Copyright (C) Lutra Consulting Limited
22
#
33
# SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-MerginMaps-Commercial
4+
45
import re
56
import safe
67
from flask_wtf import FlaskForm
@@ -48,18 +49,22 @@ class ExtendedEmail(Email):
4849
1. spaces,
4950
2. special characters ,:;()<>[]\"
5051
3, multiple @ symbols,
51-
4, leading, trailing, or consecutive dots in the local part
52-
5, invalid domain part - missing top level domain (user@example), consecutive dots
53-
Custom check for additional invalid characters disallows |'— because they make our email sending service to fail
52+
4, leading, trailing, or consecutive dots in the local part,
53+
5, invalid domain part - missing top level domain (user@example), consecutive dots,
54+
The extended validation checks email addresses using the regex provided by Brevo,
55+
so that we stay consistent with their validation rules and avoid API failures.
5456
"""
5557

5658
def __call__(self, form, field):
5759
super().__call__(form, field)
5860

59-
if re.search(r"[|'—]", field.data):
60-
raise ValidationError(
61-
f"Email address '{field.data}' contains an invalid character."
62-
)
61+
email = field.data.strip()
62+
63+
pattern = r"^[\x60#&*\/=?^{!}~'+\w-]+(\.[\x60#&*\/=?^{!}~'+\w-]+)*\.?@([_a-zA-Z0-9-]+(\.[_a-zA-Z0-9-]+)*\.)[a-zA-Z0-9-]*[a-zA-Z0-9]{2,}$"
64+
email_regexp = re.compile(pattern, re.IGNORECASE)
65+
66+
if not email_regexp.match(email):
67+
raise ValidationError(f"Email address '{email}' is invalid.")
6368

6469

6570
class PasswordValidator:

server/mergin/tests/test_auth.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,14 @@ def test_logout(client):
125125
400,
126126
), # tests with upper case, but email already exists
127127
(" mergin@mergin.com ", "#pwd123", 400), # invalid password
128-
("verylonglonglonglonglonglonglongemail@example.com", "#pwd1234", 201),
128+
(
129+
"verylonglonglonglonglonglonglongemail@lutra-consulting.co.uk",
130+
"#pwd1234",
131+
201,
132+
), # long local part, second-level domain, dash in domain
129133
("us.er@mergin.com", "#pwd1234", 201), # dot is allowed
130134
("us er@mergin.com", "#pwd1234", 400), # space is disallowed
135+
("test@gmaiñ.com", "#pwd1234", 400), # non-ASCII character in the domain
131136
]
132137

133138

@@ -936,15 +941,16 @@ def test_server_usage(client):
936941
("日人日本人", True), # non-ascii character
937942
("usér", True), # non-ascii character
938943
("user\\", False), # disallowed character
939-
("user\260", True), # non-ascii character (°)
944+
("user\260", False), # not letter character (°)
940945
("user|", False), # vertical bar
941946
("us er", False), # space in the middle
942947
("us,er", False), # comma
943948
("us—er", False), # dash
944-
("us'er", False), # apostrophe
949+
("us´er", False), # acute accent
945950
(" user", True), # starting with space (will be stripped)
946951
("us.er", True), # dot in the middle
947952
(".user", False), # starting with dot
953+
("us-er", True), # hyphen
948954
]
949955

950956

0 commit comments

Comments
 (0)