From acc52a0c6123d9ece97c4cc59eb8d3992887ed8f Mon Sep 17 00:00:00 2001 From: Luna Date: Fri, 26 Apr 2019 16:48:27 -0300 Subject: [PATCH] add basic checking of webhook avatar mime --- litecord/blueprints/webhooks.py | 20 +++++++++++++++++--- litecord/images.py | 5 +++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/litecord/blueprints/webhooks.py b/litecord/blueprints/webhooks.py index fb91af0..a812a2a 100644 --- a/litecord/blueprints/webhooks.py +++ b/litecord/blueprints/webhooks.py @@ -46,6 +46,7 @@ from litecord.embed.sanitizer import fill_embed, fetch_raw_img from litecord.embed.messages import process_url_embed, is_media_url from litecord.utils import pg_set_json from litecord.enums import MessageType +from litecord.images import STATIC_IMAGE_MIMES bp = Blueprint('webhooks', __name__) @@ -346,12 +347,12 @@ async def create_message_webhook(guild_id, channel_id, webhook_id, data): return message_id -async def _create_avatar(webhook_id: int, avatar_url): +async def _create_avatar(webhook_id: int, avatar_url) -> str: """Create an avatar for a webhook out of an avatar URL, given when executing the webhook. - Litecord will query that URL via mediaproxy and store the data - via IconManager. + Litecord will write an URL that redirects to the given avatar_url, + using mediaproxy. """ if avatar_url.scheme not in ('http', 'https'): raise BadRequest('invalid avatar url scheme') @@ -359,12 +360,21 @@ async def _create_avatar(webhook_id: int, avatar_url): if not is_media_url(avatar_url): raise BadRequest('url is not media url') + # we still fetch the URL to check its validity, mimetypes, etc + # but in the end, we will store it under the webhook_avatars table, + # not IconManager. resp, raw = await fetch_raw_img(avatar_url) raw_b64 = base64.b64encode(raw).decode() mime = resp.headers['content-type'] + + # TODO: apng checks are missing (for this and everywhere else) + if mime not in STATIC_IMAGE_MIMES: + raise BadRequest('invalid mime type for given url') + b64_data = f'data:{mime};base64,{raw_b64}' + # TODO: replace this by webhook_avatars icon = await app.icons.put( 'user', webhook_id, b64_data, always_icon=True, size=(128, 128) @@ -399,6 +409,10 @@ async def execute_webhook(webhook_id: int, webhook_token): given_embeds = j.get('embeds', []) webhook = await get_webhook(webhook_id) + + # webhooks have TWO avatars. one is from settings, the other is from + # the json's icon_url. one can be handled gracefully by IconManager, + # but the other can't, at all. avatar = webhook['avatar'] if 'avatar_url' in j and j['avatar_url'] is not None: diff --git a/litecord/images.py b/litecord/images.py index ec37469..0ce0595 100644 --- a/litecord/images.py +++ b/litecord/images.py @@ -50,6 +50,11 @@ MIMES = { 'webp': 'image/webp', } +STATIC_IMAGE_MIMES = [ + 'image/png', + 'image/jpeg', + 'image/webp' +] def get_ext(mime: str) -> str: if mime in EXTENSIONS: