diff --git a/redbot/cogs/permissions/permissions.py b/redbot/cogs/permissions/permissions.py index e432f9bf2..03f3110da 100644 --- a/redbot/cogs/permissions/permissions.py +++ b/redbot/cogs/permissions/permissions.py @@ -81,6 +81,11 @@ __version__ = "1.0.0" class Permissions(commands.Cog): """Customise permissions for commands and cogs.""" + # The command groups in this cog should never directly take any configuration actions + # These should be delegated to specific commands so that it remains trivial + # to prevent the guild owner from ever locking themselves out + # see ``Permissions.__permissions_hook`` for more details + def __init__(self, bot: Red): super().__init__() self.bot = bot @@ -108,6 +113,44 @@ class Permissions(commands.Cog): self.config.init_custom(COMMAND, 1) self.config.register_custom(COMMAND) + async def __permissions_hook(self, ctx: commands.Context) -> Optional[bool]: + """ + Purpose of this hook is to prevent guild owner lockouts of permissions specifically + without modifying rule behavior in any other case. + + Guild owner is not special cased outside of these configuration commands + to allow guild owner to restrict the use of potentially damaging commands + such as, but not limited to, cleanup to specific channels. + + Leaving the configuration commands special cased allows guild owners to fix + any misconfigurations. + """ + + if ctx.guild: + if ctx.author == ctx.guild.owner: + # the below should contain all commands from this cog + # which configure or are useful to the + # configuration of guild permissions and should never + # have a potential impact on global configuration + # as well as the parent groups + if ctx.command in ( + self.permissions, # main top level group + self.permissions_acl, # acl group + self.permissions_acl_getguild, + self.permissions_acl_setguild, + self.permissions_acl_updateguild, + self.permissions_addguildrule, + self.permissions_clearguildrules, + self.permissions_removeguildrule, + self.permissions_setdefaultguildrule, + self.permissions_canrun, + self.permissions_explain, + ): + return True # permission rules will be ignored at this case + + # this delegates to permissions rules, do not change to False which would deny + return None + @commands.group() async def permissions(self, ctx: commands.Context): """Command permission management tools."""