1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
|
From: Chris Lamb <lamby@debian.org>
Date: Thu, 8 Aug 2019 10:30:35 +0100
Subject: CVE-2019-14232
Backported from
<https://github.com/django/django/commit/42a66e969023c00536256469f0e8b8a099ef109d>
---
django/utils/text.py | 4 ++--
.../filter_tests/test_truncatewords_html.py | 4 ++--
tests/utils_tests/test_text.py | 23 ++++++++++++++++++----
3 files changed, 23 insertions(+), 8 deletions(-)
diff --git a/django/utils/text.py b/django/utils/text.py
index 5e4dd3d..a69cf7a 100644
--- a/django/utils/text.py
+++ b/django/utils/text.py
@@ -24,8 +24,8 @@ def capfirst(x):
capfirst = keep_lazy_text(capfirst)
# Set up regular expressions
-re_words = re.compile(r'<.*?>|((?:\w[-\w]*|&.*?;)+)', re.U | re.S)
-re_chars = re.compile(r'<.*?>|(.)', re.U | re.S)
+re_words = re.compile(r'<[^>]+?>|([^<>\s]+)', re.S)
+re_chars = re.compile(r'<[^>]+?>|(.)', re.S)
re_tag = re.compile(r'<(/)?(\S+?)(?:(\s*/)|\s.*?)?>', re.S)
re_newlines = re.compile(r'\r\n|\r') # Used in normalize_newlines
re_camel_case = re.compile(r'(((?<=[a-z])[A-Z])|([A-Z](?![A-Z]|$)))')
diff --git a/tests/template_tests/filter_tests/test_truncatewords_html.py b/tests/template_tests/filter_tests/test_truncatewords_html.py
index aec2abf..3c73442 100644
--- a/tests/template_tests/filter_tests/test_truncatewords_html.py
+++ b/tests/template_tests/filter_tests/test_truncatewords_html.py
@@ -19,13 +19,13 @@ class FunctionTests(SimpleTestCase):
def test_truncate2(self):
self.assertEqual(
truncatewords_html('<p>one <a href="#">two - three <br>four</a> five</p>', 4),
- '<p>one <a href="#">two - three <br>four ...</a></p>',
+ '<p>one <a href="#">two - three ...</a></p>',
)
def test_truncate3(self):
self.assertEqual(
truncatewords_html('<p>one <a href="#">two - three <br>four</a> five</p>', 5),
- '<p>one <a href="#">two - three <br>four</a> five</p>',
+ '<p>one <a href="#">two - three <br>four ...</a></p>',
)
def test_truncate4(self):
diff --git a/tests/utils_tests/test_text.py b/tests/utils_tests/test_text.py
index 2e1bc70..7e56bbf 100644
--- a/tests/utils_tests/test_text.py
+++ b/tests/utils_tests/test_text.py
@@ -90,6 +90,16 @@ class TestUtilsText(SimpleTestCase):
# Ensure that lazy strings are handled correctly
self.assertEqual(text.Truncator(lazystr('The quick brown fox')).chars(12), 'The quick...')
+ def test_truncate_chars_html(self):
+ perf_test_values = [
+ (('</a' + '\t' * 50000) + '//>', None),
+ ('&' * 50000, '&' * 7 + '...'),
+ ('_X<<<<<<<<<<<>', None),
+ ]
+ for value, expected in perf_test_values:
+ truncator = text.Truncator(value)
+ self.assertEqual(expected if expected else value, truncator.chars(10, html=True))
+
def test_truncate_words(self):
truncator = text.Truncator('The quick brown fox jumped over the lazy dog.')
self.assertEqual('The quick brown fox jumped over the lazy dog.', truncator.words(10))
@@ -139,11 +149,16 @@ class TestUtilsText(SimpleTestCase):
truncator = text.Truncator('<i>Buenos días! ¿Cómo está?</i>')
self.assertEqual('<i>Buenos días! ¿Cómo...</i>', truncator.words(3, '...', html=True))
truncator = text.Truncator('<p>I <3 python, what about you?</p>')
- self.assertEqual('<p>I <3 python...</p>', truncator.words(3, '...', html=True))
+ self.assertEqual('<p>I <3 python,...</p>', truncator.words(3, '...', html=True))
- re_tag_catastrophic_test = ('</a' + '\t' * 50000) + '//>'
- truncator = text.Truncator(re_tag_catastrophic_test)
- self.assertEqual(re_tag_catastrophic_test, truncator.words(500, html=True))
+ perf_test_values = [
+ ('</a' + '\t' * 50000) + '//>',
+ '&' * 50000,
+ '_X<<<<<<<<<<<>',
+ ]
+ for value in perf_test_values:
+ truncator = text.Truncator(value)
+ self.assertEqual(value, truncator.words(50, html=True))
def test_wrap(self):
digits = '1234 67 9'
|