Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 48 additions & 16 deletions model/pfp.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,34 @@
import base64
import os

from werkzeug.utils import secure_filename

from __init__ import app


def _safe_join_upload(user_id, user_pfp):
"""
Safely joins filepaths for user controlled pfp image paths.

Paramters:
- user_id (str): The unique identifier of the user.
- user_pfp (str): The filename of the user's profile picture

Returns:
- str: The absolute filepath to the image under the configured UPLOAD_FOLDER constant
"""
base = os.path.abspath(app.config["UPLOAD_FOLDER"])
sanitized = secure_filename(user_pfp)
if not sanitized:
return None
# It's fine to leave `user_id` unsanitized because this is already filtered
# by matching the username against GH
candidate = os.path.abspath(os.path.join(base, user_id, sanitized))
if not (candidate == base or candidate.startswith(base + os.sep)):
return None
return candidate


def pfp_base64_decode(user_id, user_pfp):
"""
Reads a user's profile picture from the server.
Expand All @@ -17,15 +43,19 @@ def pfp_base64_decode(user_id, user_pfp):
Returns:
- str: The base64 encoded image if the user has a profile picture; otherwise, None.
"""
img_path = os.path.join(app.config['UPLOAD_FOLDER'], user_id, user_pfp)
img_path = _safe_join_upload(user_id, user_pfp)
if not img_path:
print("Invalid profile picture path (attempt blocked)")
return None
try:
with open(img_path, 'rb') as img_file:
base64_encoded = base64.b64encode(img_file.read()).decode('utf-8')
with open(img_path, "rb") as img_file:
base64_encoded = base64.b64encode(img_file.read()).decode("utf-8")
return base64_encoded
except Exception as e:
print(f'An error occurred while reading the profile picture: {str(e)}')
print(f"An error occurred while reading the profile picture: {str(e)}")
return None


def pfp_base64_upload(base64_image, user_uid):
"""
Uploads a base64 encoded image as a profile picture for a user.
Expand All @@ -43,18 +73,19 @@ def pfp_base64_upload(base64_image, user_uid):
"""
try:
image_data = base64.b64decode(base64_image)
filename = secure_filename(f'{user_uid}.png')
user_dir = os.path.join(app.config['UPLOAD_FOLDER'], user_uid)
filename = secure_filename(f"{user_uid}.png")
user_dir = os.path.join(app.config["UPLOAD_FOLDER"], user_uid)
if not os.path.exists(user_dir):
os.makedirs(user_dir)
file_path = os.path.join(user_dir, filename)
with open(file_path, 'wb') as img_file:
with open(file_path, "wb") as img_file:
img_file.write(image_data)
return filename
return filename
except Exception as e:
print (f'An error occurred while updating the profile picture: {str(e)}')
print(f"An error occurred while updating the profile picture: {str(e)}")
return None



def pfp_file_delete(user_uid, filename):
"""
Deletes the profile picture file from the server.
Expand All @@ -69,13 +100,14 @@ def pfp_file_delete(user_uid, filename):
Returns:
- bool: True if the file was deleted successfully; otherwise, False.
"""
img_path = _safe_join_upload(user_uid, filename)
if not img_path:
print("Invalid profile picture path (attempt blocked)")
return False
try:
img_path = os.path.join(app.config['UPLOAD_FOLDER'], user_uid, filename)
if os.path.exists(img_path):
os.remove(img_path)
# Success is when the file does not exist after calling this function
return True
return True
except Exception as e:
print(f'An error occurred while deleting the profile picture: {str(e)}')
# Failure is when the file still existes, likely a permissions issue
return False
print(f"An error occurred while deleting the profile picture: {str(e)}")
return False
Loading