# permissions.py # -*- coding: utf-8 -*- """ A plugin for irc3 that provides a permission system using TinyDB. This plugin allows bot administrators to manage command permissions using a TinyDB database. It includes commands for adding, removing, and listing permissions, as well as a policy system to enforce them. Author: Your Name License: MIT """ from irc3 import plugin from irc3.plugins.command import command from tinydb import TinyDB, Query import fnmatch from ircstyle import style # Import only the style function @plugin class TinyDBPermissions: """A plugin for managing command permissions using TinyDB.""" def __init__(self, bot): """ Initialize the TinyDBPermissions plugin. Args: bot: The irc3 bot instance. """ self.bot = bot # Initialize TinyDB with a JSON file for storing permissions self.permission_db = TinyDB('permissions.json') # Expose the database to the bot context for other components to use self.bot.permission_db = self.permission_db self.bot.log.info("TinyDB permissions plugin initialized") class TinyDBPolicy: """Permission policy using TinyDB for storage.""" def __init__(self, bot): """ Initialize the TinyDBPolicy. Args: bot: The irc3 bot instance. """ self.bot = bot self.bot.log.debug("Initializing TinyDB policy") def has_permission(self, client_mask, permission): """ Check if a client has the required permission. Args: client_mask: The client's hostmask (e.g., "user!ident@host"). permission: The permission to check (e.g., "admin"). Returns: bool: True if the client has the permission, False otherwise. """ # If no permission is required, allow access if permission is None: return True # Query the TinyDB database for permissions User = Query() entries = self.bot.permission_db.search(User.permission.test( lambda p: p == permission or p == 'all_permissions' )) # Check if the client's mask matches any entry in the database for entry in entries: if fnmatch.fnmatch(client_mask, entry['mask']): return True return False def __call__(self, predicates, meth, client, target, args, **kwargs): """ Enforce permissions for a command. Args: predicates: Command metadata (e.g., name, permission). meth: The command method to execute. client: The client issuing the command. target: The target of the command (channel or user). args: Arguments passed to the command. kwargs: Additional keyword arguments. """ # Get the command name from predicates or method name cmd_name = predicates.get('name', meth.__name__) # Check if the client has the required permission if self.has_permission(str(client), predicates.get('permission')): # Execute the command if permission is granted return meth(client, target, args) # Notify the client if they don't have permission error_message = style( f"You are not allowed to use the '{cmd_name}' command", fg='red', bold=True ) self.bot.privmsg(client.nick, error_message) @command(permission='admin') def addperm(bot, mask, target, args): """ Add a permission to a user. Usage: %%addperm """ # Access the TinyDB database db = bot.permission_db user_mask = args[''] perm = args[''] # Insert the new permission into the database db.insert({'mask': user_mask, 'permission': perm}) # Notify the user that the permission was added success_message = style( f"Added permission '{perm}' for mask '{user_mask}'", fg='green', bold=True ) bot.privmsg(target, success_message) bot.log.info(f"Added permission '{perm}' for mask '{user_mask}'") @command(permission='admin') def delperm(bot, mask, target, args): """ Remove a permission from a user. Usage: %%delperm """ # Access the TinyDB database db = bot.permission_db User = Query() user_mask = args[''] perm = args[''] # Remove the permission from the database removed = db.remove((User.mask == user_mask) & (User.permission == perm)) # Notify the user how many permissions were removed success_message = style( f"Removed {len(removed)} permission(s)", fg='green', bold=True ) bot.privmsg(target, success_message) bot.log.info(f"Removed {len(removed)} permission(s) for mask '{user_mask}'") @command(permission='admin') def listperms(bot, mask, target, args): """ List all permissions or for a specific mask. Usage: %%listperms [] """ # Access the TinyDB database db = bot.permission_db User = Query() # Use the provided mask or default to '*' (all masks) mask_filter = args[''] or '*' # Convert shell-style mask to a valid regex pattern regex_pattern = fnmatch.translate(mask_filter) # Remove the flags added by fnmatch.translate for compatibility regex_pattern = regex_pattern.rsplit('(?ms)')[0].rstrip('\\Z') # Search for permissions matching the converted regex pattern entries = db.search(User.mask.matches(regex_pattern)) # Notify the user if no permissions are found if not entries: error_message = style("No permissions found", fg='red', bold=True) bot.privmsg(target, error_message) bot.log.debug(f"No permissions found for mask '{mask_filter}'") return # List all matching permissions for entry in entries: permission_message = style( f"Mask: {entry['mask']}, Permission: {entry['permission']}", fg='blue', bold=True ) bot.privmsg(target, permission_message) bot.log.debug(f"Listed permissions for mask '{mask_filter}'") # To use this plugin, add the following to bot config: # [irc3.plugins.command] # guard = permissions.TinyDBPolicy