aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrubenwardy <rw@rubenwardy.com>2020-01-22 22:10:02 +0000
committerrubenwardy <rw@rubenwardy.com>2020-01-22 22:10:02 +0000
commit981ae74e5cda458608d64a1aa3b62cb62a8fc4f6 (patch)
tree5bc5286d7e9104c6e4caafb62263ba5c4403864d
parent2b661939699ce8e7c39569d33f2e9d42ef562a79 (diff)
downloadcheatdb-981ae74e5cda458608d64a1aa3b62cb62a8fc4f6.tar.xz
Improve markdown escaping
Fixes #118
-rw-r--r--app/__init__.py6
-rw-r--r--app/blueprints/users/profile.py4
-rw-r--r--app/markdown.py63
-rw-r--r--app/templates/packages/view.html2
-rw-r--r--app/templates/todo/topics.html2
-rw-r--r--requirements.txt4
6 files changed, 74 insertions, 7 deletions
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 <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))
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 @@
</ul>
</div>
- <div class="card my-4"">
+ <div class="card my-4">
<div class="card-header">
{% if package.approved and package.checkPerm(current_user, "CREATE_THREAD") %}
<div class="btn-group float-right">
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 %}
<div class="progress-bar bg-success" role="progressbar"
style="width: {{ perc }}%" aria-valuenow="{{ perc }}" aria-valuemin="0" aria-valuemax="100"></div>
- </div>
+ </div>
{% else %}
<p>
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