def __init__(self, headers): self.expires = None self.mtime = None self.length = 0 self.start = 0 self.size = 0 self.mimeType = None headers = InsensitiveDict(headers) encoding = headers.get("Transfer-Encoding", None) if encoding == 'chunked': raise errors.FlumotionError("Chunked transfer not supported") expires = headers.get("Expires", None) if expires is not None: try: self.expires = http.stringToDatetime(expires) except: self.expires = 0 lastmod = headers.get("Last-Modified", None) if lastmod is not None: self.mtime = http.stringToDatetime(lastmod) range = headers.get("Content-Range", None) length = headers.get("Content-Length", None) if range is not None: start, end, total = http.parseContentRange(range) self.start = start self.length = total if length is not None: self.size = int(length) else: self.size = end - start elif length is not None: self.length = int(length) self.size = int(length) else: raise errors.FlumotionError("Can't get length/size from headers", headers) ctype = headers.get("Content-Type", None) if ctype is not None: self.mimeType, _pdict = cgi.parse_header(ctype)
class IRCBot(irc.IRCClient): sasl_buffer = "" sasl_result = None sasl_login = None def __init__(self, factory, plugin): self.factory = factory self.nickname = plugin.nickname.encode('ascii') self.realname = plugin.realname.encode('ascii') self.username = plugin.ident.encode('ascii') self.ns_username = plugin.username self.ns_password = plugin.password self.password = plugin.server_password.encode('ascii') self.channel = plugin.channel.encode('ascii') self.key = plugin.key.encode('ascii') self.console = plugin.console self.irc_message = plugin.irc_message self.irc_action = plugin.irc_action self.irc_chat_status = plugin.irc_chat_status self.mangle_username = plugin.mangle_username self.users = InsensitiveDict() self.cap_requests = set() def register(self, nickname, hostname="foo", servername="bar"): self.sendLine("CAP LS") return irc.IRCClient.register(self, nickname, hostname, servername) def sendLine(self, line): irc.IRCClient.sendLine(self, line.encode('ascii', 'replace')) def _parse_cap(self, cap): mod = '' while cap[0] in "-~=": mod, cap = mod + cap[0], cap[1:] if '/' in cap: vendor, cap = cap.split('/', 1) else: vendor = None return (cap, mod, vendor) def request_cap(self, *caps): self.cap_requests |= set(caps) self.sendLine("CAP REQ :{}".format(' '.join(caps))) @defer.inlineCallbacks def end_cap(self): if self.sasl_result: yield self.sasl_result self.sendLine("CAP END") def irc_CAP(self, prefix, params): self.supports_cap = True identifier, subcommand, args = params args = args.split(' ') if subcommand == "LS": self.sasl_start(args) if not self.cap_requests: self.sendLine("CAP END") elif subcommand == "ACK": ack = [] for cap in args: if not cap: continue cap, mod, vendor = self._parse_cap(cap) if '-' in mod: if cap in self.capabilities: del self.capabilities[cap] continue self.cap_requests.remove(cap) if cap == 'sasl': self.sasl_next() if ack: self.sendLine("CAP ACK :{}".format(' '.join(ack))) if not self.cap_requests: self.end_cap() elif subcommand == "NAK": # this implementation is probably not compliant but it will have to do for now for cap in args: self.cap_requests.remove(cap) if not self.cap_requests: self.end_cap() def signedOn(self): if ISSLTransport.providedBy(self.transport): cert = self.transport.getPeerCertificate() fp = cert.digest("sha1") verified = "verified" if self.factory.parent.server_fingerprint else "unverified" self.console( "irc: connected securely. server fingerprint: {} ({})".format( fp, verified)) else: self.console("irc: connected") if self.ns_username and self.ns_password and not self.sasl_login: self.msg( 'NickServ', 'IDENTIFY {} {}'.format(self.ns_username, self.ns_password)) self.join(self.channel, self.key) def irc_JOIN(self, prefix, params): nick = prefix.split('!')[0] channel = params[-1] if nick == self.nickname: self.joined(channel) else: self.userJoined(prefix, channel) def joined(self, channel): self.console('irc: joined channel') self.factory.client = self def who(a): self.sendLine("WHO " + channel) self.factory.parent.repeating_task(who, 30, now=True) def isupport(self, args): self.compute_prefix_names() def compute_prefix_names(self): KNOWN_NAMES = {"o": "op", "h": "halfop", "v": "voice"} prefixdata = self.supported.getFeature("PREFIX", { "o": ("@", 0), "v": ("+", 1) }).items() op_priority = ([ priority for mode, (prefix, priority) in prefixdata if mode == "o" ] + [None])[0] self.prefixes, self.statuses, self.priority = {}, {}, {} for mode, (prefix, priority) in prefixdata: name = "?" if mode in KNOWN_NAMES: name = KNOWN_NAMES[mode] elif priority == 0: if op_priority == 2: name = "owner" else: name = "admin" else: name = "+" + mode self.prefixes[mode] = prefix self.statuses[prefix] = name self.priority[name] = priority self.priority[mode] = priority self.priority[prefix] = priority def parse_prefixes(self, user, nick, prefixes=''): status = [] prefixdata = self.supported.getFeature("PREFIX", { "o": ("@", 0), "v": ("+", 1) }).items() for mode, (prefix, priority) in prefixdata: if prefix in prefixes + nick: nick = nick.replace(prefix, '') status.append((prefix, priority)) if nick == self.nickname: return user.status = ''.join(t[0] for t in sorted(status, key=lambda t: t[1])) def irc_RPL_WHOREPLY(self, prefix, params): _, channel, username, host, server, nick, status, hg = params if nick == self.nickname: return hops, gecos = hg.split(' ', 1) user = IRCUser(self, nick) user.username = username user.hostname = host user.oper = '*' in status user.away = status[0] == 'G' self.users[nick] = user self.parse_prefixes(user, nick, status[1:].replace('*', '')) def modeChanged(self, user, channel, _set, modes, args): args = list(args) if channel.lower() != self.channel.lower(): return for m, arg in zip(modes, args): if m in self.prefixes and arg != self.nickname: u = self.users.get(arg, None) if u: u.status = u.status.replace(self.prefixes[m], '') if _set: u.status = ''.join( sorted(list(u.status + self.prefixes[m]), key=lambda k: self.priority[k])) def has_status(self, nick, status): if status != 0 and not status: return True if status not in self.priority: return False priority = self.priority[status] u = self.users.get(nick, None) return u and (u.priority is not None) and u.priority <= priority def userJoined(self, user, channel): nick = user.split('!')[0] user = IRCUser(self, nick) self.users[nick] = user def userRenamed(self, oldname, newname): if oldname not in self.users: return u = self.users[oldname] u.nick = newname self.users[newname] = u del self.users[oldname] def userLeft(self, user, channel): if user not in self.users: return del self.users[user] def userKicked(self, kickee, channel, kicker, message): if kickee not in self.users: return del self.users[kickee] def userQuit(self, user, quitMessage): if user not in self.users: return del self.users[user] def privmsg(self, user, channel, msg): if channel != self.channel: return if '!' not in user: return nick = user.split('!')[0] p = self.factory.parent if not self.has_status(nick, self.irc_chat_status): return if p.irc_players_enabled and msg.lower( ) == p.irc_command_prefix + "players": self.say( self.channel, p.irc_players_format.format( players=', '.join(map(self.mangle_username, p.players)))) elif p.irc_command_prefix and msg.startswith( p.irc_command_prefix ) and p.irc_command_status and self.has_status(nick, p.irc_command_status): argv = msg[len(p.irc_command_prefix):].split(' ') command = argv[0] if command.startswith('~'): if p.irc_command_mark2 and ( command.lower() in p.irc_command_allow.lower().split(',') or p.irc_command_allow == '*'): p.dispatch(Hook(line=' '.join(argv))) else: if command.lower() in p.irc_command_allow.lower().split( ',') or p.irc_command_allow == '*': p.send(' '.join(argv)) else: self.irc_message(nick, msg) def action(self, user, channel, msg): self.console("%s %s %s" % (user, channel, msg)) if channel != self.channel: return if '!' not in user: return nick = user.split('!')[0] if self.has_status(nick, self.irc_chat_status): self.irc_action(nick, msg) def irc_AUTHENTICATE(self, prefix, params): self.sasl_continue(params[0]) def sasl_send(self, data): while data and len(data) >= 400: en, data = data[:400].encode('base64').replace('\n', ''), data[400:] self.sendLine("AUTHENTICATE " + en) if data: self.sendLine("AUTHENTICATE " + data.encode('base64').replace('\n', '')) else: self.sendLine("AUTHENTICATE +") def sasl_start(self, cap_list): if 'sasl' not in cap_list: print(cap_list) return self.request_cap('sasl') self.sasl_result = defer.Deferred() self.sasl_mechanisms = list(SASL_MECHANISMS) def sasl_next(self): mech = None while not mech or not mech.is_valid(): if not self.sasl_mechanisms: return False self.sasl_auth = mech = self.sasl_mechanisms.pop(0)( self.ns_username, self.ns_password) self.sendLine("AUTHENTICATE " + self.sasl_auth.name) return True def sasl_continue(self, data): if data == '+': data = '' else: data = data.decode('base64') if len(data) == 400: self.sasl_buffer += data else: response = self.sasl_auth.respond(self.sasl_buffer + data) if response is False: # abort self.sendLine("AUTHENTICATE *") else: self.sasl_send(response) self.sasl_buffer = "" def sasl_finish(self): if self.sasl_result: self.sasl_result.callback(True) self.sasl_result = None def sasl_failed(self, whine=True): if self.sasl_login is False: return if self.sasl_next(): return self.sasl_login = False self.sendLine("AUTHENTICATE *") self.sasl_finish() if whine: self.console("irc: failed to log in.") def irc_904(self, prefix, params): print(params) self.sasl_failed() def irc_905(self, prefix, params): print(params) self.sasl_failed() def irc_906(self, prefix, params): self.sasl_failed(False) def irc_907(self, prefix, params): self.sasl_failed(False) def irc_900(self, prefix, params): self.sasl_login = params[2] self.console("irc: logged in as '{}' (using {})".format( self.sasl_login, self.sasl_auth.name)) def irc_903(self, prefix, params): self.sasl_finish() def alterCollidedNick(self, nickname): return nickname + '_' def irc_relay(self, message): self.say(self.channel, message.encode('utf8'))
class Element(Node): preserveCase = 0 caseInsensitive = 1 nsprefixes = None namespace = '' def __init__(self, tagName, attributes=None, parentNode=None, filename=None, markpos=None, caseInsensitive=1, preserveCase=0, namespace=''): Node.__init__(self, parentNode) self.preserveCase = preserveCase or not caseInsensitive self.caseInsensitive = caseInsensitive if not preserveCase: tagName = tagName.lower() if attributes is None: self.attributes = {} else: self.attributes = attributes for k, v in self.attributes.items(): self.attributes[k] = unescape(v) if caseInsensitive: self.attributes = InsensitiveDict(self.attributes, preserve=preserveCase) self.endTagName = self.nodeName = self.tagName = tagName self._filename = filename self._markpos = markpos self.namespace = namespace def addPrefixes(self, pfxs): if self.nsprefixes is None: self.nsprefixes = pfxs else: self.nsprefixes.update(pfxs) def endTag(self, endTagName): if not self.preserveCase: endTagName = endTagName.lower() self.endTagName = endTagName def isEqualToElement(self, n): if self.caseInsensitive: return (self.attributes == n.attributes) and (self.nodeName.lower() == n.nodeName.lower()) return (self.attributes == n.attributes) and (self.nodeName == n.nodeName) def cloneNode(self, deep=0, parent=None): clone = Element( self.tagName, parentNode=parent, namespace=self.namespace, preserveCase=self.preserveCase, caseInsensitive=self.caseInsensitive) clone.attributes.update(self.attributes) if deep: clone.childNodes = [child.cloneNode(1, clone) for child in self.childNodes] else: clone.childNodes = [] return clone def getElementsByTagName(self, name): if self.caseInsensitive: return getElementsByTagNameNoCase(self, name) return getElementsByTagName(self, name) def hasAttributes(self): return 1 def getAttribute(self, name, default=None): return self.attributes.get(name, default) def getAttributeNS(self, ns, name, default=None): nsk = (ns, name) if self.attributes.has_key(nsk): return self.attributes[nsk] if ns == self.namespace: return self.attributes.get(name, default) return default def getAttributeNode(self, name): return _Attr(self.getAttribute(name), self) def setAttribute(self, name, attr): self.attributes[name] = attr def removeAttribute(self, name): if name in self.attributes: del self.attributes[name] def removeAttribute_has_key(self, name): if self.attributes.has_key(name): del self.attributes[name] def hasAttribute(self, name): return name in self.attributes def hasAttribute_has_key(self, name): return self.attributes.has_key(name) if dictsAreNotSequences: hasAttribute = hasAttribute_has_key removeAttribute = removeAttribute_has_key def writexml(self, stream, indent='', addindent='', newl='', strip=0, nsprefixes={}, namespace=''): # write beginning ALLOWSINGLETON = ('img', 'br', 'hr', 'base', 'meta', 'link', 'param', 'area', 'input', 'col', 'basefont', 'isindex', 'frame') BLOCKELEMENTS = ('html', 'head', 'body', 'noscript', 'ins', 'del', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'script', 'ul', 'ol', 'dl', 'pre', 'hr', 'blockquote', 'address', 'p', 'div', 'fieldset', 'table', 'tr', 'form', 'object', 'fieldset', 'applet', 'map') FORMATNICELY = ('tr', 'ul', 'ol', 'head') # this should never be necessary unless people start # changing .tagName on the fly(?) if not self.preserveCase: self.endTagName = self.tagName w = stream.write if self.nsprefixes: newprefixes = self.nsprefixes.copy() for ns in nsprefixes.keys(): del newprefixes[ns] else: newprefixes = {} begin = ['<'] if self.tagName in BLOCKELEMENTS: begin = [newl, indent] + begin bext = begin.extend writeattr = lambda _atr, _val: bext((' ', _atr, '="', escape(_val), '"')) if namespace != self.namespace and self.namespace: if nsprefixes.has_key(self.namespace): prefix = nsprefixes[self.namespace] bext(prefix+':'+self.tagName) else: bext(self.tagName) writeattr("xmlns", self.namespace) else: bext(self.tagName) j = ''.join for attr, val in self.attributes.iteritems(): if isinstance(attr, tuple): ns, key = attr if nsprefixes.has_key(ns): prefix = nsprefixes[ns] else: prefix = genprefix() newprefixes[ns] = prefix assert val is not None writeattr(prefix+':'+key,val) else: assert val is not None writeattr(attr, val) if newprefixes: for ns, prefix in newprefixes.iteritems(): if prefix: writeattr('xmlns:'+prefix, ns) newprefixes.update(nsprefixes) downprefixes = newprefixes else: downprefixes = nsprefixes w(j(begin)) if self.childNodes: w(">") newindent = indent + addindent for child in self.childNodes: if self.tagName in BLOCKELEMENTS and \ self.tagName in FORMATNICELY: w(j((newl, newindent))) child.writexml(stream, newindent, addindent, newl, strip, downprefixes, self.namespace) if self.tagName in BLOCKELEMENTS: w(j((newl, indent))) w(j(("</", self.endTagName, '>'))) elif self.tagName.lower() not in ALLOWSINGLETON: w(j(('></', self.endTagName, '>'))) else: w(" />") def __repr__(self): rep = "Element(%s" % repr(self.nodeName) if self.attributes: rep += ", attributes=%r" % (self.attributes,) if self._filename: rep += ", filename=%r" % (self._filename,) if self._markpos: rep += ", markpos=%r" % (self._markpos,) return rep + ')' def __str__(self): rep = "<" + self.nodeName if self._filename or self._markpos: rep += " (" if self._filename: rep += repr(self._filename) if self._markpos: rep += " line %s column %s" % self._markpos if self._filename or self._markpos: rep += ")" for item in self.attributes.items(): rep += " %s=%r" % item if self.hasChildNodes(): rep += " >...</%s>" % self.nodeName else: rep += " />" return rep
class Element(Node): preserveCase = 0 caseInsensitive = 1 nsprefixes = None def __init__(self, tagName, attributes=None, parentNode=None, filename=None, markpos=None, caseInsensitive=1, preserveCase=0, namespace=None): Node.__init__(self, parentNode) self.preserveCase = preserveCase or not caseInsensitive self.caseInsensitive = caseInsensitive if not preserveCase: tagName = tagName.lower() if attributes is None: self.attributes = {} else: self.attributes = attributes for k, v in self.attributes.items(): self.attributes[k] = unescape(v) if caseInsensitive: self.attributes = InsensitiveDict(self.attributes, preserve=preserveCase) self.endTagName = self.nodeName = self.tagName = tagName self._filename = filename self._markpos = markpos self.namespace = namespace def addPrefixes(self, pfxs): if self.nsprefixes is None: self.nsprefixes = pfxs else: self.nsprefixes.update(pfxs) def endTag(self, endTagName): if not self.preserveCase: endTagName = endTagName.lower() self.endTagName = endTagName def isEqualToElement(self, n): if self.caseInsensitive: return ((self.attributes == n.attributes) and (self.nodeName.lower() == n.nodeName.lower())) return (self.attributes == n.attributes) and (self.nodeName == n.nodeName) def isEqualToNode(self, other): """ Compare this element to C{other}. If the C{nodeName}, C{namespace}, C{attributes}, and C{childNodes} are all the same, return C{True}, otherwise return C{False}. """ return (self.nodeName.lower() == other.nodeName.lower() and self.namespace == other.namespace and self.attributes == other.attributes and Node.isEqualToNode(self, other)) def cloneNode(self, deep=0, parent=None): clone = Element(self.tagName, parentNode=parent, namespace=self.namespace, preserveCase=self.preserveCase, caseInsensitive=self.caseInsensitive) clone.attributes.update(self.attributes) if deep: clone.childNodes = [ child.cloneNode(1, clone) for child in self.childNodes ] else: clone.childNodes = [] return clone def getElementsByTagName(self, name): if self.caseInsensitive: return getElementsByTagNameNoCase(self, name) return getElementsByTagName(self, name) def hasAttributes(self): return 1 def getAttribute(self, name, default=None): return self.attributes.get(name, default) def getAttributeNS(self, ns, name, default=None): nsk = (ns, name) if nsk in self.attributes: return self.attributes[nsk] if ns == self.namespace: return self.attributes.get(name, default) return default def getAttributeNode(self, name): return _Attr(self.getAttribute(name), self) def setAttribute(self, name, attr): self.attributes[name] = attr def removeAttribute(self, name): if name in self.attributes: del self.attributes[name] def hasAttribute(self, name): return name in self.attributes def writexml(self, stream, indent='', addindent='', newl='', strip=0, nsprefixes={}, namespace=''): """ Serialize this L{Element} to the given stream. @param stream: A file-like object to which this L{Element} will be written. @param nsprefixes: A C{dict} mapping namespace URIs as C{str} to prefixes as C{str}. This defines the prefixes which are already in scope in the document at the point at which this L{Element} exists. This is essentially an implementation detail for namespace support. Applications should not try to use it. @param namespace: The namespace URI as a C{str} which is the default at the point in the document at which this L{Element} exists. This is essentially an implementation detail for namespace support. Applications should not try to use it. """ # write beginning ALLOWSINGLETON = ('img', 'br', 'hr', 'base', 'meta', 'link', 'param', 'area', 'input', 'col', 'basefont', 'isindex', 'frame') BLOCKELEMENTS = ('html', 'head', 'body', 'noscript', 'ins', 'del', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'script', 'ul', 'ol', 'dl', 'pre', 'hr', 'blockquote', 'address', 'p', 'div', 'fieldset', 'table', 'tr', 'form', 'object', 'fieldset', 'applet', 'map') FORMATNICELY = ('tr', 'ul', 'ol', 'head') # this should never be necessary unless people start # changing .tagName on the fly(?) if not self.preserveCase: self.endTagName = self.tagName w = stream.write if self.nsprefixes: newprefixes = self.nsprefixes.copy() for ns in nsprefixes.keys(): if ns in newprefixes: del newprefixes[ns] else: newprefixes = {} begin = ['<'] if self.tagName in BLOCKELEMENTS: begin = [newl, indent] + begin bext = begin.extend writeattr = lambda _atr, _val: bext( (' ', _atr, '="', escape(_val), '"')) # Make a local for tracking what end tag will be used. If namespace # prefixes are involved, this will be changed to account for that # before it's actually used. endTagName = self.endTagName if namespace != self.namespace and self.namespace is not None: # If the current default namespace is not the namespace of this tag # (and this tag has a namespace at all) then we'll write out # something related to namespaces. if self.namespace in nsprefixes: # This tag's namespace already has a prefix bound to it. Use # that prefix. prefix = nsprefixes[self.namespace] bext(prefix + ':' + self.tagName) # Also make sure we use it for the end tag. endTagName = prefix + ':' + self.endTagName else: # This tag's namespace has no prefix bound to it. Change the # default namespace to this tag's namespace so we don't need # prefixes. Alternatively, we could add a new prefix binding. # I'm not sure why the code was written one way rather than the # other. -exarkun bext(self.tagName) writeattr("xmlns", self.namespace) # The default namespace just changed. Make sure any children # know about this. namespace = self.namespace else: # This tag has no namespace or its namespace is already the default # namespace. Nothing extra to do here. bext(self.tagName) j = ''.join for attr, val in sorted(self.attributes.items()): if isinstance(attr, tuple): ns, key = attr if ns in nsprefixes: prefix = nsprefixes[ns] else: prefix = genprefix() newprefixes[ns] = prefix assert val is not None writeattr(prefix + ':' + key, val) else: assert val is not None writeattr(attr, val) if newprefixes: for ns, prefix in newprefixes.iteritems(): if prefix: writeattr('xmlns:' + prefix, ns) newprefixes.update(nsprefixes) downprefixes = newprefixes else: downprefixes = nsprefixes w(j(begin)) if self.childNodes: w(">") newindent = indent + addindent for child in self.childNodes: if self.tagName in BLOCKELEMENTS and \ self.tagName in FORMATNICELY: w(j((newl, newindent))) child.writexml(stream, newindent, addindent, newl, strip, downprefixes, namespace) if self.tagName in BLOCKELEMENTS: w(j((newl, indent))) w(j(('</', endTagName, '>'))) elif self.tagName.lower() not in ALLOWSINGLETON: w(j(('></', endTagName, '>'))) else: w(" />") def __repr__(self): rep = "Element(%s" % repr(self.nodeName) if self.attributes: rep += ", attributes=%r" % (self.attributes, ) if self._filename: rep += ", filename=%r" % (self._filename, ) if self._markpos: rep += ", markpos=%r" % (self._markpos, ) return rep + ')' def __str__(self): rep = "<" + self.nodeName if self._filename or self._markpos: rep += " (" if self._filename: rep += repr(self._filename) if self._markpos: rep += " line %s column %s" % self._markpos if self._filename or self._markpos: rep += ")" for item in self.attributes.items(): rep += " %s=%r" % item if self.hasChildNodes(): rep += " >...</%s>" % self.nodeName else: rep += " />" return rep
class Element(Node): preserveCase = 0 caseInsensitive = 1 nsprefixes = None def __init__(self, tagName, attributes=None, parentNode=None, filename=None, markpos=None, caseInsensitive=1, preserveCase=0, namespace=None): Node.__init__(self, parentNode) self.preserveCase = preserveCase or not caseInsensitive self.caseInsensitive = caseInsensitive if not preserveCase: tagName = tagName.lower() if attributes is None: self.attributes = {} else: self.attributes = attributes for k, v in self.attributes.items(): self.attributes[k] = unescape(v) if caseInsensitive: self.attributes = InsensitiveDict(self.attributes, preserve=preserveCase) self.endTagName = self.nodeName = self.tagName = tagName self._filename = filename self._markpos = markpos self.namespace = namespace def addPrefixes(self, pfxs): if self.nsprefixes is None: self.nsprefixes = pfxs else: self.nsprefixes.update(pfxs) def endTag(self, endTagName): if not self.preserveCase: endTagName = endTagName.lower() self.endTagName = endTagName def isEqualToElement(self, n): if self.caseInsensitive: return ((self.attributes == n.attributes) and (self.nodeName.lower() == n.nodeName.lower())) return (self.attributes == n.attributes) and (self.nodeName == n.nodeName) def isEqualToNode(self, other): """ Compare this element to C{other}. If the C{nodeName}, C{namespace}, C{attributes}, and C{childNodes} are all the same, return C{True}, otherwise return C{False}. """ return (self.nodeName.lower() == other.nodeName.lower() and self.namespace == other.namespace and self.attributes == other.attributes and Node.isEqualToNode(self, other)) def cloneNode(self, deep=0, parent=None): clone = Element(self.tagName, parentNode=parent, namespace=self.namespace, preserveCase=self.preserveCase, caseInsensitive=self.caseInsensitive) clone.attributes.update(self.attributes) if deep: clone.childNodes = [ child.cloneNode(1, clone) for child in self.childNodes ] else: clone.childNodes = [] return clone def getElementsByTagName(self, name): if self.caseInsensitive: return getElementsByTagNameNoCase(self, name) return getElementsByTagName(self, name) def hasAttributes(self): return 1 def getAttribute(self, name, default=None): return self.attributes.get(name, default) def getAttributeNS(self, ns, name, default=None): nsk = (ns, name) if self.attributes.has_key(nsk): return self.attributes[nsk] if ns == self.namespace: return self.attributes.get(name, default) return default def getAttributeNode(self, name): return _Attr(self.getAttribute(name), self) def setAttribute(self, name, attr): self.attributes[name] = attr def removeAttribute(self, name): if name in self.attributes: del self.attributes[name] def hasAttribute(self, name): return name in self.attributes def writexml(self, stream, indent='', addindent='', newl='', strip=0, nsprefixes={}, namespace=''): # write beginning ALLOWSINGLETON = ('img', 'br', 'hr', 'base', 'meta', 'link', 'param', 'area', 'input', 'col', 'basefont', 'isindex', 'frame') BLOCKELEMENTS = ('html', 'head', 'body', 'noscript', 'ins', 'del', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'script', 'ul', 'ol', 'dl', 'pre', 'hr', 'blockquote', 'address', 'p', 'div', 'fieldset', 'table', 'tr', 'form', 'object', 'fieldset', 'applet', 'map') FORMATNICELY = ('tr', 'ul', 'ol', 'head') # this should never be necessary unless people start # changing .tagName on the fly(?) if not self.preserveCase: self.endTagName = self.tagName w = stream.write if self.nsprefixes: newprefixes = self.nsprefixes.copy() for ns in nsprefixes.keys(): if ns in newprefixes: del newprefixes[ns] else: newprefixes = {} begin = ['<'] if self.tagName in BLOCKELEMENTS: begin = [newl, indent] + begin bext = begin.extend writeattr = lambda _atr, _val: bext( (' ', _atr, '="', escape(_val), '"')) if namespace != self.namespace and self.namespace is not None: if nsprefixes.has_key(self.namespace): prefix = nsprefixes[self.namespace] bext(prefix + ':' + self.tagName) else: bext(self.tagName) writeattr("xmlns", self.namespace) else: bext(self.tagName) j = ''.join for attr, val in self.attributes.iteritems(): if isinstance(attr, tuple): ns, key = attr if nsprefixes.has_key(ns): prefix = nsprefixes[ns] else: prefix = genprefix() newprefixes[ns] = prefix assert val is not None writeattr(prefix + ':' + key, val) else: assert val is not None writeattr(attr, val) if newprefixes: for ns, prefix in newprefixes.iteritems(): if prefix: writeattr('xmlns:' + prefix, ns) newprefixes.update(nsprefixes) downprefixes = newprefixes else: downprefixes = nsprefixes w(j(begin)) if self.childNodes: w(">") newindent = indent + addindent for child in self.childNodes: if self.tagName in BLOCKELEMENTS and \ self.tagName in FORMATNICELY: w(j((newl, newindent))) child.writexml(stream, newindent, addindent, newl, strip, downprefixes, self.namespace) if self.tagName in BLOCKELEMENTS: w(j((newl, indent))) w(j(("</", self.endTagName, '>'))) elif self.tagName.lower() not in ALLOWSINGLETON: w(j(('></', self.endTagName, '>'))) else: w(" />") def __repr__(self): rep = "Element(%s" % repr(self.nodeName) if self.attributes: rep += ", attributes=%r" % (self.attributes, ) if self._filename: rep += ", filename=%r" % (self._filename, ) if self._markpos: rep += ", markpos=%r" % (self._markpos, ) return rep + ')' def __str__(self): rep = "<" + self.nodeName if self._filename or self._markpos: rep += " (" if self._filename: rep += repr(self._filename) if self._markpos: rep += " line %s column %s" % self._markpos if self._filename or self._markpos: rep += ")" for item in self.attributes.items(): rep += " %s=%r" % item if self.hasChildNodes(): rep += " >...</%s>" % self.nodeName else: rep += " />" return rep
class Element(Node): preserveCase = 0 caseInsensitive = 1 nsprefixes = None def __init__(self, tagName, attributes=None, parentNode=None, filename=None, markpos=None, caseInsensitive=1, preserveCase=0, namespace=None): Node.__init__(self, parentNode) self.preserveCase = preserveCase or not caseInsensitive self.caseInsensitive = caseInsensitive if not preserveCase: tagName = tagName.lower() if attributes is None: self.attributes = {} else: self.attributes = attributes for k, v in self.attributes.items(): self.attributes[k] = unescape(v) if caseInsensitive: self.attributes = InsensitiveDict(self.attributes, preserve=preserveCase) self.endTagName = self.nodeName = self.tagName = tagName self._filename = filename self._markpos = markpos self.namespace = namespace def addPrefixes(self, pfxs): if self.nsprefixes is None: self.nsprefixes = pfxs else: self.nsprefixes.update(pfxs) def endTag(self, endTagName): if not self.preserveCase: endTagName = endTagName.lower() self.endTagName = endTagName def isEqualToElement(self, n): if self.caseInsensitive: return ((self.attributes == n.attributes) and (self.nodeName.lower() == n.nodeName.lower())) return (self.attributes == n.attributes) and (self.nodeName == n.nodeName) def isEqualToNode(self, other): """ Compare this element to C{other}. If the C{nodeName}, C{namespace}, C{attributes}, and C{childNodes} are all the same, return C{True}, otherwise return C{False}. """ return ( self.nodeName.lower() == other.nodeName.lower() and self.namespace == other.namespace and self.attributes == other.attributes and Node.isEqualToNode(self, other)) def cloneNode(self, deep=0, parent=None): clone = Element( self.tagName, parentNode=parent, namespace=self.namespace, preserveCase=self.preserveCase, caseInsensitive=self.caseInsensitive) clone.attributes.update(self.attributes) if deep: clone.childNodes = [child.cloneNode(1, clone) for child in self.childNodes] else: clone.childNodes = [] return clone def getElementsByTagName(self, name): if self.caseInsensitive: return getElementsByTagNameNoCase(self, name) return getElementsByTagName(self, name) def hasAttributes(self): return 1 def getAttribute(self, name, default=None): return self.attributes.get(name, default) def getAttributeNS(self, ns, name, default=None): nsk = (ns, name) if self.attributes.has_key(nsk): return self.attributes[nsk] if ns == self.namespace: return self.attributes.get(name, default) return default def getAttributeNode(self, name): return _Attr(self.getAttribute(name), self) def setAttribute(self, name, attr): self.attributes[name] = attr def removeAttribute(self, name): if name in self.attributes: del self.attributes[name] def hasAttribute(self, name): return name in self.attributes def writexml(self, stream, indent='', addindent='', newl='', strip=0, nsprefixes={}, namespace=''): """ Serialize this L{Element} to the given stream. @param stream: A file-like object to which this L{Element} will be written. @param nsprefixes: A C{dict} mapping namespace URIs as C{str} to prefixes as C{str}. This defines the prefixes which are already in scope in the document at the point at which this L{Element} exists. This is essentially an implementation detail for namespace support. Applications should not try to use it. @param namespace: The namespace URI as a C{str} which is the default at the point in the document at which this L{Element} exists. This is essentially an implementation detail for namespace support. Applications should not try to use it. """ # write beginning ALLOWSINGLETON = ('img', 'br', 'hr', 'base', 'meta', 'link', 'param', 'area', 'input', 'col', 'basefont', 'isindex', 'frame') BLOCKELEMENTS = ('html', 'head', 'body', 'noscript', 'ins', 'del', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'script', 'ul', 'ol', 'dl', 'pre', 'hr', 'blockquote', 'address', 'p', 'div', 'fieldset', 'table', 'tr', 'form', 'object', 'fieldset', 'applet', 'map') FORMATNICELY = ('tr', 'ul', 'ol', 'head') # this should never be necessary unless people start # changing .tagName on the fly(?) if not self.preserveCase: self.endTagName = self.tagName w = stream.write if self.nsprefixes: newprefixes = self.nsprefixes.copy() for ns in nsprefixes.keys(): if ns in newprefixes: del newprefixes[ns] else: newprefixes = {} begin = ['<'] if self.tagName in BLOCKELEMENTS: begin = [newl, indent] + begin bext = begin.extend writeattr = lambda _atr, _val: bext((' ', _atr, '="', escape(_val), '"')) # Make a local for tracking what end tag will be used. If namespace # prefixes are involved, this will be changed to account for that # before it's actually used. endTagName = self.endTagName if namespace != self.namespace and self.namespace is not None: # If the current default namespace is not the namespace of this tag # (and this tag has a namespace at all) then we'll write out # something related to namespaces. if self.namespace in nsprefixes: # This tag's namespace already has a prefix bound to it. Use # that prefix. prefix = nsprefixes[self.namespace] bext(prefix + ':' + self.tagName) # Also make sure we use it for the end tag. endTagName = prefix + ':' + self.endTagName else: # This tag's namespace has no prefix bound to it. Change the # default namespace to this tag's namespace so we don't need # prefixes. Alternatively, we could add a new prefix binding. # I'm not sure why the code was written one way rather than the # other. -exarkun bext(self.tagName) writeattr("xmlns", self.namespace) # The default namespace just changed. Make sure any children # know about this. namespace = self.namespace else: # This tag has no namespace or its namespace is already the default # namespace. Nothing extra to do here. bext(self.tagName) j = ''.join for attr, val in self.attributes.iteritems(): if isinstance(attr, tuple): ns, key = attr if nsprefixes.has_key(ns): prefix = nsprefixes[ns] else: prefix = genprefix() newprefixes[ns] = prefix assert val is not None writeattr(prefix+':'+key,val) else: assert val is not None writeattr(attr, val) if newprefixes: for ns, prefix in newprefixes.iteritems(): if prefix: writeattr('xmlns:'+prefix, ns) newprefixes.update(nsprefixes) downprefixes = newprefixes else: downprefixes = nsprefixes w(j(begin)) if self.childNodes: w(">") newindent = indent + addindent for child in self.childNodes: if self.tagName in BLOCKELEMENTS and \ self.tagName in FORMATNICELY: w(j((newl, newindent))) child.writexml(stream, newindent, addindent, newl, strip, downprefixes, namespace) if self.tagName in BLOCKELEMENTS: w(j((newl, indent))) w(j(('</', endTagName, '>'))) elif self.tagName.lower() not in ALLOWSINGLETON: w(j(('></', endTagName, '>'))) else: w(" />") def __repr__(self): rep = "Element(%s" % repr(self.nodeName) if self.attributes: rep += ", attributes=%r" % (self.attributes,) if self._filename: rep += ", filename=%r" % (self._filename,) if self._markpos: rep += ", markpos=%r" % (self._markpos,) return rep + ')' def __str__(self): rep = "<" + self.nodeName if self._filename or self._markpos: rep += " (" if self._filename: rep += repr(self._filename) if self._markpos: rep += " line %s column %s" % self._markpos if self._filename or self._markpos: rep += ")" for item in self.attributes.items(): rep += " %s=%r" % item if self.hasChildNodes(): rep += " >...</%s>" % self.nodeName else: rep += " />" return rep
class IRCBot(irc.IRCClient): sasl_buffer = "" sasl_result = None sasl_login = None def __init__(self, factory, plugin): self.factory = factory self.nickname = plugin.nickname.encode('ascii') self.realname = plugin.realname.encode('ascii') self.username = plugin.ident.encode('ascii') self.ns_username = plugin.username self.ns_password = plugin.password self.password = plugin.server_password.encode('ascii') self.channel = plugin.channel.encode('ascii') self.console = plugin.console self.irc_message = plugin.irc_message self.users = InsensitiveDict() self.cap_requests = set() def register(self, nickname, hostname="foo", servername="bar"): self.sendLine("CAP LS") return irc.IRCClient.register(self, nickname, hostname, servername) def _parse_cap(self, cap): mod = '' while cap[0] in "-~=": mod, cap = mod + cap[0], cap[1:] if '/' in cap: vendor, cap = cap.split('/', 1) else: vendor = None return (cap, mod, vendor) def request_cap(self, *caps): self.cap_requests |= set(caps) self.sendLine("CAP REQ :{0}".format(' '.join(caps))) @defer.inlineCallbacks def end_cap(self): if self.sasl_result: yield self.sasl_result self.sendLine("CAP END") def irc_CAP(self, prefix, params): self.supports_cap = True identifier, subcommand, args = params args = args.split(' ') if subcommand == "LS": self.sasl_start(args) if not self.cap_requests: self.sendLine("CAP END") elif subcommand == "ACK": ack = [] for cap in args: if not cap: continue cap, mod, vendor = self._parse_cap(cap) if '-' in mod: if cap in self.capabilities: del self.capabilities[cap] continue self.cap_requests.remove(cap) if cap == 'sasl': self.sasl_next() if ack: self.sendLine("CAP ACK :{0}".format(' '.join(ack))) if not self.cap_requests: self.end_cap() elif subcommand == "NAK": # this implementation is probably not compliant but it will have to do for now for cap in args: self.cap_requests.remove(cap) if not self.cap_requests: self.end_cap() def signedOn(self): if ISSLTransport.providedBy(self.transport): cert = self.transport.getPeerCertificate() fp = cert.digest("sha1") verified = "verified" if self.factory.parent.server_fingerprint else "unverified" self.console("irc: connected securely. server fingerprint: {0} ({1})".format(fp, verified)) else: self.console("irc: connected") if self.ns_username and self.ns_password and not self.sasl_login: self.msg('NickServ', 'IDENTIFY {0} {1}'.format(self.ns_username, self.ns_password)) self.join(self.channel) def irc_JOIN(self, prefix, params): nick = prefix.split('!')[0] channel = params[-1] if nick == self.nickname: self.joined(channel) else: self.userJoined(prefix, channel) def joined(self, channel): self.console('irc: joined channel') self.factory.client = self def who(a): self.sendLine("WHO " + channel) self.factory.parent.repeating_task(who, 30, now=True) def isupport(self, args): self.compute_prefix_names() def compute_prefix_names(self): KNOWN_NAMES = {"o": "op", "h": "halfop", "v": "voice"} prefixdata = self.supported.getFeature("PREFIX", {"o": ("@", 0), "v": ("+", 1)}).items() op_priority = ([priority for mode, (prefix, priority) in prefixdata if mode == "o"] + [None])[0] self.prefixes, self.statuses, self.priority = {}, {}, {} for mode, (prefix, priority) in prefixdata: name = "?" if mode in KNOWN_NAMES: name = KNOWN_NAMES[mode] elif priority == 0: if op_priority == 2: name = "owner" else: name = "admin" else: name = "+" + mode self.prefixes[mode] = prefix self.statuses[prefix] = name self.priority[name] = priority self.priority[mode] = priority self.priority[prefix] = priority def parse_prefixes(self, user, nick, prefixes=''): status = [] prefixdata = self.supported.getFeature("PREFIX", {"o": ("@", 0), "v": ("+", 1)}).items() for mode, (prefix, priority) in prefixdata: if prefix in prefixes + nick: nick = nick.replace(prefix, '') status.append((prefix, priority)) if nick == self.nickname: return user.status = ''.join(t[0] for t in sorted(status, key=lambda t: t[1])) def irc_RPL_WHOREPLY(self, prefix, params): _, channel, username, host, server, nick, status, hg = params if nick == self.nickname: return hops, gecos = hg.split(' ', 1) user = IRCUser(self, nick) user.username = username user.hostname = host user.oper = '*' in status user.away = status[0] == 'G' self.users[nick] = user self.parse_prefixes(user, nick, status[1:].replace('*', '')) def modeChanged(self, user, channel, _set, modes, args): args = list(args) if channel.lower() != self.channel.lower(): return for m, arg in zip(modes, args): if m in self.prefixes and arg != self.nickname: u = self.users.get(arg, None) if u: u.status = u.status.replace(self.prefixes[m], '') if _set: u.status = ''.join(sorted(list(u.status + self.prefixes[m]), key=lambda k: self.priority[k])) def has_status(self, nick, status): if status != 0 and not status: return True if status not in self.priority: return False priority = self.priority[status] u = self.users.get(nick, None) return u and (u.priority is not None) and u.priority <= priority def userJoined(self, user, channel): nick = user.split('!')[0] user = IRCUser(self, nick) self.users[nick] = user def userRenamed(self, oldname, newname): if oldname not in self.users: return u = self.users[oldname] u.nick = newname self.users[newname] = u del self.users[oldname] def userLeft(self, user, channel): if user not in self.users: return del self.users[user] def userKicked(self, kickee, channel, kicker, message): if kickee not in self.users: return del self.users[kickee] def userQuit(self, user, quitMessage): if user not in self.users: return del self.users[user] def privmsg(self, user, channel, msg): if channel != self.channel: return if '!' not in user: return nick = user.split('!')[0] p = self.factory.parent if not self.has_status(nick, p.irc_chat_status): return if p.irc_players_enabled and msg.lower() == p.irc_command_prefix + "players": self.say(self.channel, p.irc_players_format.format(players=', '.join(p.players))) elif p.irc_command_prefix and msg.startswith(p.irc_command_prefix) and p.irc_command_status and self.has_status(nick, p.irc_command_status): argv = msg[len(p.irc_command_prefix):].split(' ') command = argv[0] if command.startswith('~'): if p.irc_command_mark2 and (command.lower() in p.irc_command_allow.lower().split(',') or p.irc_command_allow == '*'): p.dispatch(Hook(line=' '.join(argv))) else: if command.lower() in p.irc_command_allow.lower().split(',') or p.irc_command_allow == '*': p.send(' '.join(argv)) else: p.irc_message(nick, msg) def irc_AUTHENTICATE(self, prefix, params): self.sasl_continue(params[0]) def sasl_send(self, data): while data and len(data) >= 400: en, data = data[:400].encode('base64').replace('\n', ''), data[400:] self.sendLine("AUTHENTICATE " + en) if data: self.sendLine("AUTHENTICATE " + data.encode('base64').replace('\n', '')) else: self.sendLine("AUTHENTICATE +") def sasl_start(self, cap_list): if 'sasl' not in cap_list: print cap_list return self.request_cap('sasl') self.sasl_result = defer.Deferred() self.sasl_mechanisms = list(SASL_MECHANISMS) def sasl_next(self): mech = None while not mech or not mech.is_valid(): if not self.sasl_mechanisms: return False self.sasl_auth = mech = self.sasl_mechanisms.pop(0)(self.ns_username, self.ns_password) self.sendLine("AUTHENTICATE " + self.sasl_auth.name) return True def sasl_continue(self, data): if data == '+': data = '' else: data = data.decode('base64') if len(data) == 400: self.sasl_buffer += data else: response = self.sasl_auth.respond(self.sasl_buffer + data) if response is False: # abort self.sendLine("AUTHENTICATE *") else: self.sasl_send(response) self.sasl_buffer = "" def sasl_finish(self): if self.sasl_result: self.sasl_result.callback(True) self.sasl_result = None def sasl_failed(self, whine=True): if self.sasl_login is False: return if self.sasl_next(): return self.sasl_login = False self.sendLine("AUTHENTICATE *") self.sasl_finish() if whine: self.console("irc: failed to log in.") def irc_904(self, prefix, params): print params self.sasl_failed() def irc_905(self, prefix, params): print params self.sasl_failed() def irc_906(self, prefix, params): self.sasl_failed(False) def irc_907(self, prefix, params): self.sasl_failed(False) def irc_900(self, prefix, params): self.sasl_login = params[2] self.console("irc: logged in as '{0}' (using {1})".format(self.sasl_login, self.sasl_auth.name)) def irc_903(self, prefix, params): self.sasl_finish() def alterCollidedNick(self, nickname): return nickname + '_' def irc_relay(self, message): self.say(self.channel, message.encode('utf8'))
class BaseLDAPEntry(WireStrAlias): dn = None _object_class_keys = set(get_strings('objectClass')) _object_class_lower_keys = set(get_strings('objectclass')) _user_password_keys = set(get_strings('userPassword')) def __init__(self, dn, attributes={}): """ Initialize the object. @param dn: Distinguished Name of the object, as a string. @param attributes: Attributes of the object. A dictionary of attribute types to list of attribute values. """ self._attributes = InsensitiveDict() self.dn = distinguishedname.DistinguishedName(dn) for k, vs in attributes.items(): if k not in self._attributes: self._attributes[k] = [] self._attributes[k].extend(vs) for k, vs in self._attributes.items(): self._attributes[k] = self.buildAttributeSet(k, vs) def buildAttributeSet(self, key, values): return attributeset.LDAPAttributeSet(key, values) def __getitem__(self, key): for k in get_strings(key): if k in self._attributes: return self._attributes[k] raise KeyError(key) def get(self, key, default=None): for k in get_strings(key): if k in self._attributes: return self._attributes[k] return default def has_key(self, key): for k in get_strings(key): if k in self._attributes: return True return False def __contains__(self, key): return self.has_key(key) def __iter__(self): for key in self._attributes.iterkeys(): yield key def keys(self): a = [] for key in self._object_class_keys: if key in self._attributes: a.append(key) l = list(self._attributes.keys()) l.sort(key=to_bytes) for key in l: if key.lower() not in self._object_class_lower_keys: a.append(key) return a def items(self): a = [] for key in self._object_class_keys: objectClasses = list(self._attributes.get(key, [])) objectClasses.sort(key=to_bytes) if objectClasses: a.append((key, objectClasses)) l = list(self._attributes.items()) l.sort(key=lambda x: to_bytes(x[0])) for key, values in l: if key.lower() not in self._object_class_lower_keys: vs = list(values) vs.sort() a.append((key, vs)) return a def toWire(self): a = [] for key in self._object_class_keys: objectClasses = list(self._attributes.get(key, [])) objectClasses.sort(key=to_bytes) a.append((key, objectClasses)) items_gen = ((key, self[key]) for key in self) items = sorted(items_gen, key=lambda x: to_bytes(x[0])) for key, values in items: if key.lower() not in self._object_class_lower_keys: vs = list(values) vs.sort() a.append((key, vs)) return ldif.asLDIF(self.dn.getText(), a) def getLDIF(self): return self.toWire().decode('utf-8') def __eq__(self, other): if not isinstance(other, BaseLDAPEntry): return NotImplemented if self.dn != other.dn: return 0 my = sorted((key for key in self), key=to_bytes) its = sorted((key for key in other), key=to_bytes) if my != its: return 0 for key in my: myAttr = self[key] itsAttr = other[key] if myAttr != itsAttr: return 0 return 1 def __ne__(self, other): return not self == other def __len__(self): return len(self.keys()) def __bool__(self): return True def __nonzero__(self): return self.__bool__() def __repr__(self): keys = sorted((key for key in self), key=to_bytes) a = [] for key in keys: a.append('%s: %s' % (repr(key), repr(list(self[key])))) attributes = ', '.join(a) dn = to_bytes(self.dn.getText()) if six.PY2 else self.dn.getText() return '%s(%s, {%s})' % (self.__class__.__name__, repr(dn), attributes) def diff(self, other): """ Compute differences between this and another LDAP entry. @param other: An LDAPEntry to compare to. @return: None if equal, otherwise a ModifyOp that would make this entry look like other. """ assert self.dn == other.dn if self == other: return None r = [] myKeys = set(key for key in self) otherKeys = set(key for key in other) addedKeys = list(otherKeys - myKeys) addedKeys.sort(key=to_bytes) # for reproducability only for added in addedKeys: r.append(delta.Add(added, other[added])) deletedKeys = list(myKeys - otherKeys) deletedKeys.sort(key=to_bytes) # for reproducability only for deleted in deletedKeys: r.append(delta.Delete(deleted, self[deleted])) sharedKeys = list(myKeys & otherKeys) sharedKeys.sort(key=to_bytes) # for reproducability only for shared in sharedKeys: addedValues = list(other[shared] - self[shared]) if addedValues: addedValues.sort(key=to_bytes) # for reproducability only r.append(delta.Add(shared, addedValues)) deletedValues = list(self[shared] - other[shared]) if deletedValues: deletedValues.sort(key=to_bytes) # for reproducability only r.append(delta.Delete(shared, deletedValues)) return delta.ModifyOp(dn=self.dn, modifications=r) def bind(self, password): return defer.maybeDeferred(self._bind, password) def _bind(self, password): password = to_bytes(password) for key in self._user_password_keys: for digest in self.get(key, ()): digest = to_bytes(digest) if digest.startswith(b'{SSHA}'): raw = base64.decodestring(digest[len(b'{SSHA}'):]) salt = raw[20:] got = sshaDigest(password, salt) if got == digest: return self else: # Plaintext if digest == password: return self raise ldaperrors.LDAPInvalidCredentials() def hasMember(self, dn): for memberDN in self.get('member', []): if memberDN == dn: return True return False def __hash__(self): # FIXME:https://github.com/twisted/ldaptor/issues/101 # The hash should take into consideration any attribute used to # decide the equality. return hash(self.dn)
class BaseLDAPEntry(object): implements(interfaces.ILDAPEntry) dn = None def __init__(self, dn, attributes={}): """ Initialize the object. @param dn: Distinguished Name of the object, as a string. @param attributes: Attributes of the object. A dictionary of attribute types to list of attribute values. """ self._attributes=InsensitiveDict() self.dn = distinguishedname.DistinguishedName(dn) for k,vs in attributes.items(): if k not in self._attributes: self._attributes[k] = [] self._attributes[k].extend(vs) for k,vs in self._attributes.items(): self._attributes[k] = self.buildAttributeSet(k, vs) def buildAttributeSet(self, key, values): return attributeset.LDAPAttributeSet(key, values) def __getitem__(self, key): return self._attributes[key] def get(self, key, default=None): return self._attributes.get(key, default) def has_key(self, key): return key in self._attributes def __contains__(self, key): return self.has_key(key) def keys(self): return self._attributes.keys() def items(self): return self._attributes.items() def __str__(self): a=[] objectClasses = list(self.get('objectClass', [])) objectClasses.sort() a.append(('objectClass', objectClasses)) l=list(self.items()) l.sort() for key, values in l: if key.lower() != 'objectclass': vs = list(values) vs.sort() a.append((key, vs)) return ldif.asLDIF(self.dn, a) def __eq__(self, other): if not isinstance(other, BaseLDAPEntry): return 0 if self.dn != other.dn: return 0 my=self.keys() my.sort() its=other.keys() its.sort() if my!=its: return 0 for key in my: myAttr=self[key] itsAttr=other[key] if myAttr!=itsAttr: return 0 return 1 def __ne__(self, other): return not self==other def __len__(self): return len(self.keys()) def __nonzero__(self): return True def __repr__(self): x={} for key in self.keys(): x[key]=self[key] keys=self.keys() keys.sort() a=[] for key in keys: a.append('%s: %s' % (repr(key), repr(list(self[key])))) attributes=', '.join(a) return '%s(%s, {%s})' % ( self.__class__.__name__, repr(str(self.dn)), attributes) def diff(self, other): """ Compute differences between this and another LDAP entry. @param other: An LDAPEntry to compare to. @return: None if equal, otherwise a ModifyOp that would make this entry look like other. """ assert self.dn == other.dn if self == other: return None r = [] myKeys = sets.Set(self.keys()) otherKeys = sets.Set(other.keys()) addedKeys = list(otherKeys - myKeys) addedKeys.sort() # for reproducability only for added in addedKeys: r.append(delta.Add(added, other[added])) deletedKeys = list(myKeys - otherKeys) deletedKeys.sort() # for reproducability only for deleted in deletedKeys: r.append(delta.Delete(deleted, self[deleted])) sharedKeys = list(myKeys & otherKeys) sharedKeys.sort() # for reproducability only for shared in sharedKeys: addedValues = list(other[shared] - self[shared]) if addedValues: addedValues.sort() # for reproducability only r.append(delta.Add(shared, addedValues)) deletedValues = list(self[shared] - other[shared]) if deletedValues: deletedValues.sort() # for reproducability only r.append(delta.Delete(shared, deletedValues)) return delta.ModifyOp(dn=self.dn, modifications=r) def bind(self, password): return defer.maybeDeferred(self._bind, password) def _bind(self, password): for digest in self.get('userPassword', ()): if digest.startswith('{SSHA}'): raw = base64.decodestring(digest[len('{SSHA}'):]) salt = raw[20:] got = sshaDigest(password, salt) if got == digest: return self raise ldaperrors.LDAPInvalidCredentials def hasMember(self, dn): for memberDN in self.get('member', []): if memberDN == dn: return True return False def __hash__(self): return hash(self.dn)
class Element(Node): nsprefixes = None create_attr = lambda k, v: (' ', k, '="', escape(v), '"') SINGLETONS = ( 'img', 'br', 'hr', 'base', 'meta', 'link', 'param', 'area', 'input', 'col', 'basefont', 'isindex', 'frame') BLOCKELEMENTS = ( 'html', 'head', 'body', 'noscript', 'ins', 'del', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'script', 'ul', 'ol', 'dl', 'pre', 'hr', 'blockquote', 'address', 'p', 'div', 'fieldset', 'table', 'tr', 'form', 'object', 'fieldset', 'applet', 'map') NICEFORMATS = ('tr', 'ul', 'ol', 'head') def __init__( self, tagName, attributes=None, parentNode=None, filename=None, markpos=None, case_insensitive=1, namespace=None ): Node.__init__(self, parentNode) preserve_case = not case_insensitive tagName = tagName if preserve_case else tagName.lower() unescaped = unescape_dict(attributes or {}) if case_insensitive: self.attributes = InsensitiveDict(unescaped, preserve=preserve_case) else: self.attributes = unescaped self.preserve_case = not case_insensitive self.case_insensitive = case_insensitive self.endTagName = self.nodeName = self.tagName = tagName self._filename = filename self._markpos = markpos self.namespace = namespace self.tag_is_blockelement = tagName in self.BLOCKELEMENTS self.tag_is_nice_format = tagName in self.NICEFORMATS self.tag_is_singleton = tagName.lower() in self.SINGLETONS def addPrefixes(self, pfxs): if self.nsprefixes is None: self.nsprefixes = pfxs else: self.nsprefixes.update(pfxs) def endTag(self, endTagName): if self.case_insensitive: endTagName = endTagName.lower() self.endTagName = endTagName def isEqualToElement(self, n): same_attrs = self.attributes == n.attributes if self.case_insensitive: eq = same_attrs and (self.nodeName.lower() == n.nodeName.lower()) else: eq = same_attrs and (self.nodeName == n.nodeName) return eq def isEqualToNode(self, other): """ Compare this element to C{other}. If the C{nodeName}, C{namespace}, C{attributes}, and C{childNodes} are all the same, return C{True}, otherwise return C{False}. """ return ( self.nodeName.lower() == other.nodeName.lower() and self.namespace == other.namespace and self.attributes == other.attributes and Node.isEqualToNode(self, other)) def cloneNode(self, deep=0, parent=None): clone = Element( self.tagName, parentNode=parent, namespace=self.namespace, case_insensitive=self.case_insensitive) clone.attributes.update(self.attributes) if deep: clone.childNodes = [ child.cloneNode(1, clone) for child in self.childNodes] else: clone.childNodes = [] return clone def getElementsByTagName(self, name): icase = self.case_insensitive return getElementsByTagName(self.childNodes, name, icase) def hasAttributes(self): return 1 def getAttribute(self, name, default=None): return self.attributes.get(name, default) def getAttributeNS(self, ns, name, default=None): nsk = (ns, name) if nsk in self.attributes: return self.attributes[nsk] if ns == self.namespace: return self.attributes.get(name, default) return default def getAttributeNode(self, name): return _Attr(self.getAttribute(name), self) def setAttribute(self, name, attr): self.attributes[name] = attr def removeAttribute(self, name): if name in self.attributes: del self.attributes[name] def hasAttribute(self, name): return name in self.attributes def gen_prefixes(self, nsprefixes): for k, v in self.nsprefixes.items(): if k not in nsprefixes: yield (k, v) def _writexml(self, namespace, nsprefixes, newl, indent): newprefixes = dict(self.gen_prefixes(nsprefixes)) begin = [newl, indent, '<'] if self.tag_is_blockelement else ['<'] is_same_namespace = self.namespace and namespace == self.namespace # Make a local for tracking what end tag will be used. If namespace # prefixes are involved, this will be changed to account for that # before it's actually used. endTagName = self.endTagName if not is_same_namespace and self.namespace in nsprefixes: # This tag's namespace already has a prefix bound to it. Use # that prefix. prefix = nsprefixes[self.namespace] begin.extend(prefix + ':' + self.tagName) # Also make sure we use it for the end tag. endTagName = prefix + ':' + self.endTagName elif not is_same_namespace: # This tag's namespace has no prefix bound to it. Change the # default namespace to this tag's namespace so we don't need # prefixes. Alternatively, we could add a new prefix binding. # I'm not sure why the code was written one way rather than the # other. -exarkun begin.extend(self.tagName) begin.extend(self.create_attr("xmlns", self.namespace)) # The default namespace just changed. Make sure any children # know about this. namespace = self.namespace else: # This tag has no namespace or its namespace is already the default # namespace. Nothing extra to do here. begin.extend(self.tagName) prefixes = ('p%s' % str(i) for i in it.count()) for attr, val in sorted(self.attributes.items()): if val and isinstance(attr, tuple): ns, key = attr if ns in nsprefixes: prefix = nsprefixes[ns] else: newprefixes[ns] = prefix = next(prefixes) begin.extend(self.create_attr(prefix + ':' + key, val)) elif val: begin.extend(self.create_attr(attr, val)) return begin, namespace, endTagName, newprefixes def _write_child(self, stream, newl, newindent, **kwargs): for child in self.childNodes: if self.tag_is_blockelement and self.tag_is_nice_format: stream.write(''.join((newl, newindent))) child.writexml(stream, newl=newl, newindent=newindent, **kwargs) def writexml(self, stream, *args, **kwargs): """ Serialize this L{Element} to the given stream. @param stream: A file-like object to which this L{Element} will be written. @param nsprefixes: A C{dict} mapping namespace URIs as C{str} to prefixes as C{str}. This defines the prefixes which are already in scope in the document at the point at which this L{Element} exists. This is essentially an implementation detail for namespace support. Applications should not try to use it. @param namespace: The namespace URI as a C{str} which is the default at the point in the document at which this L{Element} exists. This is essentially an implementation detail for namespace support. Applications should not try to use it. """ indent = kwargs.get('indent', '') addindent = kwargs.get('addindent', '') newl = kwargs.get('newl', '') strip = kwargs.get('strip', 0) nsprefixes = kwargs.get('nsprefixes', {}) namespace = kwargs.get('namespace', '') # this should never be necessary unless people start # changing .tagName on the fly(?) if self.case_insensitive: self.endTagName = self.tagName _args = (namespace, nsprefixes, newl, indent) begin, namespace, endTagName, newprefixes = self._writexml(*_args) for ns, prefix in newprefixes.items(): if prefix: begin.extend(self.create_attr('xmlns:' + prefix, ns)) newprefixes.update(nsprefixes) downprefixes = newprefixes stream.write(''.join(begin)) if self.childNodes: stream.write(">") newindent = indent + addindent kwargs = { 'newindent': newindent, 'addindent': addindent, 'newl': newl, 'strip': strip, 'downprefixes': downprefixes, 'namespace': namespace} self._write_child(stream, newl, newindent, **kwargs) if self.tag_is_blockelement: stream.write(''.join((newl, indent))) stream.write(''.join(('</', endTagName, '>'))) elif not self.tag_is_singleton: stream.write(''.join(('></', endTagName, '>'))) else: stream.write(" />") def __repr__(self): rep = "Element(%s" % repr(self.nodeName) if self.attributes: rep += ", attributes=%r" % (self.attributes,) if self._filename: rep += ", filename=%r" % (self._filename,) if self._markpos: rep += ", markpos=%r" % (self._markpos,) return rep + ')' def __str__(self): rep = "<" + self.nodeName if self._filename or self._markpos: rep += " (" if self._filename: rep += repr(self._filename) if self._markpos: rep += " line %s column %s" % self._markpos if self._filename or self._markpos: rep += ")" for item in self.attributes.items(): rep += " %s=%r" % item if self.hasChildNodes(): rep += " >...</%s>" % self.nodeName else: rep += " />" return rep
class BaseLDAPEntry(object): implements(interfaces.ILDAPEntry) dn = None def __init__(self, dn, attributes={}): """ Initialize the object. @param dn: Distinguished Name of the object, as a string. @param attributes: Attributes of the object. A dictionary of attribute types to list of attribute values. """ self._attributes=InsensitiveDict() self.dn = distinguishedname.DistinguishedName(dn) for k,vs in attributes.items(): if k not in self._attributes: self._attributes[k] = [] self._attributes[k].extend(vs) for k,vs in self._attributes.items(): self._attributes[k] = self.buildAttributeSet(k, vs) def buildAttributeSet(self, key, values): return attributeset.LDAPAttributeSet(key, values) def __getitem__(self, key): return self._attributes[key] def get(self, key, default=None): return self._attributes.get(key, default) def has_key(self, key): return key in self._attributes def __contains__(self, key): return self.has_key(key) def keys(self): a = [] if self.get('objectClass'): a.append('objectClass') l=list(self._attributes.keys()) l.sort() for key in l: if key.lower() != 'objectclass': a.append(key) return a def items(self): a=[] objectClasses = list(self.get('objectClass', [])) objectClasses.sort() if objectClasses: a.append(('objectClass', objectClasses)) l=list(self._attributes.items()) l.sort() for key, values in l: if key.lower() != 'objectclass': vs = list(values) vs.sort() a.append((key, vs)) return a def __str__(self): a=[] objectClasses = list(self.get('objectClass', [])) objectClasses.sort() a.append(('objectClass', objectClasses)) l=list(self.items()) l.sort() for key, values in l: if key.lower() != 'objectclass': vs = list(values) vs.sort() a.append((key, vs)) return ldif.asLDIF(self.dn, a) def __eq__(self, other): if not isinstance(other, BaseLDAPEntry): return 0 if self.dn != other.dn: return 0 my=self.keys() my.sort() its=other.keys() its.sort() if my!=its: return 0 for key in my: myAttr=self[key] itsAttr=other[key] if myAttr!=itsAttr: return 0 return 1 def __ne__(self, other): return not self==other def __len__(self): return len(self.keys()) def __nonzero__(self): return True def __repr__(self): x={} for key in self.keys(): x[key]=self[key] keys=self.keys() keys.sort() a=[] for key in keys: a.append('%s: %s' % (repr(key), repr(list(self[key])))) attributes=', '.join(a) return '%s(%s, {%s})' % ( self.__class__.__name__, repr(str(self.dn)), attributes) def diff(self, other): """ Compute differences between this and another LDAP entry. @param other: An LDAPEntry to compare to. @return: None if equal, otherwise a ModifyOp that would make this entry look like other. """ assert self.dn == other.dn if self == other: return None r = [] myKeys = set(self.keys()) otherKeys = set(other.keys()) addedKeys = list(otherKeys - myKeys) addedKeys.sort() # for reproducability only for added in addedKeys: r.append(delta.Add(added, other[added])) deletedKeys = list(myKeys - otherKeys) deletedKeys.sort() # for reproducability only for deleted in deletedKeys: r.append(delta.Delete(deleted, self[deleted])) sharedKeys = list(myKeys & otherKeys) sharedKeys.sort() # for reproducability only for shared in sharedKeys: addedValues = list(other[shared] - self[shared]) if addedValues: addedValues.sort() # for reproducability only r.append(delta.Add(shared, addedValues)) deletedValues = list(self[shared] - other[shared]) if deletedValues: deletedValues.sort() # for reproducability only r.append(delta.Delete(shared, deletedValues)) return delta.ModifyOp(dn=self.dn, modifications=r) def bind(self, password): return defer.maybeDeferred(self._bind, password) def _bind(self, password): for digest in self.get('userPassword', ()): if digest.startswith('{SSHA}'): raw = base64.decodestring(digest[len('{SSHA}'):]) salt = raw[20:] got = sshaDigest(password, salt) if got == digest: return self raise ldaperrors.LDAPInvalidCredentials def hasMember(self, dn): for memberDN in self.get('member', []): if memberDN == dn: return True return False def __hash__(self): return hash(self.dn)
class Element(Node): nsprefixes = None create_attr = lambda k, v: (' ', k, '="', escape(v), '"') SINGLETONS = ('img', 'br', 'hr', 'base', 'meta', 'link', 'param', 'area', 'input', 'col', 'basefont', 'isindex', 'frame') BLOCKELEMENTS = ('html', 'head', 'body', 'noscript', 'ins', 'del', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'script', 'ul', 'ol', 'dl', 'pre', 'hr', 'blockquote', 'address', 'p', 'div', 'fieldset', 'table', 'tr', 'form', 'object', 'fieldset', 'applet', 'map') NICEFORMATS = ('tr', 'ul', 'ol', 'head') def __init__(self, tagName, attributes=None, parentNode=None, filename=None, markpos=None, case_insensitive=1, namespace=None): Node.__init__(self, parentNode) preserve_case = not case_insensitive tagName = tagName if preserve_case else tagName.lower() unescaped = unescape_dict(attributes or {}) if case_insensitive: self.attributes = InsensitiveDict(unescaped, preserve=preserve_case) else: self.attributes = unescaped self.preserve_case = not case_insensitive self.case_insensitive = case_insensitive self.endTagName = self.nodeName = self.tagName = tagName self._filename = filename self._markpos = markpos self.namespace = namespace self.tag_is_blockelement = tagName in self.BLOCKELEMENTS self.tag_is_nice_format = tagName in self.NICEFORMATS self.tag_is_singleton = tagName.lower() in self.SINGLETONS def addPrefixes(self, pfxs): if self.nsprefixes is None: self.nsprefixes = pfxs else: self.nsprefixes.update(pfxs) def endTag(self, endTagName): if self.case_insensitive: endTagName = endTagName.lower() self.endTagName = endTagName def isEqualToElement(self, n): same_attrs = self.attributes == n.attributes if self.case_insensitive: eq = same_attrs and (self.nodeName.lower() == n.nodeName.lower()) else: eq = same_attrs and (self.nodeName == n.nodeName) return eq def isEqualToNode(self, other): """ Compare this element to C{other}. If the C{nodeName}, C{namespace}, C{attributes}, and C{childNodes} are all the same, return C{True}, otherwise return C{False}. """ return (self.nodeName.lower() == other.nodeName.lower() and self.namespace == other.namespace and self.attributes == other.attributes and Node.isEqualToNode(self, other)) def cloneNode(self, deep=0, parent=None): clone = Element(self.tagName, parentNode=parent, namespace=self.namespace, case_insensitive=self.case_insensitive) clone.attributes.update(self.attributes) if deep: clone.childNodes = [ child.cloneNode(1, clone) for child in self.childNodes ] else: clone.childNodes = [] return clone def getElementsByTagName(self, name): icase = self.case_insensitive return getElementsByTagName(self.childNodes, name, icase) def hasAttributes(self): return 1 def getAttribute(self, name, default=None): return self.attributes.get(name, default) def getAttributeNS(self, ns, name, default=None): nsk = (ns, name) if nsk in self.attributes: return self.attributes[nsk] if ns == self.namespace: return self.attributes.get(name, default) return default def getAttributeNode(self, name): return _Attr(self.getAttribute(name), self) def setAttribute(self, name, attr): self.attributes[name] = attr def removeAttribute(self, name): if name in self.attributes: del self.attributes[name] def hasAttribute(self, name): return name in self.attributes def gen_prefixes(self, nsprefixes): for k, v in self.nsprefixes.items(): if k not in nsprefixes: yield (k, v) def _writexml(self, namespace, nsprefixes, newl, indent): newprefixes = dict(self.gen_prefixes(nsprefixes)) begin = [newl, indent, '<'] if self.tag_is_blockelement else ['<'] is_same_namespace = self.namespace and namespace == self.namespace # Make a local for tracking what end tag will be used. If namespace # prefixes are involved, this will be changed to account for that # before it's actually used. endTagName = self.endTagName if not is_same_namespace and self.namespace in nsprefixes: # This tag's namespace already has a prefix bound to it. Use # that prefix. prefix = nsprefixes[self.namespace] begin.extend(prefix + ':' + self.tagName) # Also make sure we use it for the end tag. endTagName = prefix + ':' + self.endTagName elif not is_same_namespace: # This tag's namespace has no prefix bound to it. Change the # default namespace to this tag's namespace so we don't need # prefixes. Alternatively, we could add a new prefix binding. # I'm not sure why the code was written one way rather than the # other. -exarkun begin.extend(self.tagName) begin.extend(self.create_attr("xmlns", self.namespace)) # The default namespace just changed. Make sure any children # know about this. namespace = self.namespace else: # This tag has no namespace or its namespace is already the default # namespace. Nothing extra to do here. begin.extend(self.tagName) prefixes = ('p%s' % str(i) for i in it.count()) for attr, val in sorted(self.attributes.items()): if val and isinstance(attr, tuple): ns, key = attr if ns in nsprefixes: prefix = nsprefixes[ns] else: newprefixes[ns] = prefix = next(prefixes) begin.extend(self.create_attr(prefix + ':' + key, val)) elif val: begin.extend(self.create_attr(attr, val)) return begin, namespace, endTagName, newprefixes def _write_child(self, stream, newl, newindent, **kwargs): for child in self.childNodes: if self.tag_is_blockelement and self.tag_is_nice_format: stream.write(''.join((newl, newindent))) child.writexml(stream, newl=newl, newindent=newindent, **kwargs) def writexml(self, stream, *args, **kwargs): """ Serialize this L{Element} to the given stream. @param stream: A file-like object to which this L{Element} will be written. @param nsprefixes: A C{dict} mapping namespace URIs as C{str} to prefixes as C{str}. This defines the prefixes which are already in scope in the document at the point at which this L{Element} exists. This is essentially an implementation detail for namespace support. Applications should not try to use it. @param namespace: The namespace URI as a C{str} which is the default at the point in the document at which this L{Element} exists. This is essentially an implementation detail for namespace support. Applications should not try to use it. """ indent = kwargs.get('indent', '') addindent = kwargs.get('addindent', '') newl = kwargs.get('newl', '') strip = kwargs.get('strip', 0) nsprefixes = kwargs.get('nsprefixes', {}) namespace = kwargs.get('namespace', '') # this should never be necessary unless people start # changing .tagName on the fly(?) if self.case_insensitive: self.endTagName = self.tagName _args = (namespace, nsprefixes, newl, indent) begin, namespace, endTagName, newprefixes = self._writexml(*_args) for ns, prefix in newprefixes.items(): if prefix: begin.extend(self.create_attr('xmlns:' + prefix, ns)) newprefixes.update(nsprefixes) downprefixes = newprefixes stream.write(''.join(begin)) if self.childNodes: stream.write(">") newindent = indent + addindent kwargs = { 'newindent': newindent, 'addindent': addindent, 'newl': newl, 'strip': strip, 'downprefixes': downprefixes, 'namespace': namespace } self._write_child(stream, newl, newindent, **kwargs) if self.tag_is_blockelement: stream.write(''.join((newl, indent))) stream.write(''.join(('</', endTagName, '>'))) elif not self.tag_is_singleton: stream.write(''.join(('></', endTagName, '>'))) else: stream.write(" />") def __repr__(self): rep = "Element(%s" % repr(self.nodeName) if self.attributes: rep += ", attributes=%r" % (self.attributes, ) if self._filename: rep += ", filename=%r" % (self._filename, ) if self._markpos: rep += ", markpos=%r" % (self._markpos, ) return rep + ')' def __str__(self): rep = "<" + self.nodeName if self._filename or self._markpos: rep += " (" if self._filename: rep += repr(self._filename) if self._markpos: rep += " line %s column %s" % self._markpos if self._filename or self._markpos: rep += ")" for item in self.attributes.items(): rep += " %s=%r" % item if self.hasChildNodes(): rep += " >...</%s>" % self.nodeName else: rep += " />" return rep
class IRCBot(irc.IRCClient): sasl_buffer = "" sasl_result = None sasl_login = None cancel_hilight_re = re.compile(ur"(?:(?<=\u00a7[0-9a-flmnor])|(?<!\u00a7)\b).+?\b") def __init__(self, factory, parent): self.factory = factory self.nickname = parent.nickname.encode('ascii') self.realname = parent.realname.encode('ascii') self.username = parent.ident.encode('ascii') self.ns_username = parent.username self.ns_password = parent.password self.password = parent.server_password.encode('ascii') self.join_channels = parent.channel_map.keys() self.users = InsensitiveDict() self.channels = InsensitiveDict() self.cap_requests = set() self.parent = parent def register(self, nickname, hostname="foo", servername="bar"): self.sendLine("CAP LS") return irc.IRCClient.register(self, nickname, hostname, servername) def sendLine(self, line): if isinstance(line, unicode): line = line.encode('utf8', 'replace') irc.IRCClient.sendLine(self, line) def _parse_cap(self, cap): mod = '' while cap[0] in "-~=": mod, cap = mod + cap[0], cap[1:] if '/' in cap: vendor, cap = cap.split('/', 1) else: vendor = None return (cap, mod, vendor) def request_cap(self, *caps): self.cap_requests |= set(caps) self.sendLine("CAP REQ :{0}".format(' '.join(caps))) @defer.inlineCallbacks def end_cap(self): if self.sasl_result: yield self.sasl_result self.sendLine("CAP END") def irc_CAP(self, prefix, params): self.supports_cap = True identifier, subcommand, args = params args = args.split(' ') if subcommand == "LS": self.sasl_start(args) if not self.cap_requests: self.sendLine("CAP END") elif subcommand == "ACK": ack = [] for cap in args: if not cap: continue cap, mod, vendor = self._parse_cap(cap) if '-' in mod: if cap in self.capabilities: del self.capabilities[cap] continue self.cap_requests.remove(cap) if cap == 'sasl': self.sasl_next() if ack: self.sendLine("CAP ACK :{0}".format(' '.join(ack))) if not self.cap_requests: self.end_cap() elif subcommand == "NAK": # this implementation is probably not compliant but it will have to do for now for cap in args: self.cap_requests.remove(cap) if not self.cap_requests: self.end_cap() def signedOn(self): if ISSLTransport.providedBy(self.transport): cert = self.transport.getPeerCertificate() fp = cert.digest("sha1") verified = "verified" if self.factory.parent.server_fingerprint else "unverified" print("irc: connected securely. server fingerprint: {0} ({1})".format(fp, verified)) else: print("irc: connected") if self.ns_username and self.ns_password and not self.sasl_login: self.msg('NickServ', 'IDENTIFY {0} {1}'.format(self.ns_username, self.ns_password)) for channel in self.join_channels: self.join(channel) def irc_JOIN(self, prefix, params): nick = prefix.split('!')[0] channel = params[-1] if nick == self.nickname: self.joined(channel) else: self.userJoined(prefix, channel) def joined(self, channel): print('irc: joined channel') self.factory.client = self def who(): self.sendLine("WHO " + channel) task.LoopingCall(who).start(30) def isupport(self, args): self.compute_prefix_names() def compute_prefix_names(self): KNOWN_NAMES = {"o": "op", "h": "halfop", "v": "voice"} prefixdata = self.supported.getFeature("PREFIX", {"o": ("@", 0), "v": ("+", 1)}).items() op_priority = ([priority for mode, (prefix, priority) in prefixdata if mode == "o"] + [None])[0] self.prefixes, self.statuses, self.priority = {}, {}, {} for mode, (prefix, priority) in prefixdata: name = "?" if mode in KNOWN_NAMES: name = KNOWN_NAMES[mode] elif priority == 0: if op_priority == 2: name = "owner" else: name = "admin" else: name = "+" + mode self.prefixes[mode] = prefix self.statuses[prefix] = name self.priority[name] = priority self.priority[mode] = priority self.priority[prefix] = priority def parse_prefixes(self, user, nick, prefixes=''): status = [] prefixdata = self.supported.getFeature("PREFIX", {"o": ("@", 0), "v": ("+", 1)}).items() for mode, (prefix, priority) in prefixdata: if prefix in prefixes + nick: nick = nick.replace(prefix, '') status.append((prefix, priority)) if nick == self.nickname: return user.status = ''.join(t[0] for t in sorted(status, key=lambda t: t[1])) def irc_RPL_WHOREPLY(self, prefix, params): _, channel, username, host, server, nick, status, hg = params if nick == self.nickname: return hops, gecos = hg.split(' ', 1) user = self.get_user(nick) or IRCUser(self, nick) user.username = username user.hostname = host user.oper = '*' in status user.away = status[0] == 'G' self.users[nick] = user self.get_channel(channel)[nick] = IRCUserInChannel(user, channel) self.parse_prefixes(user, nick, status[1:].replace('*', '')) def modeChanged(self, user, channel, _set, modes, args): args = list(args) if channel not in self.parent.channel_map: return for m, arg in zip(modes, args): if m in self.prefixes and arg != self.nickname: u = self.get_user(arg).on(channel) if u: u.status = u.status.replace(self.prefixes[m], '') if _set: u.status = ''.join(sorted(list(u.status + self.prefixes[m]), key=lambda k: self.priority[k])) def has_status(self, nick, status): if status != 0 and not status: return True if status not in self.priority: return False priority = self.priority[status] u = self.users.get(nick, None) return u and (u.priority is not None) and u.priority <= priority def get_channel(self, channel): return self.channels.setdefault(channel, InsensitiveDict()) def get_user(self, nick): return self.users.get(nick, False) def userJoined(self, user, channel): nick = user.split('!')[0] user = IRCUser(self, nick) self.users[nick] = user self.get_channel(channel)[nick] = IRCUserInChannel(user, channel) def userRenamed(self, oldname, newname): if oldname not in self.users: return u = self.users[oldname] u.nick = newname self.users[newname] = u del self.users[oldname] for k, v in self.channels.items(): if oldname in v: v[newname] = v[oldname] del v[oldname] def userLeft(self, user, channel): if user not in self.users: return del self.users[user] for k, v in self.channels.items(): if user in v: del v[user] def userKicked(self, kickee, channel, kicker, message): if kickee not in self.users: return del self.users[kickee] for k, v in self.channels.items(): if user in v: del v[user] def userQuit(self, user, quitMessage): if user not in self.users: return del self.users[user] for k, v in self.channels.items(): if user in v: del v[user] def privmsg(self, user, channel, msg): pass def action(self, user, channel, msg): pass def irc_AUTHENTICATE(self, prefix, params): self.sasl_continue(params[0]) def sasl_send(self, data): while data and len(data) >= 400: en, data = data[:400].encode('base64').replace('\n', ''), data[400:] self.sendLine("AUTHENTICATE " + en) if data: self.sendLine("AUTHENTICATE " + data.encode('base64').replace('\n', '')) else: self.sendLine("AUTHENTICATE +") def sasl_start(self, cap_list): if 'sasl' not in cap_list: return self.request_cap('sasl') self.sasl_result = defer.Deferred() self.sasl_mechanisms = list(SASL_MECHANISMS) def sasl_next(self): mech = None while not mech or not mech.is_valid(): if not self.sasl_mechanisms: return False self.sasl_auth = mech = self.sasl_mechanisms.pop(0)(self.ns_username, self.ns_password) self.sendLine("AUTHENTICATE " + self.sasl_auth.name) return True def sasl_continue(self, data): if data == '+': data = '' else: data = data.decode('base64') if len(data) == 400: self.sasl_buffer += data else: response = self.sasl_auth.respond(self.sasl_buffer + data) if response is False: # abort self.sendLine("AUTHENTICATE *") else: self.sasl_send(response) self.sasl_buffer = "" def sasl_finish(self): if self.sasl_result: self.sasl_result.callback(True) self.sasl_result = None def sasl_failed(self, whine=True): if self.sasl_login is False: return if self.sasl_next(): return self.sasl_login = False self.sendLine("AUTHENTICATE *") self.sasl_finish() if whine: print("irc: failed to log in.") def irc_904(self, prefix, params): self.sasl_failed() def irc_905(self, prefix, params): self.sasl_failed() def irc_906(self, prefix, params): self.sasl_failed(False) def irc_907(self, prefix, params): self.sasl_failed(False) def irc_900(self, prefix, params): self.sasl_login = params[2] print("irc: logged in as '{0}' (using {1})".format(self.sasl_login, self.sasl_auth.name)) def irc_903(self, prefix, params): self.sasl_finish() def alterCollidedNick(self, nickname): return nickname + '_' def cancel_hilights(self, channel, text): def hl(match): s = match.group(0) if len(s) >= 2 and s in self.get_channel(channel): return s[:-1] + '*' + s[-1] else: return s return self.cancel_hilight_re.sub(hl, text) def translate_colors(self, text): tr = { "0": "\x0301", "1": "\x0302", "2": "\x0303", "3": "\x0310", "4": "\x0304", "5": "\x0306", "6": "\x0308", "7": "\x0315", "8": "\x0314", "9": "\x0312", "a": "\x0309", "b": "\x0311", "c": "\x0304", "d": "\x0313", "e": "\x0308", "f": "\x0F", } return re.sub(ur"\u00a7([0-9a-f])", lambda m: tr.get(m.group(1), ""), text) def irc_relay(self, channel, message): message = message.decode('utf8') self.say(channel, self.translate_colors(self.cancel_hilights(channel, message)))
class IRCBot(irc.IRCClient): def __init__(self, factory, plugin): self.factory = factory self.nickname = plugin.nickname.encode('ascii') self.realname = plugin.realname.encode('ascii') self.username = plugin.username.encode('ascii') self.ns_password = plugin.password self.password = plugin.server_password.encode('ascii') self.channel = plugin.channel.encode('ascii') self.console = plugin.console self.irc_message = plugin.irc_message self.users = InsensitiveDict() def signedOn(self): if have_ssl and isinstance(self.transport, TLSMemoryBIOProtocol): cert = self.transport.getPeerCertificate() fp = cert.digest("sha1") verified = "verified" if self.factory.parent.server_fingerprint else "unverified" self.console("irc: connected securely. server fingerprint: {} ({})".format(fp, verified)) else: self.console("irc: connected") if self.ns_password: self.msg('NickServ', 'IDENTIFY %s' % self.ns_password) self.join(self.channel) def irc_JOIN(self, prefix, params): nick = prefix.split('!')[0] channel = params[-1] if nick == self.nickname: self.joined(channel) else: self.userJoined(prefix, channel) def joined(self, channel): self.console('irc: joined channel') self.factory.client = self def who(a): self.sendLine("WHO " + channel) self.factory.parent.repeating_task(who, 30, now=True) def isupport(self, args): self.compute_prefix_names() def compute_prefix_names(self): KNOWN_NAMES = {"o": "op", "h": "halfop", "v": "voice"} prefixdata = self.supported.getFeature("PREFIX", {"o": ("@", 0), "v": ("+", 1)}).items() op_priority = ([priority for mode, (prefix, priority) in prefixdata if mode == "o"] + [None])[0] self.prefixes, self.statuses, self.priority = {}, {}, {} for mode, (prefix, priority) in prefixdata: name = "?" if mode in KNOWN_NAMES: name = KNOWN_NAMES[mode] elif priority == 0: if op_priority == 2: name = "owner" else: name = "admin" else: name = "+" + mode self.prefixes[mode] = prefix self.statuses[prefix] = name self.priority[name] = priority self.priority[mode] = priority self.priority[prefix] = priority def parse_prefixes(self, user, nick, prefixes=''): status = [] prefixdata = self.supported.getFeature("PREFIX", {"o": ("@", 0), "v": ("+", 1)}).items() for mode, (prefix, priority) in prefixdata: if prefix in prefixes + nick: nick = nick.replace(prefix, '') status.append((prefix, priority)) if nick == self.nickname: return user.status = ''.join(t[0] for t in sorted(status, key=lambda t: t[1])) def irc_RPL_WHOREPLY(self, prefix, params): _, channel, username, host, server, nick, status, hg = params if nick == self.nickname: return hops, gecos = hg.split(' ', 1) user = IRCUser(self, nick) user.username = username user.hostname = host user.oper = '*' in status user.away = status[0] == 'G' self.users[nick] = user self.parse_prefixes(user, nick, status[1:].replace('*', '')) def modeChanged(self, user, channel, _set, modes, args): args = list(args) if channel.lower() != self.channel.lower(): return for m, arg in zip(modes, args): if m in self.prefixes and arg != self.nickname: u = self.users.get(arg, None) if u: u.status = u.status.replace(self.prefixes[m], '') if _set: u.status = ''.join(sorted(list(u.status + self.prefixes[m]), key=lambda k: self.priority[k])) def userJoined(self, user, channel): nick = user.split('!')[0] user = IRCUser(self, nick) self.users[nick] = user def userRenamed(self, oldname, newname): if oldname not in self.users: return u = self.users[oldname] u.nick = newname self.users[newname] = u del self.users[oldname] def userLeft(self, user, channel): if user not in self.users: return del self.users[user] def userKicked(self, kickee, channel, kicker, message): if kickee not in self.users: return del self.users[kickee] def userQuit(self, user, quitMessage): if user not in self.users: return del self.users[user] def privmsg(self, user, channel, msg): if channel != self.channel: return if '!' not in user: return nick = user.split('!')[0] p = self.factory.parent if p.irc_chat_status and p.irc_chat_status in self.priority: priority = self.priority[p.irc_chat_status] u = self.users.get(nick, None) if not u or u.priority is None or u.priority > priority: return if p.irc_players_enabled and msg == p.irc_players_trigger: self.say(self.channel, p.irc_players_format.format(players=', '.join(p.players))) else: p.irc_message(nick, msg) def alterCollidedNick(self, nickname): return nickname + '_' def irc_relay(self, message): self.say(self.channel, message.encode('utf8'))
class BaseLDAPEntry(WireStrAlias): dn = None _object_class_keys = set(get_strings('objectClass')) _object_class_lower_keys = set(get_strings('objectclass')) _user_password_keys = set(get_strings('userPassword')) def __init__(self, dn, attributes={}): """ Initialize the object. @param dn: Distinguished Name of the object, as a string. @param attributes: Attributes of the object. A dictionary of attribute types to list of attribute values. """ self._attributes = InsensitiveDict() self.dn = distinguishedname.DistinguishedName(dn) for k, vs in attributes.items(): if k not in self._attributes: self._attributes[k] = [] self._attributes[k].extend(vs) for k, vs in self._attributes.items(): self._attributes[k] = self.buildAttributeSet(k, vs) def buildAttributeSet(self, key, values): return attributeset.LDAPAttributeSet(key, values) def __getitem__(self, key): for k in get_strings(key): if k in self._attributes: return self._attributes[k] raise KeyError(key) def get(self, key, default=None): for k in get_strings(key): if k in self._attributes: return self._attributes[k] return default def has_key(self, key): for k in get_strings(key): if k in self._attributes: return True return False def __contains__(self, key): return self.has_key(key) def __iter__(self): for key in self._attributes.iterkeys(): yield key def keys(self): a = [] for key in self._object_class_keys: if key in self._attributes: a.append(key) l = list(self._attributes.keys()) l.sort(key=to_bytes) for key in l: if key.lower() not in self._object_class_lower_keys: a.append(key) return a def items(self): a = [] for key in self._object_class_keys: objectClasses = list(self._attributes.get(key, [])) objectClasses.sort(key=to_bytes) if objectClasses: a.append((key, objectClasses)) l = list(self._attributes.items()) l.sort(key=lambda x: to_bytes(x[0])) for key, values in l: if key.lower() not in self._object_class_lower_keys: vs = list(values) vs.sort() a.append((key, vs)) return a def toWire(self): a = [] for key in self._object_class_keys: objectClasses = list(self._attributes.get(key, [])) objectClasses.sort(key=to_bytes) a.append((key, objectClasses)) items_gen = ((key, self[key]) for key in self) items = sorted(items_gen, key=lambda x: to_bytes(x[0])) for key, values in items: if key.lower() not in self._object_class_lower_keys: vs = list(values) vs.sort() a.append((key, vs)) return ldif.asLDIF(self.dn.getText(), a) def getLDIF(self): return self.toWire().decode('utf-8') def __eq__(self, other): if not isinstance(other, BaseLDAPEntry): return NotImplemented if self.dn != other.dn: return 0 my = sorted((key for key in self), key=to_bytes) its = sorted((key for key in other), key=to_bytes) if my != its: return 0 for key in my: myAttr = self[key] itsAttr = other[key] if myAttr != itsAttr: return 0 return 1 def __ne__(self, other): return not self == other def __len__(self): return len(self.keys()) def __bool__(self): return True def __nonzero__(self): return self.__bool__() def __repr__(self): keys = sorted((key for key in self), key=to_bytes) a = [] for key in keys: a.append('%s: %s' % (repr(key), repr(list(self[key])))) attributes = ', '.join(a) dn = to_bytes(self.dn.getText()) if six.PY2 else self.dn.getText() return '%s(%s, {%s})' % ( self.__class__.__name__, repr(dn), attributes) def diff(self, other): """ Compute differences between this and another LDAP entry. @param other: An LDAPEntry to compare to. @return: None if equal, otherwise a ModifyOp that would make this entry look like other. """ assert self.dn == other.dn if self == other: return None r = [] myKeys = set(key for key in self) otherKeys = set(key for key in other) addedKeys = list(otherKeys - myKeys) addedKeys.sort(key=to_bytes) # for reproducability only for added in addedKeys: r.append(delta.Add(added, other[added])) deletedKeys = list(myKeys - otherKeys) deletedKeys.sort(key=to_bytes) # for reproducability only for deleted in deletedKeys: r.append(delta.Delete(deleted, self[deleted])) sharedKeys = list(myKeys & otherKeys) sharedKeys.sort(key=to_bytes) # for reproducability only for shared in sharedKeys: addedValues = list(other[shared] - self[shared]) if addedValues: addedValues.sort(key=to_bytes) # for reproducability only r.append(delta.Add(shared, addedValues)) deletedValues = list(self[shared] - other[shared]) if deletedValues: deletedValues.sort(key=to_bytes) # for reproducability only r.append(delta.Delete(shared, deletedValues)) return delta.ModifyOp(dn=self.dn, modifications=r) def bind(self, password): return defer.maybeDeferred(self._bind, password) def _bind(self, password): password = to_bytes(password) for key in self._user_password_keys: for digest in self.get(key, ()): digest = to_bytes(digest) if digest.startswith(b'{SSHA}'): raw = base64.decodestring(digest[len(b'{SSHA}'):]) salt = raw[20:] got = sshaDigest(password, salt) if got == digest: return self else: # Plaintext if digest == password: return self raise ldaperrors.LDAPInvalidCredentials() def hasMember(self, dn): for memberDN in self.get('member', []): if memberDN == dn: return True return False def __hash__(self): # FIXME:https://github.com/twisted/ldaptor/issues/101 # The hash should take into consideration any attribute used to # decide the equality. return hash(self.dn)