aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorGravatar mbaruh <[email protected]>2023-01-22 21:21:57 +0200
committerGravatar mbaruh <[email protected]>2023-01-22 21:21:57 +0200
commit44bf2477d675035bb4024d7cd4fa400d7f2b8942 (patch)
treed742b06ad064163168254f29e71b316e1499770b /tests
parentImprove logging (diff)
Bring back old system tests
Diffstat (limited to 'tests')
-rw-r--r--tests/bot/exts/filtering/test_discord_token_filter.py276
-rw-r--r--tests/bot/exts/filtering/test_extension_filter.py139
-rw-r--r--tests/bot/exts/filtering/test_settings_entries.py66
-rw-r--r--tests/bot/exts/filtering/test_token_filter.py (renamed from tests/bot/exts/filtering/test_filters.py)14
4 files changed, 484 insertions, 11 deletions
diff --git a/tests/bot/exts/filtering/test_discord_token_filter.py b/tests/bot/exts/filtering/test_discord_token_filter.py
new file mode 100644
index 000000000..ef124e6ff
--- /dev/null
+++ b/tests/bot/exts/filtering/test_discord_token_filter.py
@@ -0,0 +1,276 @@
+import unittest
+from re import Match
+from unittest import mock
+from unittest.mock import MagicMock, patch
+
+import arrow
+
+from bot.exts.filtering._filter_context import Event, FilterContext
+from bot.exts.filtering._filters.unique import discord_token
+from bot.exts.filtering._filters.unique.discord_token import DiscordTokenFilter, Token
+from tests.helpers import MockBot, MockMember, MockMessage, MockTextChannel, autospec
+
+
+class DiscordTokenFilterTests(unittest.IsolatedAsyncioTestCase):
+ """Tests the DiscordTokenFilter class."""
+
+ def setUp(self):
+ """Adds the filter, a bot, and a message to the instance for usage in tests."""
+ now = arrow.utcnow().timestamp()
+ self.filter = DiscordTokenFilter({
+ "id": 1,
+ "content": "discord_token",
+ "description": None,
+ "settings": {},
+ "additional_field": "{}", # noqa: P103
+ "created_at": now,
+ "updated_at": now
+ })
+
+ self.msg = MockMessage(id=555, content="hello world")
+ self.msg.author.__str__ = MagicMock(return_value=self.msg.author.name)
+
+ member = MockMember(id=123)
+ channel = MockTextChannel(id=345)
+ self.ctx = FilterContext(Event.MESSAGE, member, channel, "", self.msg)
+
+ def test_extract_user_id_valid(self):
+ """Should consider user IDs valid if they decode into an integer ID."""
+ id_pairs = (
+ ("NDcyMjY1OTQzMDYyNDEzMzMy", 472265943062413332),
+ ("NDc1MDczNjI5Mzk5NTQ3OTA0", 475073629399547904),
+ ("NDY3MjIzMjMwNjUwNzc3NjQx", 467223230650777641),
+ )
+
+ for token_id, user_id in id_pairs:
+ with self.subTest(token_id=token_id):
+ result = DiscordTokenFilter.extract_user_id(token_id)
+ self.assertEqual(result, user_id)
+
+ def test_extract_user_id_invalid(self):
+ """Should consider non-digit and non-ASCII IDs invalid."""
+ ids = (
+ ("SGVsbG8gd29ybGQ", "non-digit ASCII"),
+ ("0J_RgNC40LLQtdGCINC80LjRgA", "cyrillic text"),
+ ("4pO14p6L4p6C4pG34p264pGl8J-EiOKSj-KCieKBsA", "Unicode digits"),
+ ("4oaA4oaB4oWh4oWi4Lyz4Lyq4Lyr4LG9", "Unicode numerals"),
+ ("8J2fjvCdn5nwnZ-k8J2fr_Cdn7rgravvvJngr6c", "Unicode decimals"),
+ ("{hello}[world]&(bye!)", "ASCII invalid Base64"),
+ ("Þíß-ï§-ňøẗ-våłìÐ", "Unicode invalid Base64"),
+ )
+
+ for user_id, msg in ids:
+ with self.subTest(msg=msg):
+ result = DiscordTokenFilter.extract_user_id(user_id)
+ self.assertIsNone(result)
+
+ def test_is_valid_timestamp_valid(self):
+ """Should consider timestamps valid if they're greater than the Discord epoch."""
+ timestamps = (
+ "XsyRkw",
+ "Xrim9Q",
+ "XsyR-w",
+ "XsySD_",
+ "Dn9r_A",
+ )
+
+ for timestamp in timestamps:
+ with self.subTest(timestamp=timestamp):
+ result = DiscordTokenFilter.is_valid_timestamp(timestamp)
+ self.assertTrue(result)
+
+ def test_is_valid_timestamp_invalid(self):
+ """Should consider timestamps invalid if they're before Discord epoch or can't be parsed."""
+ timestamps = (
+ ("B4Yffw", "DISCORD_EPOCH - TOKEN_EPOCH - 1"),
+ ("ew", "123"),
+ ("AoIKgA", "42076800"),
+ ("{hello}[world]&(bye!)", "ASCII invalid Base64"),
+ ("Þíß-ï§-ňøẗ-våłìÐ", "Unicode invalid Base64"),
+ )
+
+ for timestamp, msg in timestamps:
+ with self.subTest(msg=msg):
+ result = DiscordTokenFilter.is_valid_timestamp(timestamp)
+ self.assertFalse(result)
+
+ def test_is_valid_hmac_valid(self):
+ """Should consider an HMAC valid if it has at least 3 unique characters."""
+ valid_hmacs = (
+ "VXmErH7j511turNpfURmb0rVNm8",
+ "Ysnu2wacjaKs7qnoo46S8Dm2us8",
+ "sJf6omBPORBPju3WJEIAcwW9Zds",
+ "s45jqDV_Iisn-symw0yDRrk_jf4",
+ )
+
+ for hmac in valid_hmacs:
+ with self.subTest(msg=hmac):
+ result = DiscordTokenFilter.is_maybe_valid_hmac(hmac)
+ self.assertTrue(result)
+
+ def test_is_invalid_hmac_invalid(self):
+ """Should consider an HMAC invalid if has fewer than 3 unique characters."""
+ invalid_hmacs = (
+ ("xxxxxxxxxxxxxxxxxx", "Single character"),
+ ("XxXxXxXxXxXxXxXxXx", "Single character alternating case"),
+ ("ASFasfASFasfASFASsf", "Three characters alternating-case"),
+ ("asdasdasdasdasdasdasd", "Three characters one case"),
+ )
+
+ for hmac, msg in invalid_hmacs:
+ with self.subTest(msg=msg):
+ result = DiscordTokenFilter.is_maybe_valid_hmac(hmac)
+ self.assertFalse(result)
+
+ async def test_no_trigger_when_no_token(self):
+ """False should be returned if the message doesn't contain a Discord token."""
+ return_value = await self.filter.triggered_on(self.ctx)
+
+ self.assertFalse(return_value)
+
+ @autospec(DiscordTokenFilter, "extract_user_id", "is_valid_timestamp", "is_maybe_valid_hmac")
+ @autospec("bot.exts.filtering._filters.unique.discord_token", "Token")
+ @autospec("bot.exts.filtering._filters.unique.discord_token", "TOKEN_RE")
+ def test_find_token_valid_match(
+ self,
+ token_re,
+ token_cls,
+ extract_user_id,
+ is_valid_timestamp,
+ is_maybe_valid_hmac,
+ ):
+ """The first match with a valid user ID, timestamp, and HMAC should be returned as a `Token`."""
+ matches = [
+ mock.create_autospec(Match, spec_set=True, instance=True),
+ mock.create_autospec(Match, spec_set=True, instance=True),
+ ]
+ tokens = [
+ mock.create_autospec(Token, spec_set=True, instance=True),
+ mock.create_autospec(Token, spec_set=True, instance=True),
+ ]
+
+ token_re.finditer.return_value = matches
+ token_cls.side_effect = tokens
+ extract_user_id.side_effect = (None, True) # The 1st match will be invalid, 2nd one valid.
+ is_valid_timestamp.return_value = True
+ is_maybe_valid_hmac.return_value = True
+
+ return_value = DiscordTokenFilter.find_token_in_message(self.msg)
+
+ self.assertEqual(tokens[1], return_value)
+
+ @autospec(DiscordTokenFilter, "extract_user_id", "is_valid_timestamp", "is_maybe_valid_hmac")
+ @autospec("bot.exts.filtering._filters.unique.discord_token", "Token")
+ @autospec("bot.exts.filtering._filters.unique.discord_token", "TOKEN_RE")
+ def test_find_token_invalid_matches(
+ self,
+ token_re,
+ token_cls,
+ extract_user_id,
+ is_valid_timestamp,
+ is_maybe_valid_hmac,
+ ):
+ """None should be returned if no matches have valid user IDs, HMACs, and timestamps."""
+ token_re.finditer.return_value = [mock.create_autospec(Match, spec_set=True, instance=True)]
+ token_cls.return_value = mock.create_autospec(Token, spec_set=True, instance=True)
+ extract_user_id.return_value = None
+ is_valid_timestamp.return_value = False
+ is_maybe_valid_hmac.return_value = False
+
+ return_value = DiscordTokenFilter.find_token_in_message(self.msg)
+
+ self.assertIsNone(return_value)
+
+ def test_regex_invalid_tokens(self):
+ """Messages without anything looking like a token are not matched."""
+ tokens = (
+ "",
+ "lemon wins",
+ "..",
+ "x.y",
+ "x.y.",
+ ".y.z",
+ ".y.",
+ "..z",
+ "x..z",
+ " . . ",
+ "\n.\n.\n",
+ "hellö.world.bye",
+ "base64.nötbåse64.morebase64",
+ "19jd3J.dfkm3d.€víł§tüff",
+ )
+
+ for token in tokens:
+ with self.subTest(token=token):
+ results = discord_token.TOKEN_RE.findall(token)
+ self.assertEqual(len(results), 0)
+
+ def test_regex_valid_tokens(self):
+ """Messages that look like tokens should be matched."""
+ # Don't worry, these tokens have been invalidated.
+ tokens = (
+ "NDcyMjY1OTQzMDYy_DEzMz-y.XsyRkw.VXmErH7j511turNpfURmb0rVNm8",
+ "NDcyMjY1OTQzMDYyNDEzMzMy.Xrim9Q.Ysnu2wacjaKs7qnoo46S8Dm2us8",
+ "NDc1MDczNjI5Mzk5NTQ3OTA0.XsyR-w.sJf6omBPORBPju3WJEIAcwW9Zds",
+ "NDY3MjIzMjMwNjUwNzc3NjQx.XsySD_.s45jqDV_Iisn-symw0yDRrk_jf4",
+ )
+
+ for token in tokens:
+ with self.subTest(token=token):
+ results = discord_token.TOKEN_RE.fullmatch(token)
+ self.assertIsNotNone(results, f"{token} was not matched by the regex")
+
+ def test_regex_matches_multiple_valid(self):
+ """Should support multiple matches in the middle of a string."""
+ token_1 = "NDY3MjIzMjMwNjUwNzc3NjQx.XsyWGg.uFNEQPCc4ePwGh7egG8UicQssz8"
+ token_2 = "NDcyMjY1OTQzMDYyNDEzMzMy.XsyWMw.l8XPnDqb0lp-EiQ2g_0xVFT1pyc"
+ message = f"garbage {token_1} hello {token_2} world"
+
+ results = discord_token.TOKEN_RE.finditer(message)
+ results = [match[0] for match in results]
+ self.assertCountEqual((token_1, token_2), results)
+
+ @autospec("bot.exts.filtering._filters.unique.discord_token", "LOG_MESSAGE")
+ def test_format_log_message(self, log_message):
+ """Should correctly format the log message with info from the message and token."""
+ token = Token("NDcyMjY1OTQzMDYyNDEzMzMy", "XsySD_", "s45jqDV_Iisn-symw0yDRrk_jf4")
+ log_message.format.return_value = "Howdy"
+
+ return_value = DiscordTokenFilter.format_log_message(self.msg.author, self.msg.channel, token)
+
+ self.assertEqual(return_value, log_message.format.return_value)
+
+ @patch("bot.instance", MockBot())
+ @autospec("bot.exts.filtering._filters.unique.discord_token", "UNKNOWN_USER_LOG_MESSAGE")
+ @autospec("bot.exts.filtering._filters.unique.discord_token", "get_or_fetch_member")
+ async def test_format_userid_log_message_unknown(self, get_or_fetch_member, unknown_user_log_message):
+ """Should correctly format the user ID portion when the actual user it belongs to is unknown."""
+ token = Token("NDcyMjY1OTQzMDYyNDEzMzMy", "XsySD_", "s45jqDV_Iisn-symw0yDRrk_jf4")
+ unknown_user_log_message.format.return_value = " Partner"
+ get_or_fetch_member.return_value = None
+
+ return_value = await DiscordTokenFilter.format_userid_log_message(token)
+
+ self.assertEqual(return_value, (unknown_user_log_message.format.return_value, False))
+
+ @patch("bot.instance", MockBot())
+ @autospec("bot.exts.filtering._filters.unique.discord_token", "KNOWN_USER_LOG_MESSAGE")
+ async def test_format_userid_log_message_bot(self, known_user_log_message):
+ """Should correctly format the user ID portion when the ID belongs to a known bot."""
+ token = Token("NDcyMjY1OTQzMDYyNDEzMzMy", "XsySD_", "s45jqDV_Iisn-symw0yDRrk_jf4")
+ known_user_log_message.format.return_value = " Partner"
+
+ return_value = await DiscordTokenFilter.format_userid_log_message(token)
+
+ self.assertEqual(return_value, (known_user_log_message.format.return_value, True))
+
+ @patch("bot.instance", MockBot())
+ @autospec("bot.exts.filtering._filters.unique.discord_token", "KNOWN_USER_LOG_MESSAGE")
+ async def test_format_log_message_user_token_user(self, user_token_message):
+ """Should correctly format the user ID portion when the ID belongs to a known user."""
+ token = Token("NDY3MjIzMjMwNjUwNzc3NjQx", "XsySD_", "s45jqDV_Iisn-symw0yDRrk_jf4")
+ user_token_message.format.return_value = "Partner"
+
+ return_value = await DiscordTokenFilter.format_userid_log_message(token)
+
+ self.assertEqual(return_value, (user_token_message.format.return_value, True))
diff --git a/tests/bot/exts/filtering/test_extension_filter.py b/tests/bot/exts/filtering/test_extension_filter.py
new file mode 100644
index 000000000..0ad41116d
--- /dev/null
+++ b/tests/bot/exts/filtering/test_extension_filter.py
@@ -0,0 +1,139 @@
+import unittest
+from unittest.mock import MagicMock, patch
+
+import arrow
+
+from bot.constants import Channels
+from bot.exts.filtering._filter_context import Event, FilterContext
+from bot.exts.filtering._filter_lists import extension
+from bot.exts.filtering._filter_lists.extension import ExtensionsList
+from bot.exts.filtering._filter_lists.filter_list import ListType
+from tests.helpers import MockAttachment, MockBot, MockMember, MockMessage, MockTextChannel
+
+BOT = MockBot()
+
+
+class ExtensionsListTests(unittest.IsolatedAsyncioTestCase):
+ """Test the ExtensionsList class."""
+
+ def setUp(self):
+ """Sets up fresh objects for each test."""
+ self.filter_list = ExtensionsList(MagicMock())
+ now = arrow.utcnow().timestamp()
+ filters = []
+ self.whitelist = [".first", ".second", ".third"]
+ for i, filter_content in enumerate(self.whitelist, start=1):
+ filters.append({
+ "id": i, "content": filter_content, "description": None, "settings": {},
+ "additional_field": "{}", "created_at": now, "updated_at": now # noqa: P103
+ })
+ self.filter_list.add_list({
+ "id": 1,
+ "list_type": 1,
+ "created_at": now,
+ "updated_at": now,
+ "settings": {},
+ "filters": filters
+ })
+
+ self.message = MockMessage()
+ member = MockMember(id=123)
+ channel = MockTextChannel(id=345)
+ self.ctx = FilterContext(Event.MESSAGE, member, channel, "", self.message)
+
+ @patch("bot.instance", BOT)
+ async def test_message_with_allowed_attachment(self):
+ """Messages with allowed extensions should trigger the whitelist and result in no actions or messages."""
+ attachment = MockAttachment(filename="python.first")
+ self.message.attachments = [attachment]
+
+ result = await self.filter_list.actions_for(self.ctx)
+
+ self.assertEqual(result, (None, [], {ListType.ALLOW: [self.filter_list[ListType.ALLOW].filters[1]]}))
+
+ @patch("bot.instance", BOT)
+ async def test_message_without_attachment(self):
+ """Messages without attachments should return no triggers, messages, or actions."""
+ result = await self.filter_list.actions_for(self.ctx)
+
+ self.assertEqual(result, (None, [], {}))
+
+ @patch("bot.instance", BOT)
+ async def test_message_with_illegal_extension(self):
+ """A message with an illegal extension shouldn't trigger the whitelist, and return some action and message."""
+ attachment = MockAttachment(filename="python.disallowed")
+ self.message.attachments = [attachment]
+
+ result = await self.filter_list.actions_for(self.ctx)
+
+ self.assertEqual(result, ({}, ["`.disallowed`"], {ListType.ALLOW: []}))
+
+ @patch("bot.instance", BOT)
+ async def test_python_file_redirect_embed_description(self):
+ """A message containing a .py file should result in an embed redirecting the user to our paste site."""
+ attachment = MockAttachment(filename="python.py")
+ self.message.attachments = [attachment]
+
+ await self.filter_list.actions_for(self.ctx)
+
+ self.assertEqual(self.ctx.dm_embed, extension.PY_EMBED_DESCRIPTION)
+
+ @patch("bot.instance", BOT)
+ async def test_txt_file_redirect_embed_description(self):
+ """A message containing a .txt/.json/.csv file should result in the correct embed."""
+ test_values = (
+ ("text", ".txt"),
+ ("json", ".json"),
+ ("csv", ".csv"),
+ )
+
+ for file_name, disallowed_extension in test_values:
+ with self.subTest(file_name=file_name, disallowed_extension=disallowed_extension):
+
+ attachment = MockAttachment(filename=f"{file_name}{disallowed_extension}")
+ self.message.attachments = [attachment]
+
+ await self.filter_list.actions_for(self.ctx)
+
+ self.assertEqual(
+ self.ctx.dm_embed,
+ extension.TXT_EMBED_DESCRIPTION.format(
+ blocked_extension=disallowed_extension,
+ )
+ )
+
+ @patch("bot.instance", BOT)
+ async def test_other_disallowed_extension_embed_description(self):
+ """Test the description for a non .py/.txt/.json/.csv disallowed extension."""
+ attachment = MockAttachment(filename="python.disallowed")
+ self.message.attachments = [attachment]
+
+ await self.filter_list.actions_for(self.ctx)
+ meta_channel = BOT.get_channel(Channels.meta)
+
+ self.assertEqual(
+ self.ctx.dm_embed,
+ extension.DISALLOWED_EMBED_DESCRIPTION.format(
+ joined_whitelist=", ".join(self.whitelist),
+ blocked_extensions_str=".disallowed",
+ meta_channel_mention=meta_channel.mention
+ )
+ )
+
+ @patch("bot.instance", BOT)
+ async def test_get_disallowed_extensions(self):
+ """The return value should include all non-whitelisted extensions."""
+ test_values = (
+ ([], []),
+ (self.whitelist, []),
+ ([".first"], []),
+ ([".first", ".disallowed"], ["`.disallowed`"]),
+ ([".disallowed"], ["`.disallowed`"]),
+ ([".disallowed", ".illegal"], ["`.disallowed`", "`.illegal`"]),
+ )
+
+ for extensions, expected_disallowed_extensions in test_values:
+ with self.subTest(extensions=extensions, expected_disallowed_extensions=expected_disallowed_extensions):
+ self.message.attachments = [MockAttachment(filename=f"filename{ext}") for ext in extensions]
+ result = await self.filter_list.actions_for(self.ctx)
+ self.assertCountEqual(result[1], expected_disallowed_extensions)
diff --git a/tests/bot/exts/filtering/test_settings_entries.py b/tests/bot/exts/filtering/test_settings_entries.py
index 34b155d6b..5a1eb6fe6 100644
--- a/tests/bot/exts/filtering/test_settings_entries.py
+++ b/tests/bot/exts/filtering/test_settings_entries.py
@@ -50,7 +50,9 @@ class FilterTests(unittest.TestCase):
def test_context_doesnt_trigger_for_empty_channel_scope(self):
"""A filter is enabled for all channels by default."""
channel = MockTextChannel()
- scope = ChannelScope(disabled_channels=None, disabled_categories=None, enabled_channels=None)
+ scope = ChannelScope(
+ disabled_channels=None, disabled_categories=None, enabled_channels=None, enabled_categories=None
+ )
self.ctx.channel = channel
result = scope.triggers_on(self.ctx)
@@ -60,7 +62,9 @@ class FilterTests(unittest.TestCase):
def test_context_doesnt_trigger_for_disabled_channel(self):
"""A filter shouldn't trigger if it's been disabled in the channel."""
channel = MockTextChannel(id=123)
- scope = ChannelScope(disabled_channels=["123"], disabled_categories=None, enabled_channels=None)
+ scope = ChannelScope(
+ disabled_channels=["123"], disabled_categories=None, enabled_channels=None, enabled_categories=None
+ )
self.ctx.channel = channel
result = scope.triggers_on(self.ctx)
@@ -70,7 +74,9 @@ class FilterTests(unittest.TestCase):
def test_context_doesnt_trigger_in_disabled_category(self):
"""A filter shouldn't trigger if it's been disabled in the category."""
channel = MockTextChannel(category=MockCategoryChannel(id=456))
- scope = ChannelScope(disabled_channels=None, disabled_categories=["456"], enabled_channels=None)
+ scope = ChannelScope(
+ disabled_channels=None, disabled_categories=["456"], enabled_channels=None, enabled_categories=None
+ )
self.ctx.channel = channel
result = scope.triggers_on(self.ctx)
@@ -80,13 +86,51 @@ class FilterTests(unittest.TestCase):
def test_context_triggers_in_enabled_channel_in_disabled_category(self):
"""A filter should trigger in an enabled channel even if it's been disabled in the category."""
channel = MockTextChannel(id=123, category=MockCategoryChannel(id=234))
- scope = ChannelScope(disabled_channels=None, disabled_categories=["234"], enabled_channels=["123"])
+ scope = ChannelScope(
+ disabled_channels=None, disabled_categories=["234"], enabled_channels=["123"], enabled_categories=None
+ )
+ self.ctx.channel = channel
+
+ result = scope.triggers_on(self.ctx)
+
+ self.assertTrue(result)
+
+ def test_context_triggers_inside_enabled_category(self):
+ """A filter shouldn't trigger outside enabled categories, if there are any."""
+ channel = MockTextChannel(id=123, category=MockCategoryChannel(id=234))
+ scope = ChannelScope(
+ disabled_channels=None, disabled_categories=None, enabled_channels=None, enabled_categories=["234"]
+ )
self.ctx.channel = channel
result = scope.triggers_on(self.ctx)
self.assertTrue(result)
+ def test_context_doesnt_trigger_outside_enabled_category(self):
+ """A filter shouldn't trigger outside enabled categories, if there are any."""
+ channel = MockTextChannel(id=123, category=MockCategoryChannel(id=234))
+ scope = ChannelScope(
+ disabled_channels=None, disabled_categories=None, enabled_channels=None, enabled_categories=["789"]
+ )
+ self.ctx.channel = channel
+
+ result = scope.triggers_on(self.ctx)
+
+ self.assertFalse(result)
+
+ def test_context_doesnt_trigger_inside_disabled_channel_in_enabled_category(self):
+ """A filter shouldn't trigger outside enabled categories, if there are any."""
+ channel = MockTextChannel(id=123, category=MockCategoryChannel(id=234))
+ scope = ChannelScope(
+ disabled_channels=["123"], disabled_categories=None, enabled_channels=None, enabled_categories=["234"]
+ )
+ self.ctx.channel = channel
+
+ result = scope.triggers_on(self.ctx)
+
+ self.assertFalse(result)
+
def test_filtering_dms_when_necessary(self):
"""A filter correctly ignores or triggers in a channel depending on the value of FilterDM."""
cases = (
@@ -112,14 +156,16 @@ class FilterTests(unittest.TestCase):
infraction_reason="hi",
infraction_duration=10,
dm_content="how",
- dm_embed="what is"
+ dm_embed="what is",
+ infraction_channel=0
)
infraction2 = InfractionAndNotification(
infraction_type="MUTE",
infraction_reason="there",
infraction_duration=20,
dm_content="are you",
- dm_embed="your name"
+ dm_embed="your name",
+ infraction_channel=0
)
result = infraction1 | infraction2
@@ -132,6 +178,7 @@ class FilterTests(unittest.TestCase):
"infraction_duration": 20.0,
"dm_content": "are you",
"dm_embed": "your name",
+ "infraction_channel": 0
}
)
@@ -142,14 +189,16 @@ class FilterTests(unittest.TestCase):
infraction_reason="hi",
infraction_duration=20,
dm_content="",
- dm_embed=""
+ dm_embed="",
+ infraction_channel=0
)
infraction2 = InfractionAndNotification(
infraction_type="BAN",
infraction_reason="",
infraction_duration=10,
dm_content="there",
- dm_embed=""
+ dm_embed="",
+ infraction_channel=0
)
result = infraction1 | infraction2
@@ -162,5 +211,6 @@ class FilterTests(unittest.TestCase):
"infraction_duration": 10.0,
"dm_content": "there",
"dm_embed": "",
+ "infraction_channel": 0
}
)
diff --git a/tests/bot/exts/filtering/test_filters.py b/tests/bot/exts/filtering/test_token_filter.py
index 29b50188a..0dfc8ae9f 100644
--- a/tests/bot/exts/filtering/test_filters.py
+++ b/tests/bot/exts/filtering/test_token_filter.py
@@ -1,11 +1,13 @@
import unittest
+import arrow
+
from bot.exts.filtering._filter_context import Event, FilterContext
from bot.exts.filtering._filters.token import TokenFilter
from tests.helpers import MockMember, MockMessage, MockTextChannel
-class FilterTests(unittest.IsolatedAsyncioTestCase):
+class TokenFilterTests(unittest.IsolatedAsyncioTestCase):
"""Test functionality of the token filter."""
def setUp(self) -> None:
@@ -20,8 +22,12 @@ class FilterTests(unittest.IsolatedAsyncioTestCase):
(r"hi", "oh hi there", True),
(r"hi", "goodbye", False),
(r"bla\d{2,4}", "bla18", True),
- (r"bla\d{2,4}", "bla1", False)
+ (r"bla\d{2,4}", "bla1", False),
+ # See advisory https://github.com/python-discord/bot/security/advisories/GHSA-j8c3-8x46-8pp6
+ (r"TOKEN", "https://google.com TOKEN", True),
+ (r"TOKEN", "https://google.com something else", False)
)
+ now = arrow.utcnow().timestamp()
for pattern, content, expected in test_cases:
with self.subTest(
@@ -34,7 +40,9 @@ class FilterTests(unittest.IsolatedAsyncioTestCase):
"content": pattern,
"description": None,
"settings": {},
- "additional_field": "{}" # noqa: P103
+ "additional_field": "{}", # noqa: P103
+ "created_at": now,
+ "updated_at": now
})
self.ctx.content = content
result = await filter_.triggered_on(self.ctx)