Source code for xmpp.extensions.xep0114

# -*- coding: utf-8 -*-
#
# <xmpp - stateless and concurrency-agnostic XMPP library for python>
#
# Copyright (C) <2016-2017> Gabriel Falcao <gabriel@nacaolivre.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import hashlib
from speakers import Speaker as Events
from xmpp.models import Node, StartTLS, Stream
from xmpp.extensions import Extension


class ComponentStream(Stream):
    """``<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' />``"""

    __tag__ = 'stream:stream'
    __etag__ = None
    __namespaces__ = [
        ('', 'jabber:component:accept'),
        ('stream', 'http://etherx.jabber.org/streams'),
    ]


class SecretHandshake(Node):
    """``<handshake>hash</handshake>``"""
    __tag__ = 'handshake'
    __etag__ = '{jabber:component:accept}handshake'
    __namespaces__ = []
    __children_of__ = ComponentStream


class SuccessHandshake(Node):
    """``<handshake />``"""
    __etag__ = 'handshake'
    __children_of__ = ComponentStream


[docs]class Component(Extension): """Provides an `external component <http://www.xmpp.org/extensions/xep-0114.html>`_ API while keeping minimal state based on a single boolean flag. """ __xep__ = '0114' def initialize(self): self.on = Events('component', [ 'success', # the server returned a <handshake /> 'error', # the server returned a stream error ]) self.stream.on.node(self.route_nodes) self.__success_handshake = None def route_nodes(self, event, node): if isinstance(node, SuccessHandshake): self.__success_handshake = node self.on.success.shout(node)
[docs] def is_authenticated(self): """:returns: ``True`` if a success handshake was received by the bound XMLStream""" return self.__success_handshake is not None
[docs] def authenticate(self, secret): """sends a ``<handshake>`` to the server with the encoded version of the given secret :param secret: the secret string to authenticate the component """ stream_id = self.stream.id text = "".join([stream_id, secret]) secret = hashlib.sha1(text).hexdigest() handshake = SecretHandshake.create(secret) self.stream.send(handshake)
[docs] def create_node(self, to, tls=False): """creates a :py:class:`~xmpp.extensions.xep0114.ComponentStream` with an optional ``<starttls />`` in it. """ node = ComponentStream.create(to=to) if tls: node.append(StartTLS.create()) return node
[docs] def open(self, domain, tls=False): """sends an ``<stream:stream xmlns="jabber:component:accept">``""" initial = self.create_node(to=domain, tls=tls) self.stream.send(initial)