From 4d068796690c15ae4f98c29463b2ed6add558e96 Mon Sep 17 00:00:00 2001 From: Rapptz Date: Sun, 7 Apr 2019 00:22:57 -0400 Subject: [PATCH] Add ignore_links and as_needed options to utils.escape_markdown. This allows for URLs to be left alone since they can include markdown characters and allows for total escaping of all markdown characters by default to prevent some form of data manipulation. --- discord/utils.py | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/discord/utils.py b/discord/utils.py index 0882250c7..6bdca37d9 100644 --- a/discord/utils.py +++ b/discord/utils.py @@ -369,15 +369,26 @@ def resolve_invite(invite): _MARKDOWN_ESCAPE_SUBREGEX = '|'.join(r'\{0}(?=([\s\S]*((?%s)' % _MARKDOWN_ESCAPE_SUBREGEX) -def escape_markdown(text): - """A helper function that escapes Discord's markdown. +def escape_markdown(text, *, as_needed=False, ignore_links=True): + r"""A helper function that escapes Discord's markdown. Parameters ----------- text: :class:`str` The text to escape markdown from. + as_needed: :class:`bool` + Whether to escape the markdown characters as needed. This + means that it does not escape extraneous characters if it's + not necessary, e.g. ``**hello**`` is escaped into ``\*\*hello**`` + instead of ``\*\*hello\*\*``. Note however that this can open + you up to some clever syntax abuse. Defaults to ``False``. + ignore_links: :class:`bool` + Whether to leave links alone when escaping markdown. For example, + if a URL in the text contains characters such as ``_`` then it will + be left alone. This option is not supported with ``as_needed``. + Defaults to ``True``. Returns -------- @@ -385,8 +396,22 @@ def escape_markdown(text): The text with the markdown special characters escaped with a slash. """ - text = re.sub(r'\\', r'\\\\', text) - return _MARKDOWN_ESCAPE_REGEX.sub(r'\\\1', text) + if not as_needed: + url_regex = r'(?P(?:https?|steam)://(?:-\.)?(?:[^\s/?\.#-]+\.?)+(?:/[^\s]*)?)' + def replacement(match): + groupdict = match.groupdict() + is_url = groupdict.get('url') + if is_url: + return is_url + return '\\' + groupdict['markdown'] + + regex = r'(?P[_\\~|\*])' + if ignore_links: + regex = '(?:%s|%s)' % (url_regex, regex) + return re.sub(regex, replacement, text) + else: + text = re.sub(r'\\', r'\\\\', text) + return _MARKDOWN_ESCAPE_REGEX.sub(r'\\\1', text) def escape_mentions(text): """A helper function that escapes everyone, here, role, and user mentions.