From 1cb5fda44a9c853631d08b66f7d85a1ba9413b9b Mon Sep 17 00:00:00 2001
From: PGijsbers
Date: Sat, 23 Aug 2025 13:37:32 +0300
Subject: [PATCH 1/4] Limit profile image file types to webp, jp(e)g, and png
---
server/src/client/app/src/pages/auth/Profile.js | 2 +-
server/user/views.py | 8 ++++++++
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/server/src/client/app/src/pages/auth/Profile.js b/server/src/client/app/src/pages/auth/Profile.js
index 9d28c837..1832feeb 100755
--- a/server/src/client/app/src/pages/auth/Profile.js
+++ b/server/src/client/app/src/pages/auth/Profile.js
@@ -189,7 +189,7 @@ function Public() {
Date: Sat, 23 Aug 2025 16:16:46 +0300
Subject: [PATCH 2/4] Prevent profile paths from having potentially sensitive
information
---
server/user/views.py | 28 +++++++++++++++++++++-------
1 file changed, 21 insertions(+), 7 deletions(-)
diff --git a/server/user/views.py b/server/user/views.py
index 7f9c273a..a354149e 100644
--- a/server/user/views.py
+++ b/server/user/views.py
@@ -1,5 +1,6 @@
import os
import secrets
+import uuid
from distutils.util import strtobool
from http import HTTPStatus
from urllib.parse import parse_qs, urlparse
@@ -143,21 +144,34 @@ def image():
if "file" not in request.files:
return jsonify({"msg": "No image file supplied"}), HTTPStatus.BAD_REQUEST
file_name = request.files["file"].filename
- if '.' not in file_name or file_name.rsplit('.')[1].casefold() not in ALLOWED_IMAGE_EXTENSIONS:
+ if '.' not in file_name or (file_extension := file_name.rsplit('.')[1].casefold()) not in ALLOWED_IMAGE_EXTENSIONS:
return jsonify({"msg": "Images of this file type are not supported"}), HTTPStatus.UNSUPPORTED_MEDIA_TYPE
current_user = get_jwt_identity()
+ previous_image = None
with Session() as session:
user = session.query(User).filter_by(username=current_user).first()
+ previous_image = getattr(user, "image", None)
+
f = request.files["file"]
- Path("dev_data/" + str(user.username)).mkdir(parents=True, exist_ok=True)
- f.save(
- os.path.join("dev_data/" + str(user.username) + "/", secure_filename(f.filename))
- )
- path = "imgs/dev_data/" + str(user.username) + "/" + secure_filename(f.filename)
- user.update_image_address(path)
+
+ file_directory = Path("dev_data/" + str(user.id))
+ file_directory.mkdir(parents=True, exist_ok=True)
+
+ new_file_name = secure_filename(f.filename)
+ if not new_file_name:
+ new_file_name = uuid.uuid4().hex + file_extension
+
+ new_file_path = file_directory / new_file_name
+
+ f.save(new_file_path)
+ user.update_image_address(new_file_path)
session.merge(user)
session.commit()
+
+ if previous_image and Path(previous_image).exists():
+ Path(previous_image).unlink()
+
return jsonify({"msg": "User image changed"}), 200
From 8bc8b8ab0d9621948d46769031e6faaa8216fb01 Mon Sep 17 00:00:00 2001
From: PGijsbers
Date: Sat, 23 Aug 2025 16:19:45 +0300
Subject: [PATCH 3/4] Restrict to just jpg for now
---
server/src/client/app/src/pages/auth/Profile.js | 2 +-
server/user/views.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/server/src/client/app/src/pages/auth/Profile.js b/server/src/client/app/src/pages/auth/Profile.js
index 1832feeb..750e108c 100755
--- a/server/src/client/app/src/pages/auth/Profile.js
+++ b/server/src/client/app/src/pages/auth/Profile.js
@@ -189,7 +189,7 @@ function Public() {
Date: Tue, 26 Aug 2025 10:21:40 +0300
Subject: [PATCH 4/4] Only look at the last extension
---
server/user/views.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/server/user/views.py b/server/user/views.py
index e3bcb035..1c4417ed 100644
--- a/server/user/views.py
+++ b/server/user/views.py
@@ -144,7 +144,7 @@ def image():
if "file" not in request.files:
return jsonify({"msg": "No image file supplied"}), HTTPStatus.BAD_REQUEST
file_name = request.files["file"].filename
- if '.' not in file_name or (file_extension := file_name.rsplit('.')[1].casefold()) not in ALLOWED_IMAGE_EXTENSIONS:
+ if '.' not in file_name or (file_extension := file_name.rsplit('.', 1)[1].casefold()) not in ALLOWED_IMAGE_EXTENSIONS:
return jsonify({"msg": "Images of this file type are not supported"}), HTTPStatus.UNSUPPORTED_MEDIA_TYPE
current_user = get_jwt_identity()