From 99b0b8b7db6325c64fc3a39701d9893e33fb3389 Mon Sep 17 00:00:00 2001 From: lelo Date: Sun, 23 Mar 2025 12:55:49 +0000 Subject: [PATCH] fix analytics --- analytics.py | 5 +--- app.py | 21 ++++++++++----- auth.py | 39 ++++++++++++++++++++++++++- requirements.txt | 1 + templates/overview.html | 60 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 114 insertions(+), 12 deletions(-) create mode 100644 templates/overview.html diff --git a/analytics.py b/analytics.py index b4c412d..8a3ac04 100644 --- a/analytics.py +++ b/analytics.py @@ -39,7 +39,7 @@ def shorten_referrer(url): segment_decoded = unquote(segment) return segment_decoded -def log_file_access(full_path): +def log_file_access(full_path, ip_address, user_agent, referrer): """ Log file access details to a SQLite database. Records the timestamp, full file path, client IP, user agent, and referrer. @@ -61,9 +61,6 @@ def log_file_access(full_path): ''') # Gather information from the request timestamp = datetime.now().isoformat() - ip_address = request.remote_addr - user_agent = request.headers.get('User-Agent') - referrer = request.headers.get('Referer') # Insert the access record into the database cursor.execute(''' diff --git a/app.py b/app.py index da5e3a7..da52ee1 100755 --- a/app.py +++ b/app.py @@ -17,7 +17,7 @@ from urllib.parse import urlparse, unquote from werkzeug.middleware.proxy_fix import ProxyFix -from auth import require_secret +import auth import analytics as a cache = diskcache.Cache('./filecache', size_limit= 48 * 1024**3) # 48 GB limit @@ -33,6 +33,7 @@ if os.environ.get('FLASK_ENV') == 'production': app.add_url_rule('/dashboard', view_func=a.dashboard) app.add_url_rule('/network', view_func=a.network) +app.add_url_rule('/overview', view_func=auth.overview) socketio = SocketIO(app, async_mode='eventlet') background_thread_running = False @@ -154,7 +155,7 @@ def serve_sw(): # API endpoint for AJAX: returns JSON for a given directory. @app.route('/api/path/', defaults={'subpath': ''}) @app.route('/api/path/') -@require_secret +@auth.require_secret def api_browse(subpath): if subpath == '': # root directory foldernames = [] @@ -184,7 +185,7 @@ def api_browse(subpath): }) @app.route("/media/") -@require_secret +@auth.require_secret def serve_file(subpath): root, *relative_parts = subpath.split('/') base_path = session['folders'][root] @@ -206,7 +207,13 @@ def serve_file(subpath): range_header = request.headers.get('Range') # only request with starting from the beginning of the file will be tracked if request.method != 'HEAD' and (not range_header or range_header.startswith("bytes=0-")): - threading.Thread(target=a.log_file_access, args=(full_path,)).start() + ip_address = request.remote_addr + user_agent = request.headers.get('User-Agent') + referrer = request.headers.get('Referer') + threading.Thread( + target=a.log_file_access, + args=(full_path, ip_address, user_agent, referrer) + ).start() # Check cache first (using diskcache) response = None @@ -246,7 +253,7 @@ def serve_file(subpath): @app.route("/transcript/") -@require_secret +@auth.require_secret def get_transcript(subpath): root, *relative_parts = subpath.split('/') @@ -261,7 +268,7 @@ def get_transcript(subpath): return content, 200, {'Content-Type': 'text/markdown; charset=utf-8'} @app.route("/crawl/") -@require_secret +@auth.require_secret def crawl_and_cache(subpath): """ Crawls through a directory and caches each file. @@ -376,7 +383,7 @@ def handle_request_initial_data(): # Catch-all route to serve the single-page application template. @app.route('/', defaults={'path': ''}) @app.route('/') -@require_secret +@auth.require_secret def index(path): return render_template("app.html") diff --git a/auth.py b/auth.py index 5157002..4dff268 100644 --- a/auth.py +++ b/auth.py @@ -1,7 +1,10 @@ from flask import Flask, render_template, request, session from functools import wraps from datetime import datetime, date, timedelta +import io import json +import qrcode +import base64 folder_config = {} @@ -73,4 +76,38 @@ def require_secret(f): else: return render_template('index.html') - return decorated_function \ No newline at end of file + return decorated_function + + +@require_secret +def overview(): + allowed_secrets = session.get('allowed_secrets', []) + host = request.host + + secret_qr_codes = {} + secret_folders = {} + + # Build a QR code for each secret (using the URL with the secret as query parameter) + for secret in allowed_secrets: + url = f"https://{host}?secret={secret}" + qr = qrcode.QRCode(version=1, box_size=10, border=4) + qr.add_data(url) + qr.make(fit=True) + img = qr.make_image(fill_color="black", back_color="white") + buffer = io.BytesIO() + img.save(buffer, format="PNG") + buffer.seek(0) + img_base64 = base64.b64encode(buffer.getvalue()).decode('ascii') + secret_qr_codes[secret] = img_base64 + + # Lookup folder info for this secret from the global folder_config. + config_item = next((c for c in folder_config if c['secret'] == secret), None) + if config_item: + secret_folders[secret] = config_item['folders'] + else: + secret_folders[secret] = [] + + return render_template('overview.html', + allowed_secrets=allowed_secrets, + secret_qr_codes=secret_qr_codes, + secret_folders=secret_folders) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index c1af722..4de8d00 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,7 @@ flask flask_socketio pillow +qrcode diskcache geoip2 gunicorn diff --git a/templates/overview.html b/templates/overview.html new file mode 100644 index 0000000..cacaa97 --- /dev/null +++ b/templates/overview.html @@ -0,0 +1,60 @@ + + + + + Übersicht gültiger Verbindungen + + + + + + +
+

Übersicht deiner gültigen Verbindungen

+ {% if allowed_secrets %} +
+ {% for secret in allowed_secrets %} +
+
+ QR Code for secret +
+
Geheimnis: {{ secret }}
+

+ + https://{{ request.host }}?secret={{ secret }} + +

+ {% if secret_folders[secret] %} +
Ordner
+
    + {% for folder in secret_folders[secret] %} +
  • + {{ folder.foldername }} +
  • + {% endfor %} +
+ {% else %} +

No folders available for this secret.

+ {% endif %} +
+
+
+ {% endfor %} +
+ {% else %} + + {% endif %} +
+ + + + +