diff options
Diffstat (limited to 'sleekxmpp/features')
23 files changed, 266 insertions, 85 deletions
diff --git a/sleekxmpp/features/__init__.py b/sleekxmpp/features/__init__.py index 5bfe173d..c63d72bf 100644 --- a/sleekxmpp/features/__init__.py +++ b/sleekxmpp/features/__init__.py @@ -6,4 +6,10 @@ See the file LICENSE for copying permission. """ -__all__ = ['feature_starttls', 'feature_mechanisms', 'feature_bind'] +__all__ = [ + 'feature_starttls', + 'feature_mechanisms', + 'feature_bind', + 'feature_session', + 'feature_rosterver' +] diff --git a/sleekxmpp/features/feature_bind/__init__.py b/sleekxmpp/features/feature_bind/__init__.py index aa854f87..9e0831dd 100644 --- a/sleekxmpp/features/feature_bind/__init__.py +++ b/sleekxmpp/features/feature_bind/__init__.py @@ -6,5 +6,14 @@ See the file LICENSE for copying permission. """ -from sleekxmpp.features.feature_bind.bind import feature_bind +from sleekxmpp.plugins.base import register_plugin + +from sleekxmpp.features.feature_bind.bind import FeatureBind from sleekxmpp.features.feature_bind.stanza import Bind + + +register_plugin(FeatureBind) + + +# Retain some backwards compatibility +feature_bind = FeatureBind diff --git a/sleekxmpp/features/feature_bind/bind.py b/sleekxmpp/features/feature_bind/bind.py index d3b2b737..b828e26f 100644 --- a/sleekxmpp/features/feature_bind/bind.py +++ b/sleekxmpp/features/feature_bind/bind.py @@ -11,22 +11,20 @@ import logging from sleekxmpp.stanza import Iq, StreamFeatures from sleekxmpp.features.feature_bind import stanza from sleekxmpp.xmlstream import register_stanza_plugin -from sleekxmpp.xmlstream.matcher import * -from sleekxmpp.xmlstream.handler import * -from sleekxmpp.plugins.base import base_plugin +from sleekxmpp.plugins import BasePlugin, register_plugin log = logging.getLogger(__name__) -class feature_bind(base_plugin): +class FeatureBind(BasePlugin): - def plugin_init(self): - self.name = 'Bind Resource' - self.rfc = '6120' - self.description = 'Resource Binding Stream Feature' - self.stanza = stanza + name = 'feature_bind' + description = 'RFC 6120: Stream Feature: Resource Binding' + dependencies = set() + stanza = stanza + def plugin_init(self): self.xmpp.register_feature('bind', self._handle_bind_resource, restart=False, @@ -52,6 +50,7 @@ class feature_bind(base_plugin): self.xmpp.set_jid(response['bind']['jid']) self.xmpp.bound = True + self.xmpp.event('session_bind', self.xmpp.boundjid, direct=True) self.xmpp.features.add('bind') diff --git a/sleekxmpp/features/feature_bind/stanza.py b/sleekxmpp/features/feature_bind/stanza.py index 2c1484e0..8ce7536f 100644 --- a/sleekxmpp/features/feature_bind/stanza.py +++ b/sleekxmpp/features/feature_bind/stanza.py @@ -6,8 +6,7 @@ See the file LICENSE for copying permission. """ -from sleekxmpp.stanza import Iq, StreamFeatures -from sleekxmpp.xmlstream import ElementBase, ET, register_stanza_plugin +from sleekxmpp.xmlstream import ElementBase class Bind(ElementBase): diff --git a/sleekxmpp/features/feature_mechanisms/__init__.py b/sleekxmpp/features/feature_mechanisms/__init__.py index 5379ef4e..9f7611ed 100644 --- a/sleekxmpp/features/feature_mechanisms/__init__.py +++ b/sleekxmpp/features/feature_mechanisms/__init__.py @@ -6,8 +6,17 @@ See the file LICENSE for copying permission. """ -from sleekxmpp.features.feature_mechanisms.mechanisms import feature_mechanisms +from sleekxmpp.plugins.base import register_plugin + +from sleekxmpp.features.feature_mechanisms.mechanisms import FeatureMechanisms from sleekxmpp.features.feature_mechanisms.stanza import Mechanisms from sleekxmpp.features.feature_mechanisms.stanza import Auth from sleekxmpp.features.feature_mechanisms.stanza import Success from sleekxmpp.features.feature_mechanisms.stanza import Failure + + +register_plugin(FeatureMechanisms) + + +# Retain some backwards compatibility +feature_mechanisms = FeatureMechanisms diff --git a/sleekxmpp/features/feature_mechanisms/mechanisms.py b/sleekxmpp/features/feature_mechanisms/mechanisms.py index 2b8321c2..6f01cb14 100644 --- a/sleekxmpp/features/feature_mechanisms/mechanisms.py +++ b/sleekxmpp/features/feature_mechanisms/mechanisms.py @@ -9,36 +9,47 @@ import logging from sleekxmpp.thirdparty import suelta +from sleekxmpp.thirdparty.suelta.exceptions import SASLCancelled, SASLError from sleekxmpp.stanza import StreamFeatures from sleekxmpp.xmlstream import RestartStream, register_stanza_plugin -from sleekxmpp.xmlstream.matcher import * -from sleekxmpp.xmlstream.handler import * -from sleekxmpp.plugins.base import base_plugin +from sleekxmpp.plugins import BasePlugin +from sleekxmpp.xmlstream.matcher import MatchXPath +from sleekxmpp.xmlstream.handler import Callback from sleekxmpp.features.feature_mechanisms import stanza log = logging.getLogger(__name__) -class feature_mechanisms(base_plugin): +class FeatureMechanisms(BasePlugin): - def plugin_init(self): - self.name = 'SASL Mechanisms' - self.rfc = '6120' - self.description = "SASL Stream Feature" - self.stanza = stanza + name = 'feature_mechanisms' + description = 'RFC 6120: Stream Feature: SASL' + dependencies = set() + stanza = stanza + def plugin_init(self): self.use_mech = self.config.get('use_mech', None) + if not self.use_mech and not self.xmpp.boundjid.user: + self.use_mech = 'ANONYMOUS' + def tls_active(): return 'starttls' in self.xmpp.features def basic_callback(mech, values): - if 'username' in values: - values['username'] = self.xmpp.boundjid.user - if 'password' in values: - values['password'] = self.xmpp.password + creds = self.xmpp.credentials + for value in values: + if value == 'username': + values['username'] = self.xmpp.boundjid.user + elif value == 'password': + values['password'] = creds['password'] + elif value == 'email': + jid = self.xmpp.boundjid.bare + values['email'] = creds.get('email', jid) + elif value in creds: + values[value] = creds[value] mech.fulfill(values) sasl_callback = self.config.get('sasl_callback', None) @@ -53,6 +64,9 @@ class feature_mechanisms(base_plugin): tls_active=tls_active, mech=self.use_mech) + self.mech_list = set() + self.attempted_mechs = set() + register_stanza_plugin(StreamFeatures, stanza.Mechanisms) self.xmpp.register_stanza(stanza.Success) @@ -60,19 +74,18 @@ class feature_mechanisms(base_plugin): self.xmpp.register_stanza(stanza.Auth) self.xmpp.register_stanza(stanza.Challenge) self.xmpp.register_stanza(stanza.Response) + self.xmpp.register_stanza(stanza.Abort) self.xmpp.register_handler( Callback('SASL Success', MatchXPath(stanza.Success.tag_name()), self._handle_success, - instream=True, - once=True)) + instream=True)) self.xmpp.register_handler( Callback('SASL Failure', MatchXPath(stanza.Failure.tag_name()), self._handle_fail, - instream=True, - once=True)) + instream=True)) self.xmpp.register_handler( Callback('SASL Challenge', MatchXPath(stanza.Challenge.tag_name()), @@ -95,14 +108,29 @@ class feature_mechanisms(base_plugin): # server has incorrectly offered it again. return False - mech_list = features['mechanisms'] + if not self.use_mech: + self.mech_list = set(features['mechanisms']) + else: + self.mech_list = set([self.use_mech]) + return self._send_auth() + + def _send_auth(self): + mech_list = self.mech_list - self.attempted_mechs self.mech = self.sasl.choose_mechanism(mech_list) - if self.mech is not None: + if mech_list and self.mech is not None: resp = stanza.Auth(self.xmpp) resp['mechanism'] = self.mech.name - resp['value'] = self.mech.process() - resp.send(now=True) + try: + resp['value'] = self.mech.process() + except SASLCancelled: + self.attempted_mechs.add(self.mech.name) + self._send_auth() + except SASLError: + self.attempted_mechs.add(self.mech.name) + self._send_auth() + else: + resp.send(now=True) else: log.error("No appropriate login method.") self.xmpp.event("no_auth", direct=True) @@ -112,18 +140,26 @@ class feature_mechanisms(base_plugin): def _handle_challenge(self, stanza): """SASL challenge received. Process and send response.""" resp = self.stanza.Response(self.xmpp) - resp['value'] = self.mech.process(stanza['value']) - resp.send(now=True) + try: + resp['value'] = self.mech.process(stanza['value']) + except SASLCancelled: + self.stanza.Abort(self.xmpp).send() + except SASLError: + self.stanza.Abort(self.xmpp).send() + else: + resp.send(now=True) def _handle_success(self, stanza): """SASL authentication succeeded. Restart the stream.""" + self.attempted_mechs = set() self.xmpp.authenticated = True self.xmpp.features.add('mechanisms') raise RestartStream() def _handle_fail(self, stanza): """SASL authentication failed. Disconnect and shutdown.""" + self.attempted_mechs.add(self.mech.name) log.info("Authentication failed: %s", stanza['condition']) self.xmpp.event("failed_auth", stanza, direct=True) - self.xmpp.disconnect() + self._send_auth() return True diff --git a/sleekxmpp/features/feature_mechanisms/stanza/__init__.py b/sleekxmpp/features/feature_mechanisms/stanza/__init__.py index 8b80f358..38991d89 100644 --- a/sleekxmpp/features/feature_mechanisms/stanza/__init__.py +++ b/sleekxmpp/features/feature_mechanisms/stanza/__init__.py @@ -13,3 +13,4 @@ from sleekxmpp.features.feature_mechanisms.stanza.success import Success from sleekxmpp.features.feature_mechanisms.stanza.failure import Failure from sleekxmpp.features.feature_mechanisms.stanza.challenge import Challenge from sleekxmpp.features.feature_mechanisms.stanza.response import Response +from sleekxmpp.features.feature_mechanisms.stanza.abort import Abort diff --git a/sleekxmpp/features/feature_mechanisms/stanza/abort.py b/sleekxmpp/features/feature_mechanisms/stanza/abort.py new file mode 100644 index 00000000..aaca348d --- /dev/null +++ b/sleekxmpp/features/feature_mechanisms/stanza/abort.py @@ -0,0 +1,24 @@ +""" + SleekXMPP: The Sleek XMPP Library + Copyright (C) 2011 Nathanael C. Fritz + This file is part of SleekXMPP. + + See the file LICENSE for copying permission. +""" + +from sleekxmpp.xmlstream import StanzaBase + + +class Abort(StanzaBase): + + """ + """ + + name = 'abort' + namespace = 'urn:ietf:params:xml:ns:xmpp-sasl' + interfaces = set() + plugin_attrib = name + + def setup(self, xml): + StanzaBase.setup(self, xml) + self.xml.tag = self.tag_name() diff --git a/sleekxmpp/features/feature_mechanisms/stanza/auth.py b/sleekxmpp/features/feature_mechanisms/stanza/auth.py index e069b57f..69769507 100644 --- a/sleekxmpp/features/feature_mechanisms/stanza/auth.py +++ b/sleekxmpp/features/feature_mechanisms/stanza/auth.py @@ -10,9 +10,7 @@ import base64 from sleekxmpp.thirdparty.suelta.util import bytes -from sleekxmpp.stanza import StreamFeatures -from sleekxmpp.xmlstream import ElementBase, StanzaBase, ET -from sleekxmpp.xmlstream import register_stanza_plugin +from sleekxmpp.xmlstream import StanzaBase class Auth(StanzaBase): @@ -25,15 +23,28 @@ class Auth(StanzaBase): interfaces = set(('mechanism', 'value')) plugin_attrib = name + #: Some SASL mechs require sending values as is, + #: without converting base64. + plain_mechs = set(['X-MESSENGER-OAUTH2']) + def setup(self, xml): StanzaBase.setup(self, xml) self.xml.tag = self.tag_name() def get_value(self): - return base64.b64decode(bytes(self.xml.text)) + if not self['mechanism'] in self.plain_mechs: + return base64.b64decode(bytes(self.xml.text)) + else: + return self.xml.text def set_value(self, values): - self.xml.text = bytes(base64.b64encode(values)).decode('utf-8') + if not self['mechanism'] in self.plain_mechs: + if values: + self.xml.text = bytes(base64.b64encode(values)).decode('utf-8') + else: + self.xml.text = '=' + else: + self.xml.text = bytes(values).decode('utf-8') def del_value(self): self.xml.text = '' diff --git a/sleekxmpp/features/feature_mechanisms/stanza/challenge.py b/sleekxmpp/features/feature_mechanisms/stanza/challenge.py index 82af869f..85d65403 100644 --- a/sleekxmpp/features/feature_mechanisms/stanza/challenge.py +++ b/sleekxmpp/features/feature_mechanisms/stanza/challenge.py @@ -10,9 +10,7 @@ import base64 from sleekxmpp.thirdparty.suelta.util import bytes -from sleekxmpp.stanza import StreamFeatures -from sleekxmpp.xmlstream import ElementBase, StanzaBase, ET -from sleekxmpp.xmlstream import register_stanza_plugin +from sleekxmpp.xmlstream import StanzaBase class Challenge(StanzaBase): @@ -33,7 +31,10 @@ class Challenge(StanzaBase): return base64.b64decode(bytes(self.xml.text)) def set_value(self, values): - self.xml.text = bytes(base64.b64encode(values)).decode('utf-8') + if values: + self.xml.text = bytes(base64.b64encode(values)).decode('utf-8') + else: + self.xml.text = '=' def del_value(self): self.xml.text = '' diff --git a/sleekxmpp/features/feature_mechanisms/stanza/failure.py b/sleekxmpp/features/feature_mechanisms/stanza/failure.py index 027cc5af..5dd0de56 100644 --- a/sleekxmpp/features/feature_mechanisms/stanza/failure.py +++ b/sleekxmpp/features/feature_mechanisms/stanza/failure.py @@ -6,9 +6,7 @@ See the file LICENSE for copying permission. """ -from sleekxmpp.stanza import StreamFeatures -from sleekxmpp.xmlstream import ElementBase, StanzaBase, ET -from sleekxmpp.xmlstream import register_stanza_plugin +from sleekxmpp.xmlstream import StanzaBase, ET class Failure(StanzaBase): diff --git a/sleekxmpp/features/feature_mechanisms/stanza/mechanisms.py b/sleekxmpp/features/feature_mechanisms/stanza/mechanisms.py index c09cafbd..bbd56813 100644 --- a/sleekxmpp/features/feature_mechanisms/stanza/mechanisms.py +++ b/sleekxmpp/features/feature_mechanisms/stanza/mechanisms.py @@ -6,9 +6,7 @@ See the file LICENSE for copying permission. """ -from sleekxmpp.stanza import StreamFeatures -from sleekxmpp.xmlstream import ElementBase, StanzaBase, ET -from sleekxmpp.xmlstream import register_stanza_plugin +from sleekxmpp.xmlstream import ElementBase, ET class Mechanisms(ElementBase): diff --git a/sleekxmpp/features/feature_mechanisms/stanza/response.py b/sleekxmpp/features/feature_mechanisms/stanza/response.py index 45bb8207..78636c9e 100644 --- a/sleekxmpp/features/feature_mechanisms/stanza/response.py +++ b/sleekxmpp/features/feature_mechanisms/stanza/response.py @@ -10,9 +10,7 @@ import base64 from sleekxmpp.thirdparty.suelta.util import bytes -from sleekxmpp.stanza import StreamFeatures -from sleekxmpp.xmlstream import ElementBase, StanzaBase, ET -from sleekxmpp.xmlstream import register_stanza_plugin +from sleekxmpp.xmlstream import StanzaBase class Response(StanzaBase): @@ -33,7 +31,10 @@ class Response(StanzaBase): return base64.b64decode(bytes(self.xml.text)) def set_value(self, values): - self.xml.text = bytes(base64.b64encode(values)).decode('utf-8') + if values: + self.xml.text = bytes(base64.b64encode(values)).decode('utf-8') + else: + self.xml.text = '=' def del_value(self): self.xml.text = '' diff --git a/sleekxmpp/features/feature_mechanisms/stanza/success.py b/sleekxmpp/features/feature_mechanisms/stanza/success.py index 028e28a3..7a5a73f2 100644 --- a/sleekxmpp/features/feature_mechanisms/stanza/success.py +++ b/sleekxmpp/features/feature_mechanisms/stanza/success.py @@ -6,9 +6,7 @@ See the file LICENSE for copying permission. """ -from sleekxmpp.stanza import StreamFeatures -from sleekxmpp.xmlstream import ElementBase, StanzaBase, ET -from sleekxmpp.xmlstream import register_stanza_plugin +from sleekxmpp.xmlstream import StanzaBase class Success(StanzaBase): diff --git a/sleekxmpp/features/feature_rosterver/__init__.py b/sleekxmpp/features/feature_rosterver/__init__.py new file mode 100644 index 00000000..33bbf416 --- /dev/null +++ b/sleekxmpp/features/feature_rosterver/__init__.py @@ -0,0 +1,19 @@ +""" + SleekXMPP: The Sleek XMPP Library + Copyright (C) 2012 Nathanael C. Fritz + This file is part of SleekXMPP. + + See the file LICENSE for copying permission. +""" + +from sleekxmpp.plugins.base import register_plugin + +from sleekxmpp.features.feature_rosterver.rosterver import FeatureRosterVer +from sleekxmpp.features.feature_rosterver.stanza import RosterVer + + +register_plugin(FeatureRosterVer) + + +# Retain some backwards compatibility +feature_rosterver = FeatureRosterVer diff --git a/sleekxmpp/features/feature_rosterver/rosterver.py b/sleekxmpp/features/feature_rosterver/rosterver.py new file mode 100644 index 00000000..9e0bb8e8 --- /dev/null +++ b/sleekxmpp/features/feature_rosterver/rosterver.py @@ -0,0 +1,42 @@ +""" + SleekXMPP: The Sleek XMPP Library + Copyright (C) 2012 Nathanael C. Fritz + This file is part of SleekXMPP. + + See the file LICENSE for copying permission. +""" + +import logging + +from sleekxmpp.stanza import Iq, StreamFeatures +from sleekxmpp.features.feature_rosterver import stanza +from sleekxmpp.xmlstream import register_stanza_plugin +from sleekxmpp.plugins.base import BasePlugin + + +log = logging.getLogger(__name__) + + +class FeatureRosterVer(BasePlugin): + + name = 'feature_rosterver' + description = 'RFC 6121: Stream Feature: Roster Versioning' + dependences = set() + stanza = stanza + + def plugin_init(self): + self.xmpp.register_feature('rosterver', + self._handle_rosterver, + restart=False, + order=9000) + + register_stanza_plugin(StreamFeatures, stanza.RosterVer) + + def _handle_rosterver(self, features): + """Enable using roster versioning. + + Arguments: + features -- The stream features stanza. + """ + log.debug("Enabling roster versioning.") + self.xmpp.features.add('rosterver') diff --git a/sleekxmpp/features/feature_rosterver/stanza.py b/sleekxmpp/features/feature_rosterver/stanza.py new file mode 100644 index 00000000..025872fa --- /dev/null +++ b/sleekxmpp/features/feature_rosterver/stanza.py @@ -0,0 +1,17 @@ +""" + SleekXMPP: The Sleek XMPP Library + Copyright (C) 2012 Nathanael C. Fritz + This file is part of SleekXMPP. + + See the file LICENSE for copying permission. +""" + +from sleekxmpp.xmlstream import ElementBase + + +class RosterVer(ElementBase): + + name = 'ver' + namespace = 'urn:xmpp:features:rosterver' + interfaces = set() + plugin_attrib = 'rosterver' diff --git a/sleekxmpp/features/feature_session/__init__.py b/sleekxmpp/features/feature_session/__init__.py index 3c84baed..28bb3f77 100644 --- a/sleekxmpp/features/feature_session/__init__.py +++ b/sleekxmpp/features/feature_session/__init__.py @@ -6,5 +6,14 @@ See the file LICENSE for copying permission. """ -from sleekxmpp.features.feature_session.session import feature_session +from sleekxmpp.plugins.base import register_plugin + +from sleekxmpp.features.feature_session.session import FeatureSession from sleekxmpp.features.feature_session.stanza import Session + + +register_plugin(FeatureSession) + + +# Retain some backwards compatibility +feature_session = FeatureSession diff --git a/sleekxmpp/features/feature_session/session.py b/sleekxmpp/features/feature_session/session.py index 0daec5da..c799a763 100644 --- a/sleekxmpp/features/feature_session/session.py +++ b/sleekxmpp/features/feature_session/session.py @@ -10,9 +10,7 @@ import logging from sleekxmpp.stanza import Iq, StreamFeatures from sleekxmpp.xmlstream import register_stanza_plugin -from sleekxmpp.xmlstream.matcher import * -from sleekxmpp.xmlstream.handler import * -from sleekxmpp.plugins.base import base_plugin +from sleekxmpp.plugins import BasePlugin from sleekxmpp.features.feature_session import stanza @@ -20,14 +18,14 @@ from sleekxmpp.features.feature_session import stanza log = logging.getLogger(__name__) -class feature_session(base_plugin): +class FeatureSession(BasePlugin): - def plugin_init(self): - self.name = 'Start Session' - self.rfc = '3920' - self.description = 'Start Session Stream Feature' - self.stanza = stanza + name = 'feature_session' + description = 'RFC 3920: Stream Feature: Start Session' + dependencies = set() + stanza = stanza + def plugin_init(self): self.xmpp.register_feature('session', self._handle_start_session, restart=False, @@ -46,7 +44,7 @@ class feature_session(base_plugin): iq = self.xmpp.Iq() iq['type'] = 'set' iq.enable('session') - response = iq.send(now=True) + iq.send(now=True) self.xmpp.features.add('session') diff --git a/sleekxmpp/features/feature_session/stanza.py b/sleekxmpp/features/feature_session/stanza.py index 40ea583d..94e949ee 100644 --- a/sleekxmpp/features/feature_session/stanza.py +++ b/sleekxmpp/features/feature_session/stanza.py @@ -6,8 +6,7 @@ See the file LICENSE for copying permission. """ -from sleekxmpp.stanza import Iq, StreamFeatures -from sleekxmpp.xmlstream import ElementBase, ET, register_stanza_plugin +from sleekxmpp.xmlstream import ElementBase class Session(ElementBase): diff --git a/sleekxmpp/features/feature_starttls/__init__.py b/sleekxmpp/features/feature_starttls/__init__.py index 4ae89433..68697ce5 100644 --- a/sleekxmpp/features/feature_starttls/__init__.py +++ b/sleekxmpp/features/feature_starttls/__init__.py @@ -6,5 +6,14 @@ See the file LICENSE for copying permission. """ -from sleekxmpp.features.feature_starttls.starttls import feature_starttls +from sleekxmpp.plugins.base import register_plugin + +from sleekxmpp.features.feature_starttls.starttls import FeatureSTARTTLS from sleekxmpp.features.feature_starttls.stanza import * + + +register_plugin(FeatureSTARTTLS) + + +# Retain some backwards compatibility +feature_starttls = FeatureSTARTTLS diff --git a/sleekxmpp/features/feature_starttls/stanza.py b/sleekxmpp/features/feature_starttls/stanza.py index 8b09ad94..b968e134 100644 --- a/sleekxmpp/features/feature_starttls/stanza.py +++ b/sleekxmpp/features/feature_starttls/stanza.py @@ -6,9 +6,7 @@ See the file LICENSE for copying permission. """ -from sleekxmpp.stanza import StreamFeatures from sleekxmpp.xmlstream import StanzaBase, ElementBase -from sleekxmpp.xmlstream import register_stanza_plugin class STARTTLS(ElementBase): diff --git a/sleekxmpp/features/feature_starttls/starttls.py b/sleekxmpp/features/feature_starttls/starttls.py index 4e2b6621..212b9da5 100644 --- a/sleekxmpp/features/feature_starttls/starttls.py +++ b/sleekxmpp/features/feature_starttls/starttls.py @@ -10,23 +10,23 @@ import logging from sleekxmpp.stanza import StreamFeatures from sleekxmpp.xmlstream import RestartStream, register_stanza_plugin -from sleekxmpp.xmlstream.matcher import * -from sleekxmpp.xmlstream.handler import * -from sleekxmpp.plugins.base import base_plugin +from sleekxmpp.plugins import BasePlugin +from sleekxmpp.xmlstream.matcher import MatchXPath +from sleekxmpp.xmlstream.handler import Callback from sleekxmpp.features.feature_starttls import stanza log = logging.getLogger(__name__) -class feature_starttls(base_plugin): +class FeatureSTARTTLS(BasePlugin): - def plugin_init(self): - self.name = "STARTTLS" - self.rfc = '6120' - self.description = "STARTTLS Stream Feature" - self.stanza = stanza + name = 'feature_starttls' + description = 'RFC 6120: Stream Feature: STARTTLS' + dependencies = set() + stanza = stanza + def plugin_init(self): self.xmpp.register_handler( Callback('STARTTLS Proceed', MatchXPath(stanza.Proceed.tag_name()), |