diff --git a/plugins/MessageParser/config.py b/plugins/MessageParser/config.py index 8a89d8f5f..456feb023 100644 --- a/plugins/MessageParser/config.py +++ b/plugins/MessageParser/config.py @@ -39,7 +39,6 @@ def configure(advanced): from supybot.questions import expect, anything, something, yn conf.registerPlugin('MessageParser', True) - MessageParser = conf.registerPlugin('MessageParser') # This is where your configuration variables (if any) should go. For example: # conf.registerGlobalValue(MessageParser, 'someConfigVariableName', @@ -57,5 +56,13 @@ conf.registerChannelValue(MessageParser, 'rankListLength', conf.registerChannelValue(MessageParser, 'requireVacuumCapability', registry.String('admin', """Determines the capability required (if any) to vacuum the database.""")) - +conf.registerChannelValue(MessageParser, 'requireManageCapability', + registry.String('admin; channel,op', + """Determines the + capabilities required (if any) to manage the regexp database, + including add, remove, lock, unlock. Use 'channel,capab' for + channel-level capabilities. + Note that absence of an explicit anticapability means user has + capability.""")) + # vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79: diff --git a/plugins/MessageParser/plugin.py b/plugins/MessageParser/plugin.py index b63c1c202..c7e13d19b 100644 --- a/plugins/MessageParser/plugin.py +++ b/plugins/MessageParser/plugin.py @@ -117,13 +117,27 @@ class MessageParser(callbacks.Plugin, plugins.ChannelDBHandler): def _runCommandFunction(self, irc, msg, command): """Run a command from message, as if command was sent over IRC.""" - # need to encode it from unicode, since sqlite stores text as unicode. tokens = callbacks.tokenize(command) try: self.Proxy(irc.irc, msg, tokens) except Exception, e: log.exception('Uncaught exception in scheduled function:') + def _checkManageCapabilities(self, irc, msg, channel): + """Check if the user has any of the required capabilities to manage + the regexp database.""" + capabilities = self.registryValue('requireManageCapability') + if capabilities: + for capability in re.split(r'\s*;\s*', capabilities): + if capability.startswith('channel,'): + capability = ircdb.makeChannelCapability(channel, capability[8:]) + if capability and ircdb.checkCapability(msg.prefix, capability): + #print "has capability:", capability + return True + return False + else: + return True + def doPrivmsg(self, irc, msg): channel = msg.args[0] if not irc.isChannel(channel): @@ -157,6 +171,9 @@ class MessageParser(callbacks.Plugin, plugins.ChannelDBHandler): necessary if the message isn't sent on the channel itself. Action is echoed upon regexp match, with variables $1, $2, etc. being interpolated from the regexp match groups.""" + if not self._checkManageCapabilities(irc, msg, channel): + capabilities = self.registryValue('requireManageCapability') + irc.errorNoCapability(capabilities, Raise=True) db = self.getDb(channel) cursor = db.cursor() cursor.execute("SELECT id, usage_count, locked FROM triggers WHERE regexp=?", (regexp,)) @@ -194,6 +211,9 @@ class MessageParser(callbacks.Plugin, plugins.ChannelDBHandler): the message isn't sent in the channel itself. If option --id specified, will retrieve by regexp id, not content. """ + if not self._checkManageCapabilities(irc, msg, channel): + capabilities = self.registryValue('requireManageCapability') + irc.errorNoCapability(capabilities, Raise=True) db = self.getDb(channel) cursor = db.cursor() target = 'regexp' @@ -227,6 +247,9 @@ class MessageParser(callbacks.Plugin, plugins.ChannelDBHandler): removed or overwritten to. is only necessary if the message isn't sent in the channel itself. """ + if not self._checkManageCapabilities(irc, msg, channel): + capabilities = self.registryValue('requireManageCapability') + irc.errorNoCapability(capabilities, Raise=True) db = self.getDb(channel) cursor = db.cursor() cursor.execute("SELECT id FROM triggers WHERE regexp=?", (regexp,)) @@ -246,6 +269,9 @@ class MessageParser(callbacks.Plugin, plugins.ChannelDBHandler): removed or overwritten. is only necessary if the message isn't sent in the channel itself. """ + if not self._checkManageCapabilities(irc, msg, channel): + capabilities = self.registryValue('requireManageCapability') + irc.errorNoCapability(capabilities, Raise=True) db = self.getDb(channel) cursor = db.cursor() cursor.execute("SELECT id FROM triggers WHERE regexp=?", (regexp,)) diff --git a/plugins/MessageParser/test.py b/plugins/MessageParser/test.py index 949bedac5..870f83ebd 100644 --- a/plugins/MessageParser/test.py +++ b/plugins/MessageParser/test.py @@ -52,6 +52,22 @@ class MessageParserTestCase(ChannelPluginTestCase): self.assertNotError('messageparser add "stuff" "echo i saw no stuff"') #overwrite existing regexp self.assertRegexp('messageparser show "stuff"', '.*i saw no stuff.*') + + try: + world.testing = False + origuser = self.prefix + self.prefix = 'stuff!stuff@stuff' + self.assertNotError('register nottester stuff', private=True) + + self.assertError('messageparser add "aoeu" "echo vowels are nice"') + origconf = conf.supybot.plugins.MessageParser.requireManageCapability() + conf.supybot.plugins.MessageParser.requireManageCapability.setValue('') + self.assertNotError('messageparser add "aoeu" "echo vowels are nice"') + finally: + world.testing = True + self.prefix = origuser + conf.supybot.plugins.MessageParser.requireManageCapability.setValue(origconf) + def testShow(self): self.assertNotError('messageparser add "stuff" "echo i saw some stuff"') self.assertRegexp('messageparser show "nostuff"', 'there is no such regexp trigger')