Improve markdown escaping

Fixes #118
This commit is contained in:
rubenwardy 2020-01-22 22:10:02 +00:00
parent 2b66193969
commit 981ae74e5c
6 changed files with 74 additions and 7 deletions

View File

@ -20,7 +20,6 @@ from flask_user import *
from flask_gravatar import Gravatar from flask_gravatar import Gravatar
import flask_menu as menu import flask_menu as menu
from flask_mail import Mail from flask_mail import Mail
from flaskext.markdown import Markdown
from flask_github import GitHub from flask_github import GitHub
from flask_wtf.csrf import CsrfProtect from flask_wtf.csrf import CsrfProtect
from flask_flatpages import FlatPages from flask_flatpages import FlatPages
@ -35,7 +34,6 @@ app.config.from_pyfile(os.environ["FLASK_CONFIG"])
r = redis.Redis.from_url(app.config["REDIS_URL"]) r = redis.Redis.from_url(app.config["REDIS_URL"])
menu.Menu(app=app) menu.Menu(app=app)
markdown = Markdown(app, extensions=["fenced_code"], safe_mode=True, output_format="html5")
github = GitHub(app) github = GitHub(app)
csrf = CsrfProtect(app) csrf = CsrfProtect(app)
mail = Mail(app) mail = Mail(app)
@ -59,6 +57,10 @@ if not app.debug and app.config["MAIL_UTILS_ERROR_SEND_TO"]:
register_mail_error_handler(app, mail) register_mail_error_handler(app, mail)
from .markdown import init_app
init_app(app)
@babel.localeselector @babel.localeselector
def get_locale(): def get_locale():
return request.accept_languages.best_match(app.config['LANGUAGES'].keys()) return request.accept_languages.best_match(app.config['LANGUAGES'].keys())

View File

@ -18,7 +18,7 @@
from flask import * from flask import *
from flask_user import * from flask_user import *
from flask_login import login_user, logout_user from flask_login import login_user, logout_user
from app import markdown from app.markdown import render_markdown
from . import bp from . import bp
from app.models import * from app.models import *
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
@ -153,7 +153,7 @@ def send_email(username):
form = SendEmailForm(request.form) form = SendEmailForm(request.form)
if form.validate_on_submit(): if form.validate_on_submit():
text = form.text.data text = form.text.data
html = markdown(text) html = render_markdown(text)
task = sendEmailRaw.delay([user.email], form.subject.data, text, html) task = sendEmailRaw.delay([user.email], form.subject.data, text, html)
return redirect(url_for("tasks.check", id=task.id, r=next_url)) return redirect(url_for("tasks.check", id=task.id, r=next_url))

63
app/markdown.py Normal file
View File

@ -0,0 +1,63 @@
import bleach
from markdown import Markdown
from flask import Markup
# Whitelist source: MIT
#
# https://github.com/Wenzil/mdx_bleach/blob/master/mdx_bleach/whitelist.py
"""
Default whitelist of allowed HTML tags. Any other HTML tags will be escaped or
stripped from the text. This applies to the html output that Markdown produces.
"""
ALLOWED_TAGS = [
'ul',
'ol',
'li',
'p',
'pre',
'code',
'blockquote',
'h1',
'h2',
'h3',
'h4',
'h5',
'h6',
'hr',
'br',
'strong',
'em',
'a',
'img'
]
"""
Default whitelist of attributes. It allows the href and title attributes for <a>
tags and the src, title and alt attributes for <img> tags. Any other attribute
will be stripped from its tag.
"""
ALLOWED_ATTRIBUTES = {
'a': ['href', 'title'],
'img': ['src', 'title', 'alt']
}
"""
If you allow tags that have attributes containing a URI value
(like the href attribute of an anchor tag,) you may want to adapt
the accepted protocols. The default list only allows http, https and mailto.
"""
ALLOWED_PROTOCOLS = ['http', 'https', 'mailto']
md = Markdown(extensions=["fenced_code"], output_format="html5")
def render_markdown(source):
return bleach.clean(md.convert(source), \
tags=ALLOWED_TAGS, attributes=ALLOWED_ATTRIBUTES, \
styles=[], protocols=ALLOWED_PROTOCOLS)
def init_app(app):
@app.template_filter()
def markdown(source):
return Markup(render_markdown(source))

View File

@ -364,7 +364,7 @@
</ul> </ul>
</div> </div>
<div class="card my-4""> <div class="card my-4">
<div class="card-header"> <div class="card-header">
{% if package.approved and package.checkPerm(current_user, "CREATE_THREAD") %} {% if package.approved and package.checkPerm(current_user, "CREATE_THREAD") %}
<div class="btn-group float-right"> <div class="btn-group float-right">

View File

@ -60,7 +60,7 @@ Topics to be Added
{% set perc = 100 * (total - topic_count) / total %} {% set perc = 100 * (total - topic_count) / total %}
<div class="progress-bar bg-success" role="progressbar" <div class="progress-bar bg-success" role="progressbar"
style="width: {{ perc }}%" aria-valuenow="{{ perc }}" aria-valuemin="0" aria-valuemax="100"></div> style="width: {{ perc }}%" aria-valuenow="{{ perc }}" aria-valuemin="0" aria-valuemax="100"></div>
</div> </div>
{% else %} {% else %}
<p> <p>
The forum topic crawler needs to run at least once for this section to work. The forum topic crawler needs to run at least once for this section to work.

View File

@ -2,7 +2,6 @@ Flask~=1.1
Flask-FlatPages~=0.7 Flask-FlatPages~=0.7
Flask-Gravatar~=0.5 Flask-Gravatar~=0.5
Flask-Login~=0.4.1 Flask-Login~=0.4.1
Flask-Markdown~=0.3
Flask-Menu~=0.7 Flask-Menu~=0.7
Flask-Migrate~=2.3 Flask-Migrate~=2.3
Flask-SQLAlchemy~=2.3 Flask-SQLAlchemy~=2.3
@ -11,6 +10,9 @@ Flask-Babel
GitHub-Flask~=3.2 GitHub-Flask~=3.2
SQLAlchemy-Searchable~=1.1 SQLAlchemy-Searchable~=1.1
markdown ~= 3.1
bleach ~= 3.1
beautifulsoup4~=4.6 beautifulsoup4~=4.6
celery~=4.4 celery~=4.4
kombu~=4.6 kombu~=4.6