Mercurial > moin > 1.9
changeset 2958:6eebb112108b
GHOP: 1st part of XEP-115 (Entity Capabilities) implementation by starGaming
author | Karol 'grzywacz' Nowak <grzywacz@sul.uni.lodz.pl> |
---|---|
date | Sun, 09 Dec 2007 22:36:14 +0100 |
parents | bc85e5200dd3 |
children | fcfa07f447f5 |
files | MoinMoin/support/python_compatibility.py jabberbot/_tests/test_capat.py jabberbot/capat.py |
diffstat | 3 files changed, 149 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/MoinMoin/support/python_compatibility.py Tue Dec 04 22:24:53 2007 +0100 +++ b/MoinMoin/support/python_compatibility.py Sun Dec 09 22:36:14 2007 +0100 @@ -74,3 +74,18 @@ else: d = kw or self.kw return self.fn(*(self.args + args), **d) +""" +This is a feature from python 2.5, needed for compatibility with python 2.3 and 2.4, +although it may not be 100% compatible. +""" +try: + from hashlib import new as hash_new +except (NameError, ImportError): + def hash_new(name, string=''): + if name in ('SHA1', 'sha1'): + import sha + return sha.new(string) + elif name in ('MD5', 'md5'): + import md5 + return md5.new(string) + raise ValueError("unsupported hash type")
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jabberbot/_tests/test_capat.py Sun Dec 09 22:36:14 2007 +0100 @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- + +import py.test +import capat + +def test_ver_simple(): + # example values supplied by the XEP + ident = (("client", "pc"),) + feat = ("http://jabber.org/protocol/disco#info", + "http://jabber.org/protocol/disco#items", + "http://jabber.org/protocol/muc", + ) + + assert capat.generate_ver(ident, feat) == "8RovUdtOmiAjzj+xI7SK5BCw3A8=" + +def test_ver_complex(): + # this test should verify that ordering works properly + ident = (("client", "animal"), + ("client", "bear"), # type ordering after category ordering + ("apples", "bar"), + ("apple", "foo"), # "apples" starts with "apple" + # thus it's greater + ) + feat = () + + expected = capat.hash_new('sha1') + expected.update("apple/foo<apples/bar<client/animal<client/bear<") + expected = capat.base64.b64encode(expected.digest()) + assert capat.generate_ver(ident, feat) == expected + +def test_xml(): + try: + import pyxmpp.iq + except ImportError: + py.test.skip("pyxmpp needs to be installed for this test") + x = pyxmpp.iq.Iq(stanza_type='result', stanza_id='disco1', + from_jid='romeo@montague.lit/orchard', + to_jid='juliet@capulet.lit/chamber') + y = x.new_query(ns_uri='http://jabber.org/protocol/disco#info') + z = y.newChild(None, 'identity', None) + z.setProp('category', 'client') + z.setProp('type', 'pc') + y.newChild(None, 'feature', None).setProp( + 'var','http://jabber.org/protocol/disco#info') + y.newChild(None, 'feature', None).setProp( + 'var', 'http://jabber.org/protocol/disco#items') + y.newChild(None, 'feature', None).setProp( + 'var', 'http://jabber.org/protocol/muc') + + assert capat.hash_iq(x) == "8RovUdtOmiAjzj+xI7SK5BCw3A8=" + # hash value taken from `test_ver_simple`
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jabberbot/capat.py Sun Dec 09 22:36:14 2007 +0100 @@ -0,0 +1,83 @@ +# -*- coding: utf-8 -*- + +""" + MoinMoin - Entity Capabilities (XEP-0115) implementation + + Enables Jabber/XMPP clients to save bandwidth by caching + information about extensions supported by various client + implementations. + + @copyright: 2007 by Robert Lehmann <lehmannro@gmail.com> + @license: GNU GPL, see COPYING for details. +""" + +import base64 +import itertools +from MoinMoin.support.python_compatibility import hash_new + +HASHALIASES = { # IANA Hash Function Textual Names Registry + # to `hashlib.new` mapping + 'sha-1': 'sha1', + 'sha-224': 'sha224', + 'sha-256': 'sha256', + 'sha-384': 'sha384', + 'sha-512': 'sha512', + 'md5': 'md5', + 'md2': 'md2', +} + + +def generate_ver(identities, features, algo='sha-1'): + """Generate the 'ver' attribute according to XEP-0115. + + See http://www.xmpp.org/extensions/xep-0115.html#ver + + @param identities: a number of (category, type) identity pairs + @param algo: optional algo attribute with IANA aliasing + + @type identities: iterable of 2-tuples of strings + @type features: iterable of strings + @type algo: string (IANA Hash Function Textual Name) + """ + + # only IANA aliases are supported + if algo not in HASHALIASES: + raise ValueError("undefined hash algorithm") + algo = hash_new(HASHALIASES[algo]) + + ident = list(identities) + # default sorting already considers both, category and type + ident.sort() + ident = ('%s/%s' % (idcat, idtype) for idcat, idtype in ident) + + feat = list(features) + # strings (byte arrays) are ordered by i;octet by default + feat.sort() + + s = '<'.join(itertools.chain(ident, feat, ('',))) + # the trailing empty string adds a trailing '<' to the result + algo.update(s) + s = base64.b64encode(algo.digest()) + + return s + +def hash_iq(stanza, algo='sha-1'): + """Search an <Iq/> entity for features/identities and generate a + 'ver' attribute hash. + + @type stanza: pyxmpp.iq.Iq + """ + stanza = iter(stanza.get_query()) + stanza.next() # drop first item: whole query + + feat = [] + ident = [] + + # traverse all child nodes + for item in stanza: + if item.name == 'identity': + ident.append((item.prop('category'), item.prop('type'))) + elif item.name == 'feature': + feat.append(item.prop('var')) + + return generate_ver(ident, feat, algo)