Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Allow Image.MAX_IMAGE_PIXELS to be None #1475

Merged
merged 16 commits into from
Aug 7, 2024
Merged
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
26 changes: 21 additions & 5 deletions filer/models/abstract.py
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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):
Expand Down Expand Up @@ -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:
Expand Down
27 changes: 27 additions & 0 deletions tests/test_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down
Loading