Revert "Revert "Apply all patches up to CVE-2023-36053""
This reverts commit 225f60a6a28626ffa36438447e57abefdb6b4eda.
This commit is contained in:
parent
225f60a6a2
commit
6de259abcf
@ -104,6 +104,8 @@ class URLValidator(RegexValidator):
|
|||||||
r'\Z', re.IGNORECASE)
|
r'\Z', re.IGNORECASE)
|
||||||
message = _('Enter a valid URL.')
|
message = _('Enter a valid URL.')
|
||||||
schemes = ['http', 'https', 'ftp', 'ftps']
|
schemes = ['http', 'https', 'ftp', 'ftps']
|
||||||
|
unsafe_chars = frozenset('\t\r\n')
|
||||||
|
max_length = 2048
|
||||||
|
|
||||||
def __init__(self, schemes=None, **kwargs):
|
def __init__(self, schemes=None, **kwargs):
|
||||||
super(URLValidator, self).__init__(**kwargs)
|
super(URLValidator, self).__init__(**kwargs)
|
||||||
@ -112,6 +114,10 @@ class URLValidator(RegexValidator):
|
|||||||
|
|
||||||
def __call__(self, value):
|
def __call__(self, value):
|
||||||
value = force_text(value)
|
value = force_text(value)
|
||||||
|
if not isinstance(value, str) or len(value) > self.max_length:
|
||||||
|
raise ValidationError(self.message, code=self.code, params={'value': value})
|
||||||
|
if self.unsafe_chars.intersection(value):
|
||||||
|
raise ValidationError(self.message, code=self.code)
|
||||||
# Check first if the scheme is valid
|
# Check first if the scheme is valid
|
||||||
scheme = value.split('://')[0].lower()
|
scheme = value.split('://')[0].lower()
|
||||||
if scheme not in self.schemes:
|
if scheme not in self.schemes:
|
||||||
@ -183,7 +189,9 @@ class EmailValidator(object):
|
|||||||
def __call__(self, value):
|
def __call__(self, value):
|
||||||
value = force_text(value)
|
value = force_text(value)
|
||||||
|
|
||||||
if not value or '@' not in value:
|
# The maximum length of an email is 320 characters per RFC 3696
|
||||||
|
# section 3.
|
||||||
|
if not value or '@' not in value or len(value) > 320:
|
||||||
raise ValidationError(self.message, code=self.code)
|
raise ValidationError(self.message, code=self.code)
|
||||||
|
|
||||||
user_part, domain_part = value.rsplit('@', 1)
|
user_part, domain_part = value.rsplit('@', 1)
|
||||||
|
@ -24,10 +24,12 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
|
|||||||
c.execute('PRAGMA foreign_keys')
|
c.execute('PRAGMA foreign_keys')
|
||||||
self._initial_pragma_fk = c.fetchone()[0]
|
self._initial_pragma_fk = c.fetchone()[0]
|
||||||
c.execute('PRAGMA foreign_keys = 0')
|
c.execute('PRAGMA foreign_keys = 0')
|
||||||
|
self.connection.cursor().execute('PRAGMA legacy_alter_table = ON')
|
||||||
return super(DatabaseSchemaEditor, self).__enter__()
|
return super(DatabaseSchemaEditor, self).__enter__()
|
||||||
|
|
||||||
def __exit__(self, exc_type, exc_value, traceback):
|
def __exit__(self, exc_type, exc_value, traceback):
|
||||||
super(DatabaseSchemaEditor, self).__exit__(exc_type, exc_value, traceback)
|
super(DatabaseSchemaEditor, self).__exit__(exc_type, exc_value, traceback)
|
||||||
|
self.connection.cursor().execute('PRAGMA legacy_alter_table = OFF')
|
||||||
with self.connection.cursor() as c:
|
with self.connection.cursor() as c:
|
||||||
# Restore initial FK setting - PRAGMA values can't be parametrized
|
# Restore initial FK setting - PRAGMA values can't be parametrized
|
||||||
c.execute('PRAGMA foreign_keys = %s' % int(self._initial_pragma_fk))
|
c.execute('PRAGMA foreign_keys = %s' % int(self._initial_pragma_fk))
|
||||||
|
@ -546,6 +546,12 @@ class EmailField(CharField):
|
|||||||
widget = EmailInput
|
widget = EmailInput
|
||||||
default_validators = [validators.validate_email]
|
default_validators = [validators.validate_email]
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
# The default maximum length of an email is 320 characters per RFC 3696
|
||||||
|
# section 3.
|
||||||
|
kwargs.setdefault("max_length", 320)
|
||||||
|
super(EmailField, self).__init__(*args, strip=True, **kwargs)
|
||||||
|
|
||||||
def clean(self, value):
|
def clean(self, value):
|
||||||
value = self.to_python(value).strip()
|
value = self.to_python(value).strip()
|
||||||
return super(EmailField, self).clean(value)
|
return super(EmailField, self).clean(value)
|
||||||
|
@ -805,7 +805,10 @@ class FieldsTests(SimpleTestCase):
|
|||||||
|
|
||||||
def test_emailfield_1(self):
|
def test_emailfield_1(self):
|
||||||
f = EmailField()
|
f = EmailField()
|
||||||
self.assertWidgetRendersTo(f, '<input type="email" name="f" id="id_f" />')
|
self.assertEqual(f.max_length, 320)
|
||||||
|
self.assertWidgetRendersTo(
|
||||||
|
f, '<input type="email" name="f" id="id_f" maxlength="320" required>'
|
||||||
|
)
|
||||||
self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, '')
|
self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, '')
|
||||||
self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, None)
|
self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, None)
|
||||||
self.assertEqual('person@example.com', f.clean('person@example.com'))
|
self.assertEqual('person@example.com', f.clean('person@example.com'))
|
||||||
|
@ -416,11 +416,17 @@ class FormsTestCase(SimpleTestCase):
|
|||||||
get_spam = BooleanField()
|
get_spam = BooleanField()
|
||||||
|
|
||||||
f = SignupForm(auto_id=False)
|
f = SignupForm(auto_id=False)
|
||||||
self.assertHTMLEqual(str(f['email']), '<input type="email" name="email" />')
|
self.assertHTMLEqual(
|
||||||
|
str(f["email"]),
|
||||||
|
'<input type="email" name="email" maxlength="320" required />',
|
||||||
|
)
|
||||||
self.assertHTMLEqual(str(f['get_spam']), '<input type="checkbox" name="get_spam" />')
|
self.assertHTMLEqual(str(f['get_spam']), '<input type="checkbox" name="get_spam" />')
|
||||||
|
|
||||||
f = SignupForm({'email': 'test@example.com', 'get_spam': True}, auto_id=False)
|
f = SignupForm({'email': 'test@example.com', 'get_spam': True}, auto_id=False)
|
||||||
self.assertHTMLEqual(str(f['email']), '<input type="email" name="email" value="test@example.com" />')
|
self.assertHTMLEqual(
|
||||||
|
str(f["email"]),
|
||||||
|
'<input type="email" name="email" maxlength="320" required />',
|
||||||
|
)
|
||||||
self.assertHTMLEqual(str(f['get_spam']), '<input checked="checked" type="checkbox" name="get_spam" />')
|
self.assertHTMLEqual(str(f['get_spam']), '<input checked="checked" type="checkbox" name="get_spam" />')
|
||||||
|
|
||||||
# 'True' or 'true' should be rendered without a value attribute
|
# 'True' or 'true' should be rendered without a value attribute
|
||||||
@ -2595,7 +2601,7 @@ Good luck picking a username that doesn't already exist.</p>
|
|||||||
<option value="2">Yes</option>
|
<option value="2">Yes</option>
|
||||||
<option value="3">No</option>
|
<option value="3">No</option>
|
||||||
</select></li>
|
</select></li>
|
||||||
<li><label for="id_email">Email:</label> <input type="email" name="email" id="id_email" /></li>
|
<li><label for="id_email">Email:</label> <input type="email" name="email" id="id_email" maxlength="320" /></li>
|
||||||
<li class="required error"><ul class="errorlist"><li>This field is required.</li></ul>
|
<li class="required error"><ul class="errorlist"><li>This field is required.</li></ul>
|
||||||
<label class="required" for="id_age">Age:</label> <input type="number" name="age" id="id_age" /></li>"""
|
<label class="required" for="id_age">Age:</label> <input type="number" name="age" id="id_age" /></li>"""
|
||||||
)
|
)
|
||||||
@ -2611,7 +2617,7 @@ Good luck picking a username that doesn't already exist.</p>
|
|||||||
<option value="2">Yes</option>
|
<option value="2">Yes</option>
|
||||||
<option value="3">No</option>
|
<option value="3">No</option>
|
||||||
</select></p>
|
</select></p>
|
||||||
<p><label for="id_email">Email:</label> <input type="email" name="email" id="id_email" /></p>
|
<p><label for="id_email">Email:</label> <input type="email" name="email" id="id_email" maxlength="320" /></p>
|
||||||
<ul class="errorlist"><li>This field is required.</li></ul>
|
<ul class="errorlist"><li>This field is required.</li></ul>
|
||||||
<p class="required error"><label class="required" for="id_age">Age:</label>
|
<p class="required error"><label class="required" for="id_age">Age:</label>
|
||||||
<input type="number" name="age" id="id_age" /></p>"""
|
<input type="number" name="age" id="id_age" /></p>"""
|
||||||
@ -2630,7 +2636,7 @@ Good luck picking a username that doesn't already exist.</p>
|
|||||||
<option value="3">No</option>
|
<option value="3">No</option>
|
||||||
</select></td></tr>
|
</select></td></tr>
|
||||||
<tr><th><label for="id_email">Email:</label></th><td>
|
<tr><th><label for="id_email">Email:</label></th><td>
|
||||||
<input type="email" name="email" id="id_email" /></td></tr>
|
<input type="email" name="email" id="id_email" maxlength="320" /></td></tr>
|
||||||
<tr class="required error"><th><label class="required" for="id_age">Age:</label></th>
|
<tr class="required error"><th><label class="required" for="id_age">Age:</label></th>
|
||||||
<td><ul class="errorlist"><li>This field is required.</li></ul>
|
<td><ul class="errorlist"><li>This field is required.</li></ul>
|
||||||
<input type="number" name="age" id="id_age" /></td></tr>"""
|
<input type="number" name="age" id="id_age" /></td></tr>"""
|
||||||
@ -3216,7 +3222,7 @@ Good luck picking a username that doesn't already exist.</p>
|
|||||||
f = CommentForm(data, auto_id=False, error_class=DivErrorList)
|
f = CommentForm(data, auto_id=False, error_class=DivErrorList)
|
||||||
self.assertHTMLEqual(f.as_p(), """<p>Name: <input type="text" name="name" maxlength="50" /></p>
|
self.assertHTMLEqual(f.as_p(), """<p>Name: <input type="text" name="name" maxlength="50" /></p>
|
||||||
<div class="errorlist"><div class="error">Enter a valid email address.</div></div>
|
<div class="errorlist"><div class="error">Enter a valid email address.</div></div>
|
||||||
<p>Email: <input type="email" name="email" value="invalid" /></p>
|
<p>Email: <input type="email" name="email" value="invalid" maxlength="320" required /></p>
|
||||||
<div class="errorlist"><div class="error">This field is required.</div></div>
|
<div class="errorlist"><div class="error">This field is required.</div></div>
|
||||||
<p>Comment: <input type="text" name="comment" /></p>""")
|
<p>Comment: <input type="text" name="comment" /></p>""")
|
||||||
|
|
||||||
|
@ -192,11 +192,13 @@ class RequestsTests(SimpleTestCase):
|
|||||||
"Cookie will expire when an distant expiration time is provided"
|
"Cookie will expire when an distant expiration time is provided"
|
||||||
response = HttpResponse()
|
response = HttpResponse()
|
||||||
response.set_cookie('datetime', expires=datetime(2028, 1, 1, 4, 5, 6))
|
response.set_cookie('datetime', expires=datetime(2028, 1, 1, 4, 5, 6))
|
||||||
|
response.set_cookie('datetime', expires=datetime(2038, 1, 1, 4, 5, 6))
|
||||||
datetime_cookie = response.cookies['datetime']
|
datetime_cookie = response.cookies['datetime']
|
||||||
self.assertIn(
|
self.assertIn(
|
||||||
datetime_cookie['expires'],
|
datetime_cookie['expires'],
|
||||||
# Slight time dependency; refs #23450
|
# Slight time dependency; refs #23450
|
||||||
('Sat, 01-Jan-2028 04:05:06 GMT', 'Sat, 01-Jan-2028 04:05:07 GMT')
|
('Sat, 01-Jan-2028 04:05:06 GMT', 'Sat, 01-Jan-2028 04:05:07 GMT')
|
||||||
|
('Fri, 01-Jan-2038 04:05:06 GMT', 'Fri, 01-Jan-2038 04:05:07 GMT')
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_max_age_expiration(self):
|
def test_max_age_expiration(self):
|
||||||
|
@ -54,6 +54,7 @@ TEST_DATA = [
|
|||||||
|
|
||||||
(validate_email, 'example@atm.%s' % ('a' * 64), ValidationError),
|
(validate_email, 'example@atm.%s' % ('a' * 64), ValidationError),
|
||||||
(validate_email, 'example@%s.atm.%s' % ('b' * 64, 'a' * 63), ValidationError),
|
(validate_email, 'example@%s.atm.%s' % ('b' * 64, 'a' * 63), ValidationError),
|
||||||
|
(validate_email, "example@%scom" % (("a" * 63 + ".") * 100), ValidationError),
|
||||||
(validate_email, None, ValidationError),
|
(validate_email, None, ValidationError),
|
||||||
(validate_email, '', ValidationError),
|
(validate_email, '', ValidationError),
|
||||||
(validate_email, 'abc', ValidationError),
|
(validate_email, 'abc', ValidationError),
|
||||||
@ -207,6 +208,11 @@ TEST_DATA = [
|
|||||||
(URLValidator(EXTENDED_SCHEMES), 'git://example.com/', None),
|
(URLValidator(EXTENDED_SCHEMES), 'git://example.com/', None),
|
||||||
|
|
||||||
(URLValidator(EXTENDED_SCHEMES), 'git://-invalid.com', ValidationError),
|
(URLValidator(EXTENDED_SCHEMES), 'git://-invalid.com', ValidationError),
|
||||||
|
(
|
||||||
|
URLValidator(),
|
||||||
|
"http://example." + ("a" * 63 + ".") * 1000 + "com",
|
||||||
|
ValidationError,
|
||||||
|
),
|
||||||
# Trailing newlines not accepted
|
# Trailing newlines not accepted
|
||||||
(URLValidator(), 'http://www.djangoproject.com/\n', ValidationError),
|
(URLValidator(), 'http://www.djangoproject.com/\n', ValidationError),
|
||||||
(URLValidator(), 'http://[::ffff:192.9.5.5]\n', ValidationError),
|
(URLValidator(), 'http://[::ffff:192.9.5.5]\n', ValidationError),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user