Ejemplo n.º 1
0
    def handle(self, tree, msg, lastRetVal=None):
        if len(tree) > 0:
            # get the original iq msg
            origIQ = tree
        else:
            logging.warning("[%s] Original <iq> missing:\n%s",
                            self.__class__, tostring(tree))
            return

        id = origIQ.get('id')
        if id:
            res = Element('iq', {
                                 'type' : 'error',
                                 'id' : id
                                })
            res.append(origIQ)

            err = Element('error', {'type' : 'cancel'})
            SubElement(err, 'service-unavailable',
                       {'xmlns' : 'urn:ietf:params:xml:ns:xmpp-stanzas'})

            res.append(err)

            return chainOutput(lastRetVal, res)
        else:
            logging.warning("[%s] No id in <iq>:\n%s",
                            self.__class__, tostring(origIQ))

        return lastRetVal
Ejemplo n.º 2
0
 def get_error_tree(iq, type, code, tag):
     result = Element('iq', {'type': 'error', 'id': iq.get('id')})
     result.append(iq)
     err_tree = Element('error', {'type': type, 'code': code,})
     SubElement(err_tree, tag, {'xmlns': 'urn:ietf:params:xml:ns:xmpp-stanzas'})
     result.append(err_tree)
     return result
Ejemplo n.º 3
0
    def handle(self, tree, msg, lastRetVal=None):
        iq = tree
        id = iq.get("id")
        if id:
            bind = iq[0]
            if len(bind) > 0:
                resource = bind[0].text
            else:
                # generate an id
                resource = generateId()[:6]

            # TODO: check that we don't already have such a resource
            jid = msg.conn.data["user"]["jid"]
            bindResource(msg, resource)

            res = Element("iq", {"type": "result", "id": id})
            bind = Element("bind", {"xmlns": "urn:ietf:params:xml:ns:xmpp-bind"})
            jidEl = Element("jid")
            jidEl.text = "%s/%s" % (jid, resource)
            bind.append(jidEl)
            res.append(bind)

            return chainOutput(lastRetVal, res)
        else:
            logging.warning("[%s] No id in <iq>:\n%s", self.__class__, tostring(iq))

        return lastRetVal
Ejemplo n.º 4
0
    def handle(self, tree, msg, lastRetVal=None):
        if len(tree) > 0:
            # get the original iq msg
            origIQ = tree
        else:
            logging.warning("[%s] Original <iq> missing:\n%s", self.__class__,
                            tostring(tree))
            return

        id = origIQ.get('id')
        if id:
            res = Element('iq', {'type': 'error', 'id': id})
            res.append(origIQ)

            err = Element('error', {'type': 'cancel'})
            SubElement(err, 'service-unavailable',
                       {'xmlns': 'urn:ietf:params:xml:ns:xmpp-stanzas'})

            res.append(err)

            return chainOutput(lastRetVal, res)
        else:
            logging.warning("[%s] No id in <iq>:\n%s", self.__class__,
                            tostring(origIQ))

        return lastRetVal
Ejemplo n.º 5
0
    def handle(self, tree, msg, lastRetVal=None):
        iq = tree
        id = iq.get('id')
        if id:
            bind = iq[0]
            if len(bind) > 0:
                resource = bind[0].text
            else:
                # generate an id
                resource = generateId()[:6]

            # TODO: check that we don't already have such a resource
            jid = msg.conn.data['user']['jid']
            bindResource(msg, resource)

            res = Element('iq', {'type': 'result', 'id': id})
            bind = Element('bind',
                           {'xmlns': 'urn:ietf:params:xml:ns:xmpp-bind'})
            jidEl = Element('jid')
            jidEl.text = '%s/%s' % (jid, resource)
            bind.append(jidEl)
            res.append(bind)

            return chainOutput(lastRetVal, res)
        else:
            logging.warning("[%s] No id in <iq>:\n%s", self.__class__,
                            tostring(iq))

        return lastRetVal
Ejemplo n.º 6
0
    def handle(self, tree, msg, lastRetVal=None):
        iq = tree
        id = iq.get('id')
        if id:
            bind = iq[0]
            if len(bind) > 0:
                resource = bind[0].text
            else:
                # generate an id
                resource = generateId()[:6]

            # TODO: check that we don't already have such a resource
            jid = msg.conn.data['user']['jid']
            bindResource(msg, resource)

            res = Element('iq', {'type' : 'result', 'id' : id})
            bind = Element('bind', {'xmlns' : 'urn:ietf:params:xml:ns:xmpp-bind'})
            jidEl = Element('jid')
            jidEl.text = '%s/%s' % (jid, resource)
            bind.append(jidEl)
            res.append(bind)

            return chainOutput(lastRetVal, res)
        else:
            logging.warning("[%s] No id in <iq>:\n%s", self.__class__, tostring(iq))

        return lastRetVal
Ejemplo n.º 7
0
    def getAsTree(self):
        """Returns the roster Element tree starting from <query>. Call
        loadRoster() before this.
        """
        query = Element('query', {'xmlns' : 'jabber:iq:roster'})
        for item in self.items:
            query.append(self.items[item].getAsTree())

        return query
Ejemplo n.º 8
0
    def getAsTree(self):
        """Returns the roster Element tree starting from <query>. Call
        loadRoster() before this.
        """
        query = Element('query', {'xmlns': 'jabber:iq:roster'})
        for item in self.items:
            query.append(self.items[item].getAsTree())

        return query
Ejemplo n.º 9
0
 def makeServiceUnavailableError():
     fromJID = cjid.__str__()
     reply = Element("message", {"type": "error", "to": fromJID})
     reply.append(copy(tree))
     error = Element("error", {"type": "cancel"})
     SubElement(error, "service-unavailable", {"xmlns": "urn:ietf:params:xml:ns:xmpp-stanzas"})
     routeData = {"to": fromJID, "data": reply}
     msg.setNextHandler("route-client")
     return chainOutput(lastRetVal, routeData)
Ejemplo n.º 10
0
 def makeServiceUnavailableError():
     fromJID = cjid.__str__()
     reply = Element('message', {'type': 'error', 'to': fromJID})
     reply.append(copy(tree))
     error = Element('error', {'type': 'cancel'})
     SubElement(error, 'service-unavailable',
                {'xmlns': 'urn:ietf:params:xml:ns:xmpp-stanzas'})
     routeData = {'to': fromJID, 'data': reply}
     msg.setNextHandler('route-client')
     return chainOutput(lastRetVal, routeData)
Ejemplo n.º 11
0
 def handle(self, tree, msg, lastRetVal=None):
     if isinstance(lastRetVal, SASLError):
         el = Element('failure', {'xmlns' : 'urn:ietf:params:xml:ns:xmpp-sasl'})
         el.append(lastRetVal.errorElement())
         
         return chainOutput(lastRetVal, el)
     else:
         logging.warning("[%s] SASLErrorHandler was passed a non-SASL " +\
                         "exception. Exception: %s",
                         self.__class__, lastRetVal)
         raise Exception, "can't handle a non-SASL error"
Ejemplo n.º 12
0
    def handle(self, tree, msg, lastRetVal=None):
        if isinstance(lastRetVal, SASLError):
            el = Element('failure',
                         {'xmlns': 'urn:ietf:params:xml:ns:xmpp-sasl'})
            el.append(lastRetVal.errorElement())

            return chainOutput(lastRetVal, el)
        else:
            logging.warning("[%s] SASLErrorHandler was passed a non-SASL " +\
                            "exception. Exception: %s",
                            self.__class__, lastRetVal)
            raise Exception, "can't handle a non-SASL error"
Ejemplo n.º 13
0
    def handle_close(self):
        # we want to be able to do stuff in handlers when the connection is
        # closed, so we dispatch into the 'stream-end' phase.

        # we set the tree to a dummy element so that the handlers could modify
        # it.
        if self.data['stream']['closing']:
            # already closing
            return
        wrapper = Element('wrapper')
        tree = Element('tag')
        wrapper.append(tree)
        Dispatcher().dispatch(wrapper, self, 'stream-end')
Ejemplo n.º 14
0
 def makeServiceUnavailableError():
     fromJID = cjid.__str__()
     reply = Element('message', {
                                 'type' : 'error',
                                 'to' : fromJID
                                 })
     reply.append(copy(tree))
     error = Element('error', {'type' : 'cancel'})
     SubElement(error, 'service-unavailable', {
                   'xmlns' : 'urn:ietf:params:xml:ns:xmpp-stanzas'
                   })
     routeData = {
                  'to' : fromJID,
                  'data' : reply
                  }
     msg.setNextHandler('route-client')
     return chainOutput(lastRetVal, routeData)
Ejemplo n.º 15
0
        def act():
            # TODO: verify that it's coming from a known user
            jid = msg.conn.data["user"]["jid"]
            resource = msg.conn.data["user"]["resource"]
            id = tree.get("id")
            if id is None:
                logging.warning("[%s] No id in roster get query. Tree: %s", self.__class__, tree)
                # TODO: throw exception here
                return

            roster = Roster(jid)

            roster.loadRoster()

            res = Element("iq", {"to": "/".join([jid, resource]), "type": "result", "id": id})

            res.append(roster.getAsTree())
            return chainOutput(lastRetVal, res)
Ejemplo n.º 16
0
        def act():
            # TODO: verify that it's coming from a known user
            jid = msg.conn.data['user']['jid']
            resource = msg.conn.data['user']['resource']
            id = tree.get('id')
            if id is None:
                logging.warning('[%s] No id in roster get query. Tree: %s',
                                self.__class__, tree)
                # TODO: throw exception here
                return

            roster = Roster(jid)

            roster.loadRoster()

            res = Element('iq', {
                                 'to' : '/'.join([jid, resource]),
                                 'type' : 'result',
                                 'id' : id
                                 })

            res.append(roster.getAsTree())
            return chainOutput(lastRetVal, res)
Ejemplo n.º 17
0
    def handle(self, tree, msg, lastRetVal=None):
        if len(tree) > 0:
            # get the original iq msg
            origIQ = tree
        else:
            logging.warning("[%s] Original <iq> missing:\n%s", self.__class__, tostring(tree))
            return

        id = origIQ.get("id")
        if id:
            res = Element("iq", {"type": "error", "id": id})
            res.append(origIQ)

            err = Element("error", {"type": "cancel"})
            SubElement(err, "service-unavailable", {"xmlns": "urn:ietf:params:xml:ns:xmpp-stanzas"})

            res.append(err)

            return chainOutput(lastRetVal, res)
        else:
            logging.warning("[%s] No id in <iq>:\n%s", self.__class__, tostring(origIQ))

        return lastRetVal
Ejemplo n.º 18
0
        def act():
            # TODO: verify that it's coming from a known user
            jid = msg.conn.data['user']['jid']
            resource = msg.conn.data['user']['resource']
            id = tree.get('id')
            if id is None:
                logging.warning('[%s] No id in roster get query. Tree: %s',
                                self.__class__, tree)
                # TODO: throw exception here
                return

            roster = Roster(jid)

            roster.loadRoster()

            res = Element('iq', {
                'to': '/'.join([jid, resource]),
                'type': 'result',
                'id': id
            })

            res.append(roster.getAsTree())
            return chainOutput(lastRetVal, res)
Ejemplo n.º 19
0
        def act():
            # we have to be passed a tree to work
            # or a tuple with routingData and a tree
            if not isinstance(lastRetVal, list):
                logging.warning("[%s] lastRetVal is not a list", self.__class__)
                return
            if isinstance(lastRetVal[-1], Element):
                if lastRetVal[-1].tag.find("query") == -1:
                    logging.warning(
                        "[%s] Got a non-query Element last return value" + ". Last return value: %s",
                        self.__class__,
                        lastRetVal,
                    )
            elif isinstance(lastRetVal[-1], tuple):
                if not isinstance(lastRetVal[-1][0], dict) or not isinstance(lastRetVal[-1][1], Element):
                    logging.warning(
                        "[%s] Got a non-query Element last return value" + ". Last return value: %s",
                        self.__class__,
                        lastRetVal,
                    )
                    return
            else:
                logging.warning(
                    "[%s] Roster push needs either a <query> Element "
                    + "as the last item in lastRetVal or a tuple "
                    + "with (routeData, query Element)",
                    self.__class__,
                )
                return

            # this is the roster <query> that we'll send
            # it could be a tuple if we got routing data as well
            query = lastRetVal.pop(-1)
            routeData = None

            # did we get routing data (from S2S)
            if isinstance(query, tuple):
                routeData = query[0]
                query = query[1]

            if routeData:
                jid = routeData["jid"]
                resources = routeData["resources"]
            else:
                jid = msg.conn.data["user"]["jid"]
                resource = msg.conn.data["user"]["resource"]
                resources = msg.conn.server.data["resources"][jid]

            for res, con in resources.items():
                # don't send the roster to clients that didn't request it
                if con.data["user"]["requestedRoster"]:
                    iq = Element("iq", {"to": "%s/%s" % (jid, res), "type": "set", "id": generateId()[:10]})
                    iq.append(query)

                    # TODO: remove this. debug.
                    logging.debug("Sending " + tostring(iq))
                    con.send(tostring(iq))

            if tree.tag == "{jabber:client}iq" and tree.get("id"):
                # send an ack to client if this is in reply to a roster get/set
                id = tree.get("id")
                d = {"to": "%s/%s" % (jid, resource), "type": "result", "id": id}
                iq = Element("iq", d)
                return chainOutput(lastRetVal, iq)
Ejemplo n.º 20
0
        def act():
            # we have to be passed a tree to work
            # or a tuple with routingData and a tree
            if not isinstance(lastRetVal, list):
                logging.warning('[%s] lastRetVal is not a list',
                                self.__class__)
                return
            if isinstance(lastRetVal[-1], Element):
                if lastRetVal[-1].tag.find('query') == -1:
                    logging.warning('[%s] Got a non-query Element last return value' +\
                                '. Last return value: %s',
                                self.__class__, lastRetVal)
            elif isinstance(lastRetVal[-1], tuple):
                if not isinstance(lastRetVal[-1][0], dict) \
                or not isinstance(lastRetVal[-1][1], Element):
                    logging.warning('[%s] Got a non-query Element last return value' +\
                                '. Last return value: %s',
                                self.__class__, lastRetVal)
                    return
            else:
                logging.warning('[%s] Roster push needs either a <query> Element ' +\
                                'as the last item in lastRetVal or a tuple ' + \
                                'with (routeData, query Element)', self.__class__)
                return

            # this is the roster <query> that we'll send
            # it could be a tuple if we got routing data as well
            query = lastRetVal.pop(-1)
            routeData = None

            # did we get routing data (from S2S)
            if isinstance(query, tuple):
                routeData = query[0]
                query = query[1]

            if routeData:
                jid = routeData['jid']
                resources = routeData['resources']
            else:
                jid = msg.conn.data['user']['jid']
                resource = msg.conn.data['user']['resource']
                resources = msg.conn.server.data['resources'][jid]

            for res, con in resources.items():
                # don't send the roster to clients that didn't request it
                if con.data['user']['requestedRoster']:
                    iq = Element(
                        'iq', {
                            'to': '%s/%s' % (jid, res),
                            'type': 'set',
                            'id': generateId()[:10]
                        })
                    iq.append(query)

                    # TODO: remove this. debug.
                    logging.debug("Sending " + tostring(iq))
                    con.send(tostring(iq))

            if tree.tag == '{jabber:client}iq' and tree.get('id'):
                # send an ack to client if this is in reply to a roster get/set
                id = tree.get('id')
                d = {
                    'to': '%s/%s' % (jid, resource),
                    'type': 'result',
                    'id': id
                }
                iq = Element('iq', d)
                return chainOutput(lastRetVal, iq)
Ejemplo n.º 21
0
        def act():
            # we have to be passed a tree to work
            # or a tuple with routingData and a tree
            if not isinstance(lastRetVal, list):
                logging.warning('[%s] lastRetVal is not a list', self.__class__)
                return
            if isinstance(lastRetVal[-1], Element):
                if lastRetVal[-1].tag.find('query') == -1:
                    logging.warning('[%s] Got a non-query Element last return value' +\
                                '. Last return value: %s',
                                self.__class__, lastRetVal)
            elif isinstance(lastRetVal[-1], tuple):
                if not isinstance(lastRetVal[-1][0], dict) \
                or not isinstance(lastRetVal[-1][1], Element):
                    logging.warning('[%s] Got a non-query Element last return value' +\
                                '. Last return value: %s',
                                self.__class__, lastRetVal)
                    return
            else:
                logging.warning('[%s] Roster push needs either a <query> Element ' +\
                                'as the last item in lastRetVal or a tuple ' + \
                                'with (routeData, query Element)', self.__class__)
                return

            # this is the roster <query> that we'll send
            # it could be a tuple if we got routing data as well
            query = lastRetVal.pop(-1)
            routeData = None

            # did we get routing data (from S2S)
            if isinstance(query, tuple):
                routeData = query[0]
                query = query[1]

            if routeData:
                jid = routeData['jid']
                resources = routeData['resources']
            else:
                jid = msg.conn.data['user']['jid']
                resource = msg.conn.data['user']['resource']
                resources = msg.conn.server.data['resources'][jid]

            for res, con in resources.items():
                # don't send the roster to clients that didn't request it
                if con.data['user']['requestedRoster']:
                    iq = Element('iq', {
                                        'to' : '%s/%s' % (jid, res),
                                        'type' : 'set',
                                        'id' : generateId()[:10]
                                        })
                    iq.append(query)

                    # TODO: remove this. debug.
                    logging.debug("Sending " + tostring(iq))
                    con.send(tostring(iq))

            if tree.tag == '{jabber:client}iq' and tree.get('id'):
                # send an ack to client if this is in reply to a roster get/set
                id = tree.get('id')
                d = {
                     'to' : '%s/%s' % (jid, resource),
                     'type' : 'result',
                     'id' : id
                     }
                iq = Element('iq', d)
                return chainOutput(lastRetVal, iq)
Ejemplo n.º 22
0
        def act():
            d = msg.conn.data

            retVal = lastRetVal

            jid = d['user']['jid']
            resource = d['user']['resource']

            roster = Roster(jid)

            presTree = deepcopy(tree)
            presTree.set('from', '%s/%s' % (jid, resource))

            probes = []
            init_rosters = []
            offline_msgs = []
            if tree.get('to') is None and not d['user']['active']:
                # initial presence
                # TODO: we don't need to do it every time. we can cache the
                # data after the first resource is active and just resend
                # that to all new resources
                d['user']['active'] = True

                # get jids of the contacts whose status we're interested in
                cjids = roster.getPresenceSubscriptions()

                probeTree = Element('presence', {
                                                 'type': 'probe',
                                                 'from' : '%s/%s' \
                                                    % (jid, resource)
                                                 })

                # TODO: replace this with a more efficient router handler
                for cjid in cjids:
                    probeTree.set('to', cjid)
                    probeRouteData = {
                                      'to' : cjid,
                                      'data' : deepcopy(probeTree)
                                      }
                    probes.append(probeRouteData)
                    # they're sent first. see below

                # send initial roster list to this user
                rosterTree = Element('presence', {
                                                 'type': 'unavailable',
                                                 'to' : '%s/%s' \
                                                    % (jid, resource)
                                                 })
                for cjid in cjids:
                    rosterTree.set('from', cjid)
                    rosterRouterData = {
                                           'to' : '%s/%s' % (jid, resource),
                                           'data' : deepcopy(rosterTree)
                                       }
                    init_rosters.append(rosterRouterData)

                # send offline message to this user
                try:
                    con = DB()
                    result = []
                    to_jid = JID(jid)
                    with closing(con.cursor()) as cursor:
                        cursor.execute("SELECT fromid, time, content FROM offline WHERE toid = %d ORDER BY time DESC" %
                                       (to_jid.getNumId()))
                        con.commit()
                        result = cursor.fetchall()
                    with closing(con.cursor()) as cursor:
                        cursor.execute("DELETE FROM offline WHERE toid = %d" %
                                       (to_jid.getNumId()))
                        con.commit()
                    for fromid, time, content in result:
                        fromJID = JID(fromid, True).getBare()
                        toJID = '%s/%s' % (jid, resource)

                        reply = Element('message', {
                            'to': toJID,
                            'from': fromJID,
                            'type': 'chat'
                        })

                        body = Element('body')
                        body.text = content
                        reply.append(body)

                        delay = Element('delay', {
                            'xmlns': 'urn:xmpp:delay',
                            'from': fromJID,
                            'stamp': time.strftime("%Y-%m-%dT%H:%M:%SZ")
                        })
                        reply.append(delay)

                        routeData = {
                            'to' : toJID,
                            'data': reply
                        }
                        offline_msgs.append(routeData)
                    logging.debug("[%s] Sending %d offline messages to %s", self.__class__, len(offline_msgs), to_jid.getBare())
                except Exception as e:
                    logging.warning("[%s] Failed to read offline messages: %s", self.__class__, str(e))

                # broadcast to other resources of this user
                retVal = self.broadcastToOtherResources(presTree, msg, retVal, jid, resource)

            elif tree.get('to') is not None:
                # TODO: directed presence
                return
            elif tree.get('type') == 'unavailable':
                # broadcast to other resources of this user
                d['user']['active'] = False
                retVal = self.broadcastToOtherResources(presTree, msg, retVal, jid, resource)

            # record this stanza as the last presence sent from this client
            lastPresence = deepcopy(tree)
            lastPresence.set('from', '%s/%s' % (jid, resource))
            d['user']['lastPresence'] = lastPresence

            # lookup contacts interested in presence
            cjids = roster.getPresenceSubscribers()

            # TODO: replace this with another router handler that would send
            # it out to all cjids in a batch instead of queuing a handler
            # for each
            for cjid in cjids:
                presTree.set('to', cjid)
                presRouteData = {
                     'to' : cjid,
                     'data' : deepcopy(presTree)
                     }
                retVal = chainOutput(retVal, presRouteData)
                msg.setNextHandler('route-server')

            # send the probes first
            for probe in probes:
                msg.setNextHandler('route-server')
                retVal = chainOutput(retVal, probe)

            # send initial rosters
            for init_roster in init_rosters:
                msg.setNextHandler('route-client')
                retVal = chainOutput(retVal, init_roster)

            # send offline messages
            for offline_msg in offline_msgs:
                msg.setNextHandler('route-client')
                retVal = chainOutput(retVal, offline_msg)

            return retVal
Ejemplo n.º 23
0
    def handle(self, tree, msg, lastRetVal=None):

        # generate error response tree
        def get_error_tree(iq, type, code, tag):
            result = Element('iq', {'type': 'error', 'id': iq.get('id')})
            result.append(iq)
            err_tree = Element('error', {'type': type, 'code': code,})
            SubElement(err_tree, tag, {'xmlns': 'urn:ietf:params:xml:ns:xmpp-stanzas'})
            result.append(err_tree)
            return result

        if len(tree) > 0:
            # get the original iq msg
            origIQ = tree
        else:
            logging.warning("[%s] Original <iq> missing:\n%s",
                            self.__class__, tostring(tree))
            return lastRetVal

        id = origIQ.get('id')
        if id:
            try:
                username_tree = origIQ[0][0]
                password_tree = origIQ[0][1]
                if username_tree.tag == '{jabber:iq:register}username' and password_tree.tag == '{jabber:iq:register}password':
                    username = username_tree.text
                    password = password_tree.text

                    # ruling out illegal username
                    if not re.match("^[a-zA-Z0-9_.-]+$", username):
                        raise Exception('Username not accepted')

                    # write to database
                    try:
                        con = DB()
                        with closing(con.cursor()) as cursor:
                            cursor.execute("INSERT INTO jids (jid, password) VALUES ('%s@%s', '%s')" %
                                           (username, msg.conn.server.hostname, password))
                            con.commit()
                        res = Element('iq', {'type': 'result', 'id': id})
                        query = deepcopy(origIQ[0])
                        query.insert(0, Element('registered'))
                        res.append(query)
                        return chainOutput(lastRetVal, res)

                    # conflict response
                    except sqlite.IntegrityError as e:
                        if e.message.find('column jid is not unique') >= 0:
                            logging.warning("[%s] Username conflict in <iq>:\n%s",
                            self.__class__, str(e), tostring(origIQ))
                            res = get_error_tree(origIQ, 'cancel', '409', 'conflict')
                            return chainOutput(lastRetVal, res)
                        else:
                            raise e

                else:
                    raise Exception('IQ missing registration fields')

            # error response
            except Exception as e:
                error_string = str(e)
                logging.warning("[%s] Register failed '%s' in <iq>:\n%s",
                            self.__class__, str(e) if error_string else 'Unknown error',
                            tostring(origIQ))
                res = get_error_tree(origIQ, 'modify', '406', 'not-acceptable')
                return chainOutput(lastRetVal, res)

        else:
            logging.warning("[%s] No id in <iq>:\n%s",
                            self.__class__, tostring(origIQ))

        return lastRetVal