From 7479bd8bd6052ed53ff131bc859d95a21be1116d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20H=C3=B6rist?= Date: Thu, 8 Feb 2018 21:05:15 +0100 Subject: [PATCH] Refactor getting avatars from pubsub - use SendAndCallForResponse instead of triggering an Event - validate iq result even more, it didnt print iq errors before --- gajim/common/connection_handlers_events.py | 44 ----------- gajim/common/exceptions.py | 10 +++ gajim/common/pep.py | 4 +- gajim/common/pubsub.py | 91 +++++++++++++++++----- 4 files changed, 82 insertions(+), 67 deletions(-) diff --git a/gajim/common/connection_handlers_events.py b/gajim/common/connection_handlers_events.py index 1a293b794..70fb41453 100644 --- a/gajim/common/connection_handlers_events.py +++ b/gajim/common/connection_handlers_events.py @@ -24,8 +24,6 @@ from calendar import timegm import datetime import hashlib -import binascii -import base64 import hmac import logging import sys @@ -604,48 +602,6 @@ class PubsubBookmarksReceivedEvent(nec.NetworkIncomingEvent, BookmarksHelper): self.parse_bookmarks() return True -class PubsubAvatarReceivedEvent(nec.NetworkIncomingEvent): - name = 'pubsub-avatar-received' - base_network_events = ['pubsub-received'] - - def __init__(self, name, base_event): - ''' - Pre-Generated attributes on self: - - :conn: Connection instance - :jid: The from jid - :pubsub_node: The 'pubsub' node - :items_node: The 'items' node - ''' - self._set_base_event_vars_as_attributes(base_event) - - def generate(self): - if self.items_node.getAttr('node') != 'urn:xmpp:avatar:data': - return - item = self.items_node.getTag('item') - if not item: - log.warning('Received malformed avatar data via pubsub') - log.debug(self.stanza) - return - self.sha = item.getAttr('id') - data_tag = item.getTag('data', namespace='urn:xmpp:avatar:data') - if self.sha is None or data_tag is None: - log.warning('Received malformed avatar data via pubsub') - log.debug(self.stanza) - return - self.data = data_tag.getData() - if self.data is None: - log.warning('Received malformed avatar data via pubsub') - log.debug(self.stanza) - return - try: - self.data = base64.b64decode(self.data.encode('utf-8')) - except binascii.Error as err: - log.debug('Received malformed avatar data via pubsub: %s' % err) - return - - return True - class SearchFormReceivedEvent(nec.NetworkIncomingEvent, HelperEvent): name = 'search-form-received' base_network_events = [] diff --git a/gajim/common/exceptions.py b/gajim/common/exceptions.py index 788a9190a..04f8ef0f0 100644 --- a/gajim/common/exceptions.py +++ b/gajim/common/exceptions.py @@ -147,3 +147,13 @@ class PluginsystemError(Exception): def __str__(self): return self.text + +class StanzaMalformed(Exception): + """ + Malfromed Stanza + """ + def __init__(self, message, stanza=''): + Exception.__init__(self, message, stanza) + self._msg = '{}\n{}'.format(message, stanza) + def __str__(self): + return self._msg diff --git a/gajim/common/pep.py b/gajim/common/pep.py index 6f45d940f..192243fd9 100644 --- a/gajim/common/pep.py +++ b/gajim/common/pep.py @@ -509,8 +509,8 @@ class AvatarNotificationPEP(AbstractPEP): jid, self.avatar['id']) return app.log('avatar').info('Request (Pubsub): %s', jid) - con.send_pb_retrieve(jid, 'urn:xmpp:avatar:data', - self.avatar['id']) + con.get_pubsub_avatar(jid, 'urn:xmpp:avatar:data', + self.avatar['id']) SUPPORTED_PERSONAL_USER_EVENTS = [ diff --git a/gajim/common/pubsub.py b/gajim/common/pubsub.py index aae994827..963c548a5 100644 --- a/gajim/common/pubsub.py +++ b/gajim/common/pubsub.py @@ -21,16 +21,18 @@ ## along with Gajim. If not, see . ## +import base64 +import binascii + import nbxmpp from gajim.common import app #TODO: Doesn't work #from common.connection_handlers import PEP_CONFIG PEP_CONFIG = 'pep_config' from gajim.common import ged -from gajim.common.nec import NetworkEvent from gajim.common.connection_handlers_events import PubsubReceivedEvent from gajim.common.connection_handlers_events import PubsubBookmarksReceivedEvent -from gajim.common.connection_handlers_events import PubsubAvatarReceivedEvent +from gajim.common.exceptions import StanzaMalformed import logging log = logging.getLogger('gajim.c.pubsub') @@ -39,11 +41,8 @@ class ConnectionPubSub: def __init__(self): self.__callbacks = {} app.nec.register_incoming_event(PubsubBookmarksReceivedEvent) - app.nec.register_incoming_event(PubsubAvatarReceivedEvent) app.ged.register_event_handler('pubsub-bookmarks-received', ged.CORE, self._nec_pubsub_bookmarks_received) - app.ged.register_event_handler('pubsub-avatar-received', - ged.CORE, self._nec_pubsub_avatar_received) def cleanup(self): app.ged.remove_event_handler('pubsub-bookmarks-received', @@ -103,22 +102,35 @@ class ConnectionPubSub: self.connection.send(query) + @staticmethod + def get_pb_retrieve_iq(jid, node, item_id=None): + """ + Get IQ to query items from a node + """ + query = nbxmpp.Iq('get', to=jid) + r = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB) + r = r.addChild('items', {'node': node}) + if item_id is not None: + r.addChild('item', {'id': item_id}) + return query + def send_pb_retrieve(self, jid, node, item_id=None, cb=None, *args, **kwargs): """ Get items from a node """ if not self.connection or self.connected < 2: return - query = nbxmpp.Iq('get', to=jid) - r = query.addChild('pubsub', namespace=nbxmpp.NS_PUBSUB) - r = r.addChild('items', {'node': node}) - if item_id is not None: - r.addChild('item', {'id': item_id}) + query = self.get_pb_retrieve_iq(jid, node, item_id) id_ = self.connection.send(query) if cb: self.__callbacks[id_] = (cb, args, kwargs) + def get_pubsub_avatar(self, jid, node, item_id): + query = self.get_pb_retrieve_iq(jid, node, item_id) + self.connection.SendAndCallForResponse( + query, self._nec_pubsub_avatar_received, {'jid': jid}) + def send_pb_retract(self, jid, node, id_): """ Delete item from a node @@ -211,25 +223,62 @@ class ConnectionPubSub: # We got bookmarks from pubsub, now get those from xml to merge them self.get_bookmarks(storage_type='xml') - def _nec_pubsub_avatar_received(self, obj): - if obj.conn.name != self.name: - return - - if obj.jid is None: + def _validate_avatar_node(self, stanza): + jid = stanza.getFrom() + if jid is None: jid = self.get_own_jid().getStripped() else: - jid = obj.jid.getStripped() + jid = jid.getStripped() + + if nbxmpp.isErrorNode(stanza): + raise StanzaMalformed(stanza.getErrorMsg()) + + pubsub_node = stanza.getTag('pubsub') + if pubsub_node is None: + raise StanzaMalformed('No pubsub node', stanza) + + items_node = pubsub_node.getTag('items') + if items_node is None: + raise StanzaMalformed('No items node', stanza) + + if items_node.getAttr('node') != 'urn:xmpp:avatar:data': + raise StanzaMalformed('Wrong namespace', stanza) + + item = items_node.getTag('item') + if item is None: + raise StanzaMalformed('No item node', stanza) + + sha = item.getAttr('id') + data_tag = item.getTag('data', namespace='urn:xmpp:avatar:data') + if sha is None or data_tag is None: + raise StanzaMalformed('No id attr or data node found', stanza) + + data = data_tag.getData() + if data is None: + raise StanzaMalformed('Data node empty', stanza) + + data = base64.b64decode(data.encode('utf-8')) + + return jid, sha, data + + def _nec_pubsub_avatar_received(self, conn, stanza, jid): + try: + jid, sha, data = self._validate_avatar_node(stanza) + except (StanzaMalformed, binascii.Error) as error: + app.log('avatar').warning( + 'Error loading Avatar (Pubsub): %s %s', jid, error) + return app.log('avatar').info( - 'Received Avatar (Pubsub): %s %s', jid, obj.sha) - app.interface.save_avatar(obj.data) + 'Received Avatar (Pubsub): %s %s', jid, sha) + app.interface.save_avatar(data) if self.get_own_jid().bareMatch(jid): - app.config.set_per('accounts', self.name, 'avatar_sha', obj.sha) + app.config.set_per('accounts', self.name, 'avatar_sha', sha) else: own_jid = self.get_own_jid().getStripped() - app.logger.set_avatar_sha(own_jid, jid, obj.sha) - app.contacts.set_avatar(self.name, jid, obj.sha) + app.logger.set_avatar_sha(own_jid, jid, sha) + app.contacts.set_avatar(self.name, jid, sha) app.interface.update_avatar(self.name, jid)