aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar mbaruh <[email protected]>2022-10-03 20:51:13 +0300
committerGravatar mbaruh <[email protected]>2022-10-04 15:31:24 +0300
commitf91963fd11330bca62cfdbf6c8f2030e14787829 (patch)
tree6b9a96c26ac3c262942bd7543a1105fae8d58477
parentHandle invalid UI edits (diff)
Add filter content processing before posting/patching
-rw-r--r--bot/exts/filtering/_filter_lists/domain.py2
-rw-r--r--bot/exts/filtering/_filters/domain.py15
-rw-r--r--bot/exts/filtering/_filters/extension.py11
-rw-r--r--bot/exts/filtering/_filters/filter.py9
-rw-r--r--bot/exts/filtering/_filters/invite.py23
-rw-r--r--bot/exts/filtering/_filters/token.py13
-rw-r--r--bot/exts/filtering/_ui.py7
-rw-r--r--bot/exts/filtering/filtering.py14
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: