From 5e7c6097d4446bd0941026d8764df4d09248388a Mon Sep 17 00:00:00 2001 From: Mattia Succurro Date: Mon, 14 Oct 2019 14:30:22 +0200 Subject: [PATCH] Changed enrich filter --- CHANGELOG.md | 1 + app.py | 40 +++++++++++++++++++++++++++++++++++++--- static/style.css | 1 + 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d30ccf5..a5fc7d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ * Removed `type` and `info` fields from `Message` table and merged `privacy` field, previously into a separate table, into that table. In order to make the app work, when upgrading you should run the `migrate_0_4_to_0_5.py` script. * Added flask-login dependency. Now, user logins can be persistent up to 365 days. +* Rewritten `enrich` filter, correcting a serious security flaw. The new filter uses a tokenizer and escapes all non-markup text. Plus, now the `+` of the mention is visible, but weakened; newlines are now visible in the message. ## 0.4.0 diff --git a/app.py b/app.py index 855254c..ffc2625 100644 --- a/app.py +++ b/app.py @@ -3,7 +3,7 @@ from flask import ( send_from_directory, session, url_for) import hashlib from peewee import * -import datetime, time, re, os, sys, string, json +import datetime, time, re, os, sys, string, json, html from functools import wraps import argparse from flask_login import LoginManager, login_user, logout_user, login_required @@ -566,10 +566,44 @@ def username_availability(username): is_available = False return jsonify({'is_valid':is_valid, 'is_available':is_available, 'status':'ok'}) +_enrich_symbols = [ + (r'\n', 'NEWLINE'), + (r'https?://(?:[A-Za-z0-9-]+(?:\.[A-Za-z0-9-]+)*|\[[A-Fa-f0-9:]+\])' + r'(?::\d+)?(?:/.*)?(?:\?.*)?(?:#.*)?', 'URL'), + (_mention_re, 'MENTION'), + (r'[^\n+]+', 'TEXT'), + (r'.', 'TEXT') +] + +def _tokenize(characters, table): + pos = 0 + tokens = [] + while pos < len(characters): + mo = None + for pattern, tag in table: + mo = re.compile(pattern).match(characters, pos) + if mo: + if tag: + text = mo.group(0) + tokens.append((text, tag)) + break + pos = mo.end(0) + return tokens + @app.template_filter() def enrich(s): - '''Filter for mentioning users.''' - return Markup(re.sub(_mention_re, r'\1', s)) + tokens = _tokenize(s, _enrich_symbols) + r = [] + for text, tag in tokens: + if tag == 'TEXT': + r.append(html.escape(text)) + elif tag == 'URL': + r.append('{0}'.format(html.escape(text))) + elif tag == 'MENTION': + r.append('+{1}'.format(text, text.lstrip('+'))) + elif tag == 'NEWLINE': + r.append('
') + return Markup(''.join(r)) @app.template_filter('is_following') def is_following(from_user, to_user): diff --git a/static/style.css b/static/style.css index ca2d8b8..5db922b 100644 --- a/static/style.css +++ b/static/style.css @@ -8,6 +8,7 @@ body{margin:0} .metanav{float:right} .header h1{margin:0;display:inline-block} .flash{background-color:#ff9;border:yellow 1px solid} +.weak{opacity:.5} .message-visual img{max-width:100%;max-height:8em} .create_text{width:100%;height:8em} .follow_button,input[type="submit"]{background-color:#ff3018;color:white;border-radius:3px;border:1px solid #ff3018}