Fixed #6160, #9111 -- Consistently apply conditional_escape to form errors and labels when outputing them as HTML.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@9365 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
04354e1afc
commit
bcd63cbfb0
|
@ -16,7 +16,7 @@ class PasswordResetTest(TestCase):
|
||||||
response = self.client.get('/password_reset/')
|
response = self.client.get('/password_reset/')
|
||||||
self.assertEquals(response.status_code, 200)
|
self.assertEquals(response.status_code, 200)
|
||||||
response = self.client.post('/password_reset/', {'email': 'not_a_real_email@email.com'})
|
response = self.client.post('/password_reset/', {'email': 'not_a_real_email@email.com'})
|
||||||
self.assertContains(response, "That e-mail address doesn't have an associated user account")
|
self.assertContains(response, "That e-mail address doesn't have an associated user account")
|
||||||
self.assertEquals(len(mail.outbox), 0)
|
self.assertEquals(len(mail.outbox), 0)
|
||||||
|
|
||||||
def test_email_found(self):
|
def test_email_found(self):
|
||||||
|
@ -87,7 +87,7 @@ class PasswordResetTest(TestCase):
|
||||||
response = self.client.post(path, {'new_password1': 'anewpassword',
|
response = self.client.post(path, {'new_password1': 'anewpassword',
|
||||||
'new_password2':' x'})
|
'new_password2':' x'})
|
||||||
self.assertEquals(response.status_code, 200)
|
self.assertEquals(response.status_code, 200)
|
||||||
self.assert_("The two password fields didn't match" in response.content)
|
self.assert_("The two password fields didn't match" in response.content)
|
||||||
|
|
||||||
|
|
||||||
class ChangePasswordTest(TestCase):
|
class ChangePasswordTest(TestCase):
|
||||||
|
@ -147,7 +147,7 @@ class ChangePasswordTest(TestCase):
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
self.assertEquals(response.status_code, 200)
|
self.assertEquals(response.status_code, 200)
|
||||||
self.assert_("The two password fields didn't match." in response.content)
|
self.assert_("The two password fields didn't match." in response.content)
|
||||||
|
|
||||||
def test_password_change_succeeds(self):
|
def test_password_change_succeeds(self):
|
||||||
self.login()
|
self.login()
|
||||||
|
|
|
@ -5,7 +5,7 @@ Form classes
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
|
|
||||||
from django.utils.datastructures import SortedDict
|
from django.utils.datastructures import SortedDict
|
||||||
from django.utils.html import escape
|
from django.utils.html import conditional_escape
|
||||||
from django.utils.encoding import StrAndUnicode, smart_unicode, force_unicode
|
from django.utils.encoding import StrAndUnicode, smart_unicode, force_unicode
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
|
|
||||||
|
@ -140,7 +140,7 @@ class BaseForm(StrAndUnicode):
|
||||||
output, hidden_fields = [], []
|
output, hidden_fields = [], []
|
||||||
for name, field in self.fields.items():
|
for name, field in self.fields.items():
|
||||||
bf = BoundField(self, field, name)
|
bf = BoundField(self, field, name)
|
||||||
bf_errors = self.error_class([escape(error) for error in bf.errors]) # Escape and cache in local variable.
|
bf_errors = self.error_class([conditional_escape(error) for error in bf.errors]) # Escape and cache in local variable.
|
||||||
if bf.is_hidden:
|
if bf.is_hidden:
|
||||||
if bf_errors:
|
if bf_errors:
|
||||||
top_errors.extend([u'(Hidden field %s) %s' % (name, force_unicode(e)) for e in bf_errors])
|
top_errors.extend([u'(Hidden field %s) %s' % (name, force_unicode(e)) for e in bf_errors])
|
||||||
|
@ -149,7 +149,7 @@ class BaseForm(StrAndUnicode):
|
||||||
if errors_on_separate_row and bf_errors:
|
if errors_on_separate_row and bf_errors:
|
||||||
output.append(error_row % force_unicode(bf_errors))
|
output.append(error_row % force_unicode(bf_errors))
|
||||||
if bf.label:
|
if bf.label:
|
||||||
label = escape(force_unicode(bf.label))
|
label = conditional_escape(force_unicode(bf.label))
|
||||||
# Only add the suffix if the label does not end in
|
# Only add the suffix if the label does not end in
|
||||||
# punctuation.
|
# punctuation.
|
||||||
if self.label_suffix:
|
if self.label_suffix:
|
||||||
|
@ -395,7 +395,7 @@ class BoundField(StrAndUnicode):
|
||||||
|
|
||||||
If attrs are given, they're used as HTML attributes on the <label> tag.
|
If attrs are given, they're used as HTML attributes on the <label> tag.
|
||||||
"""
|
"""
|
||||||
contents = contents or escape(self.label)
|
contents = contents or conditional_escape(self.label)
|
||||||
widget = self.field.widget
|
widget = self.field.widget
|
||||||
id_ = widget.attrs.get('id') or self.auto_id
|
id_ = widget.attrs.get('id') or self.auto_id
|
||||||
if id_:
|
if id_:
|
||||||
|
|
|
@ -39,7 +39,7 @@ class ErrorList(list, StrAndUnicode):
|
||||||
def as_ul(self):
|
def as_ul(self):
|
||||||
if not self: return u''
|
if not self: return u''
|
||||||
return mark_safe(u'<ul class="errorlist">%s</ul>'
|
return mark_safe(u'<ul class="errorlist">%s</ul>'
|
||||||
% ''.join([u'<li>%s</li>' % force_unicode(e) for e in self]))
|
% ''.join([u'<li>%s</li>' % conditional_escape(force_unicode(e)) for e in self]))
|
||||||
|
|
||||||
def as_text(self):
|
def as_text(self):
|
||||||
if not self: return u''
|
if not self: return u''
|
||||||
|
|
|
@ -593,17 +593,25 @@ u'Yesterday'
|
||||||
u'Yesterday'
|
u'Yesterday'
|
||||||
|
|
||||||
Validation errors are HTML-escaped when output as HTML.
|
Validation errors are HTML-escaped when output as HTML.
|
||||||
|
>>> from django.utils.safestring import mark_safe
|
||||||
>>> class EscapingForm(Form):
|
>>> class EscapingForm(Form):
|
||||||
... special_name = CharField()
|
... special_name = CharField(label="<em>Special</em> Field")
|
||||||
|
... special_safe_name = CharField(label=mark_safe("<em>Special</em> Field"))
|
||||||
... def clean_special_name(self):
|
... def clean_special_name(self):
|
||||||
... raise ValidationError("Something's wrong with '%s'" % self.cleaned_data['special_name'])
|
... raise ValidationError("Something's wrong with '%s'" % self.cleaned_data['special_name'])
|
||||||
|
... def clean_special_safe_name(self):
|
||||||
|
... raise ValidationError(mark_safe("'<b>%s</b>' is a safe string" % self.cleaned_data['special_safe_name']))
|
||||||
|
|
||||||
>>> f = EscapingForm({'special_name': "Nothing to escape"}, auto_id=False)
|
>>> f = EscapingForm({'special_name': "Nothing to escape", 'special_safe_name': "Nothing to escape"}, auto_id=False)
|
||||||
>>> print f
|
>>> print f
|
||||||
<tr><th>Special name:</th><td><ul class="errorlist"><li>Something's wrong with 'Nothing to escape'</li></ul><input type="text" name="special_name" value="Nothing to escape" /></td></tr>
|
<tr><th><em>Special</em> Field:</th><td><ul class="errorlist"><li>Something's wrong with 'Nothing to escape'</li></ul><input type="text" name="special_name" value="Nothing to escape" /></td></tr>
|
||||||
>>> f = EscapingForm({'special_name': "Should escape < & > and <script>alert('xss')</script>"}, auto_id=False)
|
<tr><th><em>Special</em> Field:</th><td><ul class="errorlist"><li>'<b>Nothing to escape</b>' is a safe string</li></ul><input type="text" name="special_safe_name" value="Nothing to escape" /></td></tr>
|
||||||
|
>>> f = EscapingForm(
|
||||||
|
... {'special_name': "Should escape < & > and <script>alert('xss')</script>",
|
||||||
|
... 'special_safe_name': "<i>Do not escape</i>"}, auto_id=False)
|
||||||
>>> print f
|
>>> print f
|
||||||
<tr><th>Special name:</th><td><ul class="errorlist"><li>Something's wrong with 'Should escape < & > and <script>alert('xss')</script>'</li></ul><input type="text" name="special_name" value="Should escape < & > and <script>alert('xss')</script>" /></td></tr>
|
<tr><th><em>Special</em> Field:</th><td><ul class="errorlist"><li>Something's wrong with 'Should escape < & > and <script>alert('xss')</script>'</li></ul><input type="text" name="special_name" value="Should escape < & > and <script>alert('xss')</script>" /></td></tr>
|
||||||
|
<tr><th><em>Special</em> Field:</th><td><ul class="errorlist"><li>'<b><i>Do not escape</i></b>' is a safe string</li></ul><input type="text" name="special_safe_name" value="<i>Do not escape</i>" /></td></tr>
|
||||||
|
|
||||||
""" + \
|
""" + \
|
||||||
r""" # [This concatenation is to keep the string below the jython's 32K limit].
|
r""" # [This concatenation is to keep the string below the jython's 32K limit].
|
||||||
|
|
|
@ -49,4 +49,11 @@ u''
|
||||||
# Can take a non-string.
|
# Can take a non-string.
|
||||||
>>> print ValidationError(VeryBadError()).messages
|
>>> print ValidationError(VeryBadError()).messages
|
||||||
<ul class="errorlist"><li>A very bad error.</li></ul>
|
<ul class="errorlist"><li>A very bad error.</li></ul>
|
||||||
|
|
||||||
|
# Escapes non-safe input but not input marked safe.
|
||||||
|
>>> example = 'Example of link: <a href="http://www.example.com/">example</a>'
|
||||||
|
>>> print ValidationError(example).messages
|
||||||
|
<ul class="errorlist"><li>Example of link: <a href="http://www.example.com/">example</a></li></ul>
|
||||||
|
>>> print ValidationError(mark_safe(example)).messages
|
||||||
|
<ul class="errorlist"><li>Example of link: <a href="http://www.example.com/">example</a></li></ul>
|
||||||
"""
|
"""
|
||||||
|
|
Loading…
Reference in New Issue