aboutsummaryrefslogtreecommitdiffstats
path: root/src/app.py
diff options
context:
space:
mode:
authorkj_sh6042026-06-01 13:13:13 -0400
committerkj_sh6042026-06-01 13:13:13 -0400
commit6aea2bf6305e6d266f7ec7d54bd1966b050e7f79 (patch)
treebbe495406d5b949fcda9ccbb509812e2526b8040 /src/app.py
parenta9abb6d4e0c173e44e42cb6267133ef34c6d023c (diff)
refactor: revert back to image upload
just discovered that localStorage has limits
Diffstat (limited to 'src/app.py')
-rw-r--r--src/app.py49
1 files changed, 44 insertions, 5 deletions
diff --git a/src/app.py b/src/app.py
index e97b8e6..edd0f59 100644
--- a/src/app.py
+++ b/src/app.py
@@ -3,14 +3,29 @@
import base64
import hashlib
import os
+import re
+import secrets
import subprocess
import time
from pathlib import Path
from threading import Lock
+import magic
from flask import Flask, Response, jsonify, request, send_file, send_from_directory
app = Flask(__name__, static_folder=None)
+app.config["MAX_CONTENT_LENGTH"] = 25 * 1000 * 1000 # 25 MB upload cap
+
+UPLOAD_DIR = Path(__file__).parent / "uploads"
+UPLOAD_DIR.mkdir(mode=0o755, exist_ok=True)
+
+ALLOWED_MIME = {
+ "image/png": "png",
+ "image/jpeg": "jpg",
+ "image/gif": "gif",
+ "image/webp": "webp",
+ "image/bmp": "bmp",
+}
_CSP = (
"default-src 'self'; "
@@ -203,13 +218,37 @@ def nyan_png():
return send_from_directory(app.root_path, "nyan.png")
+@app.route("/uploads/<filename>")
+def uploads(filename: str):
+ if Path(filename).suffix.lower() == ".svg":
+ return Response("not found", status=404)
+ return send_from_directory(UPLOAD_DIR, filename)
+
+
@app.route("/upload", methods=["POST"])
def upload():
- return jsonify(
- {
- "error": "server-side uploads are disabled; images stay in browser local storage"
- }
- ), 410
+ if "image" not in request.files:
+ return jsonify({"error": "no file provided"}), 400
+
+ f = request.files["image"]
+ if not f.filename:
+ return jsonify({"error": "empty filename"}), 400
+
+ data = f.read()
+ if not data:
+ return jsonify({"error": "empty file"}), 400
+
+ mime = magic.from_buffer(data, mime=True)
+ if mime not in ALLOWED_MIME:
+ return jsonify({"error": f"invalid file type: {mime}"}), 400
+
+ ext = ALLOWED_MIME[mime]
+ basename = re.sub(r"[^a-zA-Z0-9_-]", "_", Path(f.filename).stem)[:64] or "image"
+ filename = f"{basename}_{secrets.token_hex(4)}.{ext}"
+
+ (UPLOAD_DIR / filename).write_bytes(data)
+
+ return jsonify({"filename": filename, "url": f"uploads/{filename}"})
@app.route("/fonts")