mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-04 05:53:43 +00:00 
			
		
		
		
	realm_emoji: Stop swallowing all exceptions from upload_emoji_image.
Putting all of the logic in a `finally` block is equivalent to a bare `except` block, which silently consumes all exceptions. Move only the most-necessary parts into the except; this lets `BadImageError` exceptions from `zerver/lib/upload.py` to escape, allowing better the generic "Image file upload failed" to be replaced with a more specific message. It also allows unexpected exceptions, as the previous commit resolved, to escape and 500. This lets them be detected and resolved, rather than give users a silently bad experience.
This commit is contained in:
		
				
					committed by
					
						
						Tim Abbott
					
				
			
			
				
	
			
			
			
						parent
						
							96a5fa9d78
						
					
				
				
					commit
					a40b3e1118
				
			@@ -7908,7 +7908,7 @@ def notify_realm_emoji(realm: Realm) -> None:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
def check_add_realm_emoji(
 | 
					def check_add_realm_emoji(
 | 
				
			||||||
    realm: Realm, name: str, author: UserProfile, image_file: IO[bytes]
 | 
					    realm: Realm, name: str, author: UserProfile, image_file: IO[bytes]
 | 
				
			||||||
) -> Optional[RealmEmoji]:
 | 
					) -> RealmEmoji:
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        realm_emoji = RealmEmoji(realm=realm, name=name, author=author)
 | 
					        realm_emoji = RealmEmoji(realm=realm, name=name, author=author)
 | 
				
			||||||
        realm_emoji.full_clean()
 | 
					        realm_emoji.full_clean()
 | 
				
			||||||
@@ -7931,12 +7931,10 @@ def check_add_realm_emoji(
 | 
				
			|||||||
    finally:
 | 
					    finally:
 | 
				
			||||||
        if not emoji_uploaded_successfully:
 | 
					        if not emoji_uploaded_successfully:
 | 
				
			||||||
            realm_emoji.delete()
 | 
					            realm_emoji.delete()
 | 
				
			||||||
            return None
 | 
					    realm_emoji.file_name = emoji_file_name
 | 
				
			||||||
        else:
 | 
					    realm_emoji.is_animated = is_animated
 | 
				
			||||||
            realm_emoji.file_name = emoji_file_name
 | 
					    realm_emoji.save(update_fields=["file_name", "is_animated"])
 | 
				
			||||||
            realm_emoji.is_animated = is_animated
 | 
					    notify_realm_emoji(realm_emoji.realm)
 | 
				
			||||||
            realm_emoji.save(update_fields=["file_name", "is_animated"])
 | 
					 | 
				
			||||||
            notify_realm_emoji(realm_emoji.realm)
 | 
					 | 
				
			||||||
    return realm_emoji
 | 
					    return realm_emoji
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,7 @@ from zerver.lib.actions import (
 | 
				
			|||||||
from zerver.lib.exceptions import JsonableError
 | 
					from zerver.lib.exceptions import JsonableError
 | 
				
			||||||
from zerver.lib.test_classes import ZulipTestCase
 | 
					from zerver.lib.test_classes import ZulipTestCase
 | 
				
			||||||
from zerver.lib.test_helpers import get_test_image_file
 | 
					from zerver.lib.test_helpers import get_test_image_file
 | 
				
			||||||
 | 
					from zerver.lib.upload import BadImageError
 | 
				
			||||||
from zerver.models import Realm, RealmEmoji, UserProfile, get_realm
 | 
					from zerver.models import Realm, RealmEmoji, UserProfile, get_realm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -320,11 +321,13 @@ class RealmEmojiTest(ZulipTestCase):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    def test_failed_file_upload(self) -> None:
 | 
					    def test_failed_file_upload(self) -> None:
 | 
				
			||||||
        self.login("iago")
 | 
					        self.login("iago")
 | 
				
			||||||
        with mock.patch("zerver.lib.upload.write_local_file", side_effect=Exception()):
 | 
					        with mock.patch(
 | 
				
			||||||
 | 
					            "zerver.lib.upload.write_local_file", side_effect=BadImageError(msg="Broken")
 | 
				
			||||||
 | 
					        ):
 | 
				
			||||||
            with get_test_image_file("img.png") as fp1:
 | 
					            with get_test_image_file("img.png") as fp1:
 | 
				
			||||||
                emoji_data = {"f1": fp1}
 | 
					                emoji_data = {"f1": fp1}
 | 
				
			||||||
                result = self.client_post("/json/realm/emoji/my_emoji", info=emoji_data)
 | 
					                result = self.client_post("/json/realm/emoji/my_emoji", info=emoji_data)
 | 
				
			||||||
        self.assert_json_error(result, "Image file upload failed.")
 | 
					        self.assert_json_error(result, "Broken")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_check_admin_realm_emoji(self) -> None:
 | 
					    def test_check_admin_realm_emoji(self) -> None:
 | 
				
			||||||
        # Test that an user A is able to remove a realm emoji uploaded by him
 | 
					        # Test that an user A is able to remove a realm emoji uploaded by him
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2288,17 +2288,17 @@ class UploadSpaceTests(UploadSerializeMixin, ZulipTestCase):
 | 
				
			|||||||
class DecompressionBombTests(ZulipTestCase):
 | 
					class DecompressionBombTests(ZulipTestCase):
 | 
				
			||||||
    def setUp(self) -> None:
 | 
					    def setUp(self) -> None:
 | 
				
			||||||
        super().setUp()
 | 
					        super().setUp()
 | 
				
			||||||
        self.test_urls = {
 | 
					        self.test_urls = [
 | 
				
			||||||
            "/json/users/me/avatar": "Image size exceeds limit.",
 | 
					            "/json/users/me/avatar",
 | 
				
			||||||
            "/json/realm/logo": "Image size exceeds limit.",
 | 
					            "/json/realm/logo",
 | 
				
			||||||
            "/json/realm/icon": "Image size exceeds limit.",
 | 
					            "/json/realm/icon",
 | 
				
			||||||
            "/json/realm/emoji/bomb_emoji": "Image file upload failed.",
 | 
					            "/json/realm/emoji/bomb_emoji",
 | 
				
			||||||
        }
 | 
					        ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_decompression_bomb(self) -> None:
 | 
					    def test_decompression_bomb(self) -> None:
 | 
				
			||||||
        self.login("iago")
 | 
					        self.login("iago")
 | 
				
			||||||
        with get_test_image_file("bomb.png") as fp:
 | 
					        with get_test_image_file("bomb.png") as fp:
 | 
				
			||||||
            for url, error_string in self.test_urls.items():
 | 
					            for url in self.test_urls:
 | 
				
			||||||
                fp.seek(0, 0)
 | 
					                fp.seek(0, 0)
 | 
				
			||||||
                if url == "/json/realm/logo":
 | 
					                if url == "/json/realm/logo":
 | 
				
			||||||
                    result = self.client_post(
 | 
					                    result = self.client_post(
 | 
				
			||||||
@@ -2306,4 +2306,4 @@ class DecompressionBombTests(ZulipTestCase):
 | 
				
			|||||||
                    )
 | 
					                    )
 | 
				
			||||||
                else:
 | 
					                else:
 | 
				
			||||||
                    result = self.client_post(url, {"f1": fp})
 | 
					                    result = self.client_post(url, {"f1": fp})
 | 
				
			||||||
                self.assert_json_error(result, error_string)
 | 
					                self.assert_json_error(result, "Image size exceeds limit.")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -47,9 +47,7 @@ def upload_emoji(
 | 
				
			|||||||
            )
 | 
					            )
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    realm_emoji = check_add_realm_emoji(user_profile.realm, emoji_name, user_profile, emoji_file)
 | 
					    check_add_realm_emoji(user_profile.realm, emoji_name, user_profile, emoji_file)
 | 
				
			||||||
    if realm_emoji is None:
 | 
					 | 
				
			||||||
        raise JsonableError(_("Image file upload failed."))
 | 
					 | 
				
			||||||
    return json_success(request)
 | 
					    return json_success(request)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user