diff --git a/filer/models/abstract.py b/filer/models/abstract.py index db3c16dd5..c9d1b20eb 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 as register_check 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,24 @@ # 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_check() +def max_pixel_setting_check(app_configs, **kwargs): + if not FILER_MAX_IMAGE_PIXELS: + return [ + Warning( + "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=settings, + ) + ] + return [] class BaseImage(File): @@ -130,7 +146,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: diff --git a/tests/test_admin.py b/tests/test_admin.py index 13e56ff66..2ba23b3df 100644 --- a/tests/test_admin.py +++ b/tests/test_admin.py @@ -565,6 +565,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')