Merge branch 'fix-component-handshake' into 'master'

Fix component handshake

Closes #3464

See merge request poezio/slixmpp!156
This commit is contained in:
mathieui 2021-04-19 19:53:33 +02:00
commit 0d52344a31
7 changed files with 62 additions and 18 deletions

View File

@ -22,7 +22,8 @@ class TestPrivateStorage(SlixIntegration):
el, el,
) )
result = await self.clients[0]['xep_0049'].retrieve('bookmarks') result = await self.clients[0]['xep_0049'].retrieve('bookmarks')
self.assertEqual(str(result['private']['bookmarks']), str(el))
self.assertEqual(result['private']['bookmarks'], el)
# Purge bookmarks # Purge bookmarks
await self.clients[0]['xep_0049'].store( await self.clients[0]['xep_0049'].store(

View File

@ -10,6 +10,7 @@ import logging
import hashlib import hashlib
from slixmpp.basexmpp import BaseXMPP from slixmpp.basexmpp import BaseXMPP
from slixmpp.stanza import Handshake
from slixmpp.xmlstream import XMLStream from slixmpp.xmlstream import XMLStream
from slixmpp.xmlstream import ET from slixmpp.xmlstream import ET
from slixmpp.xmlstream.matcher import MatchXPath from slixmpp.xmlstream.matcher import MatchXPath
@ -123,9 +124,10 @@ class ComponentXMPP(BaseXMPP):
sid = xml.get('id', '') sid = xml.get('id', '')
pre_hash = bytes('%s%s' % (sid, self.secret), 'utf-8') pre_hash = bytes('%s%s' % (sid, self.secret), 'utf-8')
handshake = ET.Element('{jabber:component:accept}handshake') handshake = Handshake()
handshake.text = hashlib.sha1(pre_hash).hexdigest().lower() handshake['value'] = hashlib.sha1(pre_hash).hexdigest().lower()
self.send_xml(handshake)
self.send(handshake)
def _handle_handshake(self, xml): def _handle_handshake(self, xml):
"""The handshake has been accepted. """The handshake has been accepted.

View File

@ -1,4 +1,3 @@
# Slixmpp: The Slick XMPP Library # Slixmpp: The Slick XMPP Library
# Copyright (C) 2010 Nathanael C. Fritz # Copyright (C) 2010 Nathanael C. Fritz
# This file is part of Slixmpp. # This file is part of Slixmpp.
@ -10,3 +9,9 @@ from slixmpp.stanza.message import Message
from slixmpp.stanza.presence import Presence from slixmpp.stanza.presence import Presence
from slixmpp.stanza.stream_features import StreamFeatures from slixmpp.stanza.stream_features import StreamFeatures
from slixmpp.stanza.stream_error import StreamError from slixmpp.stanza.stream_error import StreamError
from slixmpp.stanza.handshake import Handshake
__all__ = [
'Error', 'Iq', 'Message', 'Presence', 'StreamFeatures', 'StreamError',
'Handshake'
]

View File

@ -0,0 +1,25 @@
# Slixmpp: The Slick XMPP Library
# Copyright (C) 2021 Mathieu Pasquet
# This file is part of Slixmpp.
# See the file LICENSE for copying permission.
from slixmpp.xmlstream import StanzaBase
class Handshake(StanzaBase):
"""
Jabber Component protocol handshake
"""
namespace = 'jabber:component:accept'
name = 'handshake'
interfaces = {'value'}
def set_value(self, value: str):
self.xml.text = value
def get_value(self) -> str:
return self.xml.text
def del_value(self):
self.xml.text = ''

View File

@ -487,7 +487,7 @@ class ElementBase(object):
else: else:
return None if check else self.init_plugin(name, lang) return None if check else self.init_plugin(name, lang)
def init_plugin(self, attrib, lang=None, existing_xml=None, reuse=True): def init_plugin(self, attrib, lang=None, existing_xml=None, element=None, reuse=True):
"""Enable and initialize a stanza plugin. """Enable and initialize a stanza plugin.
:param string attrib: The :attr:`plugin_attrib` value of the :param string attrib: The :attr:`plugin_attrib` value of the
@ -504,7 +504,10 @@ class ElementBase(object):
if reuse and (attrib, lang) in self.plugins: if reuse and (attrib, lang) in self.plugins:
return self.plugins[(attrib, lang)] return self.plugins[(attrib, lang)]
plugin = plugin_class(parent=self, xml=existing_xml) if element is not None:
plugin = element
else:
plugin = plugin_class(parent=self, xml=existing_xml)
if plugin.is_extension: if plugin.is_extension:
self.plugins[(attrib, None)] = plugin self.plugins[(attrib, None)] = plugin
@ -1172,14 +1175,18 @@ class ElementBase(object):
else: else:
raise TypeError raise TypeError
self.xml.append(item.xml) self.xml.append(item.xml)
self.iterables.append(item) if item.__class__ == self.plugin_tag_map.get(item.tag_name(), None):
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, self.init_plugin(item.plugin_attrib,
existing_xml=item.xml, existing_xml=item.xml,
element=item,
reuse=False) reuse=False)
elif item.__class__ in self.plugin_iterables:
self.iterables.append(item)
if item.__class__.plugin_multi_attrib:
self.init_plugin(item.__class__.plugin_multi_attrib)
else:
self.iterables.append(item)
return self return self
def appendxml(self, xml): def appendxml(self, xml):
@ -1269,14 +1276,14 @@ class ElementBase(object):
# Check that this stanza is a superset of the other stanza. # Check that this stanza is a superset of the other stanza.
values = self.values values = self.values
other_values = other.values
for key in other.keys(): for key in other.keys():
if key not in values or values[key] != other[key]: if key not in values or values.get(key) != other_values.get(key):
return False return False
# Check that the other stanza is a superset of this stanza. # Check that the other stanza is a superset of this stanza.
values = other.values
for key in self.keys(): for key in self.keys():
if key not in values or values[key] != self[key]: if key not in values or other_values.get(key) != values.get(key):
return False return False
# Both stanzas are supersets of each other, therefore they # Both stanzas are supersets of each other, therefore they

View File

@ -1140,9 +1140,12 @@ class XMLStream(asyncio.BaseProtocol):
if not self._always_send_everything and not self._session_started: if not self._always_send_everything and not self._session_started:
# Avoid circular imports # Avoid circular imports
from slixmpp.stanza.rootstanza import RootStanza from slixmpp.stanza.rootstanza import RootStanza
from slixmpp.stanza import Iq from slixmpp.stanza import Iq, Handshake
is_bind = isinstance(data, Iq) and data.get_plugin('bind', check=True) passthrough = (
if isinstance(data, (RootStanza, str)) and not is_bind: (isinstance(data, Iq) and data.get_plugin('bind', check=True))
or isinstance(data, Handshake)
)
if isinstance(data, (RootStanza, str)) and not passthrough:
self.__queued_stanzas.append(data) self.__queued_stanzas.append(data)
log.debug('NOT SENT: %s %s', type(data), data) log.debug('NOT SENT: %s %s', type(data), data)
return return

View File

@ -456,6 +456,7 @@ class TestElementBase(SlixTest):
class TestSubStanza(ElementBase): class TestSubStanza(ElementBase):
name = "sub" name = "sub"
plugin_attrib = name
namespace = "baz" namespace = "baz"
interfaces = {'attrib'} interfaces = {'attrib'}