From 222d0633010e2f37f9fbd2d0559ecc4a5643c738 Mon Sep 17 00:00:00 2001 From: Tim Graham Date: Tue, 18 Aug 2015 10:09:17 -0400 Subject: [PATCH] Refs #23269 -- Removed the removetags template tag and related functions per deprecation timeline. --- django/template/defaultfilters.py | 9 +--- django/utils/html.py | 29 ----------- docs/ref/templates/builtins.txt | 38 -------------- docs/ref/utils.txt | 37 ++------------ docs/releases/1.5.txt | 2 +- .../filter_tests/test_removetags.py | 49 ------------------- tests/utils_tests/test_html.py | 32 +----------- 7 files changed, 7 insertions(+), 189 deletions(-) delete mode 100644 tests/template_tests/filter_tests/test_removetags.py diff --git a/django/template/defaultfilters.py b/django/template/defaultfilters.py index d2c77508fe..8319c66eee 100644 --- a/django/template/defaultfilters.py +++ b/django/template/defaultfilters.py @@ -13,7 +13,7 @@ from django.utils.dateformat import format, time_format from django.utils.encoding import force_text, iri_to_uri from django.utils.html import ( avoid_wrapping, conditional_escape, escape, escapejs, linebreaks, - remove_tags, strip_tags, urlize as _urlize, + strip_tags, urlize as _urlize, ) from django.utils.http import urlquote from django.utils.safestring import SafeData, mark_for_escaping, mark_safe @@ -500,13 +500,6 @@ def safeseq(value): return [mark_safe(force_text(obj)) for obj in value] -@register.filter(is_safe=True) -@stringfilter -def removetags(value, tags): - """Removes a space separated list of [X]HTML tags from the output.""" - return remove_tags(value, tags) - - @register.filter(is_safe=True) @stringfilter def striptags(value): diff --git a/django/utils/html.py b/django/utils/html.py index 9387e712dc..1d86441a28 100644 --- a/django/utils/html.py +++ b/django/utils/html.py @@ -3,10 +3,8 @@ from __future__ import unicode_literals import re -import warnings from django.utils import six -from django.utils.deprecation import RemovedInDjango110Warning from django.utils.encoding import force_str, force_text from django.utils.functional import allow_lazy from django.utils.http import RFC3986_GENDELIMS, RFC3986_SUBDELIMS @@ -184,39 +182,12 @@ def strip_tags(value): strip_tags = allow_lazy(strip_tags) -def remove_tags(html, tags): - """Returns the given HTML with given tags removed.""" - warnings.warn( - "django.utils.html.remove_tags() and the removetags template filter " - "are deprecated. Consider using the bleach library instead.", - RemovedInDjango110Warning, stacklevel=3 - ) - tags = [re.escape(tag) for tag in tags.split()] - tags_re = '(%s)' % '|'.join(tags) - starttag_re = re.compile(r'<%s(/?>|(\s+[^>]*>))' % tags_re, re.U) - endtag_re = re.compile('' % tags_re) - html = starttag_re.sub('', html) - html = endtag_re.sub('', html) - return html -remove_tags = allow_lazy(remove_tags, six.text_type) - - def strip_spaces_between_tags(value): """Returns the given HTML with spaces between tags removed.""" return re.sub(r'>\s+<', '><', force_text(value)) strip_spaces_between_tags = allow_lazy(strip_spaces_between_tags, six.text_type) -def strip_entities(value): - """Returns the given HTML with all entities (&something;) stripped.""" - warnings.warn( - "django.utils.html.strip_entities() is deprecated.", - RemovedInDjango110Warning, stacklevel=2 - ) - return re.sub(r'&(?:\w+|#\d+);', '', force_text(value)) -strip_entities = allow_lazy(strip_entities, six.text_type) - - def smart_urlquote(url): "Quotes a URL if it isn't already quoted." def unquote_quote(segment): diff --git a/docs/ref/templates/builtins.txt b/docs/ref/templates/builtins.txt index 9bf22e4740..1623ff357b 100644 --- a/docs/ref/templates/builtins.txt +++ b/docs/ref/templates/builtins.txt @@ -1866,44 +1866,6 @@ For example:: If ``value`` is the list ``['a', 'b', 'c', 'd']``, the output could be ``"b"``. -.. templatefilter:: removetags - -removetags -^^^^^^^^^^ - -.. deprecated:: 1.8 - - ``removetags`` cannot guarantee HTML safe output and has been deprecated due - to security concerns. Consider using `bleach`_ instead. - -.. _bleach: http://bleach.readthedocs.org/en/latest/ - -Removes a space-separated list of [X]HTML tags from the output. - -For example:: - - {{ value|removetags:"b span" }} - -If ``value`` is ``"Joel a slug"`` the -unescaped output will be ``"Joel a slug"``. - -Note that this filter is case-sensitive. - -If ``value`` is ``"Joel a slug"`` the -unescaped output will be ``"Joel a slug"``. - -.. admonition:: No safety guarantee - - Note that ``removetags`` doesn't give any guarantee about its output being - HTML safe. In particular, it doesn't work recursively, so an input like - ``"ript>alert('XSS')ript>"`` won't be safe even if - you apply ``|removetags:"script"``. So if the input is user provided, - **NEVER** apply the ``safe`` filter to a ``removetags`` output. If you are - looking for something more robust, you can use the ``bleach`` Python - library, notably its `clean`_ method. - -.. _clean: http://bleach.readthedocs.org/en/latest/clean.html - .. templatefilter:: rjust rjust diff --git a/docs/ref/utils.txt b/docs/ref/utils.txt index c24551b9ec..6843c8c9ce 100644 --- a/docs/ref/utils.txt +++ b/docs/ref/utils.txt @@ -621,6 +621,8 @@ escaping HTML. through :func:`conditional_escape` which (ultimately) calls :func:`~django.utils.encoding.force_text` on the values. + .. _str.format: https://docs.python.org/library/stdtypes.html#str.format + .. function:: format_html_join(sep, format_string, args_generator) A wrapper of :func:`format_html`, for the common case of a group of @@ -650,39 +652,8 @@ escaping HTML. If ``value`` is ``"Joel a slug"`` the return value will be ``"Joel is a slug"``. - If you are looking for a more robust solution, take a look at the `bleach`_ - Python library. - -.. function:: remove_tags(value, tags) - - .. deprecated:: 1.8 - - ``remove_tags()`` cannot guarantee HTML safe output and has been - deprecated due to security concerns. Consider using `bleach`_ instead. - - Removes a space-separated list of [X]HTML tag names from the output. - - Absolutely NO guarantee is provided about the resulting string being HTML - safe. In particular, it doesn't work recursively, so the output of - ``remove_tags("ript>alert('XSS')ript>", "script")`` - won't remove the "nested" script tags. So if the ``value`` is untrusted, - NEVER mark safe the result of a ``remove_tags()`` call without escaping it - first, for example with :func:`~django.utils.html.escape`. - - For example:: - - remove_tags(value, "b span") - - If ``value`` is ``"Joel a slug"`` - the return value will be ``"Joel a slug"``. - - Note that this filter is case-sensitive. - - If ``value`` is ``"Joel a slug"`` - the return value will be ``"Joel a slug"``. - -.. _str.format: https://docs.python.org/library/stdtypes.html#str.format -.. _bleach: https://pypi.python.org/pypi/bleach + If you are looking for a more robust solution, take a look at the `bleach + `_ Python library. .. function:: html_safe() diff --git a/docs/releases/1.5.txt b/docs/releases/1.5.txt index 6c861a5359..dc42ddbf66 100644 --- a/docs/releases/1.5.txt +++ b/docs/releases/1.5.txt @@ -671,7 +671,7 @@ Miscellaneous * The ``slugify`` template filter is now available as a standard python function at :func:`django.utils.text.slugify`. Similarly, ``remove_tags`` is - available at :func:`django.utils.html.remove_tags`. + available at ``django.utils.html.remove_tags()``. * Uploaded files are no longer created as executable by default. If you need them to be executable change :setting:`FILE_UPLOAD_PERMISSIONS` to your diff --git a/tests/template_tests/filter_tests/test_removetags.py b/tests/template_tests/filter_tests/test_removetags.py deleted file mode 100644 index 9cc6c5a4f9..0000000000 --- a/tests/template_tests/filter_tests/test_removetags.py +++ /dev/null @@ -1,49 +0,0 @@ -from django.template.defaultfilters import removetags -from django.test import SimpleTestCase, ignore_warnings -from django.utils.deprecation import RemovedInDjango110Warning -from django.utils.safestring import mark_safe - -from ..utils import setup - - -@ignore_warnings(category=RemovedInDjango110Warning) -class RemovetagsTests(SimpleTestCase): - - @setup({'removetags01': '{{ a|removetags:"a b" }} {{ b|removetags:"a b" }}'}) - def test_removetags01(self): - output = self.engine.render_to_string( - 'removetags01', - { - 'a': 'x

y

', - 'b': mark_safe('x

y

'), - }, - ) - self.assertEqual(output, 'x <p>y</p> x

y

') - - @setup({'removetags02': - '{% autoescape off %}{{ a|removetags:"a b" }} {{ b|removetags:"a b" }}{% endautoescape %}'}) - def test_removetags02(self): - output = self.engine.render_to_string( - 'removetags02', - { - 'a': 'x

y

', - 'b': mark_safe('x

y

'), - }, - ) - self.assertEqual(output, 'x

y

x

y

') - - -@ignore_warnings(category=RemovedInDjango110Warning) -class FunctionTests(SimpleTestCase): - - def test_removetags(self): - self.assertEqual( - removetags( - 'some html with disallowed tags', - 'script img', - ), - 'some html with alert("You smell") disallowed tags', - ) - - def test_non_string_input(self): - self.assertEqual(removetags(123, 'a'), '123') diff --git a/tests/utils_tests/test_html.py b/tests/utils_tests/test_html.py index 298aa304a3..ed026f0a28 100644 --- a/tests/utils_tests/test_html.py +++ b/tests/utils_tests/test_html.py @@ -4,10 +4,9 @@ from __future__ import unicode_literals import os from datetime import datetime -from django.test import SimpleTestCase, ignore_warnings +from django.test import SimpleTestCase from django.utils import html, safestring, six from django.utils._os import upath -from django.utils.deprecation import RemovedInDjango110Warning from django.utils.encoding import force_text @@ -123,25 +122,6 @@ class TestUtilsHtml(SimpleTestCase): for value, output in items: self.check_output(f, value, output) - @ignore_warnings(category=RemovedInDjango110Warning) - def test_strip_entities(self): - f = html.strip_entities - # Strings that should come out untouched. - values = ("&", "&a", "&a", "a&#a") - for value in values: - self.check_output(f, value) - # Valid entities that should be stripped from the patterns. - entities = ("", " ", "&a;", "&fdasdfasdfasdf;") - patterns = ( - ("asdf %(entity)s ", "asdf "), - ("%(entity)s%(entity)s", ""), - ("&%(entity)s%(entity)s", "&"), - ("%(entity)s3", "3"), - ) - for entity in entities: - for in_pattern, output in patterns: - self.check_output(f, in_pattern % {'entity': entity}, output) - def test_escapejs(self): f = html.escapejs items = ( @@ -160,16 +140,6 @@ class TestUtilsHtml(SimpleTestCase): for value, output in items: self.check_output(f, value, output) - @ignore_warnings(category=RemovedInDjango110Warning) - def test_remove_tags(self): - f = html.remove_tags - items = ( - ("Yes", "b i", "Yes"), - ("x

y

", "a b", "x

y

"), - ) - for value, tags, output in items: - self.assertEqual(f(value, tags), output) - def test_smart_urlquote(self): quote = html.smart_urlquote # Ensure that IDNs are properly quoted