From 6e88c253396c654b72fd61528fddeff5b7b118b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Enrique=20G=C3=B3mez=20G=C3=B3mez?= Date: Tue, 2 Aug 2022 07:29:12 +0000 Subject: [PATCH] Adds hash to URL and effects to new content. Avoids page refresh --- main.py | 69 ++++++++++++++++++++++++++-------------- static/loading.gif | Bin 0 -> 37037 bytes templates/template.html | 36 +++++++++++++++++---- 3 files changed, 74 insertions(+), 31 deletions(-) create mode 100644 static/loading.gif diff --git a/main.py b/main.py index bcde793..a9a2ee6 100755 --- a/main.py +++ b/main.py @@ -6,8 +6,10 @@ from datetime import datetime from flask import Flask, request, render_template from flask_uuid import FlaskUUID from flask_qrcode import QRcode -from flask_socketio import SocketIO +from flask_socketio import SocketIO, emit from werkzeug.middleware.proxy_fix import ProxyFix +import hashlib +import json # WIP: use sockets to broadcast when a hit to the expected uuid has been # received, so that connected clients (the Chromium public browser) can @@ -16,7 +18,8 @@ from werkzeug.middleware.proxy_fix import ProxyFix app = Flask(__name__) FlaskUUID(app) -QRcode(app) +#QRcode(app) +qrcode = QRcode(app) app.config['SECRET_KEY'] = '53a8373e7ae652cd38beba15454b1dc4' #app = ProxyFix(app, x_for=1, x_host=1) app.wsgi_app = ProxyFix(app.wsgi_app) @@ -27,23 +30,28 @@ def get_db_connection(): conn.row_factory = sqlite3.Row return conn +def hash_string(string): + salt = 'xpwQDFQ7gvcQ--rgO7l9yA' + return hashlib.md5(salt.encode() + string.encode()).hexdigest() + +def check_hash(string, hashed_string): + salt = 'xpwQDFQ7gvcQ--rgO7l9yA' + return hashed_string == hashlib.md5(salt.encode() + string.encode()).hexdigest() + +def generate_next_url(): + next_uuid = str(uuid.uuid1()) + url = request.url_root + str(next_uuid) + '/' + hash_string(next_uuid) + return url + @app.route('/') def show_qr_and_list(): # TODO: reject direct connections to server; allow access only via proxy - conn = get_db_connection() - data = conn.execute('SELECT * FROM hits ORDER BY id DESC LIMIT 10').fetchall() - conn.close() - # TODO: store next_uuid in a queue, and remove it once it's used. Accept only ids - # from the queue - next_uuid = uuid.uuid1() - return render_template("template.html", - next_uuid=str(next_uuid), - hits=data) + return render_template("template.html") -@app.route('/') -def catch_uuids(id): - ua = request.headers.get('Remote-User') +@app.route('//') +def catch_uuids(id, hashed): + user = request.headers.get('Remote-User') # TODO: Check directly with Authelia using https://auth.agofer.net/api/verify time = datetime.now().strftime("%A %Y-%m-%d %H:%M:%S") error = None @@ -51,31 +59,44 @@ def catch_uuids(id): conn = get_db_connection() existing = conn.execute( 'SELECT * FROM hits WHERE uuid = ?', (str(id),)).fetchone() - if not ua: + if not user: error = 'NO_USERNAME' - elif id.fields[5] != uuid.getnode(): - error = 'DIFFERENT_NODE' elif existing: error = 'ALREADY_USED' + elif not check_hash(str(id), str(hashed)): + error = 'DIFFERENT_NODE' else: - conn.execute("INSERT INTO hits (uuid, user) VALUES (?, ?)", (str(id), ua)) + conn.execute("INSERT INTO hits (uuid, user) VALUES (?, ?)", (str(id), user)) conn.commit() - socketio.emit('qr_used', {'data': (time, ua, str(id))}) + #socketio.emit('qr_used', {'data': (time, user, str(id))}) + url = generate_next_url() + qr = qrcode(url) + socketio.emit('qr_used', {'data': (qr, url, user, time)}) data = conn.execute( - 'SELECT * FROM hits WHERE user = ? ORDER BY id DESC LIMIT 10', (ua,) + 'SELECT * FROM hits WHERE user = ? ORDER BY id DESC LIMIT 10', (user,) ).fetchall() conn.close() - return render_template('thanks.html', user=ua, time=time, error=error, hits=data) + return render_template('thanks.html', user=user, time=time, error=error, hits=data) @socketio.on('message') def handle_message(data): print('received message: ' + data) -@socketio.on('my_event') -def handle_my_custom_event(json): - print('received json: ' + str(json)) +@socketio.on('connection') +def handle_initial_connection(json_data): + url = generate_next_url() + qr = qrcode(url) + conn = get_db_connection() + last_entries = conn.execute('SELECT user, created FROM hits ORDER BY id DESC LIMIT 10') + array_entries = [] + for entry in last_entries: + array_entries.append((entry[0], entry[1])) + conn.close() + emit('initial_qr', {'data': (qr, url, array_entries)}) + #socketio.emit('initial_qr', {'data': (qr,)}) + print('received json: ' + str(json_data)) if __name__ == '__main__': #app.run(host='0.0.0.0') diff --git a/static/loading.gif b/static/loading.gif new file mode 100644 index 0000000000000000000000000000000000000000..a84d1cac20ffb189d5d79f2222a4ca59e3e44f22 GIT binary patch literal 37037 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 CBd5&( literal 0 HcmV?d00001 diff --git a/templates/template.html b/templates/template.html index bed9666..30a968e 100644 --- a/templates/template.html +++ b/templates/template.html @@ -7,16 +7,32 @@ $(document).ready(function() { var socket = io(); socket.on('connect', function() { - socket.emit('my_event', {data: 'Connected to server'}); + socket.emit('connection', {data: 'Connected to server'}); }); - socket.on('qr_used', function(msg, cb) { - location.reload(true); - /* - $('#log').append('
  • ' + msg.data[0] + ': ' + msg.data[1] + ' (' + msg.data[2] + ')
  • '); - $('#qrcode').attr('src',src); + socket.on('initial_qr', function(msg, cb) { + $('#qrcode').prop('src', msg.data[0]); + $('#url').prop('href', msg.data[1]).text(msg.data[1]); + $('#log').empty(); + msg.data[2].forEach(function(item) { + $('#log').append('
  • ' + item[0] + ': ' + item[1] + '
  • '); + } + ); if (cb) cb(); + }); + socket.on('qr_used', function(msg, cb) { + /* + location.reload(true); */ + $('#qrcode').prop('src', msg.data[0]).fadeTo('fast', 0.05, function(){$(this).delay(100).fadeTo('slow', 1)}); + $('#url').prop('href', msg.data[1]).text(msg.data[1]); + //$('#log').fadeIn(500, function() { $(this).prepend('
  • ' + msg.data[2] + ': ' + msg.data[3] + '
  • ') }); + var new_entry = '
  • ' + msg.data[2] + ': ' + msg.data[3] + '
  • '; + $(new_entry).hide().prependTo('#log').fadeIn('slow'); + $('#log').fadeIn(500, function() { $(this).prepend() }); + $('#log li:gt(9)' ).remove(); + if (cb) + cb(); }); }); @@ -24,15 +40,21 @@

    QR Code:

    + {#

    For URL {{ request.url_root + next_uuid }}

    + #} +

    For URL __loading...__

    +

    Last 10 users:

    - +
      + {#
        {% for hit in hits %}
      • {{ hit['created'] }}, {{ hit['user'] }}
      • {% endfor %}
      + #}