Esempio n. 1
0
    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")
Esempio n. 2
0
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
Esempio n. 3
0
    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,
        )
Esempio n. 4
0
    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,
                '',
            )
Esempio n. 5
0
    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)
Esempio n. 6
0
    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
Esempio n. 7
0
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)
Esempio n. 8
0
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
Esempio n. 10
0
    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)
Esempio n. 12
0
    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()
Esempio n. 13
0
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
Esempio n. 14
0
 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)
Esempio n. 15
0
    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)
Esempio n. 17
0
    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
Esempio n. 18
0
    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)
Esempio n. 20
0
    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)
Esempio n. 21
0
    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")
Esempio n. 25
0
    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
Esempio n. 26
0
    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'")
Esempio n. 27
0
    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))
Esempio n. 28
0
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
Esempio n. 29
0
    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)
Esempio n. 30
0
    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)