Merge branch 'miohtama-python_magic_validation'

This commit is contained in:
Johannes Wilm 2022-08-15 12:04:22 +02:00
commit 6f827c5312
6 changed files with 57 additions and 3 deletions

View file

@ -22,6 +22,7 @@ class AvatarConf(AppConf):
HASH_USERDIRNAMES = False
EXPOSE_USERNAMES = False
ALLOWED_FILE_EXTS = None
ALLOWED_MIMETYPES = None
CACHE_TIMEOUT = 60 * 60
STORAGE = settings.DEFAULT_FILE_STORAGE
CLEANUP_DELETED = True

View file

@ -29,6 +29,34 @@ class UploadAvatarForm(forms.Form):
def clean_avatar(self):
data = self.cleaned_data["avatar"]
if settings.AVATAR_ALLOWED_MIMETYPES:
try:
import magic
except ImportError:
raise ImportError(
"python-magic library must be installed in order to use uploaded file content limitation"
)
# Construct 256 bytes needed for mime validation
magic_buffer = bytes()
for chunk in data.chunks():
magic_buffer += chunk
if len(magic_buffer) >= 256:
break
# https://github.com/ahupp/python-magic#usage
mime = magic.from_buffer(magic_buffer, mime=True)
if mime not in settings.AVATAR_ALLOWED_MIMETYPES:
raise forms.ValidationError(
_(
"File content is invalid. Detected: %(mimetype)s Allowed content types are: %(valid_mime_list)s"
)
% {
"valid_mime_list": ", ".join(settings.AVATAR_ALLOWED_MIMETYPES),
"mimetype": mime,
}
)
if settings.AVATAR_ALLOWED_FILE_EXTS:
root, ext = os.path.splitext(data.name.lower())
if ext not in settings.AVATAR_ALLOWED_FILE_EXTS:

View file

@ -140,7 +140,7 @@ class Avatar(models.Model):
try:
orientation = image._getexif()[0x0112]
ops = EXIF_ORIENTATION_STEPS[orientation]
except TypeError:
except (AttributeError, TypeError):
ops = []
for method in ops:
image = image.transpose(getattr(Image, method))

BIN
tests/data/test.tiff Normal file

Binary file not shown.

View file

@ -1,2 +1,3 @@
coverage==6.2
django
python-magic

View file

@ -117,15 +117,39 @@ class AvatarTests(TestCase):
self.assertEqual(avatar.user, self.user)
self.assertTrue(avatar.primary)
# We allow the .tiff file extension but not the mime type
@override_settings(AVATAR_ALLOWED_FILE_EXTS=(".png", ".gif", ".jpg", ".tiff"))
@override_settings(
AVATAR_ALLOWED_MIMETYPES=("image/png", "image/gif", "image/jpeg")
)
def test_unsupported_image_format_upload(self):
"""Check with python-magic that we detect corrupted / unapprovd image files correctly"""
response = upload_helper(self, "test.tiff")
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.redirect_chain), 0) # Redirect only if it worked
self.assertNotEqual(response.context["upload_avatar_form"].errors, {})
# We allow the .tiff file extension and the mime type
@override_settings(AVATAR_ALLOWED_FILE_EXTS=(".png", ".gif", ".jpg", ".tiff"))
@override_settings(
AVATAR_ALLOWED_MIMETYPES=("image/png", "image/gif", "image/jpeg", "image/tiff")
)
def test_supported_image_format_upload(self):
"""Check with python-magic that we detect corrupted / unapprovd image files correctly"""
response = upload_helper(self, "test.tiff")
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.redirect_chain), 1) # Redirect only if it worked
self.assertEqual(response.context["upload_avatar_form"].errors, {})
@override_settings(AVATAR_ALLOWED_FILE_EXTS=(".jpg", ".png"))
def test_image_without_wrong_extension(self):
# use with AVATAR_ALLOWED_FILE_EXTS = ('.jpg', '.png')
response = upload_helper(self, "imagefilewithoutext")
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.redirect_chain), 0) # Redirect only if it worked
self.assertNotEqual(response.context["upload_avatar_form"].errors, {})
@override_settings(AVATAR_ALLOWED_FILE_EXTS=(".jpg", ".png"))
def test_image_with_wrong_extension(self):
# use with AVATAR_ALLOWED_FILE_EXTS = ('.jpg', '.png')
response = upload_helper(self, "imagefilewithwrongext.ogg")
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.redirect_chain), 0) # Redirect only if it worked