From d13bf378451b7a85b8fcb343efcf9f4f67317c9e Mon Sep 17 00:00:00 2001 From: Michael H Date: Fri, 15 Feb 2019 19:34:38 -0500 Subject: [PATCH] [Utils] Add filters for spoiler markdown (#2401) This also wraps some fields of the modlog with the same sanitization, as well as the `[p]names` command. --- redbot/cogs/mod/mod.py | 11 +++++--- redbot/core/modlog.py | 27 +++++++++++++------ redbot/core/utils/common_filters.py | 40 +++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 12 deletions(-) diff --git a/redbot/cogs/mod/mod.py b/redbot/cogs/mod/mod.py index e064e51e7..b96a6cfca 100644 --- a/redbot/cogs/mod/mod.py +++ b/redbot/cogs/mod/mod.py @@ -12,11 +12,14 @@ from redbot.core import checks, Config, modlog, commands from redbot.core.bot import Red from redbot.core.i18n import Translator, cog_i18n from redbot.core.utils.chat_formatting import box, escape, pagify, format_perms_list -from redbot.core.utils.common_filters import filter_invites, filter_various_mentions +from redbot.core.utils.common_filters import ( + filter_invites, + filter_various_mentions, + escape_spoilers, +) from redbot.core.utils.mod import is_mod_or_superior, is_allowed_by_hierarchy, get_audit_reason from .log import log - _ = T_ = Translator("Mod", __file__) @@ -1546,9 +1549,9 @@ class Mod(commands.Cog): names = await self.settings.user(user).past_names() nicks = await self.settings.member(user).past_nicks() if names: - names = [escape(name, mass_mentions=True) for name in names if name] + names = [escape_spoilers(escape(name, mass_mentions=True)) for name in names if name] if nicks: - nicks = [escape(nick, mass_mentions=True) for nick in nicks if nick] + nicks = [escape_spoilers(escape(nick, mass_mentions=True)) for nick in nicks if nick] return names, nicks async def check_tempban_expirations(self): diff --git a/redbot/core/modlog.py b/redbot/core/modlog.py index 95104f209..6a3b4dc4d 100644 --- a/redbot/core/modlog.py +++ b/redbot/core/modlog.py @@ -6,7 +6,12 @@ import discord from redbot.core import Config from redbot.core.bot import Red -from .utils.common_filters import filter_invites, filter_mass_mentions, filter_urls +from .utils.common_filters import ( + filter_invites, + filter_mass_mentions, + filter_urls, + escape_spoilers, +) __all__ = [ "Case", @@ -113,8 +118,10 @@ class Case: reason = "**Reason:** Use `[p]reason {} ` to add it".format(self.case_number) if self.moderator is not None: - moderator = "{}#{} ({})\n".format( - self.moderator.name, self.moderator.discriminator, self.moderator.id + moderator = escape_spoilers( + "{}#{} ({})\n".format( + self.moderator.name, self.moderator.discriminator, self.moderator.id + ) ) else: moderator = "Unknown" @@ -131,8 +138,10 @@ class Case: amended_by = None if self.amended_by: - amended_by = "{}#{} ({})".format( - self.amended_by.name, self.amended_by.discriminator, self.amended_by.id + amended_by = escape_spoilers( + "{}#{} ({})".format( + self.amended_by.name, self.amended_by.discriminator, self.amended_by.id + ) ) last_modified = None @@ -141,9 +150,11 @@ class Case: datetime.fromtimestamp(self.modified_at).strftime("%Y-%m-%d %H:%M:%S") ) - user = filter_invites( - "{}#{} ({})\n".format(self.user.name, self.user.discriminator, self.user.id) - ) # Invites get rendered even in embeds. + user = escape_spoilers( + filter_invites( + "{}#{} ({})\n".format(self.user.name, self.user.discriminator, self.user.id) + ) + ) # Invites and spoilers get rendered even in embeds. if embed: emb = discord.Embed(title=title, description=reason) diff --git a/redbot/core/utils/common_filters.py b/redbot/core/utils/common_filters.py index 13457e723..608a6be52 100644 --- a/redbot/core/utils/common_filters.py +++ b/redbot/core/utils/common_filters.py @@ -9,6 +9,8 @@ __all__ = [ "filter_mass_mentions", "filter_various_mentions", "normalize_smartquotes", + "escape_spoilers", + "escape_spoilers_and_mass_mentions", ] # regexes @@ -29,6 +31,10 @@ SMART_QUOTE_REPLACEMENT_DICT = { SMART_QUOTE_REPLACE_RE = re.compile("|".join(SMART_QUOTE_REPLACEMENT_DICT.keys())) +SPOILER_CONTENT_RE = re.compile( + r"(?s)(?\|{2})(?P.*?)(?\|{2})" +) + # convenience wrappers def filter_urls(to_filter: str) -> str: @@ -133,3 +139,37 @@ def normalize_smartquotes(to_normalize: str) -> str: return SMART_QUOTE_REPLACEMENT_DICT.get(obj.group(0), "") return SMART_QUOTE_REPLACE_RE.sub(replacement_for, to_normalize) + + +def escape_spoilers(content: str) -> str: + """ + Get a string with spoiler syntax escaped. + + Parameters + ---------- + content : str + The string to escape. + + Returns + ------- + str + The escaped string. + """ + return SPOILER_CONTENT_RE.sub(r"\\\g\g\\\g", content) + + +def escape_spoilers_and_mass_mentions(content: str) -> str: + """ + Get a string with spoiler syntax and mass mentions escaped + + Parameters + ---------- + content : str + The string to escape. + + Returns + ------- + str + The escaped string. + """ + return escape_spoilers(filter_mass_mentions(content))