Big-Old-Update Edition

FreenodeAuth has been replaced by the IRCLogin plugin
Bantracker, Bugtracker, Encyclopedia and Lart have some fixes updates
This commit is contained in:
Terence Simpson 2008-07-20 16:59:27 +01:00
parent c46c983c71
commit 168050b05c
12 changed files with 362 additions and 124 deletions

View File

@ -55,8 +55,18 @@ tz = 'UTC'
def now():
return cPickle.dumps(datetime.datetime.now(pytz.timezone(tz)))
def capab(user, capability):
try:
if capability in user.capabilities:
return True
else:
return False
except:
return False
class Bantracker(callbacks.Plugin):
"""This plugin has no commands"""
"""Use @mark to add a bantracker entry manually and
@btlogin to log into the bantracker"""
noIgnore = True
def __init__(self, irc):
@ -244,13 +254,17 @@ class Bantracker(callbacks.Plugin):
return
user.addAuth(msg.prefix)
ircdb.users.setUser(user, flush=False)
if not self.registryValue('bansite'):
irc.error("No bansite set, please set supybot.plugins.Bantracker.bansite")
return
sessid = md5.new('%s%s%d' % (msg.prefix, time.time(), random.randint(1,100000))).hexdigest()
self.db_run("""INSERT INTO sessions (session_id, user, time) VALUES (%s, %s, %d);""",
(sessid, msg.prefix[:msg.prefix.find('!')], int(time.time())))
irc.reply('Log in at %s/bans/cgi?sess=%s' % (self.registryValue('bansite'), sessid), private=True)
if not capab(user, 'bantracker'):
irc.error(conf.supybot.replies.noCapability() % 'bantracker')
return
if not self.registryValue('bansite'):
irc.error("No bansite set, please set supybot.plugins.Bantracker.bansite")
return
sessid = md5.new('%s%s%d' % (msg.prefix, time.time(), random.randint(1,100000))).hexdigest()
self.db_run("INSERT INTO sessions (session_id, user, time) VALUES (%s, %s, %d);",
(sessid, msg.prefix[:msg.prefix.find('!')], int(time.time())))
irc.reply('Log in at %s/bans/cgi?sess=%s' % (self.registryValue('bansite'), sessid), private=True)
btlogin = wrap(btlogin)
@ -264,16 +278,28 @@ class Bantracker(callbacks.Plugin):
irc.error(conf.supybot.replies.incorrectAuthentication())
return
try:
user = ircdb.users.getUser(msg.prefix[:msg.prefix.find('!')])
user = ircdb.users.getUser(msg.prefix[:msg.prefix.find('!')].lower())
except:
irc.error(conf.supybot.replies.incorrectAuthentication())
return
user.addAuth(msg.prefix)
ircdb.users.setUser(user, flush=False)
if not capab(user, 'bantracker'):
irc.error(conf.supybot.replies.noCapability() % 'bantracker')
return
if not channel:
irc.error('<channel> must be given if not in a channel')
return
channels = []
for (chan, c) in irc.state.channels.iteritems():
channels.append(chan)
if not channel in channels:
irc.error('Not in that channel')
return
if not kickmsg:
kickmsg = '**MARK**'
else:
@ -287,8 +313,8 @@ class Bantracker(callbacks.Plugin):
irc.reply('Could not get hostmask, using nick instead')
hostmask = target
self.doLog(irc, channel, '*** %s requested a mark for %s\n' % (msg.nick, target))
self.doKickban(irc, channel, msg.nick, target, kickmsg)
self.doLog(irc, channel.lower(), '*** %s requested a mark for %s\n' % (msg.nick, target))
self.doKickban(irc, channel.lower(), msg.nick, hostmask, kickmsg)
irc.replySuccess()
mark = wrap(mark, [optional('channel'), 'something', additional('text')])

View File

@ -217,7 +217,7 @@ class Bugtracker(callbacks.PluginRegexp):
Add a bugtracker <url> to the list of defined bugtrackers. <type> is the
type of the tracker (currently only Launchpad, Debbugs, Bugzilla,
Issuezilla and Trac are known). <name> is the name that will be used to
Issuezilla, Mantis and Trac are known). <name> is the name that will be used to
reference the bugzilla in all commands. Unambiguous abbreviations of
<name> will be accepted also. <description> is the common name for the
bugzilla and will be listed with the bugzilla query; if not given, it
@ -659,6 +659,27 @@ class Debbugs(IBugtracker):
s = 'Could not parse data returned by %s bugtracker: %s' % (self.description, e)
raise BugtrackerError, s
class Mantis(IBugtracker):
def __init__(self, *args, **kwargs):
IBugtracker.__init__(self, *args, **kwargs)
self.soap_proxy = SOAPpy.SOAPProxy(self.url + "/api/soap/mantisconnect.php", "http://futureware.biz/mantisconnect")
self.soap_proxy.soapaction = "http://futureware.biz/mantisconnect#mc_issue_get"
def get_bug(self, id):
url = self.url + "/view.php?id=%i" % id
try:
raw = self.soap_proxy.mc_issue_get('', "", id)
except Exception, e:
s = 'Could not parse data returned by %s: %s' % (self.description, e)
raise BugtrackerError, s
if not raw:
raise BugNotFoundError
try:
return [(id, raw['project']['name'], raw['summary'], raw['priority']['name'], raw['resolution']['name'], '', url)]
except Exception, e:
s = 'Could not parse data returned by %s bugtracker: %s' % (self.description, e)
raise BugtrackerError, s
# For trac based trackers we also need to do some screenscraping - should be
# doable unless a certain track instance uses weird templates.
class Trac(IBugtracker):
@ -801,6 +822,7 @@ registerBugtracker('django', 'http://code.djangoproject.com/ticket', 'Django', '
registerBugtracker('cups', 'http://www.cups.org/str.php', 'CUPS', 'str')
registerBugtracker('gnewsense', 'http://bugs.gnewsense.org/Bugs', 'gNewSense', 'wikiforms')
registerBugtracker('supybot', 'http://sourceforge.net/tracker/?group_id=58965&atid=489447', 'Supybot', 'sourceforge')
registerBugtracker('mantis', "http://www.mantisbt.org/bugs", "Mantis", 'mantis')
# Don't delete this one
registerBugtracker('sourceforge', 'http://sourceforge.net/tracker/', 'Sourceforge', 'sourceforge')
Class = Bugtracker

View File

@ -392,6 +392,8 @@ class Encyclopedia(callbacks.Plugin):
ret = self.registryValue('notfoundmsg')
if ret.count('%') == ret.count('%s') == 1:
ret = ret % text
if not target.startswith('#') and not channel.lower() == irc.nick.lower():
queue(irc, channel, "%s, please see my private message" % target)
if type(ret) != list:
queue(irc, target, retmsg + ret)
else:
@ -414,7 +416,7 @@ class Encyclopedia(callbacks.Plugin):
cs.execute('''insert into log (author, name, added, oldvalue) values (%s, %s, %s, %s)''',
(editor, factoid.name, str(datetime.datetime.now()), factoid.value))
db.commit()
if '<alias>' in text.lower() and not text.lower().startswith('no'):
return self.factoid_add(text,channel,editor)

View File

@ -1,3 +0,0 @@
Allows any nickserv-identified user to login without password. Written
specifically for Freenode. Can also auto-create accounts from a list with
nicknames.

View File

@ -1,93 +0,0 @@
###
# Copyright (c) 2007, Dennis Kaarsemaker
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of version 2 of the GNU General Public License as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
###
import supybot.utils as utils
from supybot.commands import *
import supybot.plugins as plugins
import supybot.ircutils as ircutils
import supybot.ircmsgs as ircmsgs
import supybot.callbacks as callbacks
import supybot.ircdb as ircdb
import supybot.conf as conf
import supybot.schedule as schedule
import random, os
class FreenodeAuth(callbacks.Plugin):
"""Use @login to login"""
threaded = True
def loadnicks(self):
uf = self.registryValue('UserList')
if not uf or not os.path.exists(uf):
self.log.info('Not loading non-existant userlist')
return
fd = open(uf)
users = fd.read()
fd.close()
knownusers = [x.lower() for x in users.split() if x]
self.knownusers = knownusers
allusers = [u.name.lower() for u in ircdb.users.itervalues()]
to_add = [x for x in knownusers if x not in allusers]
for a in to_add:
self.log.info("Adding %s" % a)
user = ircdb.users.newUser()
user.name = a
rp = ''
chars = '''1234567890-=~!@#$%^&*()_qwertyuiop[]QWERTYUIOP{}}|asdfghjkl;ASDFGHJKL:zxcvbnm,./ZXCVBNM<>?'''
for i in range(16):
rp += chars[random.randint(1,len(chars))-1]
user.setPassword(rp)
# irc.queueMsg(ircmsgs.IrcMsg('CAPAB IDENTIFY-MSG'))
def do290(self, irc, msg):
assert 'IDENTIFY-MSG' in msg.args[1]
irc.getRealIrc()._Freenode_capabed = True
def do376(self, irc, msg):
irc.queueMsg(ircmsgs.IrcMsg('CAPAB IDENTIFY-MSG'))
def do422(self, irc, msg): # MOTD missing
irc.queueMsg(ircmsgs.IrcMsg('CAPAB IDENTIFY-MSG'))
def inFilter(self, irc, msg):
if getattr(irc,'_Freenode_capabed',None) and msg.command == 'PRIVMSG':
first = msg.args[1][0]
rest = msg.args[1][1:]
msg.tag('identified', first == '+')
msg = ircmsgs.privmsg(msg.args[0], rest, msg=msg)
assert msg.receivedAt and msg.receivedOn and msg.receivedBy
return msg
def login(self, irc, msg, args):
"""takes no arguments
Allows users who are identified to NickServ to login without a password.
"""
if not msg.tagged('identified'):
irc.error(conf.supybot.replies.incorrectAuthentication())
return
try:
user = ircdb.users.getUser(msg.prefix[:msg.prefix.find('!')])
except:
self.loadnicks()
try:
user = ircdb.users.getUser(msg.prefix[:msg.prefix.find('!')])
except:
irc.error(conf.supybot.replies.incorrectAuthentication())
return
user.addAuth(msg.prefix)
ircdb.users.setUser(user, flush=False)
irc.replySuccess()
login = wrap(login)
Class = FreenodeAuth

9
IRCLogin/README.txt Normal file
View File

@ -0,0 +1,9 @@
Allows any nickserv-identified user to login without password.
Grabs IRC nicks from the members in the ubuntu-irc Launchpad team, these are
stored in a binary file.
It is recommended to run @updateusers manually when the plugin is first loaded
to grab the users list from launchpad.
This plugin is designed to work with the bantracker plugin, so adds the
'bantracker' capability to all the users it finds in the team.

View File

@ -1,5 +1,5 @@
###
# Copyright (c) 2007, Dennis Kaarsemaker
# Copyright (c) 2008, Terence Simpson
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of version 2 of the GNU General Public License as
@ -13,16 +13,16 @@
###
"""
Let nickserv-identified users log in without password
Let nickserv-identified users log in without password via Launchpad
"""
import supybot
import supybot.world as world
__version__ = "0.2"
__author__ = supybot.Author("Dennis Kaarsemaker","Seveas","dennis@kaarsemaker.net")
__version__ = "0.1"
__author__ = supybot.Author("Terence Simpson","stdin","stdin@stdin.me.uk")
__contributors__ = {}
__url__ = 'http://ubotu.ubuntu-nl.org/'
__url__ = 'http://jussi01.com/web/'
import config
reload(config)

View File

@ -1,5 +1,5 @@
###
# Copyright (c) 2007, Dennis Kaarsemaker
# Copyright (c) 2008, Terence Simpson
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of version 2 of the GNU General Public License as
@ -17,8 +17,8 @@ import supybot.registry as registry
def configure(advanced):
from supybot.questions import expect, anything, something, yn
conf.registerPlugin('FreenodeAuth', True)
conf.registerPlugin('IRCLogin', True)
FreenodeAuth = conf.registerPlugin('FreenodeAuth')
conf.registerGlobalValue(FreenodeAuth, 'UserList',
IRCLogin = conf.registerPlugin('IRCLogin')
conf.registerGlobalValue(IRCLogin, 'UserList',
registry.String('', """Filename of file with list of users""",private=True))

99
IRCLogin/lp.py Normal file
View File

@ -0,0 +1,99 @@
###
# Copyright (c) 2008, Terence Simpson
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of version 2 of the GNU General Public License as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
###
import sys, re, urllib2, RDF
def striphtml(data):
'''striphtml(data) -> list
Try to strip away the HTML tags in the list "data"
'''
start = re.compile('<[a-z]+.*>') # opening HTML tag <...>
end = re.compile('</[a-z]+>') # closing HTML tag </...>
# find and replace code
for i in range(0, len(data)):
# replace the closing tag first, as the starting regex will match up to the closing other wise
r = end.search(data[i])
while r:
data[i] = data[i].replace(data[i][r.start():r.end()], '', 1)
r = end.search(data[i])
r = start.search(data[i])
while r:
data[i] = data[i].replace(data[i][r.start():r.end()], '', 1)
r = start.search(data[i])
# return the list back
return data
def getIRCNick(user, errors=True):
'''getIRCNick(user, errors) -> list
Try to get the IRC nick(s) from the LP account "user".
If errors is True print any errors to stderr, defaults to True
'''
# Get the HTML data from LP
try:
data = urllib2.urlopen('https://launchpad.net/~%s' % user).read()
except Exception, e:
if errors: print >> sys.stderr, "Could not get user info (%s)" % e
return
details = '<div class="portletContent portletBody">'
# Try and find the "Contact details" section
sindex = data.find(details)
if sindex == -1:
if errors: print >> sys.stderr, "Could not get user info (No data)"
return
eindex = data.find('</div>', sindex) + 6
data = data[sindex:eindex]
data = [l.strip() for l in data.splitlines() if l.strip()]
# Look for IRC info
try:
sindex = data.index('<th>IRC:</th>')
eindex = data.index('</div>', sindex)
except:
if errors: print >> sys.stderr, "Could not get user info (No IRC nick(s) specified)"
return
data = data[sindex:eindex]
ircnames = []
count = 0
# Loop through the data looking for IRC nicks
while True:
count += 1
if count >= 10:
break # Try not to loop forever :)
try:
# When this fails, it raises an exception
s = data.index('<th>IRC:</th>')
e = data.index('</tr>') + 1
if e <= s:
break
# Limit to freenode nicks
if 'on network <code style="font-size: 120%">irc.freenode.net</code>' in data[s:e]:
ircnames.append(data[s:e])
del data[s:e]
except:
return [striphtml(i)[1].lower() for i in ircnames]
# incase we got to a break in the loop
return [striphtml(i)[1].lower() for i in ircnames]
def getUsers(team='ubuntu-irc'):
parser = RDF.Parser()
stream = parser.parse_as_stream("https://launchpad.net/~%s/+rdf" % team) # Parse the teams RDF
d = []
# Get the RDF data for the team members
for f in stream:
if 'http://xmlns.com/foaf/0.1/nick' in str(f.predicate):
d.append(f)
# Do some silly text replacement and get the actual nick
d = [str(i).replace('{',"").replace('}',"").split(', ')[2].replace('"','') for i in d]
d.sort()
return d

177
IRCLogin/plugin.py Normal file
View File

@ -0,0 +1,177 @@
###
# Copyright (c) 2008, Terence Simpson
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of version 2 of the GNU General Public License as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
###
import supybot.utils as utils
from supybot.commands import *
import supybot.plugins as plugins
import supybot.ircutils as ircutils
import supybot.ircmsgs as ircmsgs
import supybot.callbacks as callbacks
import supybot.ircdb as ircdb
import supybot.conf as conf
import supybot.schedule as schedule
import random, os, sys
from cPickle import Unpickler, Pickler
import lp
def checkCapab(msg, irc):
try:
user = ircdb.users.getUser(msg.prefix[:msg.prefix.find('!')])
except:
irc.error(conf.supybot.replies.incorrectAuthentication())
return False
try:
if not user.capabilities.check('Admin'):
irc.error(conf.supybot.replies.noCapability() % 'Admin')
return False
except KeyError:
irc.error(conf.supybot.replies.noCapability() % 'Admin')
return False
return True
class IRCLogin(callbacks.Plugin):
"""Use @login to login, @reloadusers to reload the user list and @updateusers to update the user database from
launchpad"""
threaded = True
def updateusers(self, irc, msg, args):
"""Takes no arguments
Update the user database from Launchpad"""
def writePickle(uf, user2nick, nick2user):
global self
try:
fd = open(uf, 'wb')
except IOError, e:
self.log.error("Could not write to %s (%s)" % (uf, e))
return
except Exception, e:
self.log.error("Unknown error while opening %s for writing:\n%s" % (uf, e))
return
pi = Pickler(fd, 2)
pi.dump((user2nick, nick2user))
if not checkCapab(msg, irc):
return
uf = self.registryValue('UserList')
if not uf:
self.log.info('no UserList config set')
irc.error('No UserList config set')
return
if not os.path.exists(uf):
self.log.info('Creating initial userlist')
else:
self.log.info('Updating userlist')
irc.reply('Running...')
user2nick = {}
nick2user = {}
#TODO: Make the team configurable, just needs a config entry
users = lp.getUsers()
for user in users:
lpuser = lp.getIRCNick(user, False)
if not lpuser:
lpuser = [user]
user2nick[user] = lpuser
for nick in lpuser:
nick2user[nick] = user
writePickle(uf, user2nick, nick2user)
self.loadUsers()
irc.reply('updateusers run complete')
updateusers = wrap(updateusers)
def loadUsers(self):
uf = self.registryValue('UserList')
if not uf or not os.path.exists(uf) or not os.access(uf, os.R_OK):
self.log.info('Not loading non-existant userlist')
return
fd = open(uf, 'rb')
up = Unpickler(fd)
(user2nick, nick2user) = up.load()
self.knownusers = [i.lower() for i in nick2user.keys()]
allusers = [u.name.lower() for u in ircdb.users.itervalues()]
to_add = [x for x in self.knownusers if x not in allusers]
for a in to_add:
self.log.info("Adding %s" % a)
user = ircdb.users.newUser()
user.name = a
rp = ''
chars = '''1234567890-=~!@#$%^&*()_qwertyuiop[]QWERTYUIOP{}}|asdfghjkl;ASDFGHJKL:zxcvbnm,./ZXCVBNM<>?'''
for i in range(16):
rp += chars[random.randint(1,len(chars))-1]
user.setPassword(rp)
bu = []
for u in nick2user.keys():
try:
user = ircdb.users.getUser(u.lower())
#Add bantracker capability to all users from launchpad team
if not 'bantracker' in user.capabilities:
user.addCapability('bantracker')
except Exception, e:
bu.append("%s (%s)" % (u, e))
pass
if bu:
self.log.info("Could not add users %s" % bu)
def reloadusers(self, irc, msg, args):
"""Takes no arguments
Read the user database and add the users in it"""
if not checkCapab(msg, irc):
return
self.loadUsers()
irc.replySuccess()
reloadusers = wrap(reloadusers)
def login(self, irc, msg, args):
"""takes no arguments
Allows users who are identified to NickServ to login without a password.
"""
if not msg.tagged('identified'):
irc.error('You are not identified')
return
try:
user = ircdb.users.getUser(msg.prefix[:msg.prefix.find('!')].lower())
except:
self.loadUsers()
try:
user = ircdb.users.getUser(msg.prefix[:msg.prefix.find('!')].lower())
except:
irc.error(conf.supybot.replies.incorrectAuthentication())
return
user.addAuth(msg.prefix)
ircdb.users.setUser(user, flush=False)
irc.replySuccess()
login = wrap(login)
def do290(self, irc, msg):
assert 'IDENTIFY-MSG' in msg.args[1]
irc.getRealIrc()._Freenode_capabed = True
def do376(self, irc, msg):
irc.queueMsg(ircmsgs.IrcMsg('CAPAB IDENTIFY-MSG'))
def do422(self, irc, msg): # MOTD missing
irc.queueMsg(ircmsgs.IrcMsg('CAPAB IDENTIFY-MSG'))
def inFilter(self, irc, msg):
if getattr(irc,'_Freenode_capabed',None) and msg.command == 'PRIVMSG':
first = msg.args[1][0]
rest = msg.args[1][1:]
msg.tag('identified', first == '+')
msg = ircmsgs.privmsg(msg.args[0], rest, msg=msg)
assert msg.receivedAt and msg.receivedOn and msg.receivedBy
return msg
Class = IRCLogin

View File

@ -1,5 +1,5 @@
###
# Copyright (c) 2007, Dennis Kaarsemaker
# Copyright (c) 2008, Terence Simpson
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of version 2 of the GNU General Public License as
@ -14,5 +14,5 @@
from supybot.test import *
class FreenodeAuthTestCase(PluginTestCase):
plugins = ('FreenodeAuth',)
class IRCLoginTestCase(PluginTestCase):
plugins = ('IRCLogin',)

View File

@ -75,9 +75,8 @@ class Lart(plugins.ChannelIdDatabasePlugin):
return
text = self._replaceFirstPerson(lart.text, msg.nick)
if ircutils.strEqual(target, irc.nick) or \
'ubotu' in ircutils.stripFormatting(target).lower() or \
'seveas' in ircutils.stripFormatting(target).lower() or \
((not msg.prefix.endswith('seveas')) and random.uniform(0,100) < 25):
irc.nick.lower() in ircutils.stripFormatting(target).lower() or \
random.uniform(0,100) < 25:
target = msg.nick
reason = ''
else: