From 785a7786b42d869918bc3cba483f2c9a443e2bb1 Mon Sep 17 00:00:00 2001 From: Zodiac Date: Fri, 14 Feb 2025 13:48:23 -0800 Subject: [PATCH] add permissions json --- permissions.json | 1 + plugins/services/permissions.py | 311 +++++++++++++++----------------- 2 files changed, 151 insertions(+), 161 deletions(-) create mode 100644 permissions.json diff --git a/permissions.json b/permissions.json new file mode 100644 index 0000000..ad3dc1c --- /dev/null +++ b/permissions.json @@ -0,0 +1 @@ +{"_default": {"2": {"mask": "*!uid677411@2266CC43:5D1E0B1F:A5B0466C:IP", "permission": "admin"}}} \ No newline at end of file diff --git a/plugins/services/permissions.py b/plugins/services/permissions.py index 346c062..a351e86 100644 --- a/plugins/services/permissions.py +++ b/plugins/services/permissions.py @@ -1,199 +1,188 @@ # 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. +A plugin for irc3 that provides a permission system using TinyDB, including message blocking. Author: Your Name License: MIT """ -from irc3 import plugin +import irc3 from irc3.plugins.command import command from tinydb import TinyDB, Query import fnmatch -from ircstyle import style # Import only the style function +from ircstyle import style -@plugin +@irc3.plugin class TinyDBPermissions: - """A plugin for managing command permissions using TinyDB.""" - + """Integrated permissions plugin with message blocking""" + priority = 10 # Lower number = higher priority + 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.User = Query() self.bot.log.info("TinyDB permissions plugin initialized") + @irc3.event(irc3.rfc.PRIVMSG) + async def check_ignored_users(self, mask, event, target, data): + """Block messages from ignored users first""" + hostmask = str(mask) + ignored = self.permission_db.search(self.User.permission == 'ignore') + + for entry in ignored: + if fnmatch.fnmatch(hostmask, entry['mask']): + self.bot.log.debug(f"Blocking message from ignored user: {hostmask}") + return True # Block processing + return False + + @command(permission='admin') + def perm(self, mask, target, args): + """ + Manage permissions. Use --add, --del, or --list. + + Usage: + %%perm --add + %%perm --del + %%perm --list [] + """ + if args['--add']: + self._add_permission(target, args[''], args['']) + elif args['--del']: + self._del_permission(target, args[''], args['']) + elif args['--list']: + self._list_permissions(target, args['']) + else: + error_msg = style( + "Invalid syntax. Use --add, --del, or --list.", + fg='red', bold=True + ) + self.bot.privmsg(target, error_msg) + + def _add_permission(self, target, user_mask, perm): + existing = self.permission_db.search( + (self.User.mask == user_mask) & + (self.User.permission == perm) + ) + if existing: + msg = style( + f"Permission '{perm}' already exists for {user_mask}", + fg='yellow', bold=True + ) + else: + self.permission_db.insert({'mask': user_mask, 'permission': perm}) + msg = style( + f"Added permission '{perm}' for {user_mask}", + fg='green', bold=True + ) + self.bot.privmsg(target, msg) + + def _del_permission(self, target, user_mask, perm): + removed = self.permission_db.remove( + (self.User.mask == user_mask) & + (self.User.permission == perm) + ) + if removed: + msg = style( + f"Removed {len(removed)} '{perm}' permission(s) for {user_mask}", + fg='green', bold=True + ) + else: + msg = style( + f"No '{perm}' permissions found for {user_mask}", + fg='red', bold=True + ) + self.bot.privmsg(target, msg) + + def _list_permissions(self, target, mask_filter): + mask_filter = mask_filter or '*' + regex = fnmatch.translate(mask_filter).split('(?ms)')[0].rstrip('\\Z') + entries = self.permission_db.search(self.User.mask.matches(regex)) + + if not entries: + msg = style("No permissions found", fg='red', bold=True) + self.bot.privmsg(target, msg) + return + + for entry in entries: + msg = style( + f"{entry['mask']}: {entry['permission']}", + fg='blue', bold=True + ) + self.bot.privmsg(target, msg) + + @command(permission='admin') + def ignore(self, mask, target, args): + """Manage ignores + Usage: + %%ignore --add + %%ignore --del + """ + nick = args[''] + user_mask = f"{nick}!*@*" + + if args['--add']: + if self.permission_db.contains( + (self.User.mask == user_mask) & + (self.User.permission == 'ignore') + ): + msg = style(f"{nick} already ignored", fg='yellow', bold=True) + else: + self.permission_db.insert({'mask': user_mask, 'permission': 'ignore'}) + msg = style(f"Ignored {nick}", fg='green', bold=True) + + elif args['--del']: + removed = self.permission_db.remove( + (self.User.mask == user_mask) & + (self.User.permission == 'ignore') + ) + msg = style(f"Unignored {nick} ({len(removed)} entries)", fg='green', bold=True) + + else: + msg = style("Invalid syntax", fg='red', bold=True) + + self.bot.privmsg(target, msg) class TinyDBPolicy: - """Permission policy using TinyDB for storage.""" - + """Permission policy enforcement""" + def __init__(self, bot): - """ - Initialize the TinyDBPolicy. - - Args: - bot: The irc3 bot instance. - """ self.bot = bot - self.bot.log.debug("Initializing TinyDB policy") + self.User = Query() def has_permission(self, client_mask, permission): - """ - Check if a client has the required permission. + # Check ignore list first using fnmatch + ignored_entries = self.bot.permission_db.search( + self.User.permission == 'ignore' + ) + for entry in ignored_entries: + if fnmatch.fnmatch(client_mask, entry['mask']): + return False - 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 + # Check permissions if not ignored 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: + perm_entries = self.bot.permission_db.search( + (self.User.permission == permission) | + (self.User.permission == 'all_permissions') + ) + for entry in perm_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 + def __call__(self, predicates, meth, client, target, args): 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 + client_hostmask = str(client) + + if self.has_permission(client_hostmask, predicates.get('permission')): 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", + + error_msg = style( + f"Access denied for '{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 \ No newline at end of file + self.bot.privmsg(client.nick, error_msg) \ No newline at end of file