diff options
| author | 2022-10-03 20:51:13 +0300 | |
|---|---|---|
| committer | 2022-10-04 15:31:24 +0300 | |
| commit | f91963fd11330bca62cfdbf6c8f2030e14787829 (patch) | |
| tree | 6b9a96c26ac3c262942bd7543a1105fae8d58477 | |
| parent | Handle invalid UI edits (diff) | |
Add filter content processing before posting/patching
| -rw-r--r-- | bot/exts/filtering/_filter_lists/domain.py | 2 | ||||
| -rw-r--r-- | bot/exts/filtering/_filters/domain.py | 15 | ||||
| -rw-r--r-- | bot/exts/filtering/_filters/extension.py | 11 | ||||
| -rw-r--r-- | bot/exts/filtering/_filters/filter.py | 9 | ||||
| -rw-r--r-- | bot/exts/filtering/_filters/invite.py | 23 | ||||
| -rw-r--r-- | bot/exts/filtering/_filters/token.py | 13 | ||||
| -rw-r--r-- | bot/exts/filtering/_ui.py | 7 | ||||
| -rw-r--r-- | bot/exts/filtering/filtering.py | 14 |
8 files changed, 89 insertions, 5 deletions
diff --git a/bot/exts/filtering/_filter_lists/domain.py b/bot/exts/filtering/_filter_lists/domain.py index 6e12dad41..c407108ca 100644 --- a/bot/exts/filtering/_filter_lists/domain.py +++ b/bot/exts/filtering/_filter_lists/domain.py @@ -16,7 +16,7 @@ from bot.exts.filtering._utils import clean_input if typing.TYPE_CHECKING: from bot.exts.filtering.filtering import Filtering -URL_RE = re.compile(r"https?://([^\s]+)", flags=re.IGNORECASE) +URL_RE = re.compile(r"https?://(\S+)", flags=re.IGNORECASE) class DomainsList(FilterList): diff --git a/bot/exts/filtering/_filters/domain.py b/bot/exts/filtering/_filters/domain.py index 9f5f97413..2a0cd3c31 100644 --- a/bot/exts/filtering/_filters/domain.py +++ b/bot/exts/filtering/_filters/domain.py @@ -1,3 +1,4 @@ +import re from typing import ClassVar, Optional import tldextract @@ -6,6 +7,8 @@ from pydantic import BaseModel from bot.exts.filtering._filter_context import FilterContext from bot.exts.filtering._filters.filter import Filter +URL_RE = re.compile(r"(?:https?://)?(\S+?)[\\/]*", flags=re.IGNORECASE) + class ExtraDomainSettings(BaseModel): """Extra settings for how domains should be matched in a message.""" @@ -43,3 +46,15 @@ class DomainFilter(Filter): ctx.notification_domain = self.content return not self.extra_fields.exact or self.content == found_url return False + + @classmethod + async def process_content(cls, content: str) -> str: + """ + Process the content into a form which will work with the filtering. + + A ValueError should be raised if the content can't be used. + """ + match = URL_RE.fullmatch(content) + if not match or not match.group(1): + raise ValueError(f"`{content}` is not a URL.") + return match.group(1) diff --git a/bot/exts/filtering/_filters/extension.py b/bot/exts/filtering/_filters/extension.py index 1a2ab8617..926a6a2fb 100644 --- a/bot/exts/filtering/_filters/extension.py +++ b/bot/exts/filtering/_filters/extension.py @@ -14,3 +14,14 @@ class ExtensionFilter(Filter): def triggered_on(self, ctx: FilterContext) -> bool: """Searches for an attachment extension in the context content, given as a set of extensions.""" return self.content in ctx.content + + @classmethod + async def process_content(cls, content: str) -> str: + """ + Process the content into a form which will work with the filtering. + + A ValueError should be raised if the content can't be used. + """ + if not content.startswith("."): + content = f".{content}" + return content diff --git a/bot/exts/filtering/_filters/filter.py b/bot/exts/filtering/_filters/filter.py index 92393871a..957957d83 100644 --- a/bot/exts/filtering/_filters/filter.py +++ b/bot/exts/filtering/_filters/filter.py @@ -48,6 +48,15 @@ class Filter(FieldRequiring): else: return True, None + @classmethod + async def process_content(cls, content: str) -> str: + """ + Process the content into a form which will work with the filtering. + + A ValueError should be raised if the content can't be used. + """ + return content + def __str__(self) -> str: """A string representation of the filter.""" string = f"#{self.id}. `{self.content}`" diff --git a/bot/exts/filtering/_filters/invite.py b/bot/exts/filtering/_filters/invite.py index 5a9924833..e0f469520 100644 --- a/bot/exts/filtering/_filters/invite.py +++ b/bot/exts/filtering/_filters/invite.py @@ -1,3 +1,7 @@ +from botcore.utils.regex import DISCORD_INVITE +from discord import NotFound + +import bot from bot.exts.filtering._filter_context import FilterContext from bot.exts.filtering._filters.filter import Filter @@ -18,3 +22,22 @@ class InviteFilter(Filter): def triggered_on(self, ctx: FilterContext) -> bool: """Searches for a guild ID in the context content, given as a set of IDs.""" return self.content in ctx.content + + @classmethod + async def process_content(cls, content: str) -> str: + """ + Process the content into a form which will work with the filtering. + + A ValueError should be raised if the content can't be used. + """ + match = DISCORD_INVITE.fullmatch(content) + if not match or not match.group("invite"): + raise ValueError(f"`{content}` is not a valid Discord invite.") + invite_code = match.group("invite") + try: + invite = await bot.instance.fetch_invite(invite_code) + except NotFound: + raise ValueError(f"`{invite_code}` is not a valid Discord invite code.") + if not invite.guild: + raise ValueError("Did you just try to add a group DM?") + return str(invite.guild.id) diff --git a/bot/exts/filtering/_filters/token.py b/bot/exts/filtering/_filters/token.py index c955b269b..a4c646c5a 100644 --- a/bot/exts/filtering/_filters/token.py +++ b/bot/exts/filtering/_filters/token.py @@ -18,3 +18,16 @@ class TokenFilter(Filter): ctx.matches.append(match[0]) return True return False + + @classmethod + async def process_content(cls, content: str) -> str: + """ + Process the content into a form which will work with the filtering. + + A ValueError should be raised if the content can't be used. + """ + try: + re.compile(content) + except re.error as e: + raise ValueError(str(e)) + return content diff --git a/bot/exts/filtering/_ui.py b/bot/exts/filtering/_ui.py index 7030bf07b..12d1f213d 100644 --- a/bot/exts/filtering/_ui.py +++ b/bot/exts/filtering/_ui.py @@ -488,6 +488,11 @@ class SettingsEditView(discord.ui.View): except ResponseCodeError as e: await interaction.message.reply(embed=format_response_error(e)) await interaction.message.edit(view=self) + except ValueError as e: + await interaction.message.reply( + embed=Embed(colour=discord.Colour.red(), title="Bad Content", description=str(e)) + ) + await interaction.message.edit(view=self) else: self.stop() @@ -556,7 +561,7 @@ class SettingsEditView(discord.ui.View): # Update the embed with the new content and/or description. self.embed.description = f"`{content}`" if content else "*No content*" - if description is not None and description is not self._REMOVE: + if description and description is not self._REMOVE: self.embed.description += f" - {description}" if setting_name: diff --git a/bot/exts/filtering/filtering.py b/bot/exts/filtering/filtering.py index b6153487c..cdbb521fb 100644 --- a/bot/exts/filtering/filtering.py +++ b/bot/exts/filtering/filtering.py @@ -651,9 +651,12 @@ class Filtering(Cog): filter_type = filter_list.get_filter_type(content) if noui: - await self._post_new_filter( - ctx.message, filter_list, list_type, filter_type, content, description, settings, filter_settings - ) + try: + await self._post_new_filter( + ctx.message, filter_list, list_type, filter_type, content, description, settings, filter_settings + ) + except ValueError as e: + raise BadArgument(str(e)) else: embed = Embed(colour=Colour.blue()) @@ -710,6 +713,8 @@ class Filtering(Cog): if not valid: raise BadArgument(f"Error while validating filter-specific settings: {error_msg}") + content = await filter_type.process_content(content) + list_id = filter_list.list_ids[list_type] description = description or None payload = { @@ -738,6 +743,9 @@ class Filtering(Cog): if not valid: raise BadArgument(f"Error while validating filter-specific settings: {error_msg}") + if content != filter_.content: + content = await filter_type.process_content(content) + # If the setting is not in `settings`, the override was either removed, or there wasn't one in the first place. for current_settings in (filter_.actions, filter_.validations): if current_settings: |