import md5, time import services, util import config from twisted.internet import reactor from store import NetID, IRCUser from config import NetIDs, IRCUsers from mode import Mode def canonicalize(nick): if type(nick) != str: return nick suffixchars = "@[({|" for char in suffixchars: nick = nick.split(char)[0] return nick.lower() class NickServ(services.SimpleService): nick = "NickServ" description = "NetID-enabled Nickname Service" def __init__(self, *args, **kw): super(NickServ, self).__init__(*args, **kw) self.idTimers = {} def irc_NICK(self, args, oldnick, data): nick = args[0] nickbase = canonicalize(nick) oldnickbase = canonicalize(oldnick) mode = Mode(len(args) > 3 and args[3] or "") if oldnick in self.idTimers: self.idTimers[oldnick].cancel() del self.idTimers[oldnick] if nickbase in IRCUsers and not mode.r: self.notice(nick, "Username '%s' is registered. Please identify yourself by typing:" % nickbase) self.notice(nick, "/msg NickServ IDENTIFY [password]") self.idTimers[nick] = reactor.callLater(int(config.NICKSERVAUTHTIME), self.noAuth, nickbase, nick) def noAuth(self, nickbase, nick): del self.idTimers[nick] self.conn.changeNick(nick, "UNAUTH_%.10s" % nick) def setmode(self, nick, mode): ts = "%d" % time.time() # XXX: todo the Right Way (wrt constructing modestring) self.conn.send('SVSMODE', nick, mode+"+d "+ts, prefix=self.conn.hostname) def cmd_HELP(self, frm, args): self.notice(frm, "No help yet.") def cmd_IDENTIFY(self, frm, args): if frm in self.idTimers: user = IRCUsers[canonicalize(frm)] if args == user.password: self.setmode(frm, '+r') self.idTimers[frm].cancel() del self.idTimers[frm] self.notice(frm, "Thanks. You're now registered.") else: self.notice(frm, "Invalid password.") else: self.notice(frm, "I was not expecting an IDENTIFY from you.") cmd_ID = cmd_IDENTIFY cmd_SIDENTIFY = cmd_IDENTIFY def cmd_CONTROL(self, frm, args): parts = args.split(None, 1) if len(parts) == 2: sig, text = parts if util.validsig(sig, text, config.SALT): args = util.unserialize(text) cmdid = args[0] cmd = args[1] method = getattr(self, 'remote_%s' % cmd, None) if method: result = method(*args[2:]) serialized = util.serialize([cmdid, result]) newsig = util.sign(serialized, config.SALT) self.notice(frm, "RESPONSE %s %s" % (newsig, serialized)) def remote_getNetID(self, name): name = name.lower() netid = None if name in NetIDs: netid = NetIDs[name] else: netid = NetID(name, 2, '') NetIDs.update(netid) NetIDs.save() return ' '.join([netid.netid, str(netid.namesallowed), ','.join(netid.names)]) def remote_updateNetID(self, name, namesallowed, names): namesallowed = int(namesallowed) netid = None if name in NetIDs: netid = NetIDs[name] netid.netid = name netid.namesallowed = namesallowed netid.names = names.split(',') else: netid = NetID(name, namesallowed, names) NetIDs.update(netid) NetIDs.save() return "OK" def remote_getIRCUser(self, username): username = username.lower() if username in IRCUsers: user = IRCUsers[username] return ' '.join([user.username, user.netid, user.password]) return "ERR" def remote_deleteIRCUser(self, username): username = username.lower() ircuser = IRCUsers[username] netid = NetIDs[ircuser.netid] netid.names = [name for name in netid.names if name != username] NetIDs.update(netid) del IRCUsers[username] NetIDs.save() IRCUsers.save() return "OK" def remote_updateIRCUser(self, username, netid, password): username = username.lower() netid = netid.lower() user = None if username in IRCUsers: user = IRCUsers[username] user.netid = netid user.password = password else: user = IRCUser(username, netid, password) id = NetIDs[netid] id.names.append(username) NetIDs.update(id) NetIDs.save() IRCUsers.update(user) IRCUsers.save() return "OK"