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)
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)
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') })
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)
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
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')
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')
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('')
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)
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'})
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')
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)
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)
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("*****@*****.**"))
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)
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}')
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)
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
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)
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")
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('')
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])
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)
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()
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)
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
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')
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)
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')
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, )