From 1ac262e34eec564c12251523c1951ef6059d8ff5 Mon Sep 17 00:00:00 2001 From: Lauri Lubi Date: Tue, 5 Mar 2019 16:47:07 +0100 Subject: [PATCH] Bots that prefetch should not destroy the secret (#100) * Create preview view, remove sneaky-user-agents logic * unit tests * rename openSecret to viewSecret * code clean-up and style * rename view secret to reveal secret * update authors list * bump version to 1.5.0 --- .bumpversion.cfg | 3 ++- AUTHORS.rst | 1 + setup.cfg | 2 +- setup.py | 2 +- snappass/__init__.py | 2 +- snappass/main.py | 28 ++++++++++----------- snappass/static/snappass/scripts/preview.js | 10 ++++++++ snappass/templates/preview.html | 23 +++++++++++++++++ tests.py | 27 +++++--------------- 9 files changed, 59 insertions(+), 39 deletions(-) create mode 100644 snappass/static/snappass/scripts/preview.js create mode 100644 snappass/templates/preview.html diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 095cb45..560db08 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -2,4 +2,5 @@ files = setup.py commit = True tag = True -current_version = 0.1.0 +current_version = 1.5.0 + diff --git a/AUTHORS.rst b/AUTHORS.rst index de6caf6..ea0a431 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -19,3 +19,4 @@ Thanks a lot for the contributions of: * Donny Winston * James Barclay * Thomas Decaux +* Lauri Lubi diff --git a/setup.cfg b/setup.cfg index bb96d31..ca21be4 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 1.4.0 +current_version = 1.5.0 commit = True tag = True files = setup.py snappass/__init__.py diff --git a/setup.py b/setup.py index 28287be..1bd4f7f 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup setup( name='snappass', - version='1.4.1', + version='1.5.0', description="It's like SnapChat... for Passwords.", long_description=(open('README.rst').read() + '\n\n' + open('AUTHORS.rst').read()), diff --git a/snappass/__init__.py b/snappass/__init__.py index 8e3c933..77f1c8e 100644 --- a/snappass/__init__.py +++ b/snappass/__init__.py @@ -1 +1 @@ -__version__ = '1.4.1' +__version__ = '1.5.0' diff --git a/snappass/main.py b/snappass/main.py index 128ebd9..790b30b 100644 --- a/snappass/main.py +++ b/snappass/main.py @@ -11,10 +11,6 @@ from redis.exceptions import ConnectionError from werkzeug.urls import url_quote_plus from werkzeug.urls import url_unquote_plus - -SNEAKY_USER_AGENTS = ('Slackbot', 'facebookexternalhit', 'Twitterbot', - 'Facebot', 'WhatsApp', 'SkypeUriPreview', 'Iframely') -SNEAKY_USER_AGENTS_RE = re.compile('|'.join(SNEAKY_USER_AGENTS)) NO_SSL = os.environ.get('NO_SSL', False) TOKEN_SEPARATOR = '~' @@ -127,6 +123,11 @@ def get_password(token): return password.decode('utf-8') +@check_redis_alive +def password_exists(token): + storage_key, decryption_key = parse_token(token) + return redis_client.exists(storage_key) + def empty(value): if not value: return True @@ -150,14 +151,6 @@ def clean_input(): return TIME_CONVERSION[time_period], request.form['password'] -def request_is_valid(request): - """ - Ensure the request validates the following: - - not made by some specific User-Agents (to avoid chat's preview feature issue) - """ - return not SNEAKY_USER_AGENTS_RE.search(request.headers.get('User-Agent', '')) - - @app.route('/', methods=['GET']) def index(): return render_template('set_password.html') @@ -177,9 +170,16 @@ def handle_password(): @app.route('/', methods=['GET']) -def show_password(password_key): - if not request_is_valid(request): +def preview_password(password_key): + password_key = url_unquote_plus(password_key) + if not password_exists(password_key): abort(404) + + return render_template('preview.html') + + +@app.route('/', methods=['POST']) +def show_password(password_key): password_key = url_unquote_plus(password_key) password = get_password(password_key) if not password: diff --git a/snappass/static/snappass/scripts/preview.js b/snappass/static/snappass/scripts/preview.js new file mode 100644 index 0000000..f0ab063 --- /dev/null +++ b/snappass/static/snappass/scripts/preview.js @@ -0,0 +1,10 @@ +(function () { + + $('#revealSecret').click(function () { + var form = $('
') + .attr('id', 'revealSecretForm') + .attr('method', 'post'); + form.appendTo($('body')); + form.submit(); + }); +})(); \ No newline at end of file diff --git a/snappass/templates/preview.html b/snappass/templates/preview.html new file mode 100644 index 0000000..1e54277 --- /dev/null +++ b/snappass/templates/preview.html @@ -0,0 +1,23 @@ +{% extends "base.html" %} + +{% block content %} +
+
+ +

You can only reveal the secret once!

+
+
+ +
+
+
+
+{% endblock %} + +{% block js %} + + + +{% endblock %} \ No newline at end of file diff --git a/tests.py b/tests.py index a2be23d..b5cc99c 100644 --- a/tests.py +++ b/tests.py @@ -106,32 +106,17 @@ class SnapPassRoutesTestCase(TestCase): snappass.app.config['TESTING'] = True self.app = snappass.app.test_client() - def test_show_password(self): + def test_preview_password(self): password = "I like novelty kitten statues!" key = snappass.set_password(password, 30) rv = self.app.get('/{0}'.format(key)) - self.assertIn(password, rv.get_data(as_text=True)) + self.assertNotIn(password, rv.get_data(as_text=True)) - def test_bots_denial(self): - """ - Main known bots User-Agent should be denied access - """ - password = "Bots can't access this" + def test_show_password(self): + password = "I like novelty kitten statues!" key = snappass.set_password(password, 30) - a_few_sneaky_bots = [ - "Slackbot-LinkExpanding 1.0 (+https://api.slack.com/robots)", - "facebookexternalhit/1.1", - "Facebot/1.0", - "Twitterbot/1.0", - "_WhatsApp/2.12.81 (Windows NT 6.1; U; es-ES) Presto/2.9.181 Version/12.00", - "WhatsApp/2.16.6/i", - "SkypeUriPreview Preview/0.5", - "Iframely/0.8.5 (+http://iframely.com/;)", - ] - - for ua in a_few_sneaky_bots: - rv = self.app.get('/{0}'.format(key), headers={'User-Agent': ua}) - self.assertEqual(404, rv.status_code) + rv = self.app.post('/{0}'.format(key)) + self.assertIn(password, rv.get_data(as_text=True)) if __name__ == '__main__':