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

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

parent ddeb1a66
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