Why does this Jinja nl2br filter slip away, but not <p>?

I am trying to implement this Jinja filter nl2br. It works correctly, except it is being added <br>. This is strange for me, because it is <p>not escaped, and they are all on the same line.

I use a flask, so Jinja is included autoescape. I really hoped when I found this guy , saying that autoescapethey escape(value)could cause double-escaping, but the removal escape()did not help.

Here is my modified code and its output:

@app.template_filter()
@evalcontextfilter
def nl2br(eval_ctx, value):
    _paragraph_re = re.compile(r'(?:\r\n|\r(?!\n)|\n){2,}')
    result = u'\n\n'.join(u'<p>%s</p>' % escape(p.replace(u'\r\n', u'<br>\n')) for p in _paragraph_re.split(value))
    if eval_ctx.autoescape:
        result = Markup(result)
    return result

:

u'1\r\n2\r\n\r\n3\r\n4\r\n\r\n5\r\n6\r\n7'

output:

<p>1&lt;br&gt;
2</p>

<p>3&lt;br&gt;
4</p>

<p>5&lt;br&gt;
6&lt;br&gt;
7</p>

desired result:

<p>1<br>2</p>

<p>3<br>4</p>

<p>5<br>6<br>7</p>

What can lead to escaping <br>but resolution <p>?

+5
source share
3

? ?

@app.template_filter()
@evalcontextfilter
def nl2br(eval_ctx, value):
   _paragraph_re = re.compile(r'(?:\r\n|\r(?!\n)|\n){2,}')
   result = u'\n\n'.join(u'<p>%s</p>' % p.replace(u'\r\n', u'<br/>') for p in _paragraph_re.split(value))
   if eval_ctx.autoescape:
       result = Markup(result)
   return result

, :

{{ '1\r\n2\r\n\r\n3\r\n4\r\n\r\n5\r\n6\r\n7' | nl2br}}

<p>1<br/>2</p>

<p>3<br/>4</p>

<p>5<br/>6<br/>7</p>
+5

nl2br Markup . value - , <br> . , <br> :

@app.template_filter()
@evalcontextfilter
def nl2br(eval_ctx, value):
    _paragraph_re = re.compile(r'(?:\r\n|\r(?!\n)|\n){2,}')
    result = u'\n\n'.join(u'<p>%s</p>' % p.replace(u'\n', Markup('<br>\n'))
                                         for p in _paragraph_re.split(value))
    if eval_ctx.autoescape:
        result = Markup(result)
    return result

. \n.

, :

Markup, Markup:

>>> Markup("hello there").split()
[Markup(u'hello'), Markup(u'there')]

Jinja :

- , , escape().

nl2br, , :

result = u'\n\n'.join(u'<p>%s</p>' % p.replace(u'\n', u'<br>\n')
                                     for p in _paragraph_re.split(value))

u'\n\n' u'<br>\n' unicode, p Markup value, Markup. p.replace Unicode Markup p, Markup .

<p> - , Python , % unicode, unicode . Markup , . result .

+5

2 , , , <br/>, XSS. :

';alert(String.fromCharCode(88,83,83))//';alert(String.fromCharCode(88,83,83))//";
alert(String.fromCharCode(88,83,83))//";alert(String.fromCharCode(88,83,83))//--
></SCRIPT>">'><SCRIPT>alert(String.fromCharCode(88,83,83))</SCRIPT>

The original nl2br jinja snippet from Dan Jacob is almost there:

import re

from jinja2 import evalcontextfilter, Markup, escape

_paragraph_re = re.compile(r'(?:\r\n|\r|\n){2,}')

app = Flask(__name__)

@app.template_filter()
@evalcontextfilter
def nl2br(eval_ctx, value):
    result = u'\n\n'.join(u'<p>%s</p>' % p.replace('\n', '<br>\n') \
        for p in _paragraph_re.split(escape(value)))
    if eval_ctx.autoescape:
        result = Markup(result)
    return result

Just combine this with @joemaller's answer about creating an object Markup('<br/>\n'). I.e:

result = u'\n\n'.join(u'<p>%s</p>' % p.replace('\n', Markup('<br/>\n')) \
    for p in _paragraph_re.split(escape(value)))
+4
source

All Articles