Disabling autoescape in a bulb

I want to show the user some text. the string variable I'm sending has several newline characters and I don't want to display \n . so i did:

 footext = """f o o""" #footext == "f\no\no" @app.route("/someurl") def foo(): return render_template("bar.html", text = footext.replace("\n", "<br />")) 

bar.html:

 <html> {{ text }} </html> 

However, autoescape is turned on, and I see f<br />o<br />o . Also my method is unsafe, I want every tag except <br /> be removed from the text. I looked at the flask. Markup module and, nevertheless, they do not work either.

What is the right way to do this?

+8
python flask
source share
3 answers

There are two reasonable approaches.

Solution 1

Since you combine unsafe input with HTML into a single flask.Markup variable, this is actually a pretty convenient way to do this. The basic idea is to split the text into newlines, make sure you select HTML from each line that you don’t trust, and then glue them together by adding the <br /> tags you trust.

Here's the full app to demonstrate this. It uses the same bar.html template as in your question. Please note that I added insecure HTML to footext as a demonstration of why disabling autoescaping is not a safe solution to your problem.

 import flask app = flask.Flask(__name__) footext = """f o <script>alert('oops')</script> o""" @app.route("/foo") def foo(): text = "" for line in footext.split('\n'): text += flask.Markup.escape(line) + flask.Markup('<br />') return flask.render_template("bar.html", text=text) if __name__ == "__main__": app.run(debug=True) 

Decision 2

Another option would be that you add complexity to your template, leaving you with a much simpler look. Just split the footext into lines, then you can footext over it in your template, and autoescaping will take care to keep it safe.

Simplified view:

 @app.route("/foo") def foo(): return flask.render_template("bar.html", text=footext.split('\n')) 

The bar.html template becomes:

 <html> {%- for line in text -%} {{ line }} {%- if not loop.last -%} <br /> {%- endif -%} {%- endfor -%} </html> 

Conclusion

I personally prefer solution 2 because it poses rendering problems (lines are separated by <br /> tags) in the template where they belong. If you ever want to change this in the future, say, show the lines in a bulleted list, you just need to change your template, not your code.

+7
source share

I will leave my previous answer as a bad example.

A very good solution for this kind is a custom filter that allows you to use syntax like

 {{ block_of_text | nl2br }} 

which you can conveniently use this nl2br filter nl2br (or easy to configure)!

+6
source share

Turn autoescaping off in the Jinja2 template or use the raw block .

0
source share

All Articles