add permissions json

This commit is contained in:
Zodiac 2025-02-14 13:48:23 -08:00
parent a89bd0b334
commit 785a7786b4
2 changed files with 151 additions and 161 deletions

1
permissions.json Normal file
View File

@ -0,0 +1 @@
{"_default": {"2": {"mask": "*!uid677411@2266CC43:5D1E0B1F:A5B0466C:IP", "permission": "admin"}}}

View File

@ -1,199 +1,188 @@
# permissions.py # permissions.py
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
A plugin for irc3 that provides a permission system using TinyDB. A plugin for irc3 that provides a permission system using TinyDB, including message blocking.
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 Author: Your Name
License: MIT License: MIT
""" """
from irc3 import plugin import irc3
from irc3.plugins.command import command from irc3.plugins.command import command
from tinydb import TinyDB, Query from tinydb import TinyDB, Query
import fnmatch import fnmatch
from ircstyle import style # Import only the style function from ircstyle import style
@plugin @irc3.plugin
class TinyDBPermissions: 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): def __init__(self, bot):
"""
Initialize the TinyDBPermissions plugin.
Args:
bot: The irc3 bot instance.
"""
self.bot = bot self.bot = bot
# Initialize TinyDB with a JSON file for storing permissions
self.permission_db = TinyDB('permissions.json') 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.permission_db = self.permission_db
self.User = Query()
self.bot.log.info("TinyDB permissions plugin initialized") 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 <mask> <permission>
%%perm --del <mask> <permission>
%%perm --list [<mask>]
"""
if args['--add']:
self._add_permission(target, args['<mask>'], args['<permission>'])
elif args['--del']:
self._del_permission(target, args['<mask>'], args['<permission>'])
elif args['--list']:
self._list_permissions(target, args['<mask>'])
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 <nick>
%%ignore --del <nick>
"""
nick = args['<nick>']
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: class TinyDBPolicy:
"""Permission policy using TinyDB for storage.""" """Permission policy enforcement"""
def __init__(self, bot): def __init__(self, bot):
"""
Initialize the TinyDBPolicy.
Args:
bot: The irc3 bot instance.
"""
self.bot = bot self.bot = bot
self.bot.log.debug("Initializing TinyDB policy") self.User = Query()
def has_permission(self, client_mask, permission): def has_permission(self, client_mask, permission):
""" # Check ignore list first using fnmatch
Check if a client has the required permission. 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: # Check permissions if not ignored
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: if permission is None:
return True return True
# Query the TinyDB database for permissions perm_entries = self.bot.permission_db.search(
User = Query() (self.User.permission == permission) |
entries = self.bot.permission_db.search(User.permission.test( (self.User.permission == 'all_permissions')
lambda p: p == permission or p == 'all_permissions' )
)) for entry in perm_entries:
# Check if the client's mask matches any entry in the database
for entry in entries:
if fnmatch.fnmatch(client_mask, entry['mask']): if fnmatch.fnmatch(client_mask, entry['mask']):
return True return True
return False return False
def __call__(self, predicates, meth, client, target, args, **kwargs): def __call__(self, predicates, meth, client, target, args):
"""
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__) cmd_name = predicates.get('name', meth.__name__)
client_hostmask = str(client)
# Check if the client has the required permission if self.has_permission(client_hostmask, predicates.get('permission')):
if self.has_permission(str(client), predicates.get('permission')):
# Execute the command if permission is granted
return meth(client, target, args) return meth(client, target, args)
# Notify the client if they don't have permission error_msg = style(
error_message = style( f"Access denied for '{cmd_name}' command",
f"You are not allowed to use the '{cmd_name}' command",
fg='red', bold=True fg='red', bold=True
) )
self.bot.privmsg(client.nick, error_message) self.bot.privmsg(client.nick, error_msg)
@command(permission='admin')
def addperm(bot, mask, target, args):
"""
Add a permission to a user.
Usage:
%%addperm <mask> <permission>
"""
# Access the TinyDB database
db = bot.permission_db
user_mask = args['<mask>']
perm = args['<permission>']
# 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 <mask> <permission>
"""
# Access the TinyDB database
db = bot.permission_db
User = Query()
user_mask = args['<mask>']
perm = args['<permission>']
# 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 [<mask>]
"""
# Access the TinyDB database
db = bot.permission_db
User = Query()
# Use the provided mask or default to '*' (all masks)
mask_filter = args['<mask>'] 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