From bd03f071c611225984223c6d942cab49b46bfcc8 Mon Sep 17 00:00:00 2001 From: Lance Stout Date: Mon, 3 Feb 2014 19:15:08 -0600 Subject: [PATCH] Fix verifying 'from' for IQ results. Closes issue #278 --- sleekxmpp/stanza/iq.py | 15 +++++--- sleekxmpp/test/sleektest.py | 3 +- sleekxmpp/xmlstream/matcher/__init__.py | 1 + sleekxmpp/xmlstream/matcher/idsender.py | 47 +++++++++++++++++++++++++ 4 files changed, 61 insertions(+), 5 deletions(-) create mode 100644 sleekxmpp/xmlstream/matcher/idsender.py diff --git a/sleekxmpp/stanza/iq.py b/sleekxmpp/stanza/iq.py index ba945e08..e377b82f 100644 --- a/sleekxmpp/stanza/iq.py +++ b/sleekxmpp/stanza/iq.py @@ -9,7 +9,7 @@ from sleekxmpp.stanza.rootstanza import RootStanza from sleekxmpp.xmlstream import StanzaBase, ET from sleekxmpp.xmlstream.handler import Waiter, Callback -from sleekxmpp.xmlstream.matcher import MatcherId +from sleekxmpp.xmlstream.matcher import MatchIDSender from sleekxmpp.exceptions import IqTimeout, IqError @@ -193,6 +193,13 @@ class Iq(RootStanza): """ if timeout is None: timeout = self.stream.response_timeout + + criteria = { + 'id': self['id'], + 'self': self.stream.boundjid, + 'peer': self['to'] + } + if callback is not None and self['type'] in ('get', 'set'): handler_name = 'IqCallback_%s' % self['id'] if timeout_callback: @@ -203,19 +210,19 @@ class Iq(RootStanza): self._fire_timeout, repeat=False) handler = Callback(handler_name, - MatcherId(self['id']), + MatchIDSender(criteria), self._handle_result, once=True) else: handler = Callback(handler_name, - MatcherId(self['id']), + MatchIDSender(criteria), callback, once=True) self.stream.register_handler(handler) StanzaBase.send(self, now=now) return handler_name elif block and self['type'] in ('get', 'set'): - waitfor = Waiter('IqWait_%s' % self['id'], MatcherId(self['id'])) + waitfor = Waiter('IqWait_%s' % self['id'], MatchIDSender(criteria)) self.stream.register_handler(waitfor) StanzaBase.send(self, now=now) result = waitfor.wait(timeout) diff --git a/sleekxmpp/test/sleektest.py b/sleekxmpp/test/sleektest.py index 04fb106d..51cda3ee 100644 --- a/sleekxmpp/test/sleektest.py +++ b/sleekxmpp/test/sleektest.py @@ -16,7 +16,7 @@ from sleekxmpp.test import TestSocket, TestLiveSocket from sleekxmpp.xmlstream import ET from sleekxmpp.xmlstream import ElementBase from sleekxmpp.xmlstream.tostring import tostring -from sleekxmpp.xmlstream.matcher import StanzaPath, MatcherId +from sleekxmpp.xmlstream.matcher import StanzaPath, MatcherId, MatchIDSender from sleekxmpp.xmlstream.matcher import MatchXMLMask, MatchXPath @@ -212,6 +212,7 @@ class SleekTest(unittest.TestCase): matchers = {'stanzapath': StanzaPath, 'xpath': MatchXPath, 'mask': MatchXMLMask, + 'idsender': MatchIDSender, 'id': MatcherId} Matcher = matchers.get(method, None) if Matcher is None: diff --git a/sleekxmpp/xmlstream/matcher/__init__.py b/sleekxmpp/xmlstream/matcher/__init__.py index 1038d1bd..aa74c434 100644 --- a/sleekxmpp/xmlstream/matcher/__init__.py +++ b/sleekxmpp/xmlstream/matcher/__init__.py @@ -7,6 +7,7 @@ """ from sleekxmpp.xmlstream.matcher.id import MatcherId +from sleekxmpp.xmlstream.matcher.idsender import MatchIDSender from sleekxmpp.xmlstream.matcher.many import MatchMany from sleekxmpp.xmlstream.matcher.stanzapath import StanzaPath from sleekxmpp.xmlstream.matcher.xmlmask import MatchXMLMask diff --git a/sleekxmpp/xmlstream/matcher/idsender.py b/sleekxmpp/xmlstream/matcher/idsender.py new file mode 100644 index 00000000..5c2c1f51 --- /dev/null +++ b/sleekxmpp/xmlstream/matcher/idsender.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- +""" + sleekxmpp.xmlstream.matcher.id + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Part of SleekXMPP: The Sleek XMPP Library + + :copyright: (c) 2011 Nathanael C. Fritz + :license: MIT, see LICENSE for more details +""" + +from sleekxmpp.xmlstream.matcher.base import MatcherBase + + +class MatchIDSender(MatcherBase): + + """ + The IDSender matcher selects stanzas that have the same stanza 'id' + interface value as the desired ID, and that the 'from' value is one + of a set of approved entities that can respond to a request. + """ + + def match(self, xml): + """Compare the given stanza's ``'id'`` attribute to the stored + ``id`` value, and verify the sender's JID. + + :param xml: The :class:`~sleekxmpp.xmlstream.stanzabase.ElementBase` + stanza to compare against. + """ + + selfjid = self._criteria['self'] + peerjid = self._criteria['peer'] + + allowed = {} + allowed[''] = True + allowed[selfjid.bare] = True + allowed[selfjid.host] = True + allowed[peerjid.full] = True + allowed[peerjid.bare] = True + allowed[peerjid.host] = True + + _from = xml['from'] + + try: + return xml['id'] == self._criteria['id'] and allowed[_from] + except KeyError: + return False