diff options
| -rw-r--r-- | bot/__main__.py | 1 | ||||
| -rw-r--r-- | bot/cogs/filtering.py | 89 | ||||
| -rw-r--r-- | bot/constants.py | 5 | ||||
| -rw-r--r-- | config-default.yml | 6 | 
4 files changed, 89 insertions, 12 deletions
| diff --git a/bot/__main__.py b/bot/__main__.py index 4429c2a0d..3ecf8cb18 100644 --- a/bot/__main__.py +++ b/bot/__main__.py @@ -41,6 +41,7 @@ bot.load_extension("bot.cogs.logging")  bot.load_extension("bot.cogs.modlog")  bot.load_extension("bot.cogs.security")  bot.load_extension("bot.cogs.events") +bot.load_extension("bot.cogs.filtering")  # Commands, etc  bot.load_extension("bot.cogs.bigbrother") diff --git a/bot/cogs/filtering.py b/bot/cogs/filtering.py index 23b0d9e96..eee1dbd16 100644 --- a/bot/cogs/filtering.py +++ b/bot/cogs/filtering.py @@ -4,27 +4,71 @@ import re  from discord import Message  from discord.ext.commands import Bot -from bot.constants import Channels +from bot.constants import Channels, Filter  log = logging.getLogger(__name__) +INVITE_RE = ( +    r"(?:discord(?:[\.,]|dot)gg|"                     # Could be discord.gg/ +    r"discord(?:[\.,]|dot)com(?:\/|slash)invite|"     # or discord.com/invite/ +    r"discordapp(?:[\.,]|dot)com(?:\/|slash)invite|"  # or discordapp.com/invite/ +    r"discord(?:[\.,]|dot)me|"                        # or discord.me +    r"discord(?:[\.,]|dot)io"                         # or discord.io. +    r")(?:[\/]|slash)"                                # / or slash +    r"([a-zA-Z0-9]+)"                                 # the invite code itself +) + +URL_RE = "(https?://[^\s]+)" +ZALGO_RE = r"[\u0300-\u036F\u0489]" +  class Filtering:      """      Filtering out invites, blacklisting domains, -    and preventing certain expressions""" +    and preventing certain expressions +    """      def __init__(self, bot: Bot):          self.bot = bot      async def on_message(self, msg: Message): -        has_zalgo = await self._filter_zalgo(msg.content) +        if msg.channel.id == Channels.devtest and not msg.author.bot: -        if has_zalgo: -            self.bot.get_channel(Channels.modlog).send( -                content="ZALGO!" -            ) +            has_zalgo = await self._has_zalgo(msg.content) +            has_invites = await self._has_invites(msg.content) +            has_urls = await self._has_urls(msg.content) + +            if has_zalgo: +                await self.bot.get_channel(msg.channel.id).send( +                    content="ZALGO!" +                ) + +            if has_invites: +                await self.bot.get_channel(msg.channel.id).send( +                    content="INVITES!" +                ) + +            if has_urls: +                await self.bot.get_channel(msg.channel.id).send( +                    content="EVIL ILLEGAL HITLER DOMAINS!" +                ) + +    @staticmethod +    async def _has_urls(text): +        """ +        Returns True if the text contains one of +        the blacklisted URLs from the config file. +        """ + +        if not re.search(URL_RE, text): +            return False + +        for url in Filter.domain_blacklist: +            if url in text: +                return True + +        return False      @staticmethod      async def _has_zalgo(text): @@ -34,7 +78,36 @@ class Filtering:          Zalgo range is \u0300 – \u036F and \u0489.          """ -        return bool(re.search(r"[\u0300-\u036F\u0489]", text)) +        return bool(re.search(ZALGO_RE, text)) + +    @staticmethod +    async def _has_invites(text): +        """ +        Returns True if the text contains an invite which +        is not on the guild_invite_whitelist in config.yml. + +        Also catches a lot of common ways to try to cheat the system. +        """ + +        # Remove spaces to prevent cases like +        # d i s c o r d . c o m / i n v i t e / p y t h o n +        text = text.replace(" ", "") + +        # Remove backslashes to prevent escape character aroundfuckery like +        # discord\.gg/gdudes-pony-farm +        text = text.replace("\\", "") + +        invites = re.findall(INVITE_RE, text) +        for invite in invites: + +            filter_invite = ( +                invite not in Filter.guild_invite_whitelist +                and invite.lower() not in Filter.vanity_url_whitelist +            ) + +            if filter_invite: +                return True +        return False  def setup(bot: Bot): diff --git a/bot/constants.py b/bot/constants.py index 834c14fd8..597c7c4a7 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -191,8 +191,8 @@ class Bot(metaclass=YAMLGetter):      token: str -class Filtering(metaclass=YAMLGetter): -    section = "filtering" +class Filter(metaclass=YAMLGetter): +    section = "filter"      filter_zalgo: bool      filter_invites: bool @@ -202,6 +202,7 @@ class Filtering(metaclass=YAMLGetter):      domain_blacklist: List[str]      watched_expressions: List[str]      guild_invite_whitelist: List[str] +    vanity_url_whitelist: List[str]      channel_whitelist: List[int]      role_whitelist: List[int] diff --git a/config-default.yml b/config-default.yml index eeeb5fb34..06117ef05 100644 --- a/config-default.yml +++ b/config-default.yml @@ -90,7 +90,7 @@ guild:          helpers:                          267630620367257601 -filtering: +filter:      # What do we filter?      filter_zalgo:      true @@ -111,6 +111,9 @@ filtering:          - 010z0Kw1A9ql5c1Qe  # Programming: Meme Edition          - XBGetGp            # STEM +    vanity_url_whitelist: +        - python             # Python Discord +      # Censor doesn't apply to these      channel_whitelist:          - *ADMINS @@ -126,7 +129,6 @@ filtering:          - *MOD_ROLE          - *OWNER_ROLE -  keys:      deploy_bot:  !ENV "DEPLOY_BOT_KEY"      deploy_site: !ENV "DEPLOY_SITE" | 
