From 772df777ba102fbd5a2af8514ea20314fd61fb79 Mon Sep 17 00:00:00 2001 From: "Brian S. Stephan" Date: Sat, 20 Jun 2015 10:08:51 -0500 Subject: [PATCH] ircbot: tie bot users to django auth user, part 3 get rid of is_admin(), instead check for django permissions. a couple things were using is_admin(), so now there's an example of the permission adding and usage, as those were ported --- dr_botzo/ircbot/bot.py | 10 ++++--- dr_botzo/ircbot/ircplugins/ircmgmt.py | 8 +++--- dr_botzo/ircbot/lib.py | 16 ++++++++++-- .../migrations/0011_auto_20150620_0951.py | 26 +++++++++++++++++++ dr_botzo/ircbot/models.py | 13 ++++++++++ dr_botzo/twitter/ircplugin.py | 14 +++++----- .../migrations/0003_auto_20150620_0951.py | 18 +++++++++++++ dr_botzo/twitter/models.py | 5 ++++ 8 files changed, 93 insertions(+), 17 deletions(-) create mode 100644 dr_botzo/ircbot/migrations/0011_auto_20150620_0951.py create mode 100644 dr_botzo/twitter/migrations/0003_auto_20150620_0951.py diff --git a/dr_botzo/ircbot/bot.py b/dr_botzo/ircbot/bot.py index d34284f..7c18741 100644 --- a/dr_botzo/ircbot/bot.py +++ b/dr_botzo/ircbot/bot.py @@ -558,8 +558,9 @@ class IRCBot(irc.client.SimpleIRCClient): def handle_load(self, connection, event, match): """Handle IRC requests to load a plugin.""" - log.debug(u"is admin?: %s", str(ircbotlib.is_admin(event.source))) - if ircbotlib.is_admin(event.source): + has_perm = ircbotlib.has_permission(event.source, 'ircbot.manage_loaded_plugins') + log.debug(u"has permission to load?: %s", str(has_perm)) + if has_perm: plugin_path = match.group(1) log.debug(u"calling _load_plugin on %s", plugin_path) self._load_plugin(connection, event, plugin_path) @@ -611,8 +612,9 @@ class IRCBot(irc.client.SimpleIRCClient): def handle_unload(self, connection, event, match): """Handle IRC requests to unload a plugin.""" - log.debug(u"is admin?: %s", str(ircbotlib.is_admin(event.source))) - if ircbotlib.is_admin(event.source): + has_perm = ircbotlib.has_permission(event.source, 'ircbot.manage_loaded_plugins') + log.debug(u"has permission to unload?: %s", str(has_perm)) + if has_perm: plugin_path = match.group(1) log.debug(u"calling _unload_plugin on %s", plugin_path) self._unload_plugin(connection, event, plugin_path) diff --git a/dr_botzo/ircbot/ircplugins/ircmgmt.py b/dr_botzo/ircbot/ircplugins/ircmgmt.py index 24fa130..68aa7b2 100644 --- a/dr_botzo/ircbot/ircplugins/ircmgmt.py +++ b/dr_botzo/ircbot/ircplugins/ircmgmt.py @@ -1,6 +1,6 @@ import logging -from ircbot.lib import Plugin, is_admin +from ircbot.lib import Plugin, has_permission from ircbot.models import IrcChannel @@ -35,7 +35,7 @@ class ChannelManagement(Plugin): def handle_join(self, connection, event, match): """Handle the join command.""" - if is_admin(event.source): + if has_permission(event.source, 'ircbot.manage_current_channels'): channel = match.group(1) # put it in the database if it isn't already chan_mod, c = IrcChannel.objects.get_or_create(name=channel) @@ -47,7 +47,7 @@ class ChannelManagement(Plugin): def handle_part(self, connection, event, match): """Handle the join command.""" - if is_admin(event.source): + if has_permission(event.source, 'ircbot.manage_current_channels'): channel = match.group(1) # put it in the database if it isn't already chan_mod, c = IrcChannel.objects.get_or_create(name=channel) @@ -59,7 +59,7 @@ class ChannelManagement(Plugin): def handle_quit(self, connection, event, match): """Handle the join command.""" - if is_admin(event.source): + if has_permission(event.source, 'ircbot.quit_bot'): self.bot.die(msg=match.group(1)) diff --git a/dr_botzo/ircbot/lib.py b/dr_botzo/ircbot/lib.py index b0bf32d..3400a58 100644 --- a/dr_botzo/ircbot/lib.py +++ b/dr_botzo/ircbot/lib.py @@ -6,6 +6,8 @@ import logging import irc.client +from django.core.exceptions import ObjectDoesNotExist + from ircbot.models import BotUser @@ -44,7 +46,7 @@ class Plugin(object): return text -def is_admin(source): +def has_permission(source, permission): """Check if the provided event source is a bot admin.""" try: @@ -54,7 +56,17 @@ def is_admin(source): log.debug("could not find bot user for {0:s}".format(source)) return False - return True + try: + django_user = bot_user.user + if django_user.has_perm(permission): + log.debug("bot user {0:s} has requested permission {1:s}".format(bot_user, permission)) + return True + except ObjectDoesNotExist: + log.error("could not find django user for bot user {0:s}".format(bot_user)) + return False + + log.debug("bot user {0:s} does not have requested permission {1:s}".format(bot_user, permission)) + return False def reply_destination_for_event(event): diff --git a/dr_botzo/ircbot/migrations/0011_auto_20150620_0951.py b/dr_botzo/ircbot/migrations/0011_auto_20150620_0951.py new file mode 100644 index 0000000..fee3e31 --- /dev/null +++ b/dr_botzo/ircbot/migrations/0011_auto_20150620_0951.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('ircbot', '0010_auto_20150620_0930'), + ] + + operations = [ + migrations.AlterModelOptions( + name='botuser', + options={'permissions': (('quit_bot', 'Can tell the bot to quit via IRC'),)}, + ), + migrations.AlterModelOptions( + name='ircchannel', + options={'permissions': (('manage_current_channels', 'Can join/part channels via IRC'),)}, + ), + migrations.AlterModelOptions( + name='ircplugin', + options={'ordering': ['path'], 'permissions': (('manage_loaded_plugins', 'Can load/unload plugins via IRC'),)}, + ), + ] diff --git a/dr_botzo/ircbot/models.py b/dr_botzo/ircbot/models.py index 5b58aab..798cd0a 100644 --- a/dr_botzo/ircbot/models.py +++ b/dr_botzo/ircbot/models.py @@ -43,6 +43,11 @@ class BotUser(models.Model): nickmask = models.CharField(max_length=200, unique=True) user = models.ForeignKey(settings.AUTH_USER_MODEL) + class Meta: + permissions = ( + ('quit_bot', "Can tell the bot to quit via IRC"), + ) + def __unicode__(self): """String representation.""" @@ -60,6 +65,11 @@ class IrcChannel(models.Model): topic_time = models.DateTimeField(default=timezone.now) topic_by = models.CharField(max_length=200, default='', blank=True) + class Meta: + permissions = ( + ('manage_current_channels', "Can join/part channels via IRC"), + ) + def __unicode__(self): """String representation.""" @@ -75,6 +85,9 @@ class IrcPlugin(models.Model): class Meta: ordering = ['path'] + permissions = ( + ('manage_loaded_plugins', "Can load/unload plugins via IRC"), + ) def __unicode__(self): """String representation.""" diff --git a/dr_botzo/twitter/ircplugin.py b/dr_botzo/twitter/ircplugin.py index 5561357..ccfb080 100644 --- a/dr_botzo/twitter/ircplugin.py +++ b/dr_botzo/twitter/ircplugin.py @@ -10,7 +10,7 @@ import twython from django.conf import settings -from ircbot.lib import Plugin, is_admin +from ircbot.lib import Plugin, has_permission from twitter.models import TwitterClient @@ -137,9 +137,9 @@ class Twitter(Plugin): tweet = match.group(1) if not self.twit.verify_credentials(): - return self.bot.reply(event, "You must be authenticated to tweet.") - if not is_admin(event.source): - return self.bot.reply(event, "Only admins can tweet.") + return self.bot.reply(event, "The bot must be authenticated to tweet.") + if not has_permission(event.source, 'twitter.send_tweets'): + return self.bot.reply(event, "You do not have permission to send tweets.") try: if self.twit.update_status(status=tweet, display_coordinates=False) is not None: @@ -156,9 +156,9 @@ class Twitter(Plugin): tweet = match.group(2) if not self.twit.verify_credentials(): - return self.bot.reply(event, "You must be authenticated to tweet.") - if not is_admin(event.source): - return self.bot.reply(event, "Only admins can tweet.") + return self.bot.reply(event, "The bot must be authenticated to tweet.") + if not has_permission(event.source, 'twitter.send_tweets'): + return self.bot.reply(event, "you do not have permission to send tweets.") replyee_tweet = self.twit.show_status(id=status_id) target = replyee_tweet['user']['screen_name'].encode('utf-8', 'ignore') diff --git a/dr_botzo/twitter/migrations/0003_auto_20150620_0951.py b/dr_botzo/twitter/migrations/0003_auto_20150620_0951.py new file mode 100644 index 0000000..6657627 --- /dev/null +++ b/dr_botzo/twitter/migrations/0003_auto_20150620_0951.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('twitter', '0002_auto_20150616_2022'), + ] + + operations = [ + migrations.AlterModelOptions( + name='twitterclient', + options={'permissions': (('send_tweets', 'Can send tweets via IRC'),)}, + ), + ] diff --git a/dr_botzo/twitter/models.py b/dr_botzo/twitter/models.py index bb1d78a..d153612 100644 --- a/dr_botzo/twitter/models.py +++ b/dr_botzo/twitter/models.py @@ -18,3 +18,8 @@ class TwitterClient(models.Model): output_channel = models.CharField(max_length=200, default='', blank=True) oauth_token = models.CharField(max_length=256, default='', blank=True) oauth_token_secret = models.CharField(max_length=256, default='', blank=True) + + class Meta: + permissions = ( + ('send_tweets', "Can send tweets via IRC"), + )