Skip to content
Snippets Groups Projects
Commit 55c4a05b authored by Eliot Berriot's avatar Eliot Berriot
Browse files

Merge branch '374-strip-exif' into 'develop'

Fix #374: Strip EXIF metadata from uploaded avatars to avoid leaking private data

Closes #374

See merge request !509
parents ddeb1a66 a7d77565
No related branches found
No related tags found
No related merge requests found
import collections
import io
import PIL
import os
from rest_framework import serializers
from django.core.exceptions import ObjectDoesNotExist
from django.core.files.uploadedfile import SimpleUploadedFile
from django.utils.encoding import smart_text
from django.utils.translation import ugettext_lazy as _
......@@ -190,3 +194,25 @@ def track_fields_for_update(*fields):
return serializer_class
return decorator
class StripExifImageField(serializers.ImageField):
def to_internal_value(self, data):
file_obj = super().to_internal_value(data)
image = PIL.Image.open(file_obj)
data = list(image.getdata())
image_without_exif = PIL.Image.new(image.mode, image.size)
image_without_exif.putdata(data)
with io.BytesIO() as output:
image_without_exif.save(
output,
format=PIL.Image.EXTENSION[os.path.splitext(file_obj.name)[-1]],
quality=100,
)
content = output.getvalue()
return SimpleUploadedFile(
file_obj.name, content, content_type=file_obj.content_type
)
......@@ -11,7 +11,7 @@ from rest_framework import serializers
from versatileimagefield.serializers import VersatileImageFieldSerializer
from funkwhale_api.activity import serializers as activity_serializers
from funkwhale_api.common import serializers as common_serializers
from . import models
......@@ -66,7 +66,13 @@ class UserActivitySerializer(activity_serializers.ModelSerializer):
return "Person"
avatar_field = VersatileImageFieldSerializer(allow_null=True, sizes="square")
class AvatarField(
common_serializers.StripExifImageField, VersatileImageFieldSerializer
):
pass
avatar_field = AvatarField(allow_null=True, sizes="square")
class UserBasicSerializer(serializers.ModelSerializer):
......
api/tests/common/exif.jpg

4.18 KiB

import os
import PIL
from django.core.files.uploadedfile import SimpleUploadedFile
import django_filters
from funkwhale_api.common import serializers
......@@ -163,3 +168,17 @@ def test_track_fields_for_update(mocker):
{"field1": "value1", "field2": "value2"},
{"field1": "newvalue1", "field2": "newvalue2"},
)
def test_strip_exif_field():
source_path = os.path.join(os.path.dirname(__file__), "exif.jpg")
source = PIL.Image.open(source_path)
assert bool(source._getexif())
with open(source_path, "rb") as f:
uploaded = SimpleUploadedFile("source.jpg", f.read(), content_type="image/jpeg")
field = serializers.StripExifImageField()
cleaned = PIL.Image.open(field.to_internal_value(uploaded))
assert cleaned._getexif() is None
Strip EXIF metadata from uploaded avatars to avoid leaking private data (#374)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment