This commit is contained in:
Zodiac 2025-02-14 15:15:37 -08:00
parent 785a7786b4
commit 345d60dfbd

View File

@ -1,24 +1,18 @@
# 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.
Author: Your Name
License: MIT
"""
import irc3 import irc3
from irc3.plugins.command import command from irc3.plugins.command import command
from tinydb import TinyDB, Query from tinydb import Query, TinyDB
import fnmatch import fnmatch
from ircstyle import style from ircstyle import style
@irc3.plugin @irc3.plugin
class TinyDBPermissions: class TinyDBPermissions:
"""Integrated permissions plugin with message blocking""" """Main permission system plugin handling storage and commands."""
priority = 10 # Lower number = higher priority
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
self.permission_db = TinyDB('permissions.json') self.permission_db = TinyDB('permissions.json')
@ -26,23 +20,10 @@ class TinyDBPermissions:
self.User = Query() 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') @command(permission='admin')
def perm(self, mask, target, args): def perm(self, mask, target, args):
""" """Manage permissions through command interface.
Manage permissions. Use --add, --del, or --list.
Usage: Usage:
%%perm --add <mask> <permission> %%perm --add <mask> <permission>
%%perm --del <mask> <permission> %%perm --del <mask> <permission>
@ -61,61 +42,10 @@ class TinyDBPermissions:
) )
self.bot.privmsg(target, error_msg) 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') @command(permission='admin')
def ignore(self, mask, target, args): def ignore(self, mask, target, args):
"""Manage ignores """Manage user ignore list.
Usage: Usage:
%%ignore --add <nick> %%ignore --add <nick>
%%ignore --del <nick> %%ignore --del <nick>
@ -145,19 +75,77 @@ class TinyDBPermissions:
self.bot.privmsg(target, msg) self.bot.privmsg(target, msg)
def _add_permission(self, target, user_mask, perm):
"""Add a permission to the database."""
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):
"""Remove a permission from the database."""
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):
"""List permissions matching a filter pattern."""
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)
class TinyDBPolicy: class TinyDBPolicy:
"""Permission policy enforcement""" """Authorization system for command access control."""
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
self.User = Query() 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 required permissions."""
ignored_entries = self.bot.permission_db.search( # Check ignore list first
ignored = self.bot.permission_db.search(
self.User.permission == 'ignore' self.User.permission == 'ignore'
) )
for entry in ignored_entries: for entry in ignored:
if fnmatch.fnmatch(client_mask, entry['mask']): if fnmatch.fnmatch(client_mask, entry['mask']):
return False return False
@ -165,16 +153,18 @@ class TinyDBPolicy:
if permission is None: if permission is None:
return True return True
perm_entries = self.bot.permission_db.search( # Check for matching permissions using fnmatch
(self.User.permission == permission) | entries = self.bot.permission_db.search(
(self.User.permission == 'all_permissions') self.User.permission.test(lambda p: p in (permission, 'all_permissions'))
) )
for entry in perm_entries: 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): def __call__(self, predicates, meth, client, target, args):
"""Enforce command permissions."""
cmd_name = predicates.get('name', meth.__name__) cmd_name = predicates.get('name', meth.__name__)
client_hostmask = str(client) client_hostmask = str(client)