From d16df7914c486cab6e6758c8788a21eddf7a6452 Mon Sep 17 00:00:00 2001 From: ToxicKidz Date: Sun, 23 May 2021 11:37:06 -0400 Subject: fix: Remove the extra 'as' in floats.md --- bot/resources/tags/floats.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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: -- cgit v1.2.3 From 20fd49666519fa8228ce942a8f2bb6f15aa79e34 Mon Sep 17 00:00:00 2001 From: Gustav Odinger <65498475+gustavwilliam@users.noreply.github.com> Date: Mon, 24 May 2021 19:38:40 +0200 Subject: Up duck pond threshold to 7 Makes duck pond entries less common, by requiring more ducks for a message to be ducked --- config-default.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 -- cgit v1.2.3 From 725b8acc6d1b7216b7e7ab24350838c6893cf0bc Mon Sep 17 00:00:00 2001 From: Chris Date: Mon, 24 May 2021 21:24:18 +0100 Subject: Add filter for pixels API tokens --- bot/exts/filters/pixels_token_remover.py | 108 +++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 bot/exts/filters/pixels_token_remover.py diff --git a/bot/exts/filters/pixels_token_remover.py b/bot/exts/filters/pixels_token_remover.py new file mode 100644 index 000000000..11f35261f --- /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 to get a new key." +) + +PIXELS_TOKEN_RE = re.compile(r"[A-Za-z0-9-_=]+\.[A-Za-z0-9-_=]+\.?[A-Za-z0-9-_.+\=]*") + + +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)) -- cgit v1.2.3 From c9860a217eea8e19d15f5cc2d30debe089f394fb Mon Sep 17 00:00:00 2001 From: Chris Date: Tue, 25 May 2021 00:21:52 +0100 Subject: Update pixels token regex to false match less --- bot/exts/filters/pixels_token_remover.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/exts/filters/pixels_token_remover.py b/bot/exts/filters/pixels_token_remover.py index 11f35261f..2356491e5 100644 --- a/bot/exts/filters/pixels_token_remover.py +++ b/bot/exts/filters/pixels_token_remover.py @@ -21,7 +21,7 @@ DELETION_MESSAGE_TEMPLATE = ( "You can go to to get a new key." ) -PIXELS_TOKEN_RE = re.compile(r"[A-Za-z0-9-_=]+\.[A-Za-z0-9-_=]+\.?[A-Za-z0-9-_.+\=]*") +PIXELS_TOKEN_RE = re.compile(r"[A-Za-z0-9-_=]{30,}\.[A-Za-z0-9-_=]{50,}\.[A-Za-z0-9-_.+\=]{30,}") class PixelsTokenRemover(Cog): -- cgit v1.2.3 From 179db2c896100996360af9aba72c3644291e6b7e Mon Sep 17 00:00:00 2001 From: Matteo Bertucci Date: Thu, 27 May 2021 15:39:51 +0200 Subject: Recruitment: reverse nomination order This makes review appear in chronological order, making it easier to say things like "^^ what they said". --- bot/exts/recruitment/talentpool/_review.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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}" -- cgit v1.2.3