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()