diff --git a/config.py b/config.py index c7a4484..edd1f07 100644 --- a/config.py +++ b/config.py @@ -302,9 +302,9 @@ DATA_UPLOAD_MAX_MEMORY_SIZE = 5 * 1024 * 1024 # 5MB FILE_UPLOAD_PERMISSIONS = 0o644 # Enhanced file upload security -ENABLE_FILE_SECURITY_VALIDATION = False # Temporarily disable for testing -ENABLE_EXIF_SANITIZATION = False -ENABLE_MALICIOUS_CONTENT_SCAN = False +ENABLE_FILE_SECURITY_VALIDATION = True +ENABLE_EXIF_SANITIZATION = True +ENABLE_MALICIOUS_CONTENT_SCAN = True # Logging configuration - can be overridden in local config # Example: LOGS_DIR = "/var/log/ivatar" # For production deployments diff --git a/ivatar/ivataraccount/forms.py b/ivatar/ivataraccount/forms.py index 22ae4eb..4ce2146 100644 --- a/ivatar/ivataraccount/forms.py +++ b/ivatar/ivataraccount/forms.py @@ -21,7 +21,7 @@ from .models import UserPreference import logging # Initialize logger -logger = logging.getLogger("ivatar.security") +logger = logging.getLogger("ivatar.ivataraccount.forms") MAX_NUM_UNCONFIRMED_EMAILS_DEFAULT = 5 @@ -125,7 +125,13 @@ class UploadPhotoForm(forms.Form): # Read file data try: - file_data = photo.read() + # Handle different file types + if hasattr(photo, 'read'): + file_data = photo.read() + elif hasattr(photo, 'file'): + file_data = photo.file.read() + else: + file_data = bytes(photo) filename = photo.name except Exception as e: logger.error(f"Error reading uploaded file: {e}") @@ -178,8 +184,7 @@ class UploadPhotoForm(forms.Form): return photo - @staticmethod - def save(request, data): + def save(self, request, data): """ Save the model and assign it to the current user with enhanced security """ @@ -189,17 +194,17 @@ class UploadPhotoForm(forms.Form): photo.ip_address = get_client_ip(request)[0] # Use sanitized data if available, otherwise use stored file data - if hasattr(data, "sanitized_data"): - photo.data = data.sanitized_data - logger.debug(f"Using sanitized data, size: {len(data.sanitized_data)}") - elif hasattr(data, "file_data"): - photo.data = data.file_data - logger.debug(f"Using stored file data, size: {len(data.file_data)}") + if hasattr(self, "sanitized_data"): + photo.data = self.sanitized_data + elif hasattr(self, "file_data"): + photo.data = self.file_data else: - photo.data = data.read() - logger.debug(f"Using data.read(), size: {len(photo.data)}") - - logger.debug(f"Photo data size before save: {len(photo.data)}") + # Fallback: try to read from the file object + try: + photo.data = data.read() + except Exception as e: + logger.error(f"Failed to read file data: {e}") + photo.data = b"" photo.save() return photo if photo.pk else None diff --git a/ivatar/ivataraccount/models.py b/ivatar/ivataraccount/models.py index dd32366..3af7c5f 100644 --- a/ivatar/ivataraccount/models.py +++ b/ivatar/ivataraccount/models.py @@ -193,14 +193,11 @@ class Photo(BaseAccountModel): Override save from parent, taking care about the image """ # Use PIL to read the file format - logger.debug(f"Photo.save(): data size: {len(self.data)}") try: img = Image.open(BytesIO(self.data)) - logger.debug(f"Photo.save(): PIL opened image, format: {img.format}") except Exception as exc: # pylint: disable=broad-except # For debugging only logger.error(f"Exception caught in Photo.save(): {exc}") - logger.debug(f"Photo.save(): First 20 bytes: {self.data[:20]}") return False self.format = file_format(img.format) if not self.format: diff --git a/ivatar/ivataraccount/test_views.py b/ivatar/ivataraccount/test_views.py index 45a4eb5..7c6e8e7 100644 --- a/ivatar/ivataraccount/test_views.py +++ b/ivatar/ivataraccount/test_views.py @@ -573,16 +573,25 @@ class Tester(TestCase): # pylint: disable=too-many-public-methods self.login() url = reverse("upload_photo") # rb => Read binary - with open(TEST_IMAGE_FILE, "rb") as photo: - response = self.client.post( - url, - { - "photo": photo, - "not_porn": True, - "can_distribute": True, - }, - follow=True, - ) + with open(TEST_IMAGE_FILE, "rb") as photo_file: + photo_data = photo_file.read() + + from django.core.files.uploadedfile import SimpleUploadedFile + uploaded_file = SimpleUploadedFile( + "deadbeef.png", + photo_data, + content_type="image/png" + ) + + response = self.client.post( + url, + { + "photo": uploaded_file, + "not_porn": True, + "can_distribute": True, + }, + follow=True, + ) if not test_only_one: return response self.assertEqual( diff --git a/ivatar/settings.py b/ivatar/settings.py index 20b9ad8..0cddeef 100644 --- a/ivatar/settings.py +++ b/ivatar/settings.py @@ -73,7 +73,7 @@ LOGGING = { "loggers": { "ivatar": { "handlers": ["file", "console"], - "level": "INFO", + "level": "INFO", # Restore normal logging level "propagate": True, }, "ivatar.security": {