From b578c45eb7e61a68941d801e2f51cea78f0488f9 Mon Sep 17 00:00:00 2001 From: Noelle Wang <73260931+No767@users.noreply.github.com> Date: Sun, 21 Jan 2024 01:55:11 -0800 Subject: [PATCH] Include proper security practices (#48) --- bot/cogs/admin.py | 2 +- bot/cogs/config.py | 2 ++ bot/cogs/tickets.py | 5 +++++ bot/libs/utils/errors.py | 34 ++++++++++++++++------------------ 4 files changed, 24 insertions(+), 19 deletions(-) diff --git a/bot/cogs/admin.py b/bot/cogs/admin.py index 15bbec7..9a2dcd7 100644 --- a/bot/cogs/admin.py +++ b/bot/cogs/admin.py @@ -104,7 +104,7 @@ def reload_lib_modules(self, module: str) -> list[tuple[str, str]]: # To learn more about it, see the link below (and ?tag ass on the dpy server): # https://about.abstractumbra.dev/discord.py/2023/01/29/sync-command-example.html @commands.guild_only() - @commands.command(name="sync") + @commands.command(name="sync", hidden=True) async def sync( self, ctx: RoboContext, diff --git a/bot/cogs/config.py b/bot/cogs/config.py index 258b81e..1e5b6a3 100644 --- a/bot/cogs/config.py +++ b/bot/cogs/config.py @@ -127,6 +127,7 @@ async def config(self, ctx: GuildContext) -> None: if ctx.invoked_subcommand is None: await ctx.send_help(ctx.command) + @commands.cooldown(1, 20, commands.BucketType.guild) @config.command(name="setup", usage="ticket_name: log_name: ") async def setup(self, ctx: GuildContext, *, flags: SetupFlags) -> None: """First-time setup for Rodhaj @@ -278,6 +279,7 @@ async def setup(self, ctx: GuildContext, *, flags: SetupFlags) -> None: msg = f"Rodhaj channels successfully created! The ticket channel can be found under {ticket_channel.mention}" await ctx.send(msg) + @commands.cooldown(1, 20, commands.BucketType.guild) @config.command(name="delete") async def delete(self, ctx: GuildContext) -> None: """Permanently deletes Rodhaj channels and tickets.""" diff --git a/bot/cogs/tickets.py b/bot/cogs/tickets.py index 9c09695..3ef86b7 100644 --- a/bot/cogs/tickets.py +++ b/bot/cogs/tickets.py @@ -320,6 +320,7 @@ def get_solved_tag( ### Feature commands @is_ticket_or_dm() + @commands.cooldown(1, 20, commands.BucketType.channel) @commands.hybrid_command(name="close", aliases=["solved", "closed", "resolved"]) async def close(self, ctx: RoboContext) -> None: """Closes the thread""" @@ -356,7 +357,11 @@ async def close(self, ctx: RoboContext) -> None: self.get_ticket_owner_id.cache_invalidate(closed_ticket.id) await self.notify_finished_ticket(ctx, owner_id) + # 10 command invocations per 12 seconds for each member + # These values should not be tripped unless someone is spamming + # https://github.com/Rapptz/RoboDanny/blob/rewrite/cogs/mod.py#L524C9-L524C74 @is_ticket_thread() + @commands.cooldown(10, 12, commands.BucketType.member) @commands.command(name="reply", aliases=["r"]) async def reply( self, ctx: GuildContext, *, message: Annotated[str, commands.clean_content] diff --git a/bot/libs/utils/errors.py b/bot/libs/utils/errors.py index ab220f0..196e9ed 100644 --- a/bot/libs/utils/errors.py +++ b/bot/libs/utils/errors.py @@ -29,27 +29,27 @@ def create_premade_embed(title: str, description: str) -> ErrorEmbed: return embed +def build_cooldown_embed(error: commands.CommandOnCooldown) -> ErrorEmbed: + embed = ErrorEmbed() + embed.timestamp = discord.utils.utcnow() + embed.title = "Command On Cooldown" + embed.description = ( + f"This command is on cooldown. Try again in {error.retry_after:.2f}s" + ) + return embed + + async def send_error_embed(ctx: commands.Context, error: commands.CommandError) -> None: - if isinstance(error, commands.CommandInvokeError) or isinstance( + if isinstance(error, commands.CommandOnCooldown): + await ctx.send(embed=build_cooldown_embed(error)) + elif isinstance(error, commands.CommandInvokeError) or isinstance( error, commands.HybridCommandError ): await ctx.send(embed=produce_error_embed(error)) - elif isinstance(error, commands.CommandNotFound): - await ctx.send( + elif isinstance(error, commands.NoPrivateMessage): + await ctx.author.send( embed=create_premade_embed( - "Command not found", - "The command you were looking for could not be found", - ) - ) - elif isinstance(error, commands.NotOwner): - # Basically completely silence it making people not know what happened - return - elif isinstance(error, commands.MissingPermissions): - missing_perms = ", ".join(error.missing_permissions).rstrip(",") - await ctx.send( - embed=create_premade_embed( - "Missing Permissions", - f"You are missing the following permissions: {missing_perms}", + "Guild Only", "This command cannot be used in private messages" ) ) elif isinstance(error, commands.MissingRequiredArgument): @@ -59,5 +59,3 @@ async def send_error_embed(ctx: commands.Context, error: commands.CommandError) f"You are missing the following argument(s): {error.param.name}", ) ) - else: - await ctx.send(embed=produce_error_embed(error))