Example #1
0
    def __init__(self, host, address, port, *args, **kwargs):
        self._test_host = host
        self._test_address = address
        self._test_port = port
        self._test_success = False
        self._test_starttls_required = None

        super().__init__(*args, **kwargs)
        self.stream_header = "<stream:stream to='%s' %s %s %s %s>" % (
            host,
            "xmlns:stream='%s'" % self.stream_ns,
            "xmlns='%s'" % self.default_ns,
            "xml:lang='%s'" % self.default_lang,
            "version='1.0'")
        self.stream_footer = "</stream:stream>"

        self.features = set()
        self._stream_feature_handlers = {}
        self._stream_feature_order = []

        self.register_stanza(StreamFeatures)
        self.register_handler(
            CoroutineCallback('Stream Features',
                              MatchXPath('{%s}features' % self.stream_ns),
                              self._handle_stream_features))
        self.register_plugin('feature_starttls')

        self.add_event_handler('stream_negotiated', self.handle_stream_negotiated)
        self.add_event_handler('session_end', self.handle_stream_end)
        self.add_event_handler('connection_failed', self.handle_connection_failed)

        self.register_handler(
            CoroutineCallback('Stream Features for TLS',
                              MatchXPath('{%s}features' % self.stream_ns),
                              self._tls_stream_features))
Example #2
0
    def _listener(self) -> None:
        """Enable callback"""
        def message_received(event):
            payload = event.get_payload()
            if len(payload) == 0:
                _LOGGER.error("%s: Invalid payload length of 0 received.",
                              self._ip_address,
                              len(payload))
                return

            for message in payload:
                data = {}
                # Try to convert JSON object if JSON object was received
                if message.text is not None and message.text != '':
                    try:
                        data = json.loads(message.text)
                    except json.JSONDecodeError:
                        # Should mean only a single value was received.
                        for item in message.text.split(':'):
                            item_split = item.split('=')
                            if len(item_split) == 2:
                                data.update({item_split[0]: item_split[1]})

                # Create response dictionary
                response = {
                    'id': event.get('id'),
                    'xmlns': message.attrib.get('xmlns'),
                    'cmd': message.attrib.get('mime'),
                    'type': message.attrib.get('type'),
                    'code': int(message.attrib.get('errorcode', '0')),
                    'codestring': message.attrib.get('errorstring'),
                    'data': data,
                }
                _LOGGER.debug("%s: Response payload: %s", self._ip_address,
                              response)
                # Put response on queue.
                self._response_queue.put_nowait(response)

        self._listener_message_received = message_received

        self._listener_message_received = message_received

        # Register our callback.
        self.register_handler(
            Callback('Listener',
                     MatchXPath('{{{0}}}iq/{{{1}}}oa'.format(self.default_ns,
                                                             DEFAULT_NS)),
                     message_received))

        self.register_handler(
            Callback('Listener',
                     MatchXPath('{{{0}}}message/{{{1}}}event'.format(
                         self.default_ns,
                         DEFAULT_NS)),
                     message_received))
Example #3
0
    def _handle_sm_feature(self, features):
        """
        Enable or resume stream management.

        If no SM-ID is stored, and resource binding has taken place,
        stream management will be enabled.

        If an SM-ID is known, and the server allows resumption, the
        previous stream will be resumed.
        """
        if 'stream_management' in self.xmpp.features:
            # We've already negotiated stream management,
            # so no need to do it again.
            return False
        if not self.sm_id:
            if 'bind' in self.xmpp.features:
                enable = stanza.Enable(self.xmpp)
                enable['resume'] = self.allow_resume
                enable.send()
                self.enabled = True
                self.handled = 0
                self.unacked_queue.clear()

                waiter = Waiter(
                    'enabled_or_failed',
                    MatchMany([
                        MatchXPath(stanza.Enabled.tag_name()),
                        MatchXPath(stanza.Failed.tag_name())
                    ]))
                self.xmpp.register_handler(waiter)
                result = yield from waiter.wait()
        elif self.sm_id and self.allow_resume and 'bind' not in self.xmpp.features:
            self.enabled = True
            resume = stanza.Resume(self.xmpp)
            resume['h'] = self.handled
            resume['previd'] = self.sm_id
            resume.send()

            # Wait for a response before allowing stream feature processing
            # to continue. The actual result processing will be done in the
            # _handle_resumed() or _handle_failed() methods.
            waiter = Waiter(
                'resumed_or_failed',
                MatchMany([
                    MatchXPath(stanza.Resumed.tag_name()),
                    MatchXPath(stanza.Failed.tag_name())
                ]))
            self.xmpp.register_handler(waiter)
            result = yield from waiter.wait()
            if result is not None and result.name == 'resumed':
                return True
        return False
    def testIqErrorException(self):
        """Test using error exceptions with Iq stanzas."""
        def handle_iq(iq):
            raise XMPPError(condition='feature-not-implemented',
                            text="We don't do things that way here.",
                            etype='cancel',
                            clear=False)

        self.stream_start()
        self.xmpp.register_handler(
            Callback('Test Iq',
                     MatchXPath('{%s}iq/{test}query' % self.xmpp.default_ns),
                     handle_iq))

        self.recv("""
          <iq type="get" id="0">
            <query xmlns="test" />
          </iq>
        """)

        self.send("""
          <iq type="error" id="0">
            <query xmlns="test" />
            <error type="cancel" code="501">
              <feature-not-implemented
                  xmlns="urn:ietf:params:xml:ns:xmpp-stanzas" />
              <text xmlns="urn:ietf:params:xml:ns:xmpp-stanzas">
                We don&apos;t do things that way here.
              </text>
            </error>
          </iq>
        """,
                  use_values=False)
Example #5
0
    def __init__(self, jid, secret, host=None, port=None, plugin_config=None, plugin_whitelist=None, use_jc_ns=False):

        if not plugin_whitelist:
            plugin_whitelist = []
        if not plugin_config:
            plugin_config = {}

        if use_jc_ns:
            default_ns = 'jabber:client'
        else:
            default_ns = 'jabber:component:accept'
        BaseXMPP.__init__(self, jid, default_ns)

        self.auto_authorize = None
        self.stream_header = '<stream:stream %s %s to="%s">' % (
                'xmlns="jabber:component:accept"',
                'xmlns:stream="%s"' % self.stream_ns,
                jid)
        self.stream_footer = "</stream:stream>"
        self.server_host = host
        self.server_port = port
        self.secret = secret

        self.plugin_config = plugin_config
        self.plugin_whitelist = plugin_whitelist
        self.is_component = True

        self.sessionstarted = False

        self.register_handler(
                Callback('Handshake',
                         MatchXPath('{jabber:component:accept}handshake'),
                         self._handle_handshake))
        self.add_event_handler('presence_probe',
                               self._handle_probe)
Example #6
0
 def plugin_init(self) -> None:
     stanza.register_plugins()
     self.xmpp.register_handler(
         Callback(
             "MIX message received",
             MatchXPath('{%s}message[@type="groupchat"]/{%s}mix' %
                        (self.xmpp.default_ns, self.namespace)),
             self._handle_mix_message,
         ))
Example #7
0
    def plugin_init(self) -> None:
        stanza.register_plugins()

        self.xmpp.register_handler(
            Callback(
                'MIX Presence received',
                MatchXPath('{%s}presence/{%s}mix' %
                           (self.xmpp.default_ns, stanza.NS)),
                self._handle_mix_presence,
            ))
Example #8
0
    def plugin_init(self):
        if self.sasl_callback is None:
            self.sasl_callback = self._default_credentials

        if self.security_callback is None:
            self.security_callback = self._default_security

        creds = self.sasl_callback({'username'}, set())
        if not self.use_mech and not creds['username']:
            self.use_mech = 'ANONYMOUS'

        self.mech = None
        self.mech_list = set()
        self.attempted_mechs = set()

        register_stanza_plugin(StreamFeatures, stanza.Mechanisms)

        self.xmpp.register_stanza(stanza.Success)
        self.xmpp.register_stanza(stanza.Failure)
        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))
        self.xmpp.register_handler(
                Callback('SASL Failure',
                         MatchXPath(stanza.Failure.tag_name()),
                         self._handle_fail,
                         instream=True))
        self.xmpp.register_handler(
                Callback('SASL Challenge',
                         MatchXPath(stanza.Challenge.tag_name()),
                         self._handle_challenge))

        self.xmpp.register_feature('mechanisms',
                self._handle_sasl_auth,
                restart=True,
                order=self.order)
Example #9
0
    def plugin_init(self):
        register_stanza_plugin(RPCQuery, stanza.MethodTimeout)

        self.xmpp.register_handler(
            Callback(
                "RPC Call",
                MatchXPath("{%s}iq/{%s}query/{%s}methodTimeout" %
                           (self.xmpp.default_ns, RPCQuery.namespace,
                            RPCQuery.namespace)),
                self._handle_method_timeout,
            ))

        self.xmpp.add_event_handler("jabber_rpc_method_timeout",
                                    self._on_jabber_rpc_method_timeout)
Example #10
0
    def plugin_init(self):
        register_stanza_plugin(Iq, stanza.GmailQuery)
        register_stanza_plugin(Iq, stanza.MailBox)
        register_stanza_plugin(Iq, stanza.NewMail)

        self.xmpp.register_handler(
            Callback(
                'Gmail New Mail',
                MatchXPath('{%s}iq/{%s}%s' %
                           (self.xmpp.default_ns, stanza.NewMail.namespace,
                            stanza.NewMail.name)), self._handle_new_mail))

        self._last_result_time = None
        self._last_result_tid = None
Example #11
0
    def plugin_init(self):
        self.xmpp.register_handler(
                CoroutineCallback('STARTTLS Proceed',
                        MatchXPath(stanza.Proceed.tag_name()),
                        self._handle_starttls_proceed,
                        instream=True))
        self.xmpp.register_feature('starttls',
                self._handle_starttls,
                restart=True,
                order=self.config.get('order', 0))

        self.xmpp.register_stanza(stanza.Proceed)
        self.xmpp.register_stanza(stanza.Failure)
        register_stanza_plugin(StreamFeatures, stanza.STARTTLS)
Example #12
0
    def plugin_init(self):
        register_stanza_plugin(Iq, RPCQuery)
        register_stanza_plugin(RPCQuery, MethodCall)
        register_stanza_plugin(RPCQuery, MethodResponse)

        self.xmpp.register_handler(
            Callback(
                'RPC Call',
                MatchXPath('{%s}iq/{%s}query/{%s}methodCall' %
                           (self.xmpp.default_ns, RPCQuery.namespace,
                            RPCQuery.namespace)), self._handle_method_call))
        self.xmpp.register_handler(
            Callback(
                'RPC Call',
                MatchXPath('{%s}iq/{%s}query/{%s}methodResponse' %
                           (self.xmpp.default_ns, RPCQuery.namespace,
                            RPCQuery.namespace)),
                self._handle_method_response))
        self.xmpp.register_handler(
            Callback(
                'RPC Call',
                MatchXPath('{%s}iq/{%s}error' %
                           (self.xmpp.default_ns, self.xmpp.default_ns)),
                self._handle_error))
        self.xmpp.add_event_handler('jabber_rpc_method_call',
                                    self._on_jabber_rpc_method_call)
        self.xmpp.add_event_handler('jabber_rpc_method_response',
                                    self._on_jabber_rpc_method_response)
        self.xmpp.add_event_handler('jabber_rpc_method_fault',
                                    self._on_jabber_rpc_method_fault)
        self.xmpp.add_event_handler('jabber_rpc_error',
                                    self._on_jabber_rpc_error)
        self.xmpp.add_event_handler('error', self._handle_error)
        #self.activeCalls = []

        self.xmpp['xep_0030'].add_feature('jabber:iq:rpc')
        self.xmpp['xep_0030'].add_identity('automation', 'rpc')
Example #13
0
    def run(self):
        self.log_debug("def run")
        if os.name == "nt":
            asyncio.set_event_loop_policy(
                asyncio.WindowsSelectorEventLoopPolicy())
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)

        xmpp = XMPPClient(
            self.jid,
            self.config.get("pw"),
            self.log_info,
            self.log_debug,
        )
        self.log_debug("activate xmpp")
        xmpp.use_ipv6 = self.config.get("use_ipv6")
        xmpp.register_plugin("xep_0030")  # Service Discovery
        xmpp.register_plugin("xep_0004")  # Data Forms
        xmpp.register_plugin("xep_0060")  # PubSub
        xmpp.register_plugin("xep_0199")  # XMPP Ping
        xmpp.ssl_version = ssl.PROTOCOL_TLSv1_2

        # The message event is triggered whenever a message
        # stanza is received. Be aware that that includes
        # MUC messages and error messages.
        xmpp.add_event_handler("message", self.message)
        xmpp.add_event_handler("connected", self.connected)
        xmpp.add_event_handler("connection_failed", self.connection_failed)
        xmpp.add_event_handler("disconnected", self.disconnected)
        xmpp.add_event_handler("failed_auth", self.failed_auth)
        xmpp.add_event_handler("changed_status", self.changed_status)
        xmpp.add_event_handler("presence_error", self.presence_error)
        xmpp.add_event_handler("presence_unavailable",
                               self.presence_unavailable)

        xmpp.register_handler(
            Callback(
                "Stream Error",
                MatchXPath(f"{{{xmpp.stream_ns}}}error"),
                self.stream_error,
            ))

        self.xmpp = xmpp
        self.xmpp.connect(
            use_ssl=self.config.get("use_ssl"),
            force_starttls=self.config.get("tls"),
        )
        self.xmpp.process(forever=True)
Example #14
0
    def __init__(self, *args, **kwargs):
        super(TestClient, self).__init__(*args, **kwargs)
        self.stream_header = "<stream:stream to='%s' %s %s %s %s>" % (
            self.boundjid.host, "xmlns:stream='%s'" % self.stream_ns,
            "xmlns='%s'" % self.default_ns,
            "xml:lang='%s'" % self.default_lang, "version='1.0'")
        self.stream_footer = "</stream:stream>"

        self.features = set()
        self._stream_feature_handlers = {}
        self._stream_feature_order = []

        self.register_stanza(StreamFeatures)
        self.register_handler(
            CoroutineCallback('Stream Features',
                              MatchXPath('{%s}features' % self.stream_ns),
                              self._handle_stream_features))

        self.register_plugin('feature_starttls')

        self.add_event_handler('stream_negotiated', self.test)
Example #15
0
    def __init__(self,
                 jid,
                 password,
                 plugin_config=None,
                 plugin_whitelist=None,
                 escape_quotes=True,
                 sasl_mech=None,
                 lang='en',
                 **kwargs):
        if not plugin_whitelist:
            plugin_whitelist = []
        if not plugin_config:
            plugin_config = {}

        BaseXMPP.__init__(self, jid, 'jabber:client', **kwargs)

        self.escape_quotes = escape_quotes
        self.plugin_config = plugin_config
        self.plugin_whitelist = plugin_whitelist
        self.default_port = 5222
        self.default_lang = lang

        self.credentials = {}

        self.password = password

        self.stream_header = "<stream:stream to='%s' %s %s %s %s>" % (
            self.boundjid.host, "xmlns:stream='%s'" % self.stream_ns,
            "xmlns='%s'" % self.default_ns,
            "xml:lang='%s'" % self.default_lang, "version='1.0'")
        self.stream_footer = "</stream:stream>"

        self.features = set()
        self._stream_feature_handlers = {}
        self._stream_feature_order = []

        self.dns_service = 'xmpp-client'

        #TODO: Use stream state here
        self.authenticated = False
        self.sessionstarted = False
        self.bound = False
        self.bindfail = False

        self.add_event_handler('connected', self._reset_connection_state)
        self.add_event_handler('session_bind', self._handle_session_bind)
        self.add_event_handler('roster_update', self._handle_roster)

        self.register_stanza(StreamFeatures)

        self.register_handler(
            CoroutineCallback('Stream Features',
                              MatchXPath('{%s}features' % self.stream_ns),
                              self._handle_stream_features))

        def roster_push_filter(iq):
            from_ = iq['from']
            if from_ and from_ != JID('') and from_ != self.boundjid.bare:
                reply = iq.reply()
                reply['type'] = 'error'
                reply['error']['type'] = 'cancel'
                reply['error']['code'] = 503
                reply['error']['condition'] = 'service-unavailable'
                reply.send()
                return
            self.event('roster_update', iq)

        self.register_handler(
            Callback('Roster Update', StanzaPath('iq@type=set/roster'),
                     roster_push_filter))

        # Setup default stream features
        self.register_plugin('feature_starttls')
        self.register_plugin('feature_bind')
        self.register_plugin('feature_session')
        self.register_plugin('feature_rosterver')
        self.register_plugin('feature_preapproval')
        self.register_plugin('feature_mechanisms')

        if sasl_mech:
            self['feature_mechanisms'].use_mech = sasl_mech
Example #16
0
    def __init__(self, jid='', default_ns='jabber:client', **kwargs):
        XMLStream.__init__(self, **kwargs)

        self.default_ns = default_ns
        self.stream_ns = 'http://etherx.jabber.org/streams'
        self.namespace_map[self.stream_ns] = 'stream'

        #: An identifier for the stream as given by the server.
        self.stream_id = None

        #: The JabberID (JID) requested for this connection.
        self.requested_jid = JID(jid)

        #: The JabberID (JID) used by this connection,
        #: as set after session binding. This may even be a
        #: different bare JID than what was requested.
        self.boundjid = JID(jid)

        self._expected_server_name = self.boundjid.host
        self._redirect_attempts = 0

        #: The maximum number of consecutive see-other-host
        #: redirections that will be followed before quitting.
        self.max_redirects = 5

        self.session_bind_event = asyncio.Event()

        #: A dictionary mapping plugin names to plugins.
        self.plugin = PluginManager(self)

        #: Configuration options for whitelisted plugins.
        #: If a plugin is registered without any configuration,
        #: and there is an entry here, it will be used.
        self.plugin_config = {}

        #: A list of plugins that will be loaded if
        #: :meth:`register_plugins` is called.
        self.plugin_whitelist = []

        #: The main roster object. This roster supports multiple
        #: owner JIDs, as in the case for components. For clients
        #: which only have a single JID, see :attr:`client_roster`.
        self.roster = roster.Roster(self)
        self.roster.add(self.boundjid)

        #: The single roster for the bound JID. This is the
        #: equivalent of::
        #:
        #:     self.roster[self.boundjid.bare]
        self.client_roster = self.roster[self.boundjid]

        #: The distinction between clients and components can be
        #: important, primarily for choosing how to handle the
        #: ``'to'`` and ``'from'`` JIDs of stanzas.
        self.is_component = False

        #: Messages may optionally be tagged with ID values. Setting
        #: :attr:`use_message_ids` to `True` will assign all outgoing
        #: messages an ID. Some plugin features require enabling
        #: this option.
        self.use_message_ids = True

        #: Presence updates may optionally be tagged with ID values.
        #: Setting :attr:`use_message_ids` to `True` will assign all
        #: outgoing messages an ID.
        self.use_presence_ids = True

        #: XEP-0359 <origin-id/> tag that gets added to <message/> stanzas.
        self.use_origin_id = True

        #: The API registry is a way to process callbacks based on
        #: JID+node combinations. Each callback in the registry is
        #: marked with:
        #:
        #:   - An API name, e.g. xep_0030
        #:   - The name of an action, e.g. get_info
        #:   - The JID that will be affected
        #:   - The node that will be affected
        #:
        #: API handlers with no JID or node will act as global handlers,
        #: while those with a JID and no node will service all nodes
        #: for a JID, and handlers with both a JID and node will be
        #: used only for that specific combination. The handler that
        #: provides the most specificity will be used.
        self.api = APIRegistry(self)

        #: Flag indicating that the initial presence broadcast has
        #: been sent. Until this happens, some servers may not
        #: behave as expected when sending stanzas.
        self.sentpresence = False

        #: A reference to :mod:`slixmpp.stanza` to make accessing
        #: stanza classes easier.
        self.stanza = stanza

        self.register_handler(
            Callback(
                'IM',
                MatchXPath('{%s}message/{%s}body' %
                           (self.default_ns, self.default_ns)),
                self._handle_message))

        self.register_handler(
            Callback(
                'IMError',
                MatchXPath('{%s}message/{%s}error' %
                           (self.default_ns, self.default_ns)),
                self._handle_message_error))

        self.register_handler(
            Callback('Presence', MatchXPath("{%s}presence" % self.default_ns),
                     self._handle_presence))

        self.register_handler(
            Callback('Stream Error', MatchXPath("{%s}error" % self.stream_ns),
                     self._handle_stream_error))

        self.add_event_handler('session_start', self._handle_session_start)
        self.add_event_handler('disconnected', self._handle_disconnected)
        self.add_event_handler('presence_available', self._handle_available)
        self.add_event_handler('presence_dnd', self._handle_available)
        self.add_event_handler('presence_xa', self._handle_available)
        self.add_event_handler('presence_chat', self._handle_available)
        self.add_event_handler('presence_away', self._handle_available)
        self.add_event_handler('presence_unavailable',
                               self._handle_unavailable)
        self.add_event_handler('presence_subscribe', self._handle_subscribe)
        self.add_event_handler('presence_subscribed', self._handle_subscribed)
        self.add_event_handler('presence_unsubscribe',
                               self._handle_unsubscribe)
        self.add_event_handler('presence_unsubscribed',
                               self._handle_unsubscribed)
        self.add_event_handler('roster_subscription_request',
                               self._handle_new_subscription)

        # Set up the XML stream with XMPP's root stanzas.
        self.register_stanza(Message)
        self.register_stanza(Iq)
        self.register_stanza(Presence)
        self.register_stanza(StreamError)

        # Initialize a few default stanza plugins.
        register_stanza_plugin(Iq, Roster)
Example #17
0
    def plugin_init(self):
        """Start the XEP-0198 plugin."""

        # Only enable stream management for non-components,
        # since components do not yet perform feature negotiation.
        if self.xmpp.is_component:
            return

        self.window_counter = self.window

        self.enabled = False
        self.unacked_queue = collections.deque()

        register_stanza_plugin(StreamFeatures, stanza.StreamManagement)
        self.xmpp.register_stanza(stanza.Enable)
        self.xmpp.register_stanza(stanza.Enabled)
        self.xmpp.register_stanza(stanza.Resume)
        self.xmpp.register_stanza(stanza.Resumed)
        self.xmpp.register_stanza(stanza.Ack)
        self.xmpp.register_stanza(stanza.RequestAck)

        # Only end the session when a </stream> element is sent,
        # not just because the connection has died.
        self.xmpp.end_session_on_disconnect = False

        # Register the feature twice because it may be ordered two
        # different ways: enabling after binding and resumption
        # before binding.
        self.xmpp.register_feature('sm',
                                   self._handle_sm_feature,
                                   restart=True,
                                   order=self.order)
        self.xmpp.register_feature('sm',
                                   self._handle_sm_feature,
                                   restart=True,
                                   order=self.resume_order)

        self.xmpp.register_handler(
            Callback('Stream Management Enabled',
                     MatchXPath(stanza.Enabled.tag_name()),
                     self._handle_enabled,
                     instream=True))

        self.xmpp.register_handler(
            Callback('Stream Management Resumed',
                     MatchXPath(stanza.Resumed.tag_name()),
                     self._handle_resumed,
                     instream=True))

        self.xmpp.register_handler(
            Callback('Stream Management Failed',
                     MatchXPath(stanza.Failed.tag_name()),
                     self._handle_failed,
                     instream=True))

        self.xmpp.register_handler(
            Callback('Stream Management Ack',
                     MatchXPath(stanza.Ack.tag_name()),
                     self._handle_ack,
                     instream=True))

        self.xmpp.register_handler(
            Callback('Stream Management Request Ack',
                     MatchXPath(stanza.RequestAck.tag_name()),
                     self._handle_request_ack,
                     instream=True))

        self.xmpp.add_filter('in', self._handle_incoming)
        self.xmpp.add_filter('out_sync', self._handle_outgoing)

        self.xmpp.add_event_handler('session_end', self.session_end)