Ejemplo n.º 1
0
    def send_user_presence(self, gid, sender, recipient):
        stub = self.lookup(recipient)
        log.debug("onProbe(%s): found %r" % (gid, stub, ))
        if stub:
            data = stub.presence()
            i = len(data)
            for x in data:
                presence = deepcopy(x)
                presence.consumed = True
                presence['to'] = sender.full()

                try:
                    # add fingerprint
                    fpr = self.parent.keyring.get_fingerprint(recipient.user)
                    if fpr:
                        pubkey = presence.addElement(('urn:xmpp:pubkey:2', 'pubkey'))
                        fprint = pubkey.addElement((None, 'print'))
                        fprint.addContent(fpr)
                except keyring.KeyNotFoundException:
                    log.warn("key not found for user %s" % (recipient, ))

                if gid:
                    # FIXME this will duplicate group elements - actually in storage there should be no group element!!!
                    group = presence.addElement((xmlstream2.NS_XMPP_STANZA_GROUP, 'group'))
                    group['id'] = gid
                    group['count'] = str(i)
                    i -= 1

                self.send(presence)
                return True

        # no such user
        return False
Ejemplo n.º 2
0
    def startService(self):
        component.Component.startService(self)
        resolver.ResolverMixIn.startService(self)

        # register the registration provider if configured
        if 'registration' in self.config:
            from kontalk.xmppserver import register
            provider = self.config['registration']['provider']
            try:
                prov_class = register.providers[provider]
                self.registration = prov_class(self,
                                               self.config['registration'])
            except:
                log.warn(traceback.format_exc())

        if self.registration:
            log.info("using registration provider %s (type=%s)" %
                     (self.registration.name, self.registration.type))
        else:
            log.info("disabling registration")

        # register push notifications providers if configured
        if 'push' in self.config:
            from kontalk.xmppserver import push
            self.push_manager = push.PushManager(self, self.config['push'])

        if self.push_manager:
            log.info("using push notifications providers: %s" %
                     (', '.join(self.push_manager.providers.keys())))
        else:
            log.info("disabling push notifictions")

        # load local presence data
        d = self.presencedb.get_all()
        d.addCallback(self._presence_data)
Ejemplo n.º 3
0
    def onVCardSet(self, stanza, sender=None):
        """
        Handle vCards set IQs.
        This simply takes care of importing the key in the keyring for future
        signature verification. Actual key verification is done by c2s when
        accepting vCards coming from clients.
        WARNING/1 does this mean that we bindly accept keys from components? --
         YES blindly :P c2s will filter invalid requests
        WARNING/2 importing the key means that keys coming from local c2s are
        imported twice because the keyring is the same. Unless we want to make
        a separated keyring only for resolver? -- YES USING .gnupg-cache
        """
        # TODO parse vcard for interesting sections

        if stanza.vcard.key is not None:
            # we do this because of the uri member in domish.Element
            keydata = stanza.vcard.key.firstChildElement()
            if keydata.name == 'uri':
                keydata = str(keydata)

                if keydata.startswith(xmlstream2.DATA_PGP_PREFIX):
                    keydata = base64.b64decode(keydata[len(xmlstream2.DATA_PGP_PREFIX):])
                    # import into cache keyring
                    userid = util.jid_user(stanza['from'])
                    # this chould take a lot of time (up to 500ms)
                    if self.parent.keyring.check_user_key(keydata, userid):
                        log.debug("key cached successfully")
                    else:
                        log.warn("invalid key")
Ejemplo n.º 4
0
    def startService(self):
        component.Component.startService(self)
        resolver.ResolverMixIn.startService(self)

        # register the registration provider if configured
        if 'registration' in self.config:
            from kontalk.xmppserver import register
            provider = self.config['registration']['provider']
            try:
                prov_class = register.providers[provider]
                self.registration = prov_class(self, self.config['registration'])
            except:
                log.warn(traceback.format_exc())

        if self.registration:
            log.info("using registration provider %s (type=%s)" % (self.registration.name, self.registration.type))
        else:
            log.info("disabling registration")

        # register push notifications providers if configured
        if 'push' in self.config:
            from kontalk.xmppserver import push
            self.push_manager = push.PushManager(self, self.config['push'])

        if self.push_manager:
            log.info("using push notifications providers: %s" % (', '.join(self.push_manager.providers.keys())))
        else:
            log.info("disabling push notifictions")

        # load local presence data
        d = self.presencedb.get_all()
        d.addCallback(self._presence_data)
Ejemplo n.º 5
0
 def _load_privacy_lists(self):
     try:
         with open(self.PERSIST_STORAGE, 'r') as f:
             import cPickle
             data = cPickle.load(f)
         self.whitelists = data['whitelists']
         self.blacklists = data['blacklists']
     except:
         log.warn("unable to load privacy lists")
         import traceback
         traceback.print_exc()
Ejemplo n.º 6
0
    def unbind(self, name):
        # send unbind command to router
        unbind = domish.Element((None, 'unbind'))
        unbind['name'] = name
        self.send(unbind)

        # unregister route
        unused, host = util.jid_component(name)
        if host in self.routes:
            self.routes[host].remove(name)

            if len(self.routes[host]) == 0:
                del self.routes[host]

        else:
            # this is an error, it shouldn't happen
            log.warn("unbinding non-registered route: %s" % (name, ))
Ejemplo n.º 7
0
    def unbind(self, name):
        # send unbind command to router
        unbind = domish.Element((None, 'unbind'))
        unbind['name'] = name
        self.send(unbind)

        # unregister route
        unused, host = util.jid_component(name)
        if host in self.routes:
            self.routes[host].remove(name)

            if len(self.routes[host]) == 0:
                del self.routes[host]

        else:
            # this is an error, it shouldn't happen
            log.warn("unbinding non-registered route: %s" % (name, ))
Ejemplo n.º 8
0
    def render_POST(self, request):
        #log.debug("request from %s: %s" % (self.userid, request.requestHeaders))

        # check mime type
        mime = request.getHeader('content-type')
        if mime not in self.config['upload']['accept_content']:
            return self._quick_response(request, 406,
                                        'unacceptable content type')

        # check length
        length = request.getHeader('content-length')
        if length != None:
            length = long(length)
            if length <= self.config['upload']['max_size']:
                # store file to storage
                # TODO convert to file-object management for less memory consumption
                data = request.content.read()
                if len(data) == length:
                    fileid = util.rand_str(40)
                    filename = self.fileserver.storage.store_data(
                        fileid, mime, data)
                    if filename:
                        log.debug(
                            "file stored to disk (filename=%s, fileid=%s)" %
                            (filename, fileid))
                        request.setHeader('content-type', 'text/url')
                        return str(self.config['upload']['url']) % (fileid, )
                    else:
                        log.error("error storing file")
                        return self._quick_response(request, 500,
                                                    'unable to store file')

                else:
                    log.warn(
                        "file length not matching content-length header (%d/%d)"
                        % (len(data), length))
                    return self._quick_response(request, 400, 'bad request')
            else:
                log.warn("file too big (%d bytes)" % length)
                return self._quick_response(request, 413, 'request too large')
        else:
            log.warn("content-length header not found")
            return self._quick_response(request, 411,
                                        'content length not declared')
Ejemplo n.º 9
0
    def render_POST(self, request):
        # log.debug("request from %s: %s" % (self.userid, request.requestHeaders))

        # check mime type
        mime = request.getHeader("content-type")
        if mime not in self.config["upload"]["accept_content"]:
            return self._quick_response(request, 406, "unacceptable content type")

        # check length
        length = request.getHeader("content-length")
        if length != None:
            length = long(length)
            if length <= self.config["upload"]["max_size"]:
                # store file to storage
                # TODO convert to file-object management for less memory consumption
                data = request.content.read()
                if len(data) == length:
                    fileid = util.rand_str(40)
                    filename = self.fileserver.storage.store_data(fileid, mime, data)
                    if filename:
                        log.debug("file stored to disk (filename=%s, fileid=%s)" % (filename, fileid))
                        request.setHeader("content-type", "text/url")
                        return str(self.config["upload"]["url"]) % (fileid,)
                    else:
                        log.error("error storing file")
                        return self._quick_response(request, 500, "unable to store file")

                else:
                    log.warn("file length not matching content-length header (%d/%d)" % (len(data), length))
                    return self._quick_response(request, 400, "bad request")
            else:
                log.warn("file too big (%d bytes)" % length)
                return self._quick_response(request, 413, "request too large")
        else:
            log.warn("content-length header not found")
            return self._quick_response(request, 411, "content length not declared")
Ejemplo n.º 10
0
    def route(self, stanza, xs):
        """
        Route a stanza.

        @param stanza: The stanza to be routed.
        @type stanza: L{domish.Element}.
        """

        if stanza.consumed:
            return
        """"
        TEST check sender host is component
        stanzaFrom = jid.JID(stanza['from'])
        if stanzaFrom.host != xs.thisEntity.host:
            log.error("stanza is not from component - dropping")
            return
        """

        # reset namespace
        util.resetNamespace(stanza, component.NS_COMPONENT_ACCEPT)

        # send stanza to logging entities
        for lg in self.logs:
            lg.send(stanza)

        if not stanza.hasAttribute('to'):
            if self.logTraffic:
                log.debug("broadcasting stanza %s" %
                          (stanza.toXml().encode('utf-8'), ))
            self.broadcast(stanza)
        else:
            """
            FIXME we have encoding problems here... (why not in other components?!?!?)
            """

            # check for stanza loops
            errors = 0
            for child in stanza.children:
                if domish.IElement.providedBy(child) and child.name == 'error':
                    errors += 1
                    if errors > 1:
                        if self.logTraffic:
                            log.debug("error loop, dropping stanza %s" %
                                      (stanza.toXml().encode('utf-8'), ))
                        else:
                            log.debug("error loop, dropping stanza")

                        return

            if self.logTraffic:
                log.debug("routing stanza %s" %
                          (stanza.toXml().encode('utf-8'), ))
            try:
                destination_host = util.jid_host(stanza['to'])

                if destination_host in self.routes:
                    self.routes[destination_host].send(stanza)
                elif destination_host in self.private:
                    self.private[destination_host].send(stanza)
                else:
                    self.routes[None].send(stanza)

            except KeyError:
                log.warn("unroutable stanza, bouncing back to component")
                e = error.StanzaError('service-unavailable')
                xs.send(e.toResponse(stanza))
Ejemplo n.º 11
0
    def onPresenceUnavailable(self, stanza):
        """Handle unavailable presence stanzas."""
        if self.parent.logTraffic:
            log.debug("user unavailable: %s" % (stanza.toXml().encode('utf-8'), ))
        else:
            log.debug("user unavailable from %s" % (stanza['from'], ))

        # local c2s or remote server has disconnected, remove presences from cache
        try:
            unused, host = util.jid_component(stanza['from'], util.COMPONENT_C2S)
            if host in self.parent.keyring.hostlist():
                log.debug("server %s is disconnecting, taking over presence data" % (host, ))
                ordered_presence = []
                for stub in self.presence_cache.itervalues():
                    if stub.jid.host == stanza['from']:
                        ordered_presence.append(stub)

                # TEST TEST TEST
                # TODO this needs serious re-design from scratch (I mean the whole presence sharing architecture)
                from operator import attrgetter
                ordered_presence.sort(key=attrgetter('jid'))
                # take the N-th part
                index = 1
                for s in self.parent.keyring.hostlist():
                    # skip missing server
                    if s == host:
                        continue
                    # we found ourselves
                    if s == self.parent.servername:
                        break
                    index += 1

                if index > len(self.parent.keyring.hostlist()):
                    log.warn("we can't find ourselves on the servers table! WTF!?!?")

                else:
                    network_len = len(self.parent.keyring.hostlist())
                    presence_len = len(ordered_presence)
                    slice_start = presence_len / (network_len-1) * (index - 1)
                    slice_end = presence_len / (network_len-1) * ((index+1) - 1)
                    log.debug("slice_start = %d, slice_end = %d" % (slice_start, slice_end))
                    for i in range(slice_start, slice_end):
                        e = ordered_presence[i]
                        rewrite = None
                        presence = e.presence()
                        for p in presence:
                            if not p.hasAttribute('type'):
                                # available presence will be converted into unavailable
                                p['type'] = 'unavailable'

                            if p.getAttribute('type') == 'unavailable':
                                # unavailable presence will be broadcasted
                                rewrite = PresenceStub.fromElement(p, util
                                    .component_jid(self.parent.servername, util.COMPONENT_C2S))
                                self.presence_cache[e.jid.user] = rewrite

                        # simulate presence broadcast so resolvers will insert it into their cache
                        if rewrite:
                            p = rewrite.presence()
                            try:
                                fpr = self.parent.keyring.get_fingerprint(e.jid.user)
                                self.parent.presencedb.presence(p[0])
                                self.parent.presencedb.public_key(e.jid.user, fpr)
                            except keyring.KeyNotFoundException:
                                pass
                            self.send(p[0].toXml().encode('utf-8'))
            return

        except TypeError:
            pass
        except:
            import traceback
            traceback.print_exc()

        # normal user unavailable
        user = jid.JID(stanza['from'])

        if user.user:
            self.user_unavailable(stanza)
Ejemplo n.º 12
0
    def route(self, stanza, xs):
        """
        Route a stanza.

        @param stanza: The stanza to be routed.
        @type stanza: L{domish.Element}.
        """

        if stanza.consumed:
            return

        """"
        TEST check sender host is component
        stanzaFrom = jid.JID(stanza['from'])
        if stanzaFrom.host != xs.thisEntity.host:
            log.error("stanza is not from component - dropping")
            return
        """

        # reset namespace
        util.resetNamespace(stanza, component.NS_COMPONENT_ACCEPT)

        # send stanza to logging entities
        for lg in self.logs:
            lg.send(stanza)

        if not stanza.hasAttribute('to'):
            if self.logTraffic:
                log.debug("broadcasting stanza %s" % (stanza.toXml().encode('utf-8'), ))
            self.broadcast(stanza)
        else:
            """
            FIXME we have encoding problems here... (why not in other components?!?!?)
            """

            # check for stanza loops
            errors = 0
            for child in stanza.children:
                if domish.IElement.providedBy(child) and child.name == 'error':
                    errors += 1
                    if errors > 1:
                        if self.logTraffic:
                            log.debug("error loop, dropping stanza %s" % (stanza.toXml().encode('utf-8'), ))
                        else:
                            log.debug("error loop, dropping stanza")

                        return

            if self.logTraffic:
                log.debug("routing stanza %s" % (stanza.toXml().encode('utf-8'), ))
            try:
                destination_host = util.jid_host(stanza['to'])

                if destination_host in self.routes:
                    self.routes[destination_host].send(stanza)
                else:
                    self.routes[None].send(stanza)

            except KeyError:
                log.warn("unroutable stanza, bouncing back to component")
                e = error.StanzaError('service-unavailable')
                xs.send(xmlstream2.errorResponse(e, stanza))