Skip to content

Commit

Permalink
Merge branch 'main' into doc-force-prefix-priority
Browse files Browse the repository at this point in the history
  • Loading branch information
Xithrius authored May 30, 2021
2 parents f00fe17 + 5006a7b commit 9d5567d
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 4 deletions.
108 changes: 108 additions & 0 deletions bot/exts/filters/pixels_token_remover.py
Original file line number Diff line number Diff line change
@@ -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))
3 changes: 2 additions & 1 deletion bot/exts/recruitment/talentpool/_review.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,8 @@ async def make_review(self, user_id: int) -> typing.Tuple[str, Optional[Emoji]]:
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}"

Expand Down
2 changes: 1 addition & 1 deletion bot/resources/tags/floats.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion bot/resources/tags/modmail.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
2 changes: 1 addition & 1 deletion config-default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ redirect_output:


duck_pond:
threshold: 5
threshold: 7
channel_blacklist:
- *ANNOUNCEMENTS
- *PYNEWS_CHANNEL
Expand Down

0 comments on commit 9d5567d

Please sign in to comment.