def test_store_and_retrieve_xml_unregistered(self): tree = etree.fromstring('<example xmlns="urn:example:unregistered">' '<payload xmlns="urn:example:unregistered">' 'foobar' '</payload>' '</example>') query = private_xml.xso.Query(None) query.unregistered_payload.append(tree) iq = aioxmpp.IQ( type_=aioxmpp.IQType.SET, payload=query, ) yield from self.client.send(iq) query.unregistered_payload[0].clear() iq = aioxmpp.IQ( type_=aioxmpp.IQType.GET, payload=query, ) retrieved = yield from self.client.send(iq) self.assertEqual(len(retrieved.unregistered_payload), 1) self.assertEqual(retrieved.unregistered_payload[0].tag, "{urn:example:unregistered}example") self.assertEqual(len(retrieved.unregistered_payload[0]), 1) self.assertEqual(retrieved.unregistered_payload[0][0].tag, "{urn:example:unregistered}payload") self.assertEqual(retrieved.unregistered_payload[0][0].text, "foobar")
async def amain(args, password): client = aioxmpp.Client( args.local_jid, aioxmpp.make_security_layer(password) ) async with client.connected() as stream: form_xso = (await stream.send( aioxmpp.IQ( to=args.service_jid, type_=aioxmpp.IQType.GET, payload=xso.Search() ) )).form form_obj = xso.SearchForm.from_xso(form_xso) form_obj.query.value = " ".join(map(shlex.quote, args.query)) form_obj.order_by.value = args.order_by if args.min_users is not None: form_obj.min_users.value = args.min_users request = xso.Search() request.form = form_obj.render_reply() request.rsm = aioxmpp.rsm.xso.ResultSetMetadata() if args.request_page_size is not None: request.rsm.max_ = args.request_page_size nresults = 0 while args.fetch_up_to is None or nresults < args.fetch_up_to: reply = await stream.send(aioxmpp.IQ( to=args.service_jid, type_=aioxmpp.IQType.GET, payload=request )) for item in reply.items: print_item(item) if not reply.items: break nresults += len(reply.items) if reply.rsm.max_ and len(reply.items) < reply.rsm.max_: break request.rsm.after = aioxmpp.rsm.xso.After() request.rsm.after.value = reply.rsm.last.value
def test__handle_command_dispatches_to_command(self): handler = CoroutineMock() handler.return_value = unittest.mock.sentinel.result self.s.register_stateless_command( "node", "Command name", handler, ) req = aioxmpp.IQ( type_=aioxmpp.IQType.SET, from_=TEST_PEER_JID, to=TEST_LOCAL_JID, payload=adhoc_xso.Command( "node", ) ) result = run_coroutine(self.s._handle_command(req)) handler.assert_called_once_with(req) self.assertEqual( result, unittest.mock.sentinel.result, )
def test_ibr_get_registration_fields(self): with unittest.mock.patch('aioxmpp.protocol.send_and_wait_for', new=CoroutineMock()) as mock1: iq_res = aioxmpp.IQ(type_=aioxmpp.IQType.GET, payload=ibr_xso.Query()) iq_res.payload.username = '' mock1.return_value = iq_res stream = unittest.mock.Mock(spec=aioxmpp.protocol.XMLStream) stream._to = TEST_PEER.domain res = run_coroutine(aioxmpp.ibr.get_registration_fields(stream)) _, (_, iq, *_), _ = mock1.mock_calls[0] iq = iq[0] self.assertIsInstance( iq, aioxmpp.IQ, ) self.assertIs( iq_res.payload, res, ) self.assertIsInstance( res, ibr_xso.Query, ) self.assertEqual( res.username, '', )
def test_handle_malformed_iq_error_gracefully(self): c = yield from self.provisioner.get_connected_client() @asyncio.coroutine def handler(iq): # this is awful, but does the trick c.stream._xmlstream.data_received( "<iq type='error' from='{}' to='{}' id='{}'/>".format( c.local_jid, c.local_jid, iq.id_, )) c.stream.register_iq_request_handler( aioxmpp.IQType.GET, MadeUpIQPayload, handler, ) iq = aioxmpp.IQ(to=c.local_jid, type_=aioxmpp.IQType.GET, payload=MadeUpIQPayload()) with self.assertRaises(aioxmpp.errors.ErroneousStanza): yield from c.stream.send(iq)
def get_vcard(self, jid=None): """ Get the vCard stored for the jid `jid`. If `jid` is :data:`None` get the vCard of the connected entity. :param jid: the object to retrieve. :returns: the stored vCard. We mask a :class:`XMPPCancelError` in case it is ``feature-not-implemented`` or ``item-not-found`` and return an empty vCard, since this can be understood to be semantically equivalent. """ iq = aioxmpp.IQ( type_=aioxmpp.IQType.GET, to=jid, payload=vcard_xso.VCard(), ) try: return (yield from self.client.send(iq)) except aioxmpp.XMPPCancelError as e: if e.condition in ( (namespaces.stanzas, "feature-not-implemented"), (namespaces.stanzas, "item-not-found")): return vcard_xso.VCard() else: raise
def register( xmlstream, query_xso, timeout=60, ): """ Create a new account on the server. :param query_xso: XSO with the information needed for the registration. :type query_xso: :class:`xso.Query` :param xmlstream: Specifies the stream connected to the server where the account will be created. :type xmlstream: :class:`aioxmpp.protocol.XMLStream` :param timeout: Maximum time in seconds to wait for an IQ response, or :data:`None` to disable the timeout. :type timeout: :class:`~numbers.Real` or :data:`None` """ iq = aioxmpp.IQ(to=aioxmpp.JID.fromstr(xmlstream._to), type_=aioxmpp.IQType.SET, payload=query_xso) iq.autoset_id() yield from aioxmpp.protocol.send_and_wait_for(xmlstream, [iq], [aioxmpp.IQ], timeout=timeout)
def query_version(stream: aioxmpp.stream.StanzaStream, target: aioxmpp.JID) -> version_xso.Query: """ Query the software version of an entity. :param stream: A stanza stream to send the query on. :type stream: :class:`aioxmpp.stream.StanzaStream` :param target: The address of the entity to query. :type target: :class:`aioxmpp.JID` :raises OSError: if a connection issue occured before a reply was received :raises aioxmpp.errors.XMPPError: if an XMPP error was returned instead of a reply. :rtype: :class:`aioxmpp.version.xso.Query` :return: The response from the peer. The response is returned as :class:`~aioxmpp.version.xso.Query` object. The attributes hold the data returned by the peer. Each attribute may be :data:`None` if the peer chose to omit that information. In an extreme case, all attributes are :data:`None`. """ return (yield from stream.send( aioxmpp.IQ( type_=aioxmpp.IQType.GET, to=target, payload=version_xso.Query(), )))
async def get_vcard(self, jid=None): """ Get the vCard stored for the jid `jid`. If `jid` is :data:`None` get the vCard of the connected entity. :param jid: the object to retrieve. :returns: the stored vCard. We mask a :class:`XMPPCancelError` in case it is ``feature-not-implemented`` or ``item-not-found`` and return an empty vCard, since this can be understood to be semantically equivalent. """ iq = aioxmpp.IQ( type_=aioxmpp.IQType.GET, to=jid, payload=vcard_xso.VCard(), ) try: return await self.client.send(iq) except aioxmpp.XMPPCancelError as e: if e.condition in (aioxmpp.ErrorCondition.FEATURE_NOT_IMPLEMENTED, aioxmpp.ErrorCondition.ITEM_NOT_FOUND): return vcard_xso.VCard() else: raise
def test__handle_command_raises_forbidden_for_disallowed_node(self): handler = CoroutineMock() handler.return_value = unittest.mock.sentinel.result is_allowed = unittest.mock.Mock() is_allowed.return_value = False self.s.register_stateless_command( "node", "Command name", handler, is_allowed=is_allowed, ) req = aioxmpp.IQ(type_=aioxmpp.IQType.SET, from_=TEST_PEER_JID, to=TEST_LOCAL_JID, payload=adhoc_xso.Command("node", )) with self.assertRaises(aioxmpp.errors.XMPPCancelError) as ctx: run_coroutine(self.s._handle_command(req)) is_allowed.assert_called_once_with(req.from_) self.assertEqual( ctx.exception.condition, aioxmpp.ErrorCondition.FORBIDDEN, ) handler.assert_not_called()
async def test_handle_malformed_iq_error_gracefully(self): c = await self.provisioner.get_connected_client() if c.stream.sm_enabled: raise unittest.SkipTest("this test breaks with SM") async def handler(iq): # this is awful, but does the trick c.stream._xmlstream.data_received( "<iq type='error' from='{}' to='{}' id='{}'/>".format( c.local_jid, c.local_jid, iq.id_, )) c.stream.register_iq_request_handler( aioxmpp.IQType.GET, MadeUpIQPayload, handler, ) iq = aioxmpp.IQ(to=c.local_jid, type_=aioxmpp.IQType.GET, payload=MadeUpIQPayload()) with self.assertRaises(aioxmpp.errors.ErroneousStanza): await c.stream.send(iq)
def test_handle_unblock_push(self): handle_block = unittest.mock.Mock() handle_unblock = unittest.mock.Mock() self.s.on_jids_blocked.connect(handle_block) self.s.on_jids_unblocked.connect(handle_unblock) self.s._blocklist = frozenset([TEST_JID1, TEST_JID2]) block = blocking_xso.UnblockCommand() block.items[:] = [TEST_JID2] iq = aioxmpp.IQ( type_=aioxmpp.IQType.SET, payload=block, ) run_coroutine(self.s.handle_unblock_push(iq)) self.assertEqual(self.s._blocklist, frozenset([TEST_JID1])) self.assertEqual(handle_unblock.mock_calls, [unittest.mock.call(frozenset([TEST_JID2]))]) handle_block.assert_not_called()
async def get_registration_fields(xmlstream, timeout=60): """ A query is sent to the server to obtain the fields that need to be filled to register with the server. :param xmlstream: Specifies the stream connected to the server where the account will be created. :type xmlstream: :class:`aioxmpp.protocol.XMLStream` :param timeout: Maximum time in seconds to wait for an IQ response, or :data:`None` to disable the timeout. :type timeout: :class:`~numbers.Real` or :data:`None` :return: :attr:`list` """ iq = aioxmpp.IQ(to=aioxmpp.JID.fromstr(xmlstream._to), type_=aioxmpp.IQType.GET, payload=xso.Query()) iq.autoset_id() reply = await aioxmpp.protocol.send_and_wait_for(xmlstream, [iq], [aioxmpp.IQ], timeout=timeout) return reply.payload
async def loop_ping(self) -> None: while True: await asyncio.sleep(60) iq = aioxmpp.IQ( type_=aioxmpp.IQType.GET, payload=aioxmpp.ping.Ping(), to=None, ) await self.stream.send(iq)
def test_receive_response_from_iq_to_bare_explicit_self(self): c = yield from self.provisioner.get_connected_client() iq = aioxmpp.IQ(to=c.local_jid.bare(), type_=aioxmpp.IQType.GET, payload=MadeUpIQPayload()) with self.assertRaises(aioxmpp.errors.XMPPCancelError): yield from c.send(iq)
async def test_receive_response_from_iq_to_bare_self_using_None(self): c = await self.provisioner.get_connected_client() iq = aioxmpp.IQ(to=None, type_=aioxmpp.IQType.GET, payload=MadeUpIQPayload()) with self.assertRaises(aioxmpp.errors.XMPPCancelError): await c.send(iq)
async def open_session(self, protocol_factory, peer_jid, *, stanza_type=ibb_xso.IBBStanzaType.IQ, block_size=4096, sid=None): """ Establish an in-band bytestream session with `peer_jid` and return the transport and protocol. :param protocol_factory: the protocol factory :type protocol_factory: a nullary callable returning an :class:`asyncio.Protocol` instance :param peer_jid: the JID with which to establish the byte-stream. :type peer_jid: :class:`aioxmpp.JID` :param stanza_type: the stanza type to use :type stanza_type: class:`~aioxmpp.ibb.IBBStanzaType` :param block_size: the maximal size of blocks to transfer :type block_size: :class:`int` :param sid: the session id to use :type sid: :class:`str` (must be a valid NMTOKEN) :returns: the transport and protocol :rtype: a tuple of :class:`aioxmpp.ibb.service.IBBTransport` and :class:`asyncio.Protocol` """ if block_size > MAX_BLOCK_SIZE: raise ValueError("block_size too large") if sid is None: sid = utils.to_nmtoken(random.getrandbits(8 * 8)) open_ = ibb_xso.Open() open_.stanza = stanza_type open_.sid = sid open_.block_size = block_size # XXX: retry on XMPPModifyError with RESOURCE_CONSTRAINT await self.client.send( aioxmpp.IQ( aioxmpp.IQType.SET, to=peer_jid, payload=open_, )) handle = self._sessions[sid, peer_jid] = IBBTransport( self, peer_jid, sid, stanza_type, block_size, ) protocol = protocol_factory() handle.set_protocol(protocol) return handle, protocol
def set_private_xml(self, xso): """ Store the serialization of `xso` on the server as the private XML data for the namespace of `xso`. :param xso: the XSO whose serialization is send as private XML data. """ iq = aioxmpp.IQ(type_=aioxmpp.IQType.SET, payload=private_xml_xso.Query(xso)) yield from self.client.stream.send(iq)
def test_remote_close_unknown_session(self): close = ibb_xso.Close() close.sid = "quark" stanza = aioxmpp.IQ(aioxmpp.IQType.SET, from_=TEST_JID1, to=TEST_FROM, payload=close) try: run_coroutine(self.s._handle_close_request(stanza)) except aioxmpp.errors.XMPPCancelError as e: self.assertEqual(e.condition, aioxmpp.errors.ErrorCondition.ITEM_NOT_FOUND)
def _get_initial_blocklist(self): yield from self._check_for_blocking() if self._blocklist is None: with (yield from self._lock): iq = aioxmpp.IQ( type_=aioxmpp.IQType.GET, payload=blocking_xso.BlockList(), ) result = yield from self.client.stream.send(iq) self._blocklist = frozenset(result.items) self.on_initial_blocklist_received(self._blocklist)
def unblock_all(self): """ Unblock all JIDs currently blocked. """ yield from self._check_for_blocking() cmd = blocking_xso.UnblockCommand() iq = aioxmpp.IQ( type_=aioxmpp.IQType.SET, payload=cmd, ) yield from self.client.send(iq)
def test_remote_close(self): fut = asyncio.Future() self.protocol.connection_lost = lambda e: fut.set_result(None) close = ibb_xso.Close() close.sid = self.handle.get_extra_info("sid") stanza = aioxmpp.IQ(aioxmpp.IQType.SET, from_=TEST_JID1, to=TEST_FROM, payload=close) run_coroutine(self.s._handle_close_request(stanza)) run_coroutine(fut) self.assertFalse(self.s._sessions)
def test_open_request_resource_constraint(self): open_ = ibb_xso.Open() open_.sid = "sentinel" open_.block_size = 1 << 32 open_.stanza = ibb_xso.IBBStanzaType.IQ iq = aioxmpp.IQ(aioxmpp.IQType.SET, from_=TEST_JID1, payload=open_) try: run_coroutine(self.s._handle_open_request(iq)) except aioxmpp.errors.XMPPModifyError as e: self.assertEqual(e.condition, aioxmpp.errors.ErrorCondition.RESOURCE_CONSTRAINT) else: self.fail("missing expected exception")
def test_open_request_enforce_limit(self): open_ = ibb_xso.Open() open_.sid = "sentinel" open_.block_size = 8192 open_.stanza = ibb_xso.IBBStanzaType.IQ iq = aioxmpp.IQ(aioxmpp.IQType.SET, from_=TEST_JID1, payload=open_) try: run_coroutine(self.s._handle_open_request(iq)) except aioxmpp.errors.XMPPCancelError as e: self.assertEqual(e.condition, aioxmpp.errors.ErrorCondition.NOT_ACCEPTABLE) else: self.fail("missing expected exception")
async def get_client_info(self): """ A query is sent to the server to obtain the client's data stored at the server. :return: :class:`~aioxmpp.ibr.Query` """ iq = aioxmpp.IQ( to=self.client.local_jid.bare().replace(localpart=None), type_=aioxmpp.IQType.GET, payload=xso.Query()) reply = await self.client.send(iq) return reply
def test__handle_command_raises_item_not_found_for_unknown_node(self): req = aioxmpp.IQ(type_=aioxmpp.IQType.SET, from_=TEST_PEER_JID, to=TEST_LOCAL_JID, payload=adhoc_xso.Command("node", )) with self.assertRaises(aioxmpp.errors.XMPPCancelError) as ctx: run_coroutine(self.s._handle_command(req)) self.assertEqual( ctx.exception.condition, aioxmpp.ErrorCondition.ITEM_NOT_FOUND, ) self.assertRegex(ctx.exception.text, "no such command: 'node'")
def get_private_xml(self, query_xso): """ Get the private XML data for the element `query_xso` from the server. :param query_xso: the object to retrieve. :returns: the stored private XML data. `query_xso` *must* serialize to an empty XML node of the wanted namespace and type and *must* be registered as private XML :class:`~private_xml_xso.Query` payload. """ iq = aioxmpp.IQ(type_=aioxmpp.IQType.GET, payload=private_xml_xso.Query(query_xso)) return (yield from self.client.stream.send(iq))
async def list_items_with_rsm(domain: aioxmpp.JID, client: aioxmpp.Client, page_size: int): rsm = rsm_xso.ResultSetMetadata.limit(max_=page_size) while True: q = disco_xso.ItemsQuery() q.xep0059_set = rsm req = aioxmpp.IQ( type_=aioxmpp.IQType.GET, to=domain, payload=q, ) resp = await client.send(req) if not resp.items: break rsm = resp.xep0059_set.next_page(max_=page_size) yield resp.items
def test_handle_id_less_IQ_request_gracefully(self): c = yield from self.provisioner.get_connected_client() # let’s get even more brutal here c.stream._xmlstream.data_received("<iq type='get' to='{}'/>".format( c.local_jid).encode('utf-8')) # now we send a simple IQ which shows us that the stream survived this # attack iq = aioxmpp.IQ(to=c.local_jid.bare(), type_=aioxmpp.IQType.GET, payload=MadeUpIQPayload()) with self.assertRaises(aioxmpp.errors.XMPPCancelError): yield from c.send(iq)
def unblock_jids(self, jids_to_unblock): """ Remove the JIDs in the sequence `jids_to_block` from the client's blocklist. """ yield from self._check_for_blocking() if not jids_to_unblock: return cmd = blocking_xso.UnblockCommand(jids_to_unblock) iq = aioxmpp.IQ( type_=aioxmpp.IQType.SET, payload=cmd, ) yield from self.client.send(iq)