From 981ae74e5cda458608d64a1aa3b62cb62a8fc4f6 Mon Sep 17 00:00:00 2001 From: rubenwardy Date: Wed, 22 Jan 2020 22:10:02 +0000 Subject: [PATCH] Improve markdown escaping Fixes #118 --- app/__init__.py | 6 ++- app/blueprints/users/profile.py | 4 +- app/markdown.py | 63 ++++++++++++++++++++++++++++++++ app/templates/packages/view.html | 2 +- app/templates/todo/topics.html | 2 +- requirements.txt | 4 +- 6 files changed, 74 insertions(+), 7 deletions(-) create mode 100644 app/markdown.py diff --git a/app/__init__.py b/app/__init__.py index 478f0d8..d064087 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -20,7 +20,6 @@ from flask_user import * from flask_gravatar import Gravatar import flask_menu as menu from flask_mail import Mail -from flaskext.markdown import Markdown from flask_github import GitHub from flask_wtf.csrf import CsrfProtect 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"]) menu.Menu(app=app) -markdown = Markdown(app, extensions=["fenced_code"], safe_mode=True, output_format="html5") github = GitHub(app) csrf = CsrfProtect(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) +from .markdown import init_app +init_app(app) + + @babel.localeselector def get_locale(): return request.accept_languages.best_match(app.config['LANGUAGES'].keys()) diff --git a/app/blueprints/users/profile.py b/app/blueprints/users/profile.py index 37ea992..0036fa9 100644 --- a/app/blueprints/users/profile.py +++ b/app/blueprints/users/profile.py @@ -18,7 +18,7 @@ from flask import * from flask_user import * from flask_login import login_user, logout_user -from app import markdown +from app.markdown import render_markdown from . import bp from app.models import * from flask_wtf import FlaskForm @@ -153,7 +153,7 @@ def send_email(username): form = SendEmailForm(request.form) if form.validate_on_submit(): text = form.text.data - html = markdown(text) + html = render_markdown(text) task = sendEmailRaw.delay([user.email], form.subject.data, text, html) return redirect(url_for("tasks.check", id=task.id, r=next_url)) diff --git a/app/markdown.py b/app/markdown.py new file mode 100644 index 0000000..370d3bb --- /dev/null +++ b/app/markdown.py @@ -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 +tags and the src, title and alt attributes for 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)) diff --git a/app/templates/packages/view.html b/app/templates/packages/view.html index 0a4b2bf..77b84da 100644 --- a/app/templates/packages/view.html +++ b/app/templates/packages/view.html @@ -364,7 +364,7 @@ -
+
{% if package.approved and package.checkPerm(current_user, "CREATE_THREAD") %}
diff --git a/app/templates/todo/topics.html b/app/templates/todo/topics.html index e51f4ec..87e142f 100644 --- a/app/templates/todo/topics.html +++ b/app/templates/todo/topics.html @@ -60,7 +60,7 @@ Topics to be Added {% set perc = 100 * (total - topic_count) / total %}
-
+
{% else %}

The forum topic crawler needs to run at least once for this section to work. diff --git a/requirements.txt b/requirements.txt index 9473f9f..104755b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,6 @@ Flask~=1.1 Flask-FlatPages~=0.7 Flask-Gravatar~=0.5 Flask-Login~=0.4.1 -Flask-Markdown~=0.3 Flask-Menu~=0.7 Flask-Migrate~=2.3 Flask-SQLAlchemy~=2.3 @@ -11,6 +10,9 @@ Flask-Babel GitHub-Flask~=3.2 SQLAlchemy-Searchable~=1.1 +markdown ~= 3.1 +bleach ~= 3.1 + beautifulsoup4~=4.6 celery~=4.4 kombu~=4.6