diff options
author | 2021-05-30 11:24:07 -0700 | |
---|---|---|
committer | 2021-05-30 11:24:07 -0700 | |
commit | 9d5567dc8c78454c12f20e58cb9190a9bf0ebd04 (patch) | |
tree | 24b109e88861a3e0ba628fb0e1d0cbbc8dd07cf0 | |
parent | Add the doc group to FORCE_PREFIX_GROUPS (diff) | |
parent | Merge pull request #1615 from python-discord/reviews-revert-order (diff) |
Merge branch 'main' into doc-force-prefix-priority
-rw-r--r-- | bot/exts/filters/pixels_token_remover.py | 108 | ||||
-rw-r--r-- | bot/exts/recruitment/talentpool/_review.py | 3 | ||||
-rw-r--r-- | bot/resources/tags/floats.md | 2 | ||||
-rw-r--r-- | bot/resources/tags/modmail.md | 2 | ||||
-rw-r--r-- | config-default.yml | 2 |
5 files changed, 113 insertions, 4 deletions
diff --git a/bot/exts/filters/pixels_token_remover.py b/bot/exts/filters/pixels_token_remover.py new file mode 100644 index 000000000..2356491e5 --- /dev/null +++ b/bot/exts/filters/pixels_token_remover.py @@ -0,0 +1,108 @@ +import logging +import re +import typing as t + +from discord import Colour, Message, NotFound +from discord.ext.commands import Cog + +from bot.bot import Bot +from bot.constants import Channels, Colours, Event, Icons +from bot.exts.moderation.modlog import ModLog +from bot.utils.messages import format_user + +log = logging.getLogger(__name__) + +LOG_MESSAGE = "Censored a valid Pixels token sent by {author} in {channel}, token was `{token}`" +DELETION_MESSAGE_TEMPLATE = ( + "Hey {mention}! I noticed you posted a valid Pixels API " + "token in your message and have removed your message. " + "This means that your token has been **compromised**. " + "I have taken the liberty of invalidating the token for you. " + "You can go to <https://pixels.pythondiscord.com/authorize> to get a new key." +) + +PIXELS_TOKEN_RE = re.compile(r"[A-Za-z0-9-_=]{30,}\.[A-Za-z0-9-_=]{50,}\.[A-Za-z0-9-_.+\=]{30,}") + + +class PixelsTokenRemover(Cog): + """Scans messages for Pixels API tokens, removes and invalidates them.""" + + def __init__(self, bot: Bot): + self.bot = bot + + @property + def mod_log(self) -> ModLog: + """Get currently loaded ModLog cog instance.""" + return self.bot.get_cog("ModLog") + + @Cog.listener() + async def on_message(self, msg: Message) -> None: + """Check each message for a string that matches the RS-256 token pattern.""" + # Ignore DMs; can't delete messages in there anyway. + if not msg.guild or msg.author.bot: + return + + found_token = await self.find_token_in_message(msg) + if found_token: + await self.take_action(msg, found_token) + + @Cog.listener() + async def on_message_edit(self, before: Message, after: Message) -> None: + """Check each edit for a string that matches the RS-256 token pattern.""" + await self.on_message(after) + + async def take_action(self, msg: Message, found_token: str) -> None: + """Remove the `msg` containing the `found_token` and send a mod log message.""" + self.mod_log.ignore(Event.message_delete, msg.id) + + try: + await msg.delete() + except NotFound: + log.debug(f"Failed to remove token in message {msg.id}: message already deleted.") + return + + await msg.channel.send(DELETION_MESSAGE_TEMPLATE.format(mention=msg.author.mention)) + + log_message = self.format_log_message(msg, found_token) + log.debug(log_message) + + # Send pretty mod log embed to mod-alerts + await self.mod_log.send_log_message( + icon_url=Icons.token_removed, + colour=Colour(Colours.soft_red), + title="Token removed!", + text=log_message, + thumbnail=msg.author.avatar_url_as(static_format="png"), + channel_id=Channels.mod_alerts, + ping_everyone=False, + ) + + self.bot.stats.incr("tokens.removed_pixels_tokens") + + @staticmethod + def format_log_message(msg: Message, token: str) -> str: + """Return the generic portion of the log message to send for `token` being censored in `msg`.""" + return LOG_MESSAGE.format( + author=format_user(msg.author), + channel=msg.channel.mention, + token=token + ) + + async def find_token_in_message(self, msg: Message) -> t.Optional[str]: + """Return a seemingly valid token found in `msg` or `None` if no token is found.""" + # Use finditer rather than search to guard against method calls prematurely returning the + # token check (e.g. `message.channel.send` also matches our token pattern) + for match in PIXELS_TOKEN_RE.finditer(msg.content): + auth_header = {"Authorization": f"Bearer {match[0]}"} + async with self.bot.http_session.delete("https://pixels.pythondiscord.com/token", headers=auth_header) as r: + if r.status == 204: + # Short curcuit on first match. + return match[0] + + # No matching substring + return + + +def setup(bot: Bot) -> None: + """Load the PixelsTokenRemover cog.""" + bot.add_cog(PixelsTokenRemover(bot)) diff --git a/bot/exts/recruitment/talentpool/_review.py b/bot/exts/recruitment/talentpool/_review.py index d53c3b074..b9ff61986 100644 --- a/bot/exts/recruitment/talentpool/_review.py +++ b/bot/exts/recruitment/talentpool/_review.py @@ -120,7 +120,8 @@ class Reviewer: opening = f"<@&{Roles.mod_team}> <@&{Roles.admins}>\n{member.mention} ({member}) for Helper!" current_nominations = "\n\n".join( - f"**<@{entry['actor']}>:** {entry['reason'] or '*no reason given*'}" for entry in nomination['entries'] + f"**<@{entry['actor']}>:** {entry['reason'] or '*no reason given*'}" + for entry in nomination['entries'][::-1] ) current_nominations = f"**Nominated by:**\n{current_nominations}" diff --git a/bot/resources/tags/floats.md b/bot/resources/tags/floats.md index 7129b91bb..03fcd7268 100644 --- a/bot/resources/tags/floats.md +++ b/bot/resources/tags/floats.md @@ -5,7 +5,7 @@ You may have noticed that when doing arithmetic with floats in Python you someti 0.30000000000000004 ``` **Why this happens** -Internally your computer stores floats as as binary fractions. Many decimal values cannot be stored as exact binary fractions, which means an approximation has to be used. +Internally your computer stores floats as binary fractions. Many decimal values cannot be stored as exact binary fractions, which means an approximation has to be used. **How you can avoid this** You can use [math.isclose](https://docs.python.org/3/library/math.html#math.isclose) to check if two floats are close, or to get an exact decimal representation, you can use the [decimal](https://docs.python.org/3/library/decimal.html) or [fractions](https://docs.python.org/3/library/fractions.html) module. Here are some examples: diff --git a/bot/resources/tags/modmail.md b/bot/resources/tags/modmail.md index 7545419ee..412468174 100644 --- a/bot/resources/tags/modmail.md +++ b/bot/resources/tags/modmail.md @@ -6,4 +6,4 @@ It supports attachments, codeblocks, and reactions. As communication happens ove **To use it, simply send a direct message to the bot.** -Should there be an urgent and immediate need for a moderator or admin to look at a channel, feel free to ping the <@&267629731250176001> or <@&267628507062992896> role instead. +Should there be an urgent and immediate need for a moderator or admin to look at a channel, feel free to ping the <@&831776746206265384> or <@&267628507062992896> role instead. diff --git a/config-default.yml b/config-default.yml index 394c51c26..8099a0860 100644 --- a/config-default.yml +++ b/config-default.yml @@ -511,7 +511,7 @@ redirect_output: duck_pond: - threshold: 5 + threshold: 7 channel_blacklist: - *ANNOUNCEMENTS - *PYNEWS_CHANNEL |