From accd80c99e0eb01aeeb79b6b089a1551eaf0ece1 Mon Sep 17 00:00:00 2001 From: Fabian Braun Date: Fri, 7 Jul 2023 21:12:23 +0200 Subject: [PATCH 1/4] Fix #1377 --- filer/models/foldermodels.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/filer/models/foldermodels.py b/filer/models/foldermodels.py index a9c1e851e..54fa9c5a4 100644 --- a/filer/models/foldermodels.py +++ b/filer/models/foldermodels.py @@ -6,7 +6,7 @@ from django.urls import reverse from django.utils.functional import cached_property from django.utils.html import format_html, format_html_join -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from .. import settings as filer_settings from . import mixins From f3d6145935f319c98039b3f8aea0d8ff01dcc354 Mon Sep 17 00:00:00 2001 From: Fabian Braun Date: Wed, 22 May 2024 14:48:45 +0200 Subject: [PATCH 2/4] fix: `Image.MAX_IMAGE_SIZE = None` allowed. --- filer/models/abstract.py | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/filer/models/abstract.py b/filer/models/abstract.py index db3c16dd5..759e9d0fc 100644 --- a/filer/models/abstract.py +++ b/filer/models/abstract.py @@ -1,11 +1,13 @@ import logging from django.conf import settings +from django.core.checks import Warning, register from django.core.exceptions import ValidationError from django.db import models from django.utils.functional import cached_property from django.utils.translation import gettext_lazy as _ + import easy_thumbnails.utils from easy_thumbnails.VIL import Image as VILImage from PIL.Image import MAX_IMAGE_PIXELS @@ -24,10 +26,22 @@ # as if we allow it, it will fail while thumbnailing (first in the admin thumbnails # and then in the page itself. # Refer this https://github.com/python-pillow/Pillow/blob/b723e9e62e4706a85f7e44cb42b3d838dae5e546/src/PIL/Image.py#L3148 -FILER_MAX_IMAGE_PIXELS = min( - getattr(settings, "FILER_MAX_IMAGE_PIXELS", MAX_IMAGE_PIXELS), - MAX_IMAGE_PIXELS, -) +FILER_MAX_IMAGE_PIXELS = getattr(settings, "FILER_MAX_IMAGE_PIXELS", MAX_IMAGE_PIXELS) +if MAX_IMAGE_PIXELS is not None: + FILER_MAX_IMAGE_PIXELS = min(FILER_MAX_IMAGE_PIXELS, MAX_IMAGE_PIXELS) + + +@register() +def example_check(app_configs, **kwargs): + if not getattr(settings, "FILER_MAX_IMAGE_PIXELS", True): + return [ + Warning( + "FILER_MAX_IMAGE_PIXELS is set to 0 or None in your project settings.", + hint="Set FILER_MAX_IMAGE_PIXELS to a positive integer value", + obj=None, + ) + ] + return [] class BaseImage(File): @@ -130,7 +144,7 @@ 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: + if not self.file or not FILER_MAX_IMAGE_PIXELS: return if self._width is None or self._height is None: From 3090c046e6369a112cd90b97fd1b25b2967fa6d6 Mon Sep 17 00:00:00 2001 From: Fabian Braun Date: Wed, 22 May 2024 14:56:09 +0200 Subject: [PATCH 3/4] Improve warning message --- filer/models/abstract.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/filer/models/abstract.py b/filer/models/abstract.py index 759e9d0fc..281b4e41a 100644 --- a/filer/models/abstract.py +++ b/filer/models/abstract.py @@ -33,11 +33,13 @@ @register() def example_check(app_configs, **kwargs): - if not getattr(settings, "FILER_MAX_IMAGE_PIXELS", True): + if FILER_MAX_IMAGE_PIXELS: return [ Warning( - "FILER_MAX_IMAGE_PIXELS is set to 0 or None in your project settings.", - hint="Set FILER_MAX_IMAGE_PIXELS to a positive integer value", + "FILER_MAX_IMAGE_PIXELS and PIL.Image.MAX_IMAGE_PIXELS are not set.", + hint="Set FILER_MAX_IMAGE_PIXELS to a positive integer value. " + "This setting is used to limit the maximum number of pixels an image can have " + "to protect your site from memory bombs.", obj=None, ) ] From c92523fb38bf582f692d94c2c786d60301d2a0b1 Mon Sep 17 00:00:00 2001 From: Fabian Braun Date: Wed, 22 May 2024 16:34:01 +0200 Subject: [PATCH 4/4] Add test. --- filer/models/abstract.py | 14 +++++++------- tests/test_admin.py | 27 +++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/filer/models/abstract.py b/filer/models/abstract.py index 281b4e41a..c9d1b20eb 100644 --- a/filer/models/abstract.py +++ b/filer/models/abstract.py @@ -1,7 +1,7 @@ import logging from django.conf import settings -from django.core.checks import Warning, register +from django.core.checks import Warning, register as register_check from django.core.exceptions import ValidationError from django.db import models from django.utils.functional import cached_property @@ -31,16 +31,16 @@ FILER_MAX_IMAGE_PIXELS = min(FILER_MAX_IMAGE_PIXELS, MAX_IMAGE_PIXELS) -@register() -def example_check(app_configs, **kwargs): - if FILER_MAX_IMAGE_PIXELS: +@register_check() +def max_pixel_setting_check(app_configs, **kwargs): + if not FILER_MAX_IMAGE_PIXELS: return [ Warning( - "FILER_MAX_IMAGE_PIXELS and PIL.Image.MAX_IMAGE_PIXELS are not set.", - hint="Set FILER_MAX_IMAGE_PIXELS to a positive integer value. " + "Both settings.FILER_MAX_IMAGE_PIXELS and PIL.Image.MAX_IMAGE_PIXELS are not set.", + hint="Set FILER_MAX_IMAGE_PIXELS to a positive integer value in your settings.py. " "This setting is used to limit the maximum number of pixels an image can have " "to protect your site from memory bombs.", - obj=None, + obj=settings, ) ] return [] diff --git a/tests/test_admin.py b/tests/test_admin.py index 4aacad7c1..573e3b3e2 100644 --- a/tests/test_admin.py +++ b/tests/test_admin.py @@ -564,6 +564,33 @@ def test_filer_ajax_decompression_bomb(self): abstract.FILER_MAX_IMAGE_PIXELS = DEFAULT_MAX_IMAGE_PIXELS + def test_filer_max_pixel_deactivation(self): + from django.core.checks import Warning + + DEFAULT_MAX_IMAGE_PIXELS = abstract.FILER_MAX_IMAGE_PIXELS + abstract.FILER_MAX_IMAGE_PIXELS = None # Deactivate + + self.assertEqual(Image.objects.count(), 0) + folder = Folder.objects.create(name='foo') + with open(self.filename, 'rb') as fh: + file_obj = django.core.files.File(fh) + url = reverse( + 'admin:filer-ajax_upload', + kwargs={'folder_id': folder.pk} + ) + '?filename=%s' % self.image_name + self.client.post( + url, + data=file_obj.read(), + content_type='image/jpeg', + **{'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'} + ) + self.assertEqual(Image.objects.count(), 1) # Success + check_result = abstract.max_pixel_setting_check(None) + self.assertEqual(len(check_result), 1) + self.assertIsInstance(check_result[0], Warning) + + abstract.FILER_MAX_IMAGE_PIXELS = DEFAULT_MAX_IMAGE_PIXELS + def test_filer_ajax_upload_file_using_content_type(self): self.assertEqual(Image.objects.count(), 0) folder = Folder.objects.create(name='foo')