예제 #1
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
예제 #2
0
 def get_data(self):
     text = self.xml.text
     if not text:
         raise XMPPError('not-acceptable', 'IBB data element is empty.')
     b64_data = text.strip()
     if VALID_B64.match(b64_data).group() == b64_data:
         return from_b64(b64_data)
     else:
         raise XMPPError('not-acceptable')
예제 #3
0
    def _handle_streamhost(self, iq):
        """Handle incoming SOCKS5 session request."""
        sid = iq['socks']['sid']
        if not sid:
            raise XMPPError(etype='modify', condition='bad-request')

        if not self._accept_stream(iq):
            raise XMPPError(etype='modify', condition='not-acceptable')

        streamhosts = iq['socks']['streamhosts']
        requester = iq['from']
        target = iq['to']

        dest = self._get_dest_sha1(sid, requester, target)

        proxy_futures = []
        for streamhost in streamhosts:
            proxy_futures.append(
                self._connect_proxy(dest, streamhost['host'],
                                    streamhost['port']))

        @asyncio.coroutine
        def gather(futures, iq, streamhosts):
            proxies = yield from asyncio.gather(*futures,
                                                return_exceptions=True)
            for streamhost, proxy in zip(streamhosts, proxies):
                if isinstance(proxy, ValueError):
                    continue
                elif isinstance(proxy, socket.error):
                    log.error('Socket error while connecting to the proxy.')
                    continue
                proxy = proxy[1]
                # TODO: what if the future never happens?
                try:
                    addr, port = yield from proxy.connected
                except socket.error:
                    log.exception(
                        'Socket error while connecting to the proxy.')
                    continue
                # TODO: make a better choice than just the first working one.
                used_streamhost = streamhost['jid']
                conn = proxy
                break
            else:
                raise XMPPError(etype='cancel', condition='item-not-found')

            # TODO: close properly the connection to the other proxies.

            iq = iq.reply()
            self._sessions[sid] = conn
            iq['socks']['sid'] = sid
            iq['socks']['streamhost_used']['jid'] = used_streamhost
            iq.send()
            self.xmpp.event('socks5_stream', conn)
            self.xmpp.event('stream:%s:%s' % (sid, requester), conn)

        asyncio. async (gather(proxy_futures, iq, streamhosts))
예제 #4
0
 async def process(self, request):
     if 'username' not in request or \
        'resource' not in request:
         raise XMPPError('not-acceptable')
     username = request['username']
     if not await self.auth.check_password(username,
                                           request.get('password', '')):
         raise XMPPError('not-authorized')
     self.boundjid.user = username
     self.boundjid.resource = request['resource']
예제 #5
0
    def _handle_roster(self, iq):
        """Update the roster after receiving a roster stanza.

        :param iq: The roster stanza.
        """
        if iq['type'] == 'set':
            if iq['from'].bare and iq['from'].bare != self.boundjid.bare:
                raise XMPPError(condition='service-unavailable')

        roster = self.client_roster
        if iq['roster']['ver']:
            roster.version = iq['roster']['ver']
        items = iq['roster']['items']

        valid_subscriptions = ('to', 'from', 'both', 'none', 'remove')
        for jid, item in items.items():
            if item['subscription'] in valid_subscriptions:
                roster[jid]['name'] = item['name']
                roster[jid]['groups'] = item['groups']
                roster[jid]['from'] = item['subscription'] in ('from', 'both')
                roster[jid]['to'] = item['subscription'] in ('to', 'both')
                roster[jid]['pending_out'] = (item['ask'] == 'subscribe')

                roster[jid].save(remove=(item['subscription'] == 'remove'))

        if iq['type'] == 'set':
            resp = self.Iq(stype='result', sto=iq['from'], sid=iq['id'])
            resp.enable('roster')
            resp.send()
예제 #6
0
 def message(msg):
     raise XMPPError(condition='feature-not-implemented',
                     text="We don't do things that way here.",
                     etype='cancel',
                     extension='foo',
                     extension_ns='foo:error',
                     extension_args={'test': 'true'})
예제 #7
0
    async def _handle_command_next(self, iq):
        """
        Process a request for the next step in the workflow
        for a command with multiple steps.

        :param iq: The command continuation request.
        """
        sessionid = iq['command']['sessionid']
        session = self.sessions.get(sessionid)

        if session:
            handler = session['next']
            interfaces = session['interfaces']
            results = []
            for stanza in iq['command']['substanzas']:
                if stanza.plugin_attrib in interfaces:
                    results.append(stanza)
            if len(results) == 1:
                results = results[0]

            session = await _await_if_needed(handler, results, session)

            self._process_command_response(iq, session)
        else:
            raise XMPPError('item-not-found')
예제 #8
0
    def _start_voting(self, iq, session):
        if iq['from'].bare not in self.xmpp.xsf_members:
            self.xmpp['xep_0050'].terminate_command(session)
            raise XMPPError('forbidden')

        ballot = self.xmpp['xsf_voting'].get_ballot()
        self.xmpp['xsf_voting'].get_session(iq['from'])

        form = self.xmpp['xep_0004'].stanza.Form()
        form['type'] = 'form'
        form['title'] = 'XSF Elections: %s' % iq['command']['node']
        form['instructions'] = (
            'By proceeding, you affirm that you wish to have your '
            'vote count as a proxy vote in the official meeting to '
            'be held on %s' % ballot['date'])
        session['ballot'] = ballot
        for section in ballot['sections']:
            if section['title'] == iq['command']['node']:
                session['ballot_section'] = section
                break
        session['payload'] = form
        session['has_next'] = True
        if session['ballot_section']['limit']:
            session['next'] = self._handle_limited_voting
        else:
            session['next'] = self._handle_voting
        return session
예제 #9
0
파일: proxy.py 프로젝트: optionalg/slixmpp
        def gather(futures, iq, streamhosts):
            proxies = yield from asyncio.gather(*futures, return_exceptions=True)
            for streamhost, proxy in zip(streamhosts, proxies):
                if isinstance(proxy, ValueError):
                    continue
                elif isinstance(proxy, socket.error):
                    log.error('Socket error while connecting to the proxy.')
                    continue
                proxy = proxy[1]
                # TODO: what if the future never happens?
                try:
                    addr, port = yield from proxy.connected
                except socket.error:
                    log.exception('Socket error while connecting to the proxy.')
                    continue
                # TODO: make a better choice than just the first working one.
                used_streamhost = streamhost['jid']
                conn = proxy
                break
            else:
                raise XMPPError(etype='cancel', condition='item-not-found')

            # TODO: close properly the connection to the other proxies.

            iq = iq.reply()
            self._sessions[sid] = conn
            iq['socks']['sid'] = sid
            iq['socks']['streamhost_used']['jid'] = used_streamhost
            iq.send()
            self.xmpp.event('socks5_stream', conn)
            self.xmpp.event('stream:%s:%s' % (sid, requester), conn)
예제 #10
0
    def _handle_command_cancel(self, iq):
        """
        Process a request to cancel a command's execution.

        Arguments:
            iq -- The command cancellation request.
        """
        node = iq['command']['node']
        sessionid = iq['command']['sessionid']

        session = self.sessions.get(sessionid)

        if session:
            handler = session['cancel']
            if handler:
                handler(iq, session)
            del self.sessions[sessionid]
            iq = iq.reply()
            iq['command']['node'] = node
            iq['command']['sessionid'] = sessionid
            iq['command']['status'] = 'canceled'
            iq['command']['notes'] = session['notes']
            iq.send()
        else:
            raise XMPPError('item-not-found')
예제 #11
0
    def _add_jid(self, iq, session):
        if iq['from'].bare not in self._admins:
            raise XMPPError('forbidden')

        form = self.xmpp['xep_0004'].stanza.Form()
        form['type'] = 'form'
        form['title'] = 'Add XSF Member JID'
        form['instructions'] = 'Enter a JID for an XSF Member'
        form.add_field(var='jid',
                       ftype='jid-single',
                       title='JID',
                       desc='XSF Member JID',
                       required=True)

        session['payload'] = form
        session['has_next'] = False

        def handle_result(form, session):
            jid = JID(form['values']['jid'])

            if jid.bare not in self._members:
                self._members.add(jid)
                self._save_data()
                self.xmpp.event('xsf_jid_added', jid)

            session['payload'] = None
            session['next'] = None
            return session

        session['next'] = handle_result
        return session
예제 #12
0
 def _handle_data(self, stanza):
     sid = stanza['ibb_data']['sid']
     stream = self.api['get_stream'](stanza['to'], sid, stanza['from'])
     if stream is not None and stanza['from'] == stream.peer_jid:
         stream._recv_data(stanza)
     else:
         raise XMPPError('item-not-found')
예제 #13
0
    def _handle_command_prev(self, iq):
        """
        Process a request for the prev step in the workflow
        for a command with multiple steps.

        Arguments:
            iq -- The command continuation request.
        """
        sessionid = iq['command']['sessionid']
        session = self.sessions.get(sessionid)

        if session:
            handler = session['prev']
            interfaces = session['interfaces']
            results = []
            for stanza in iq['command']['substanzas']:
                if stanza.plugin_attrib in interfaces:
                    results.append(stanza)
            if len(results) == 1:
                results = results[0]

            session = handler(results, session)

            self._process_command_response(iq, session)
        else:
            raise XMPPError('item-not-found')
예제 #14
0
    async def _get_roster(self, iq):
        try:
            roster = await self.stream.roster_hook.get_contacts(
                self.stream.boundjid)
            if roster is None:
                raise XMPPError('item-not-found')
        except Exception as e:
            iq.exception(e)
            return

        # When clients connect, they usually get the roster first,
        # then set initial presence, which also needs the roster.
        # We could cache the roster here so that the initial presence
        # wouldn't have to retrieve it again. However, that is a risky
        # thing to do; the client might never send presence, meaning
        # we'd be wasting memory, or the client might wait a while,
        # meaning our cached roster might be outdated (unless we keep
        # it up-to-date, which is possible but not implemented).
        # So for now, we won't cache the roster, but maybe we can
        # implement a safe way to do this in the future.
        #if not self.stream.presence.available:
        #    self.cached = roster

        reply = iq.reply()
        items = reply['roster']
        for jid, values in roster:
            item = roster_stanza.RosterItem()
            item.values = values
            item.set_jid(jid)
            items.append(item)
        reply.send()
예제 #15
0
    def _recv_data(self, stanza):
        new_seq = stanza['ibb_data']['seq']
        if new_seq != (self.recv_seq + 1) % 65535:
            self.close()
            raise XMPPError('unexpected-request')
        self.recv_seq = new_seq

        data = stanza['ibb_data']['data']
        if len(data) > self.block_size:
            self.close()
            raise XMPPError('not-acceptable')

        self.recv_queue.put_nowait(data)
        self.xmpp.event('ibb_stream_data', self)

        if isinstance(stanza, Iq):
            stanza.reply().send()
예제 #16
0
    def _reload(self, iq, session):
        if iq['from'].bare not in self._admins:
            raise XMPPError('forbidden')

        self._load_data()

        session['has_next'] = False
        session['payload'] = None
        return session
예제 #17
0
 async def process(self, request):
     if request.xml.text:
         value = request['value']
     else:
         value = await self.challenge()
     toks = value.split(b'\0')
     if len(toks) != 3:
         raise XMPPError('malformed-request')
     toks = [x.decode('utf8') for x in toks]
     username = toks[1]
     if not await self.auth.check_password(username,
                                           toks[2]):
         raise XMPPError('not-authorized')
     authcid = "%s@%s" % (username, self.stream.host)
     if toks[0] != '' and toks[0] != authcid:
         # authzid not supported yet
         raise XMPPError('invalid-authzid')
     self.boundjid.user = username
예제 #18
0
 async def _handle_close(self, iq: Iq):
     sid = iq['ibb_close']['sid']
     stream = await self.api['get_stream'](iq['to'], sid, iq['from'])
     if stream is not None and iq['from'] == stream.peer_jid:
         stream._closed(iq)
         await self.api['del_stream'](stream.self_jid, stream.sid,
                                      stream.peer_jid)
     else:
         raise XMPPError('item-not-found')
예제 #19
0
    async def _handle_request(self, iq):
        profile = iq['si']['profile']
        sid = iq['si']['id']

        if not sid:
            raise XMPPError(etype='modify', condition='bad-request')
        if profile not in self._profiles:
            raise XMPPError(
                etype='modify',
                condition='bad-request',
                extension='bad-profile',
                extension_ns=SI.namespace)

        neg = iq['si']['feature_neg']['form'].get_fields()
        options = neg['stream-method']['options'] or []
        methods = []
        for opt in options:
            methods.append(opt['value'])
        for method in methods:
            if method in self._methods:
                supported = True
                break
        else:
            raise XMPPError('bad-request',
                    extension='no-valid-streams',
                    extension_ns=SI.namespace)

        selected_method = None
        log.debug('Available: %s', methods)
        for order, method, plugin in self._methods_order:
            log.debug('Testing: %s', method)
            if method in methods:
                selected_method = method
                break

        receiver = iq['to']
        sender = iq['from']

        await self.api['add_pending'](receiver, sid, sender, {
            'response_id': iq['id'],
            'method': selected_method,
            'profile': profile
        })
        self.xmpp.event('si_request', iq)
예제 #20
0
 async def _update_contact(self, jid, values):
     if self.stream.kicked:
         raise XMPPError('forbidden')
     new_values = await self.stream.roster_hook.update_contact(
         self.stream.boundjid, jid, values)
     if new_values is None:
         # If the roster hook won't add the contact,
         # tell the client that it's removed
         new_values = {'subscription': 'remove'}
     return new_values
예제 #21
0
    def _default_handler(self, iq):
        """
        As a safe default, don't actually download files.

        Register a new handler using self.register_url_handler to
        screen requests and download files.

        :param iq: The Iq stanza containing the OOB transfer request.
        """
        raise XMPPError('service-unavailable')
예제 #22
0
 async def _set_roster(self, iq):
     try:
         self.delay_pushes += 1
         items = {}
         try:
             contacts = iq['roster'].get_items()
             if len(contacts) != 1:
                 raise XMPPError('bad-request')
             for jid, values in contacts.items():
                 if jid.bare == self.stream.boundjid.bare:
                     raise XMPPError('not-allowed')
                 if values.get('subscription', 'none') != 'remove':
                     if jid.user == '':
                         # the request might be addressed to a nickname;
                         # I haven't found any reference for that actually
                         # being allowed, so for now, treat that as a
                         # query for a username on the local server
                         # (while also telling the client to remove the
                         # original request, just in case).
                         items[jid] = {'subscription': 'remove'}
                         jid = JID(jid)
                         jid.user = jid.domain
                         jid.domain = self.stream.host
                     items[jid] = await self._update_contact(jid, values)
                 else:
                     items[jid] = await self._remove_contact(jid)
         except Exception as e:
             iq.exception(e)
             return
         iq.reply().send()
         # push to other resources of the same user
         del iq['from']
         iq['roster'].set_items(items)
         await self.stream.ipc_send('roster.push', self.stream.boundjid,
                                    iq.xml)
     finally:
         self.delay_pushes -= 1
         if self.delay_pushes == 0:
             pushes = self.delayed_pushes
             self.delayed_pushes = []
             for xml, checked in pushes:
                 await self._relay_push(xml, checked)
예제 #23
0
def fail_with(message, code):

    args = {'issuer': 'enedis-data-connect'}  # TODO directly use a xml ns?
    if code is not None:
        args['code'] = code

    raise XMPPError(extension="upstream-error",
                    extension_ns="urn:quoalise:0",
                    extension_args=args,
                    text=message,
                    etype="cancel")
예제 #24
0
    def _handle_command_complete(self, iq):
        """
        Process a request to finish the execution of command
        and terminate the workflow.

        All data related to the command session will be removed.

        Arguments:
            iq -- The command completion request.
        """
        node = iq['command']['node']
        sessionid = iq['command']['sessionid']
        session = self.sessions.get(sessionid)

        if session:
            handler = session['next']
            interfaces = session['interfaces']
            results = []
            for stanza in iq['command']['substanzas']:
                if stanza.plugin_attrib in interfaces:
                    results.append(stanza)
            if len(results) == 1:
                results = results[0]

            if handler:
                handler(results, session)

            del self.sessions[sessionid]

            payload = session['payload']
            if payload is None:
                payload = []
            if not isinstance(payload, list):
                payload = [payload]

            for item in payload:
                register_stanza_plugin(Command, item.__class__, iterable=True)

            iq = iq.reply()

            iq['command']['node'] = node
            iq['command']['sessionid'] = sessionid
            iq['command']['actions'] = []
            iq['command']['status'] = 'completed'
            iq['command']['notes'] = session['notes']

            for item in payload:
                iq['command'].append(item)

            iq.send()
        else:
            raise XMPPError('item-not-found')
예제 #25
0
 async def _outbound_subscribed(self, msg):
     try:
         if self.stream.kicked:
             raise XMPPError('forbidden')
         user = self.stream.boundjid
         contact = msg['to']
         msg['from'] = user.bare
         values = (await self.stream.roster_hook.
                   outbound_subscribed(user, contact))
         await self._handle_subscribed(msg, user, contact, values)
     except Exception as e:
         msg.exception(e)
         return
예제 #26
0
    def _run_url_handler(self, iq):
        """
        Execute the appropriate handler for a transfer request.

        :param iq: The Iq stanza containing the OOB transfer request.
        """
        if iq['to'] in self.url_handlers['jid']:
            return self.url_handlers['jid'][iq['to']](iq)
        else:
            if self.url_handlers['global']:
                self.url_handlers['global'](iq)
            else:
                raise XMPPError('service-unavailable')
예제 #27
0
    def get_items(self, jid, node, ifrom, data):
        """
        Return the stored items data for the requested JID/node combination.

        The data parameter is not used.
        """
        if not self.node_exists(jid, node):
            if not node:
                return DiscoItems()
            else:
                raise XMPPError(condition='item-not-found')
        else:
            return self.get_node(jid, node)['items']
예제 #28
0
    async def _set_register(self, iq):
        if not settings.ALLOW_REGISTRATION:
            reply = iq.reply()
            reply['error']['condition'] = 'not-allowed'
            reply.send()
            return
        fields = iq['register']

        try:
            if fields.get_remove():
                # delete registration
                if 'mechanisms' not in self.stream.features:
                    raise XMPPError('forbidden')
                username = self.stream.boundjid.user
                await self.stream.roster_hook.delete_user()
                self.stream.user_deleted()
            elif 'mechanisms' in self.stream.features:
                # update registration
                username = fields['username']
                if username != self.stream.boundjid.user:
                    raise XMPPError('bad-request')
                password = fields['password']
                if password != '':
                    await self.stream.roster_hook.change_password(password)
            else:
                # create registration
                # TODO: try to avoid registration spam
                username = fields['username']
                password = fields['password']
                if username == '' or password == '':
                    raise XMPPError('not-acceptable')
                if not await self.stream.roster_hook.create_user(
                        username, password):
                    raise XMPPError('conflict')
        except Exception as e:
            iq.exception(e)
            return
        iq.reply().send()
예제 #29
0
 def _handle_get_vcard(self, iq):
     if iq['type'] == 'result':
         self.api['set_vcard'](jid=iq['from'], args=iq['vcard_temp'])
         return
     elif iq['type'] == 'get' and self.xmpp.is_component:
         vcard = self.api['get_vcard'](iq['from'].bare)
         if isinstance(vcard, Iq):
             vcard.send()
         else:
             iq = iq.reply()
             iq.append(vcard)
             iq.send()
     elif iq['type'] == 'set':
         raise XMPPError('service-unavailable')
예제 #30
0
    async def _handle_open_request(self, iq: Iq):
        sid = iq['ibb_open']['sid']
        size = iq['ibb_open']['block_size'] or self.block_size

        log.debug('Received IBB stream request from %s', iq['from'])

        if not sid:
            raise XMPPError(etype='modify', condition='bad-request')

        if not await self._accept_stream(iq):
            raise XMPPError(etype='cancel', condition='not-acceptable')

        if size > self.max_block_size:
            raise XMPPError('resource-constraint')

        stream = IBBytestream(self.xmpp, sid, size, iq['to'], iq['from'])
        stream.stream_started = True
        await self.api['set_stream'](stream.self_jid, stream.sid,
                                     stream.peer_jid, stream)
        iq.reply().send()

        self.xmpp.event('ibb_stream_start', stream)
        self.xmpp.event('stream:%s:%s' % (sid, stream.peer_jid), stream)