Skip to content

Commit 88148c3

Browse files
committed
Domains: more robust form
This form was even accepting spaces... Based on the regex from https://api.cloudflare.com/ (`pattern: ^([a-zA-Z0-9][\-a-zA-Z0-9]*\.)+[\-a-zA-Z0-9]{2,20}$`)
1 parent 046c4bd commit 88148c3

File tree

3 files changed

+29
-35
lines changed

3 files changed

+29
-35
lines changed

readthedocs/projects/forms.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -621,7 +621,7 @@ def clean_project(self):
621621
return self.project
622622

623623
def clean_domain(self):
624-
domain = self.cleaned_data['domain']
624+
domain = self.cleaned_data['domain'].lower()
625625
parsed = urlparse(domain)
626626

627627
# Force the scheme to have a valid netloc.

readthedocs/projects/validators.py

Lines changed: 3 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -12,39 +12,12 @@
1212
from django.utils.translation import ugettext_lazy as _
1313

1414

15-
domain_regex = (
16-
r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}(?<!-)\.?)|'
17-
r'localhost|' # localhost...
18-
r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|' # ...or ipv4
19-
r'\[?[A-F0-9]*:[A-F0-9:]+\]?)' # ...or ipv6
20-
)
21-
22-
2315
@deconstructible
2416
class DomainNameValidator(RegexValidator):
2517
message = _('Enter a valid plain or internationalized domain name value')
26-
regex = re.compile(domain_regex, re.IGNORECASE)
27-
28-
def __init__(self, accept_idna=True, **kwargs):
29-
message = kwargs.get('message')
30-
self.accept_idna = accept_idna
31-
super().__init__(**kwargs)
32-
if not self.accept_idna and message is None:
33-
self.message = _('Enter a valid domain name value')
34-
35-
def __call__(self, value):
36-
try:
37-
super().__call__(value)
38-
except ValidationError as exc:
39-
if not self.accept_idna:
40-
raise
41-
if not value:
42-
raise
43-
try:
44-
idnavalue = value.encode('idna')
45-
except UnicodeError:
46-
raise exc
47-
super().__call__(idnavalue)
18+
regex = re.compile(
19+
r'^([a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9-]{2,20}$'
20+
)
4821

4922

5023
validate_domain_name = DomainNameValidator()

readthedocs/rtd_tests/tests/test_domains.py

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,14 +105,35 @@ def test_domain_with_path(self):
105105
self.assertTrue(form.is_valid())
106106
domain = form.save()
107107
self.assertEqual(domain.domain, 'domain.com')
108+
109+
def test_valid_domains(self):
110+
domains = [
111+
'python.org',
112+
'a.io',
113+
'a.e.i.o.org',
114+
'my.domain.com.edu',
115+
'my-domain.fav',
116+
]
117+
for domain in domains:
118+
form = DomainForm(
119+
{'domain': domain},
120+
project=self.project,
121+
)
122+
self.assertTrue(form.is_valid(), domain)
108123

109124
def test_invalid_domains(self):
110-
invalid = [
125+
domains = [
111126
'python..org',
112-
# FIXME: '****.foo.com', current validator says this is valid :shrug:
113-
'invalid-.com'
127+
'****.foo.com',
128+
'domain',
129+
'domain.com.',
130+
'My domain.org',
131+
'i.o',
132+
'[special].com',
133+
'some_thing.org',
134+
'invalid-.com',
114135
]
115-
for domain in invalid:
136+
for domain in domains:
116137
form = DomainForm(
117138
{'domain': domain},
118139
project=self.project,

0 commit comments

Comments
 (0)