mirror of
https://github.com/bookwyrm-social/bookwyrm.git
synced 2025-04-15 14:54:06 +00:00
Updated locations that process a cover file upload to strip EXIF data with a utility function
This commit is contained in:
parent
12f94a8821
commit
7a50943ea5
5 changed files with 55 additions and 1 deletions
BIN
bookwyrm/tests/data/default_avi_exif.jpg
Normal file
BIN
bookwyrm/tests/data/default_avi_exif.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.6 KiB |
|
@ -1,9 +1,12 @@
|
|||
""" test searching for books """
|
||||
from PIL import Image
|
||||
import re
|
||||
from django.core.files.uploadedfile import InMemoryUploadedFile
|
||||
from django.test import TestCase
|
||||
|
||||
from bookwyrm.settings import BASE_URL
|
||||
from bookwyrm.utils import regex
|
||||
from bookwyrm.utils.images import remove_uploaded_image_exif
|
||||
from bookwyrm.utils.validate import validate_url_domain
|
||||
|
||||
|
||||
|
@ -24,3 +27,18 @@ class TestUtils(TestCase):
|
|||
self.assertIsNone(
|
||||
validate_url_domain("https://up-to-no-good.tld/bad-actor.exe")
|
||||
)
|
||||
|
||||
def test_remove_uploaded_image_exif(self):
|
||||
"""Check that EXIF data is removed from image"""
|
||||
image_path = "bookwyrm/tests/data/default_avi_exif.jpg"
|
||||
with open(image_path, "rb") as image_file:
|
||||
source = InMemoryUploadedFile(
|
||||
image_file,
|
||||
"cover",
|
||||
"default_avi_exif.jpg",
|
||||
"image/jpeg",
|
||||
os.fstat(image_file.fileno()).st_size,
|
||||
None,
|
||||
)
|
||||
sanitized_image = Image.open(remove_uploaded_image_exif(source).open())
|
||||
self.assertNotIn("exif", sanitized_image.info)
|
||||
|
|
27
bookwyrm/utils/images.py
Normal file
27
bookwyrm/utils/images.py
Normal file
|
@ -0,0 +1,27 @@
|
|||
""" Image utilities """
|
||||
|
||||
from io import BytesIO
|
||||
from PIL import Image
|
||||
from django.core.files.uploadedfile import InMemoryUploadedFile
|
||||
|
||||
|
||||
def remove_uploaded_image_exif(source: InMemoryUploadedFile):
|
||||
"""Removes EXIF data from provided image and returns a sanitized copy"""
|
||||
io = BytesIO()
|
||||
with Image.open(source) as image:
|
||||
if "exif" in image.info:
|
||||
del image.info["exif"]
|
||||
|
||||
if image.format == "JPEG":
|
||||
image.save(io, format=image.format, quality="keep")
|
||||
else:
|
||||
image.save(io, format=image.format)
|
||||
|
||||
return InMemoryUploadedFile(
|
||||
io,
|
||||
source.field_name,
|
||||
source.name,
|
||||
source.content_type,
|
||||
len(io.getvalue()),
|
||||
source.charset,
|
||||
)
|
|
@ -17,6 +17,7 @@ from bookwyrm.activitypub import ActivitypubResponse
|
|||
from bookwyrm.connectors import connector_manager, ConnectorException
|
||||
from bookwyrm.connectors.abstract_connector import get_image
|
||||
from bookwyrm.settings import PAGE_LENGTH
|
||||
from bookwyrm.utils.images import remove_uploaded_image_exif
|
||||
from bookwyrm.views.helpers import (
|
||||
is_api_request,
|
||||
maybe_redirect_local_path,
|
||||
|
@ -158,7 +159,7 @@ def upload_cover(request, book_id):
|
|||
if not form.is_valid() or not form.files.get("cover"):
|
||||
return redirect(book.local_path)
|
||||
|
||||
book.cover = form.files["cover"]
|
||||
book.cover = remove_uploaded_image_exif(form.files["cover"])
|
||||
book.save()
|
||||
|
||||
return redirect(book.local_path)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
""" the good stuff! the books! """
|
||||
|
||||
from re import sub, findall
|
||||
|
||||
from django.contrib.auth.decorators import login_required, permission_required
|
||||
from django.contrib.postgres.search import SearchRank, SearchVector
|
||||
from django.db import transaction
|
||||
|
@ -12,6 +13,7 @@ from django.views.decorators.http import require_POST
|
|||
from django.views import View
|
||||
|
||||
from bookwyrm import book_search, forms, models
|
||||
from bookwyrm.utils.images import remove_uploaded_image_exif
|
||||
|
||||
# from bookwyrm.activitypub.base_activity import ActivityObject
|
||||
from bookwyrm.utils.isni import (
|
||||
|
@ -71,6 +73,8 @@ class EditBook(View):
|
|||
image = set_cover_from_url(url)
|
||||
if image:
|
||||
book.cover.save(*image, save=False)
|
||||
elif "cover" in form.files:
|
||||
book.cover = remove_uploaded_image_exif(form.files["cover"])
|
||||
|
||||
book.save()
|
||||
return redirect(f"/book/{book.id}")
|
||||
|
@ -142,6 +146,8 @@ class CreateBook(View):
|
|||
image = set_cover_from_url(url)
|
||||
if image:
|
||||
book.cover.save(*image, save=False)
|
||||
elif "cover" in form.files:
|
||||
book.cover = remove_uploaded_image_exif(form.files["cover"])
|
||||
|
||||
book.save()
|
||||
return redirect(f"/book/{book.id}")
|
||||
|
@ -311,6 +317,8 @@ class ConfirmEditBook(View):
|
|||
image = set_cover_from_url(url)
|
||||
if image:
|
||||
book.cover.save(*image, save=False)
|
||||
elif "cover" in form.files:
|
||||
book.cover = remove_uploaded_image_exif(form.files["cover"])
|
||||
|
||||
# we don't tell the world when creating a book
|
||||
book.save(broadcast=False)
|
||||
|
|
Loading…
Reference in a new issue