diff --git a/comment/templates/comment/comments/content.html b/comment/templates/comment/comments/content.html
index 44ad95e..6cbbab7 100644
--- a/comment/templates/comment/comments/content.html
+++ b/comment/templates/comment/comments/content.html
@@ -4,10 +4,10 @@
{% include "comment/comments/urlhash.html" with urlhash=urlhash %}
{% endblock comment_urlhash %}
{% if text_2 %}
- {{ text_1|safe }}
- {{ text_2|safe }}
+ {{ text_1 }}
+ {{ text_2 }}
{% else %}
- {{ text_1|safe }}
+ {{ text_1 }}
{% endif %}
diff --git a/comment/templatetags/comment_tags.py b/comment/templatetags/comment_tags.py
index f85f1f0..6e73fdb 100644
--- a/comment/templatetags/comment_tags.py
+++ b/comment/templatetags/comment_tags.py
@@ -1,6 +1,8 @@
import re
from django import template
+from django.utils.html import conditional_escape
+from django.utils.safestring import mark_safe
from comment.models import ReactionInstance, FlagInstance, Follower, BlockedUser
from comment.forms import CommentForm
@@ -88,15 +90,21 @@ def render_comments(obj, request, oauth=False):
register.inclusion_tag('comment/base.html')(render_comments)
+def _restrict_line_breaks(content):
+ # Restrict 2 or more line breaks to 2
+ content = MULTIPLE_NEW_LINE_RE.sub(r'\1
\3', content)
+ return SINGLE_NEW_LINE_RE.sub(r'\1
\3', content)
+
+
def render_content(comment, number=None):
try:
number = int(number)
except (ValueError, TypeError):
number = get_wrapped_words_number()
- # Restrict 2 or more line breaks to 2
- content = MULTIPLE_NEW_LINE_RE.sub(r'\1
\3', comment.content)
- content = SINGLE_NEW_LINE_RE.sub(r'\1
\3', content)
+ # this is necessary to avoid XSS attacks
+ escaped_content = conditional_escape(comment.content)
+ content = _restrict_line_breaks(escaped_content)
content_words = content.split()
if not number or len(content_words) <= number:
text_1 = content
@@ -106,8 +114,8 @@ def render_content(comment, number=None):
text_2 = ' '.join(content_words[number:])
return {
- 'text_1': text_1,
- 'text_2': text_2,
+ 'text_1': mark_safe(text_1),
+ 'text_2': mark_safe(text_2) if text_2 else None,
'urlhash': comment.urlhash
}
diff --git a/comment/tests/test_template_tags.py b/comment/tests/test_template_tags.py
index 9e32f40..ec0d184 100644
--- a/comment/tests/test_template_tags.py
+++ b/comment/tests/test_template_tags.py
@@ -158,13 +158,13 @@ def test_urlhash(self):
result = render_content(self.comment)
self.assertEqual(result['urlhash'], self.comment.urlhash)
- @patch.object(settings, 'COMMENT_WRAP_CONTENT_WORDS', 10)
- def test_content_wrapping(self):
+ @patch.object(settings, 'COMMENT_WRAP_CONTENT_WORDS', 20)
+ def test_content_wrapping_with_large_truncate_number(self):
content_words = self.comment.content.split()
- self.assertEqual(len(content_words), len(self.content.split()))
+ self.assertIs(len(content_words) < 20, True)
result = render_content(self.comment)
- # truncate number is bigger than self.contentwords
+
self.assertEqual(result['text_1'], self.comment.content)
self.assertIsNone(result['text_2'])
@@ -190,17 +190,17 @@ def test_multiple_line_breaks(self):
self.assertIn('
', result['text_1'])
self.assertNotIn('
', result['text_1'])
- def test_wrapping_after_certain_length(self):
+ @patch.object(settings, 'COMMENT_WRAP_CONTENT_WORDS', 5)
+ def test_content_wrapping_with_small_truncate_number(self):
self.comment.refresh_from_db()
content_words = self.comment.content.split()
self.assertEqual(len(content_words), len(self.content.split()))
- truncate_words_after = 5
- result = render_content(self.comment, truncate_words_after)
+ result = render_content(self.comment)
# truncate number is smaller than words in content
- self.assertEqual(result['text_1'], ' '.join(content_words[:truncate_words_after]))
- self.assertEqual(result['text_2'], ' '.join(content_words[truncate_words_after:]))
+ self.assertEqual(result['text_1'], ' '.join(content_words[:5]))
+ self.assertEqual(result['text_2'], ' '.join(content_words[5:]))
class GetUsernameForCommentTest(BaseTemplateTagsTest):