From fdba078cb814e3b4cbed9dda377eef4d59114549 Mon Sep 17 00:00:00 2001 From: ajax146 <31014239+ajax146@users.noreply.github.com> Date: Mon, 13 Apr 2026 17:14:38 -0700 Subject: [PATCH 1/5] Add honeypot function feature --- techsupport_bot/functions/honeypot.py | 76 +++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 techsupport_bot/functions/honeypot.py diff --git a/techsupport_bot/functions/honeypot.py b/techsupport_bot/functions/honeypot.py new file mode 100644 index 00000000..e15022af --- /dev/null +++ b/techsupport_bot/functions/honeypot.py @@ -0,0 +1,76 @@ +"""The file that holds the honeypot function""" + +from __future__ import annotations + +import io +from typing import TYPE_CHECKING, Self + +import discord +import munch +from botlogging import LogContext, LogLevel +from core import cogs, extensionconfig +from discord.ext import commands +from functions import automod + +if TYPE_CHECKING: + import bot + + +async def setup(bot: bot.TechSupportBot) -> None: + """Adds the cog to the bot. Setups config + + Args: + bot (bot.TechSupportBot): The bot object to register the cog with + """ + config = extensionconfig.ExtensionConfig() + config.add( + key="channels", + datatype="list", + title="Honeypot channels", + description=("The list of channel ID's that are honeypots"), + default=[], + ) + await bot.add_cog(HoneyPot(bot=bot, extension_name="honeypot")) + bot.add_extension_config("honeypot", config) + + +class HoneyPot(cogs.MatchCog): + """The pasting module""" + + async def match( + self: Self, config: munch.Munch, ctx: commands.Context, content: str + ) -> bool: + """Checks to see if a message should be considered for a paste + + Args: + config (munch.Munch): The config of the guild to check + ctx (commands.Context): The context of the original message + content (str): The string representation of the message + + Returns: + bool: Whether the message should be inspected for a paste + """ + # If the channel isn't a honeypot, do nothing. + if not str(ctx.channel.id) in config.extensions.honeypot.channels.value: + return False + return True + + async def response( + self: Self, + config: munch.Munch, + ctx: commands.Context, + content: str, + result: bool, + ) -> None: + """Handles a paste check + + Args: + config (munch.Munch): The config of the guild where the message was sent + ctx (commands.Context): The context the message was sent in + content (str): The string content of the message + result (bool): What the match() function returned + """ + # Temporary ban and unban. + # This should be replaced with a guild wide purge when discord.py can be updated. + await ctx.author.ban(delete_message_days=1, reason="triggered honeypot") + await ctx.guild.unban(ctx.author, reason="triggered honeypot") From da28e48972fab6bd5731737b10e43f0d98b9a68d Mon Sep 17 00:00:00 2001 From: ajax146 <31014239+ajax146@users.noreply.github.com> Date: Mon, 13 Apr 2026 17:15:20 -0700 Subject: [PATCH 2/5] Update docstrings --- techsupport_bot/functions/honeypot.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/techsupport_bot/functions/honeypot.py b/techsupport_bot/functions/honeypot.py index e15022af..8012cf51 100644 --- a/techsupport_bot/functions/honeypot.py +++ b/techsupport_bot/functions/honeypot.py @@ -40,7 +40,7 @@ class HoneyPot(cogs.MatchCog): async def match( self: Self, config: munch.Munch, ctx: commands.Context, content: str ) -> bool: - """Checks to see if a message should be considered for a paste + """Checks to see if a message was sent in a honeypot channel Args: config (munch.Munch): The config of the guild to check @@ -48,7 +48,7 @@ async def match( content (str): The string representation of the message Returns: - bool: Whether the message should be inspected for a paste + bool: Whether the author sent in a honeypot channel """ # If the channel isn't a honeypot, do nothing. if not str(ctx.channel.id) in config.extensions.honeypot.channels.value: @@ -62,7 +62,7 @@ async def response( content: str, result: bool, ) -> None: - """Handles a paste check + """Handles a honeypot check Args: config (munch.Munch): The config of the guild where the message was sent From bad842c232bd946ccea00e34a1a4e5d9010d7cd8 Mon Sep 17 00:00:00 2001 From: ajax146 <31014239+ajax146@users.noreply.github.com> Date: Mon, 13 Apr 2026 17:26:34 -0700 Subject: [PATCH 3/5] Add logging --- techsupport_bot/functions/honeypot.py | 31 ++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/techsupport_bot/functions/honeypot.py b/techsupport_bot/functions/honeypot.py index 8012cf51..73755351 100644 --- a/techsupport_bot/functions/honeypot.py +++ b/techsupport_bot/functions/honeypot.py @@ -2,15 +2,13 @@ from __future__ import annotations -import io +import datetime from typing import TYPE_CHECKING, Self import discord import munch -from botlogging import LogContext, LogLevel from core import cogs, extensionconfig from discord.ext import commands -from functions import automod if TYPE_CHECKING: import bot @@ -74,3 +72,30 @@ async def response( # This should be replaced with a guild wide purge when discord.py can be updated. await ctx.author.ban(delete_message_days=1, reason="triggered honeypot") await ctx.guild.unban(ctx.author, reason="triggered honeypot") + + # Send an alert in the alert channel, if its configured + try: + alert_channel = ctx.guild.get_channel(int(config.moderation.alert_channel)) + except TypeError: + alert_channel = None + + if not alert_channel: + return + + embed = discord.Embed(title="Honeypot triggered") + embed.add_field( + name="Offending member", + value=f"{ctx.author.global_name} ({ctx.author.name})", + ) + embed.add_field(name="Message text", value=ctx.message.clean_content[:500]) + embed.add_field( + name="Number of attachments", value=len(ctx.message.attachments) + ) + embed.color = discord.Color.red() + embed.timestamp = datetime.datetime.utcnow() + + embed.set_footer( + text=f"Author ID: {ctx.author.id} • Message ID: {ctx.message.id}" + ) + + await alert_channel.send(embed=embed) From d8913722476239ee6ab10f174ebc2ecf566fdb7c Mon Sep 17 00:00:00 2001 From: ajax146 <31014239+ajax146@users.noreply.github.com> Date: Mon, 13 Apr 2026 17:52:06 -0700 Subject: [PATCH 4/5] Add message edit feature --- techsupport_bot/functions/honeypot.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/techsupport_bot/functions/honeypot.py b/techsupport_bot/functions/honeypot.py index 73755351..7474a555 100644 --- a/techsupport_bot/functions/honeypot.py +++ b/techsupport_bot/functions/honeypot.py @@ -99,3 +99,12 @@ async def response( ) await alert_channel.send(embed=embed) + + # Get only message in the channel and edit the description + # Just in case, we make sure we pick the first message in the channel, as a foolproof method + history = ctx.channel.history(oldest_first=True, limit=1) + starting_message = await anext(history) + starting_embed = starting_message.embeds[0] + starting_embed.description = f"{starting_embed.description.split(':')[0]}: {int(starting_embed.description.split(':')[1]) + 1}" + + await starting_message.edit(embeds=[starting_embed]) From 37e24ebfa240635ef8f23cd2bcffe3638b2686a9 Mon Sep 17 00:00:00 2001 From: ajax146 <31014239+ajax146@users.noreply.github.com> Date: Mon, 13 Apr 2026 17:55:11 -0700 Subject: [PATCH 5/5] Formatting changes --- techsupport_bot/functions/honeypot.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/techsupport_bot/functions/honeypot.py b/techsupport_bot/functions/honeypot.py index 7474a555..fc681f34 100644 --- a/techsupport_bot/functions/honeypot.py +++ b/techsupport_bot/functions/honeypot.py @@ -105,6 +105,9 @@ async def response( history = ctx.channel.history(oldest_first=True, limit=1) starting_message = await anext(history) starting_embed = starting_message.embeds[0] - starting_embed.description = f"{starting_embed.description.split(':')[0]}: {int(starting_embed.description.split(':')[1]) + 1}" + new_actions = int(starting_embed.description.split(":")[1]) + 1 + starting_embed.description = ( + f"{starting_embed.description.split(':')[0]}: {new_actions}" + ) await starting_message.edit(embeds=[starting_embed])