diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 3d6d268a0..d3e376bbb 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,7 +5,17 @@ CHANGELOG unreleased ========== +* feat: limit uploaded image area (width x height) to prevent decompression + bombs +* fix: Run validators on updated files in file change view +* fix: Update mime type if uploading file in file change view +* fix: Do not allow to remove the file field from an uplaoded file in + the admin interface +* fix: refactor upload checks into running validators in the admin + and adding clean methods for file and (abstract) image models. * fix: ensure uniqueness of icon admin url names +* fix: Crash with django-storage if filer file does not have a + storage file attached 3.0.6 (2023-09-08) ================== diff --git a/filer/admin/fileadmin.py b/filer/admin/fileadmin.py index b66332341..43895d7e3 100644 --- a/filer/admin/fileadmin.py +++ b/filer/admin/fileadmin.py @@ -9,6 +9,7 @@ from django.utils.safestring import mark_safe from django.utils.timezone import now from django.utils.translation import gettext as _ +from easy_thumbnails.engine import NoSourceGenerator from easy_thumbnails.exceptions import InvalidImageFormatError from easy_thumbnails.files import get_thumbnailer @@ -27,20 +28,25 @@ class Meta: model = File exclude = () + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + # self.fields["file"].widget = forms.FileInput() + def clean(self): from ..validation import validate_upload cleaned_data = super().clean() - - mime_type = mimetypes.guess_type(cleaned_data["file"].name)[0] or 'application/octet-stream' - file = cleaned_data["file"] - file.open("w+") # Allow for sanitizing upload - validate_upload( - file_name=cleaned_data["file"].name, - file=file.file, - owner=cleaned_data["owner"], - mime_type=mime_type, - ) - file.open("r") + if "file" in self.changed_data and cleaned_data["file"]: + mime_type = mimetypes.guess_type(cleaned_data["file"].name)[0] or 'application/octet-stream' + file = cleaned_data["file"] + file.open("w+") # Allow for sanitizing upload + file.seek(0) + validate_upload( + file_name=cleaned_data["file"].name, + file=file.file, + owner=cleaned_data["owner"], + mime_type=mime_type, + ) + file.open("r") return self.cleaned_data @@ -203,7 +209,7 @@ def icon_view(self, request, file_id: int, size: int) -> HttpResponse: # Touch thumbnail to allow it to be prefetched for directory listing EasyThumbnail.objects.filter(name=thumbnail.name).update(modified=now()) return HttpResponseRedirect(thumbnail.url) - except InvalidImageFormatError: + except (InvalidImageFormatError, NoSourceGenerator): return HttpResponseRedirect(staticfiles_storage.url('filer/icons/file-missing.svg')) diff --git a/filer/fields/multistorage_file.py b/filer/fields/multistorage_file.py index 715d98337..8ceb76a99 100644 --- a/filer/fields/multistorage_file.py +++ b/filer/fields/multistorage_file.py @@ -123,7 +123,7 @@ def exists(self): """ Returns ``True`` if underlying file exists in storage. """ - return self.storage.exists(self.name) + return self.name and self.storage.exists(self.name) class MultiStorageFileField(easy_thumbnails_fields.ThumbnailerField): diff --git a/filer/models/abstract.py b/filer/models/abstract.py index 57f9ccdc4..4dd3081e6 100644 --- a/filer/models/abstract.py +++ b/filer/models/abstract.py @@ -130,6 +130,8 @@ def clean(self): # the image gets attached to a folder and saved. We also # send the error msg in the JSON and also post the message # so that they know what is wrong with the image they uploaded + if not self.file: + return if self._width is None or self._height is None: pixels = 2 * FILER_MAX_IMAGE_PIXELS + 1 @@ -144,7 +146,7 @@ def clean(self): msg = _( "Image format not recognized or image size exceeds limit of %(max_pixels)d million " "pixels by a factor of two or more. Check file format or resize image to " - "%(width)d x %(height)d) resolution or lower." + "%(width)d x %(height)d resolution or lower." ) % dict(max_pixels=FILER_MAX_IMAGE_PIXELS // 1000000, width=res_x, height=res_y) raise ValidationError(str(msg), code="image_size")