diff options
Diffstat (limited to 'sleekxmpp')
-rw-r--r-- | sleekxmpp/plugins/__init__.py | 1 | ||||
-rw-r--r-- | sleekxmpp/plugins/xep_0004/stanza/form.py | 3 | ||||
-rw-r--r-- | sleekxmpp/plugins/xep_0054/vcard_temp.py | 2 | ||||
-rw-r--r-- | sleekxmpp/plugins/xep_0257/__init__.py | 17 | ||||
-rw-r--r-- | sleekxmpp/plugins/xep_0257/client_cert_management.py | 65 | ||||
-rw-r--r-- | sleekxmpp/plugins/xep_0257/stanza.py | 87 | ||||
-rw-r--r-- | sleekxmpp/xmlstream/stanzabase.py | 4 |
7 files changed, 177 insertions, 2 deletions
diff --git a/sleekxmpp/plugins/__init__.py b/sleekxmpp/plugins/__init__.py index 77e19e61..c6617a87 100644 --- a/sleekxmpp/plugins/__init__.py +++ b/sleekxmpp/plugins/__init__.py @@ -68,6 +68,7 @@ __all__ = [ 'xep_0242', # XMPP Client Compliance 2009 'xep_0249', # Direct MUC Invitations 'xep_0256', # Last Activity in Presence + 'xep_0257', # Client Certificate Management for SASL EXTERNAL 'xep_0258', # Security Labels in XMPP 'xep_0270', # XMPP Compliance Suites 2010 'xep_0279', # Server IP Check diff --git a/sleekxmpp/plugins/xep_0004/stanza/form.py b/sleekxmpp/plugins/xep_0004/stanza/form.py index bbf0ee7d..721ecc35 100644 --- a/sleekxmpp/plugins/xep_0004/stanza/form.py +++ b/sleekxmpp/plugins/xep_0004/stanza/form.py @@ -201,7 +201,8 @@ class Form(ElementBase): del self['instructions'] if instructions in [None, '']: return - instructions = instructions.split('\n') + if not isinstance(instructions, list): + instructions = instructions.split('\n') for instruction in instructions: inst = ET.Element('{%s}instructions' % self.namespace) inst.text = instruction diff --git a/sleekxmpp/plugins/xep_0054/vcard_temp.py b/sleekxmpp/plugins/xep_0054/vcard_temp.py index 83cbccf8..24da1c05 100644 --- a/sleekxmpp/plugins/xep_0054/vcard_temp.py +++ b/sleekxmpp/plugins/xep_0054/vcard_temp.py @@ -97,8 +97,8 @@ class XEP_0054(BasePlugin): def publish_vcard(self, vcard=None, jid=None, block=True, ifrom=None, callback=None, timeout=None): + self.api['set_vcard'](jid, None, ifrom, vcard) if self.xmpp.is_component: - self.api['set_vcard'](jid, None, ifrom, vcard) return iq = self.xmpp.Iq() diff --git a/sleekxmpp/plugins/xep_0257/__init__.py b/sleekxmpp/plugins/xep_0257/__init__.py new file mode 100644 index 00000000..8c5311fd --- /dev/null +++ b/sleekxmpp/plugins/xep_0257/__init__.py @@ -0,0 +1,17 @@ +""" + SleekXMPP: The Sleek XMPP Library + Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout + This file is part of SleekXMPP. + + See the file LICENSE for copying permission. +""" + +from sleekxmpp.plugins.base import register_plugin + +from sleekxmpp.plugins.xep_0257 import stanza +from sleekxmpp.plugins.xep_0257.stanza import Certs, AppendCert +from sleekxmpp.plugins.xep_0257.stanza import DisableCert, RevokeCert +from sleekxmpp.plugins.xep_0257.client_cert_management import XEP_0257 + + +register_plugin(XEP_0257) diff --git a/sleekxmpp/plugins/xep_0257/client_cert_management.py b/sleekxmpp/plugins/xep_0257/client_cert_management.py new file mode 100644 index 00000000..49317843 --- /dev/null +++ b/sleekxmpp/plugins/xep_0257/client_cert_management.py @@ -0,0 +1,65 @@ +""" + SleekXMPP: The Sleek XMPP Library + Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout + This file is part of SleekXMPP. + + See the file LICENSE for copying permission. +""" + +import logging + +from sleekxmpp import Iq +from sleekxmpp.plugins import BasePlugin +from sleekxmpp.xmlstream import register_stanza_plugin +from sleekxmpp.plugins.xep_0257 import stanza, Certs +from sleekxmpp.plugins.xep_0257 import AppendCert, DisableCert, RevokeCert + + +log = logging.getLogger(__name__) + + +class XEP_0257(BasePlugin): + + name = 'xep_0257' + description = 'XEP-0258: Client Certificate Management for SASL EXTERNAL' + dependencies = set(['xep_0030']) + stanza = stanza + + def plugin_init(self): + register_stanza_plugin(Iq, Certs) + register_stanza_plugin(Iq, AppendCert) + register_stanza_plugin(Iq, DisableCert) + register_stanza_plugin(Iq, RevokeCert) + + def get_certs(self, ifrom=None, block=True, timeout=None, callback=None): + iq = self.xmpp.Iq() + iq['type'] = 'get' + iq['from'] = ifrom + iq.enable('sasl_certs') + return iq.send(block=block, timeout=timeout, callback=callback) + + def add_cert(self, name, cert, allow_management=True, ifrom=None, + block=True, timeout=None, callback=None): + iq = self.xmpp.Iq() + iq['type'] = 'set' + iq['from'] = ifrom + iq['sasl_cert_append']['name'] = name + iq['sasl_cert_append']['x509cert'] = cert + iq['sasl_cert_append']['cert_management'] = allow_management + return iq.send(block=block, timeout=timeout, callback=callback) + + def disable_cert(self, name, ifrom=None, block=True, + timeout=None, callback=None): + iq = self.xmpp.Iq() + iq['type'] = 'set' + iq['from'] = ifrom + iq['sasl_cert_disable']['name'] = name + return iq.send(block=block, timeout=timeout, callback=callback) + + def revoke_cert(self, name, ifrom=None, block=True, + timeout=None, callback=None): + iq = self.xmpp.Iq() + iq['type'] = 'set' + iq['from'] = ifrom + iq['sasl_cert_revoke']['name'] = name + return iq.send(block=block, timeout=timeout, callback=callback) diff --git a/sleekxmpp/plugins/xep_0257/stanza.py b/sleekxmpp/plugins/xep_0257/stanza.py new file mode 100644 index 00000000..17e20136 --- /dev/null +++ b/sleekxmpp/plugins/xep_0257/stanza.py @@ -0,0 +1,87 @@ +""" + SleekXMPP: The Sleek XMPP Library + Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout + This file is part of SleekXMPP. + + See the file LICENSE for copying permission. +""" + +from sleekxmpp.xmlstream import ElementBase, ET, register_stanza_plugin + + +class Certs(ElementBase): + name = 'query' + namespace = 'urn:xmpp:saslcert:1' + plugin_attrib = 'sasl_certs' + interfaces = set() + + +class CertItem(ElementBase): + name = 'item' + namespace = 'urn:xmpp:saslcert:1' + plugin_attrib = 'item' + plugin_multi_attrib = 'items' + interfaces = set(['name', 'x509cert', 'users']) + sub_interfaces = set(['name', 'x509cert']) + + def get_users(self): + resources = self.xml.findall('{%s}users/{%s}resource' % ( + self.namespace, self.namespace)) + return set([res.text for res in resources]) + + def set_users(self, values): + users = self.xml.find('{%s}users' % self.namespace) + if users is None: + users = ET.Element('{%s}users' % self.namespace) + self.xml.append(users) + for resource in values: + res = ET.Element('{%s}resource' % self.namespace) + res.text = resource + users.append(res) + + def del_users(self): + users = self.xml.find('{%s}users' % self.namespace) + if users is not None: + self.xml.remove(users) + + +class AppendCert(ElementBase): + name = 'append' + namespace = 'urn:xmpp:saslcert:1' + plugin_attrib = 'sasl_cert_append' + interfaces = set(['name', 'x509cert', 'cert_management']) + sub_interfaces = set(['name', 'x509cert']) + + def get_cert_management(self): + manage = self.xml.find('{%s}no-cert-management' % self.namespace) + return manage is None + + def set_cert_management(self, value): + self.del_cert_management() + if not value: + manage = ET.Element('{%s}no-cert-management' % self.namespace) + self.xml.append(manage) + + def del_cert_management(self): + manage = self.xml.find('{%s}no-cert-management' % self.namespace) + if manage is not None: + self.xml.remove(manage) + + +class DisableCert(ElementBase): + name = 'disable' + namespace = 'urn:xmpp:saslcert:1' + plugin_attrib = 'sasl_cert_disable' + interfaces = set(['name']) + sub_interfaces = interfaces + + +class RevokeCert(ElementBase): + name = 'revoke' + namespace = 'urn:xmpp:saslcert:1' + plugin_attrib = 'sasl_cert_revoke' + interfaces = set(['name']) + sub_interfaces = interfaces + + +register_stanza_plugin(Certs, CertItem, iterable=True) diff --git a/sleekxmpp/xmlstream/stanzabase.py b/sleekxmpp/xmlstream/stanzabase.py index 08ce702a..122d7eb4 100644 --- a/sleekxmpp/xmlstream/stanzabase.py +++ b/sleekxmpp/xmlstream/stanzabase.py @@ -1217,6 +1217,10 @@ class ElementBase(object): if item.__class__ in self.plugin_iterables: if item.__class__.plugin_multi_attrib: self.init_plugin(item.__class__.plugin_multi_attrib) + elif item.__class__ == self.plugin_tag_map.get(item.tag_name(), None): + self.init_plugin(item.plugin_attrib, + existing_xml=item.xml, + reuse=False) return self def appendxml(self, xml): |