From 9aff13118aca2cb50fdf8b98c01b985deee0510b Mon Sep 17 00:00:00 2001 From: Humberto Rocha Date: Sat, 25 Feb 2023 16:47:43 -0500 Subject: [PATCH] Fix crash when fetching emoji without mimetype and extension (#524) --- activities/models/emoji.py | 14 +++++++++++--- tests/activities/models/test_emoji.py | 20 ++++++++++++++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/activities/models/emoji.py b/activities/models/emoji.py index 15691dd..6775bcd 100644 --- a/activities/models/emoji.py +++ b/activities/models/emoji.py @@ -11,6 +11,7 @@ from django.core.exceptions import ValidationError from django.core.files.base import ContentFile from django.db import models from django.utils.safestring import mark_safe +from PIL import Image from core.files import get_remote_file from core.html import FediverseHtmlParser @@ -47,7 +48,11 @@ class EmojiStates(StateGraph): ) except httpx.RequestError: return + if file: + if mimetype == "application/octet-stream": + mimetype = Image.open(file).get_format_mimetype() + instance.file = file instance.mimetype = mimetype await sync_to_async(instance.save)() @@ -288,8 +293,6 @@ class Emoji(StatorModel): mimetype = icon.get("mediaType") if not mimetype: mimetype, _ = mimetypes.guess_type(icon["url"]) - if mimetype is None: - raise ValueError("No mimetype on emoji JSON") # create shortcode = name.strip(":") @@ -301,6 +304,11 @@ class Emoji(StatorModel): except cls.DoesNotExist: pass else: + # default to previously discovered mimetype if not provided + # by the instance to avoid infinite outdated state + if mimetype is None: + mimetype = emoji.mimetype + # Domain previously provided this shortcode. Trample in the new emoji if emoji.remote_url != icon["url"] or emoji.mimetype != mimetype: emoji.object_uri = data["id"] @@ -319,7 +327,7 @@ class Emoji(StatorModel): domain=None if domain.local else domain, local=domain.local, object_uri=data["id"], - mimetype=mimetype, + mimetype=mimetype or "application/octet-stream", category=category, remote_url=icon["url"], ) diff --git a/tests/activities/models/test_emoji.py b/tests/activities/models/test_emoji.py index 97b0c92..12d2f8d 100644 --- a/tests/activities/models/test_emoji.py +++ b/tests/activities/models/test_emoji.py @@ -59,3 +59,23 @@ def test_emoji_ingestion(identity): create=True, ) assert cased_emoji.shortcode == "CasedEmoji" + + +@pytest.mark.django_db +def test_emoji_without_mimetype(identity): + """ + Tests that emoji ingest properly from JSON-LD + """ + + emoji = Emoji.by_ap_tag( + identity.domain, + { + "icon": {"type": "Image", "url": "https://example.com/emoji/custom/emoji"}, + "id": "https://example.com/emoji/custom/emoji", + "nameMap": {"und": ":emoji:"}, + "type": "Emoji", + "updated": "1970-01-01T00:00:00Z", + }, + create=True, + ) + assert emoji.shortcode == "emoji"