From: Armin Ronacher Date: Fri, 30 Dec 2016 23:40:38 +0000 (+0100) Subject: Make noopener the default for urlize X-Git-Tag: 2.9~39 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=47b55f8843870aa17938c5c6315cc76e0697176a;p=thirdparty%2Fjinja.git Make noopener the default for urlize --- diff --git a/CHANGES b/CHANGES index 36b0817b..aac02eff 100644 --- a/CHANGES +++ b/CHANGES @@ -11,6 +11,8 @@ Version 2.9 - Corrected a long standing issue with operator precedence of math operations not being what was expected. - Added support for Python 3.6 async iterators through a new async mode. +- Added policies for filter defaults and similar things. +- urlize now sets "rel noopener" by default. Version 2.8.2 ------------- diff --git a/jinja2/defaults.py b/jinja2/defaults.py index 3717a722..bdb538d5 100644 --- a/jinja2/defaults.py +++ b/jinja2/defaults.py @@ -39,5 +39,12 @@ DEFAULT_NAMESPACE = { } +# default policies +DEFAULT_POLICIES = { + 'urlize.rel': 'noopener', + 'urlize.target': None, +} + + # export all constants __all__ = tuple(x for x in locals().keys() if x.isupper()) diff --git a/jinja2/environment.py b/jinja2/environment.py index 7aa9cef8..1aff8f54 100644 --- a/jinja2/environment.py +++ b/jinja2/environment.py @@ -18,7 +18,7 @@ from jinja2.defaults import BLOCK_START_STRING, \ COMMENT_START_STRING, COMMENT_END_STRING, LINE_STATEMENT_PREFIX, \ LINE_COMMENT_PREFIX, TRIM_BLOCKS, NEWLINE_SEQUENCE, \ DEFAULT_FILTERS, DEFAULT_TESTS, DEFAULT_NAMESPACE, \ - KEEP_TRAILING_NEWLINE, LSTRIP_BLOCKS + DEFAULT_POLICIES, KEEP_TRAILING_NEWLINE, LSTRIP_BLOCKS from jinja2.lexer import get_lexer, TokenStream from jinja2.parser import Parser from jinja2.nodes import EvalContext @@ -317,6 +317,9 @@ class Environment(object): self.bytecode_cache = bytecode_cache self.auto_reload = auto_reload + # configurable policies + self.policies = DEFAULT_POLICIES.copy() + # load extensions self.extensions = load_extensions(self, extensions) diff --git a/jinja2/filters.py b/jinja2/filters.py index 2d459732..c93c8ff0 100644 --- a/jinja2/filters.py +++ b/jinja2/filters.py @@ -409,7 +409,7 @@ def do_pprint(value, verbose=False): @evalcontextfilter def do_urlize(eval_ctx, value, trim_url_limit=None, nofollow=False, - target=None): + target=None, rel=None): """Converts URLs in plain text into clickable links. If you pass the filter an additional integer it will shorten the urls @@ -431,7 +431,15 @@ def do_urlize(eval_ctx, value, trim_url_limit=None, nofollow=False, .. versionchanged:: 2.8+ The *target* parameter was added. """ - rv = urlize(value, trim_url_limit, nofollow, target) + policies = eval_ctx.environment.policies + rel = set((rel or '').split() or []) + if nofollow: + rel.add('nofollow') + rel.update((policies['urlize.rel'] or '').split()) + if target is None: + target = policies['urlize.target'] + rel = ' '.join(sorted(rel)) or None + rv = urlize(value, trim_url_limit, rel=rel, target=target) if eval_ctx.autoescape: rv = Markup(rv) return rv diff --git a/jinja2/utils.py b/jinja2/utils.py index 12ae68c7..292dcf06 100644 --- a/jinja2/utils.py +++ b/jinja2/utils.py @@ -183,7 +183,7 @@ def pformat(obj, verbose=False): return pformat(obj) -def urlize(text, trim_url_limit=None, nofollow=False, target=None): +def urlize(text, trim_url_limit=None, rel=None, target=None): """Converts any URLs in text into clickable links. Works on http://, https:// and www. links. Links can have trailing punctuation (periods, commas, close-parens) and leading punctuation (opening parens) and @@ -201,11 +201,9 @@ def urlize(text, trim_url_limit=None, nofollow=False, target=None): and (x[:limit] + (len(x) >=limit and '...' or '')) or x words = _word_split_re.split(text_type(escape(text))) - nofollow_attr = nofollow and ' rel="nofollow"' or '' - if target is not None and isinstance(target, string_types): - target_attr = ' target="%s"' % escape(target) - else: - target_attr = '' + rel_attr = rel and ' rel="%s"' % text_type(escape(rel)) or '' + target_attr = target and ' target="%s"' % escape(target) or '' + for i, word in enumerate(words): match = _punctuation_re.match(word) if match: @@ -221,11 +219,11 @@ def urlize(text, trim_url_limit=None, nofollow=False, target=None): middle.endswith('.com') )): middle = '%s' % (middle, - nofollow_attr, target_attr, trim_url(middle)) + rel_attr, target_attr, trim_url(middle)) if middle.startswith('http://') or \ middle.startswith('https://'): middle = '%s' % (middle, - nofollow_attr, target_attr, trim_url(middle)) + rel_attr, target_attr, trim_url(middle)) if '@' in middle and not middle.startswith('www.') and \ not ':' in middle and _simple_email_re.match(middle): middle = '%s' % (middle, middle) diff --git a/tests/test_filters.py b/tests/test_filters.py index 59999ee4..f8a2f196 100644 --- a/tests/test_filters.py +++ b/tests/test_filters.py @@ -261,21 +261,28 @@ class TestFilter(object): def test_urlize(self, env): tmpl = env.from_string( '{{ "foo http://www.example.com/ bar"|urlize }}') - assert tmpl.render() == 'foo '\ - 'http://www.example.com/ bar' + assert tmpl.render() == ( + 'foo ' + 'http://www.example.com/ bar' + ) + + def test_urlize_rel_policy(self): + env = Environment() + env.policies['urlize.rel'] = None + tmpl = env.from_string( + '{{ "foo http://www.example.com/ bar"|urlize }}') + assert tmpl.render() == ( + 'foo ' + 'http://www.example.com/ bar' + ) def test_urlize_target_parameter(self, env): tmpl = env.from_string( '{{ "foo http://www.example.com/ bar"|urlize(target="_blank") }}' ) assert tmpl.render() \ - == 'foo '\ + == 'foo '\ 'http://www.example.com/ bar' - tmpl = env.from_string( - '{{ "foo http://www.example.com/ bar"|urlize(target=42) }}' - ) - assert tmpl.render() == 'foo '\ - 'http://www.example.com/ bar' def test_wordcount(self, env): tmpl = env.from_string('{{ "foo bar baz"|wordcount }}') diff --git a/tests/test_regression.py b/tests/test_regression.py index a4aa1571..7b18ef42 100644 --- a/tests/test_regression.py +++ b/tests/test_regression.py @@ -100,7 +100,7 @@ class TestBug(): def test_urlize_filter_escaping(self, env): tmpl = env.from_string('{{ "http://www.example.org/'\ + assert tmpl.render() == ''\ 'http://www.example.org/<foo' def test_loop_call_loop(self, env):