diff options
Diffstat (limited to 'sleekxmpp/clientxmpp.py')
-rw-r--r-- | sleekxmpp/clientxmpp.py | 207 |
1 files changed, 16 insertions, 191 deletions
diff --git a/sleekxmpp/clientxmpp.py b/sleekxmpp/clientxmpp.py index 5d7ca125..9c2696da 100644 --- a/sleekxmpp/clientxmpp.py +++ b/sleekxmpp/clientxmpp.py @@ -15,8 +15,10 @@ import hashlib import random import threading +import sleekxmpp from sleekxmpp import plugins from sleekxmpp import stanza +from sleekxmpp import features from sleekxmpp.basexmpp import BaseXMPP from sleekxmpp.stanza import * from sleekxmpp.stanza.stream import tls, sasl @@ -97,10 +99,6 @@ class ClientXMPP(BaseXMPP): self.add_event_handler('connected', self._handle_connected) self.register_stanza(StreamFeatures) - self.register_stanza(tls.Proceed) - self.register_stanza(sasl.Success) - self.register_stanza(sasl.Failure) - self.register_stanza(sasl.Auth) self.register_handler( Callback('Stream Features', @@ -112,43 +110,18 @@ class ClientXMPP(BaseXMPP): self.default_ns, 'jabber:iq:roster')), self._handle_roster)) - self.register_handler( - Callback('SASL Success', - MatchXPath(sasl.Success.tag_name()), - self._handle_sasl_success, - instream=True, - once=True)) - self.register_handler( - Callback('SASL Failure', - MatchXPath(sasl.Failure.tag_name()), - self._handle_sasl_fail, - instream=True, - once=True)) - self.register_handler( - Callback('STARTTLS Proceed', - MatchXPath(tls.Proceed.tag_name()), - self._handle_starttls_proceed, - instream=True)) - - self.register_feature('starttls', self._handle_starttls, - restart=True, - order=0) - self.register_feature('mechanisms', self._handle_sasl_auth, - restart=True, - order=100) - self.register_feature('bind', self._handle_bind_resource, - restart=False, - order=10000) - self.register_feature('session', self._handle_start_session, - restart=False, - order=10001) - - self.register_sasl_mechanism('PLAIN', - self._handle_sasl_plain, - priority=1) - self.register_sasl_mechanism('ANONYMOUS', - self._handle_sasl_anonymous, - priority=0) + + # Setup default stream features + self.register_plugin('feature_starttls') + self.register_plugin('feature_mechanisms') + self.register_plugin('feature_bind') + self.register_plugin('feature_session') + + # Setup default SASL mechanisms + self.register_plugin('sasl_plain', + {'priority': 1}) + self.register_plugin('sasl_anonymous', + {'priority': 0}) def connect(self, address=tuple(), reattempt=True, use_tls=True): """ @@ -242,9 +215,7 @@ class ClientXMPP(BaseXMPP): preferred ordering for the mechanism. High values will be attempted first. """ - self._sasl_mechanism_handlers[name] = handler - self._sasl_mechanism_priorities.append((priority, name)) - self._sasl_mechanism_priorities.sort(reverse=True) + self['feature_mechanisms'].register_mechanism(name, handler, priority) def remove_sasl_mechanism(self, name): """ @@ -253,11 +224,7 @@ class ClientXMPP(BaseXMPP): Arguments: name -- The name of the mechanism to remove (all caps) """ - if name in self._sasl_mechanism_handlers: - del self._sasl_mechanism_handlers[name] - - p = self._sasl_mechanism_priorities - self._sasl_mechanism_priorities = [i for i in p if i[1] != name] + self['feature_mechanisms'].remove_mechanism(name) def update_roster(self, jid, name=None, subscription=None, groups=[], block=True, timeout=None, callback=None): @@ -359,148 +326,6 @@ class ClientXMPP(BaseXMPP): # restarting the XML stream. return True - def _handle_starttls(self, features): - """ - Handle notification that the server supports TLS. - - Arguments: - features -- The stream:features element. - """ - if not self.use_tls: - return False - elif self.ssl_support: - self.send(features['starttls'], now=True) - return True - else: - log.warning("The module tlslite is required to log in" +\ - " to some servers, and has not been found.") - return False - - def _handle_starttls_proceed(self, proceed): - """Restart the XML stream when TLS is accepted.""" - log.debug("Starting TLS") - if self.start_tls(): - self.features.append('starttls') - raise RestartStream() - - def _handle_sasl_auth(self, features): - """ - Handle authenticating using SASL. - - Arguments: - features -- The stream features stanza. - """ - for priority, mech in self._sasl_mechanism_priorities: - if mech in features['mechanisms']: - handler = self._sasl_mechanism_handlers[mech] - if handler(self): - break - else: - log.error("No appropriate login method.") - self.event("no_auth", direct=True) - self.disconnect() - - return True - - def _handle_sasl_success(self, stanza): - """SASL authentication succeeded. Restart the stream.""" - self.authenticated = True - self.features.append('mechanisms') - raise RestartStream() - - def _handle_sasl_fail(self, stanza): - """SASL authentication failed. Disconnect and shutdown.""" - log.info("Authentication failed.") - self.event("failed_auth", direct=True) - self.disconnect() - log.debug("Starting SASL Auth") - return True - - def _handle_sasl_plain(self, xmpp): - """ - Attempt to authenticate using SASL PLAIN. - - Arguments: - xmpp -- The SleekXMPP connection instance. - """ - if not xmpp.boundjid.user: - return False - - if sys.version_info < (3, 0): - user = bytes(self.boundjid.user) - password = bytes(self.password) - else: - user = bytes(self.boundjid.user, 'utf-8') - password = bytes(self.password, 'utf-8') - - auth = base64.b64encode(b'\x00' + user + \ - b'\x00' + password).decode('utf-8') - - resp = sasl.Auth(xmpp) - resp['mechanism'] = 'PLAIN' - resp['value'] = auth - resp.send(now=True) - return True - - def _handle_sasl_anonymous(self, xmpp): - """ - Attempt to authenticate using SASL ANONYMOUS. - - Arguments: - xmpp -- The SleekXMPP connection instance. - """ - if xmpp.boundjid.user: - return False - - resp = sasl.Auth(xmpp) - resp['mechanism'] = 'ANONYMOUS' - resp.send() - - return True - - def _handle_bind_resource(self, features): - """ - Handle requesting a specific resource. - - Arguments: - features -- The stream features stanza. - """ - log.debug("Requesting resource: %s" % self.boundjid.resource) - iq = self.Iq() - iq['type'] = 'set' - iq.enable('bind') - if self.boundjid.resource: - iq['bind']['resource'] = self.boundjid.resource - response = iq.send(now=True) - - self.set_jid(response['bind']['jid']) - self.bound = True - - log.info("Node set to: %s" % self.boundjid.full) - - if 'session' not in features['features']: - log.debug("Established Session") - self.sessionstarted = True - self.session_started_event.set() - self.event("session_start") - - def _handle_start_session(self, features): - """ - Handle the start of the session. - - Arguments: - feature -- The stream features element. - """ - iq = self.Iq() - iq['type'] = 'set' - iq.enable('session') - response = iq.send(now=True) - - log.debug("Established Session") - self.sessionstarted = True - self.session_started_event.set() - self.event("session_start") - def _handle_roster(self, iq, request=False): """ Update the roster after receiving a roster stanza. |