Beispiel #1
0
 def list(self, args: List[str]) -> None:
     """
     /list [server]
     Opens a MucListTab containing the list of the room in the specified server
     """
     if args is None:
         return self.help('list')
     elif args:
         try:
             jid = JID(args[0])
         except InvalidJID:
             return self.core.information('Invalid server %r' % jid,
                                          'Error')
     else:
         if not isinstance(self.core.tabs.current_tab, tabs.MucTab):
             return self.core.information('Please provide a server',
                                          'Error')
         jid = self.core.tabs.current_tab.jid
     if jid is None or not jid.domain:
         return None
     jid = JID(jid.domain)
     list_tab = tabs.MucListTab(self.core, jid)
     self.core.add_tab(list_tab, True)
     cb = list_tab.on_muc_list_item_received
     self.core.xmpp.plugin['xep_0030'].get_items(jid=jid, callback=cb)
Beispiel #2
0
    def testDomainIPv6(self):
        domain = '[::1]'

        jid1 = JID('%s' % domain)
        jid2 = JID('user@%s' % domain)
        jid3 = JID('%s/resource' % domain)
        jid4 = JID('user@%s/resource' % domain)
Beispiel #3
0
 async def publish_fail(self):
     for uid in self.bus._publish_futures.keys():
         await self.bus._on_failed_publish({
             'id': uid,
             'to': JID('someone@localhost'),
             'from': JID('test@localhost')
         })
Beispiel #4
0
    def testDomainIPv4(self):
        domain = '127.0.0.1'

        jid1 = JID('%s' % domain)
        jid2 = JID('user@%s' % domain)
        jid3 = JID('%s/resource' % domain)
        jid4 = JID('user@%s/resource' % domain)
Beispiel #5
0
    async def encrypted_send(self, body, recipient, type='chat'):
        """Helper to send encrypted messages"""

        msg = self.make_message(mto=recipient, mtype=type)
        msg['eme']['namespace'] = self.eme_ns
        msg['eme']['name'] = self['xep_0380'].mechanisms[self.eme_ns]

        expect_problems = {}  # type: Optional[Dict[JID, List[int]]]

        while True:
            try:
                # `encrypt_message` excepts the plaintext to be sent, a list of
                # bare JIDs to encrypt to, and optionally a dict of problems to
                # expect per bare JID.
                #
                # Note that this function returns an `<encrypted/>` object,
                # and not a full Message stanza. This combined with the
                # `recipients` parameter that requires for a list of JIDs,
                # allows you to encrypt for 1:1 as well as groupchats (MUC).
                #
                # `expect_problems`: See EncryptionPrepareException handling.
                recipients = [JID(recipient)]
                encrypt = await self['xep_0384'].encrypt_message(body, recipients, expect_problems)
                msg.append(encrypt)
                return msg.send()
            except UndecidedException as exn:
                # The library prevents us from sending a message to an
                # untrusted/undecided barejid, so we need to make a decision here.
                # This is where you prompt your user to ask what to do. In
                # this bot we will automatically trust undecided recipients.
                self['xep_0384'].trust(exn.bare_jid, exn.device, exn.ik)
            # TODO: catch NoEligibleDevicesException
            except EncryptionPrepareException as exn:
                # This exception is being raised when the library has tried
                # all it could and doesn't know what to do anymore. It
                # contains a list of exceptions that the user must resolve, or
                # explicitely ignore via `expect_problems`.
                # TODO: We might need to bail out here if errors are the same?
                for error in exn.errors:
                    if isinstance(error, MissingBundleException):
                        # We choose to ignore MissingBundleException. It seems
                        # to be somewhat accepted that it's better not to
                        # encrypt for a device if it has problems and encrypt
                        # for the rest, rather than error out. The "faulty"
                        # device won't be able to decrypt and should display a
                        # generic message. The receiving end-user at this
                        # point can bring up the issue if it happens.
                        log.warning('Could not find keys for device "%d" of recipient "%s". Skipping.', error.device, error.bare_jid)
                        jid = JID(error.bare_jid)
                        device_list = expect_problems.setdefault(jid, [])
                        device_list.append(error.device)
            except (IqError, IqTimeout) as exn:
                log.exception('An error occured while fetching information on %r', recipient)
                return None
            except Exception as exn:
                log.exception('An error occured while attempting to encrypt to %r', recipient)
                raise

        return None
Beispiel #6
0
    def testZeroLengthDomain(self):
        jid1 = JID('')
        jid2 = JID()
        self.assertTrue(jid1 == jid2, "Empty JIDs are not considered equal")
        self.assertTrue(jid1.domain == '', "Empty JID’s domain part not empty")
        self.assertTrue(jid1.full == '', "Empty JID’s full part not empty")

        self.assertRaises(InvalidJID, JID, 'user@')
        self.assertRaises(InvalidJID, JID, '/resource')
        self.assertRaises(InvalidJID, JID, 'user@/resource')
Beispiel #7
0
    def testJIDUnescape(self):
        jid = JID(
            'here\\27s_a_wild_\\26_\\2fcr%zy\\2f_\\40ddress\\20for\\3a\\3cwv\\3e(\\22IMPS\\22)\\[email protected]'
        )
        ujid = jid.unescape()
        self.assertEqual(
            ujid.local, 'here\'s_a_wild_&_/cr%zy/_@ddress for:<wv>("imps")\\')

        jid = JID('blah\\5cfoo\\[email protected]')
        ujid = jid.unescape()
        self.assertEqual(ujid.local, 'blah\\foo\\20bar')
Beispiel #8
0
def safeJID(*args, **kwargs) -> JID:
    """
    Construct a :py:class:`slixmpp.JID` object from a string.

    Used to avoid tracebacks during is stringprep fails
    (fall back to a JID with an empty string).
    """
    try:
        return JID(*args, **kwargs)
    except InvalidJID:
        return JID('')
Beispiel #9
0
    async def test_blocking(self):
        """Check we can block, unblock, and list blocked"""
        await self.clients[0]['xep_0191'].block(
            [JID('*****@*****.**'),
             JID('*****@*****.**')])
        blocked = {JID('*****@*****.**'), JID('*****@*****.**')}
        iq = await self.clients[0]['xep_0191'].get_blocked()
        self.assertEqual(iq['blocklist']['items'], blocked)

        info = await self.clients[0]['xep_0191'].unblock(blocked, )
        iq = await self.clients[0]['xep_0191'].get_blocked()
        self.assertEqual(len(iq['blocklist']['items']), 0)
Beispiel #10
0
 async def test_002_on_event(self):
     self.bus._connected.set()
     cb = CoroutineMock()
     with patch.object(self.bus._mucs, 'join_muc') as join_mock:
         await self.bus.subscribe('someone', cb)
         join_mock.assert_called_once_with('*****@*****.**', 'test')
     msg = self.bus.client.Message()
     msg['type'] = 'groupchat'
     msg['to'] = JID('test@localhost')
     msg['from'] = JID('someone@localhost')
     msg['body'] = '{"key": "value"}'
     await self.bus._on_event(msg)
     cb.assert_called_once_with('someone', {'key': 'value'})
Beispiel #11
0
 def testJIDaliases(self):
     """Test changing JID using aliases for domain."""
     j = JID('user@someserver/resource')
     j.server = 'anotherserver'
     self.check_jid(j, domain='anotherserver')
     j.host = 'yetanother'
     self.check_jid(j, domain='yetanother')
Beispiel #12
0
    def get_last_activity(self,
                          jid: JID,
                          local: bool = False,
                          ifrom: Optional[JID] = None,
                          **iqkwargs) -> Future:
        """Get last activity for a specific JID.

        :param local: Fetch the value from the local cache.
        """
        if jid is not None and not isinstance(jid, JID):
            jid = JID(jid)

        if self.xmpp.is_component:
            if jid.domain == self.xmpp.boundjid.domain:
                local = True
        else:
            if str(jid) == str(self.xmpp.boundjid):
                local = True
        jid = jid.full

        if local or jid in (None, ''):
            log.debug("Looking up local last activity data for %s", jid)
            return self.api['get_last_activity'](jid, None, ifrom, None)

        iq = self.xmpp.make_iq_get(ito=jid, ifrom=ifrom)
        iq.enable('last_activity')
        return iq.send(**iqkwargs)
Beispiel #13
0
    def testClientLeave(self):
        """Test a client leave"""

        fut = self.xmpp.wrap(self.xmpp['xep_0405'].leave_channel(
            JID('*****@*****.**'), ))
        self.send("""
            <iq type='set'
                to='tester@localhost'
                id='1'>
              <client-leave xmlns='urn:xmpp:mix:pam:2'
                            channel='*****@*****.**'>
                <leave xmlns='urn:xmpp:mix:core:1'/>
              </client-leave>
            </iq>
        """)
        self.recv("""
            <iq type='result'
                from='tester@localhost'
                to='tester@localhost/resource'
                id='1'>
              <client-leave xmlns='urn:xmpp:mix:pam:2'
                            channel='*****@*****.**'>
                <leave xmlns='urn:xmpp:mix:core:1'/>
              </client-leave>
            </iq>
        """)

        self.assertEqual(fut.done(), True)
        self.assertEqual(fut.exception(), None)
Beispiel #14
0
    def testRemoveContact(self):
        self.add_user()
        result = {}

        # Jabber User sends IQ-set qualified by the 'jabber:iq:roster' namespace, containing subscription
        # attribute with value of "remove".
        async def legacy_contact_remove(jid, node, ifrom, contact_jid):
            result.update(**locals())

        self.xmpp["xep_0100"].api.register(legacy_contact_remove,
                                           "legacy_contact_remove")

        # Jabber User sends IQ-set qualified by the 'jabber:iq:roster' namespace, containing subscription
        # attribute with value of "remove".
        self.recv(  # server sends this
            """
            <presence type='unsubscribe'
                      to='*****@*****.**'
                      from='*****@*****.**'/>
            """)
        for ptype in "unsubscribe", "unsubscribed", "unavailable":
            self.send(  # server sends this
                f"""
                <presence type='{ptype}'
                        from='*****@*****.**'
                        to='*****@*****.**'/>
                """)

        self.assertTrue(result["ifrom"] == "*****@*****.**")
        self.assertTrue(
            result["contact_jid"] == JID("*****@*****.**"))
Beispiel #15
0
 def get_local(self):
     """Add the locally stored bookmarks to the list."""
     rooms = config.get('rooms')
     if not rooms:
         return
     rooms = rooms.split(':')
     for room in rooms:
         try:
             jid = JID(room)
         except InvalidJID:
             continue
         if jid.bare == '':
             continue
         if jid.resource != '':
             nick = jid.resource
         else:
             nick = None
         passwd = config.get_by_tabname(
             'password', jid.bare, fallback=False) or None
         b = Bookmark(jid.bare,
                      jid.user,
                      autojoin=True,
                      nick=nick,
                      password=passwd,
                      method='local')
         self.append(b)
Beispiel #16
0
    async def test_mam_iterate(self):
        """Make sure we can iterate over messages from our archive"""
        # send messages first
        tok = randint(1, 999999)
        self.clients[0].make_message(
            mto=self.clients[1].boundjid,
            mbody=f'coucou {tok}'
        ).send()
        await self.clients[1].wait_until('message')
        self.clients[1].make_message(
            mto=self.clients[0].boundjid,
            mbody='coucou coucou %s' % tok,
        ).send()
        await self.clients[0].wait_until('message')

        # Get archive
        retrieve = self.clients[0]['xep_0313'].iterate(
            with_jid=JID(self.envjid('CI_ACCOUNT2')),
            reverse=True,
            rsm={'max': 1}
        )
        msgs = []
        count = 0
        async for msg in retrieve:
            msgs.append(
                msg['mam_result']['forwarded']['stanza']
            )
            count += 1
            if count >= 2:
                break

        self.assertEqual(msgs[0]['body'], f'coucou coucou {tok}')
        self.assertEqual(msgs[1]['body'], f'coucou {tok}')
Beispiel #17
0
 async def test():
     iterator = self.xmpp['xep_0313'].iterate(
         with_jid=JID('toto@titi'),
         start='2010-06-07T00:00:00Z',
     )
     async for message in iterator:
         msgs.append(message)
Beispiel #18
0
    def _default_get_last_activity(self, jid: JID, node: str, ifrom: JID,
                                   iq: Iq) -> Iq:
        if not isinstance(iq, Iq):
            reply = self.xmpp.Iq()
        else:
            reply = iq.reply()

        if jid not in self._last_activities:
            raise XMPPError('service-unavailable')

        bare = JID(jid).bare

        if bare != self.xmpp.boundjid.bare:
            if bare in self.xmpp.roster[jid]:
                sub = self.xmpp.roster[jid][bare]['subscription']
                if sub not in ('from', 'both'):
                    raise XMPPError('forbidden')

        td = datetime.now() - self._last_activities[jid]['seconds']
        seconds = td.seconds + td.days * 24 * 3600
        status = self._last_activities[jid]['status']

        reply['last_activity']['seconds'] = seconds
        reply['last_activity']['status'] = status

        return reply
Beispiel #19
0
async def get_mam_iterator(
        core,
        groupchat: bool,
        remote_jid: JID,
        amount: int,
        reverse: bool = True,
        start: Optional[str] = None,
        end: Optional[str] = None,
        before: Optional[str] = None,
    ) -> AsyncIterable[Message]:
    """Get an async iterator for this mam query"""
    try:
        query_jid = remote_jid if groupchat else JID(core.xmpp.boundjid.bare)
        iq = await core.xmpp.plugin['xep_0030'].get_info(jid=query_jid)
    except (IqError, IqTimeout):
        raise DiscoInfoException()
    if 'urn:xmpp:mam:2' not in iq['disco_info'].get_features():
        raise NoMAMSupportException()

    args = {
        'iterator': True,
        'reverse': reverse,
    }  # type: Dict[str, Any]

    if groupchat:
        args['jid'] = remote_jid
    else:
        args['with_jid'] = remote_jid

    if amount > 0:
        args['rsm'] = {'max': amount}
    args['start'] = start
    args['end'] = end
    return core.xmpp['xep_0313'].retrieve(**args)
Beispiel #20
0
 def testtransport_presence_event_handler_with_exception(self):
     """
     Test to check the presence method with an exception raised of the signal class.
     """
     sig_dict, signal = self.setup_vars_mocks()
     transport = XmppTransport.factory(
         "1", sig_dict["Signal"]["Overlays"]["A0FB389"], signal,
         signal._presence_publisher, None, None)
     presence = {
         "from": "raj",
         "to": "raj@ipop",
         "status": "uid?#1234434323"
     }
     transport.boundjid = JID("raj@ipop/ipop")
     transport.send_msg = MagicMock()
     transport.send_msg.side_effect = Exception()
     jid_cache = Mock()
     presence_publisher = Mock()
     transport._presence_publisher = presence_publisher
     transport._presence_publisher.post_update = MagicMock()
     transport._jid_cache = jid_cache
     transport._jid_cache.add_entry = MagicMock()
     transport._sig.sig_log = MagicMock()
     transport.presence_event_handler(presence)
     transport.send_msg.assert_called_once()
     transport._sig.sig_log.assert_called_once()
     print("Passed : testtransport_presence_event_handler_with_uid")
Beispiel #21
0
def safeJID(*args, **kwargs) -> JID:
    """
    Construct a :py:class:`slixmpp.JID` object from a string.

    Used to avoid tracebacks during is stringprep fails
    (fall back to a JID with an empty string).
    """
    try:
        return JID(*args, **kwargs)
    except InvalidJID:
        log.debug(
            'safeJID caught an invalidJID exception: %r, %r',
            args, kwargs,
            exc_info=True,
        )
        return JID('')
Beispiel #22
0
 def message(self, args):
     """
     /message <jid> [message]
     """
     if args is None:
         return self.help('message')
     jid = safeJID(args[0])
     if not jid.user and not jid.domain and not jid.resource:
         return self.core.information('Invalid JID.', 'Error')
     tab = self.core.get_conversation_by_jid(jid.full,
                                             False,
                                             fallback_barejid=False)
     muc = self.core.tabs.by_name_and_class(jid.bare, tabs.MucTab)
     if not tab and not muc:
         tab = self.core.open_conversation_window(JID(jid.full), focus=True)
     elif muc:
         if jid.resource:
             tab = self.core.tabs.by_name_and_class(jid.full,
                                                    tabs.PrivateTab)
             if tab:
                 self.core.focus_tab(tab)
             else:
                 tab = self.core.open_private_window(jid.bare, jid.resource)
         else:
             tab = muc
     else:
         self.core.focus_tab(tab)
     if len(args) == 2:
         tab.command_say(args[1])
Beispiel #23
0
 def __contains__(self, value):
     try:
         resource = JID(value).resource
     except InvalidJID:
         resource = None
     return value in self.__item.resources or \
         (resource is not None and resource in self.__item.resources)
Beispiel #24
0
    async def test_set_avatar(self):
        """Check we can set and get a PEP avatar and metadata"""
        await self._clear_avatar()

        await self.clients[0]['xep_0084'].publish_avatar(self.data)
        metadata = {
            'id': self.clients[0]['xep_0084'].generate_id(self.data),
            'bytes': 13,
            'type': 'image/jpeg',
        }
        # Wait for metadata publish event
        event = self.clients[0].wait_until('avatar_metadata_publish')
        publish = self.clients[0]['xep_0084'].publish_avatar_metadata(
            metadata, )
        res = await asyncio.gather(
            event,
            publish,
        )
        message = res[0]
        recv_meta = message['pubsub_event']['items']['item']['avatar_metadata']
        info = recv_meta['info']
        self.assertEqual(info['bytes'], metadata['bytes'])
        self.assertEqual(info['type'], metadata['type'])
        self.assertEqual(info['id'], metadata['id'])

        recv = await self.clients[0]['xep_0084'].retrieve_avatar(
            JID(self.clients[0].boundjid.bare), info['id'])
        avatar = recv['pubsub']['items']['item']['avatar_data']['value']
        self.assertEqual(avatar, self.data)

        await self._clear_avatar()
Beispiel #25
0
    def testResponse(self):
        presence = Presence()
        presence['rai']['activities'] = [
            JID('toto@titi'),
            JID('coucou@coucou'),
        ]
        self.check(presence,
                   """
<presence>
  <rai xmlns="urn:xmpp:rai:0">
    <activity>toto@titi</activity>
    <activity>coucou@coucou</activity>
  </rai>
</presence>
        """,
                   use_values=False)
Beispiel #26
0
 def real_jid(self):
     """
     The JID of the room occupant, they used to login.
     Will only work if the errbot is moderator in the MUC or it is not anonymous.
     """
     room_jid = self._node + "@" + self._domain
     jid = JID(self._room.xep0045.get_jid_property(room_jid, self.resource, "jid"))
     return jid.bare
Beispiel #27
0
 def testJIDSetFullWithUser(self):
     """Test setting the full JID with a user portion."""
     j = JID('user@domain/resource')
     j.full = 'otheruser@otherdomain/otherresource'
     self.check_jid(j, 'otheruser', 'otherdomain', 'otherresource',
                    'otheruser@otherdomain',
                    'otheruser@otherdomain/otherresource',
                    'otheruser@otherdomain/otherresource')
Beispiel #28
0
 def send(contact, resource, presence):
     jid = JID(contact)
     jid.resource = resource
     if jid == self.stream.boundjid:
         return
     msg_xml = build_presence_dbxml(jid, presence)
     msg_xml.attrib['to'] = self.stream.boundjid.bare
     self.stream.send_element(msg_xml)
Beispiel #29
0
 def testJIDBareUser(self):
     """Test setting the bare JID with a user."""
     j = JID('user@domain/resource')
     j.bare = 'otheruser@otherdomain'
     self.check_jid(j, 'otheruser', 'otherdomain', 'resource',
                    'otheruser@otherdomain',
                    'otheruser@otherdomain/resource',
                    'otheruser@otherdomain/resource')
Beispiel #30
0
 def transform_legacy_message(
     self,
     jabber_user_jid: typing.Union[JID, str],
     legacy_contact_id: str,
     body: str,
     mtype: typing.Optional[str] = None,
 ):
     """
     Transform a legacy message to an XMPP message
     """
     # Should escaping legacy IDs to valid JID local parts be handled here?
     # Maybe by internal API stuff?
     self.xmpp.send_message(
         mfrom=JID(f"{legacy_contact_id}@{self.xmpp.boundjid.bare}"),
         mto=JID(jabber_user_jid).bare,
         mbody=body,
         mtype=mtype,
     )