Пример #1
0
    def validate_user(self, tx_id, code):
        if not code or len(code) != utils.VALIDATION_CODE_LENGTH:
            return c2s.ValidationResponse.STATUS_FAILED, None

        # lookup the verification code
        valdb = database.validations(self.broker.db)

        userid = valdb.get_userid(code)
        if userid:
            # damn unicode!
            userid = str(userid)

            # delete verification entry in validations table
            valdb.delete(code)
            # touch user so we get a first presence
            self.broker.usercache.touch_user(userid)

            # here is your token
            log.debug("[%s] generating token for %s" % (tx_id, userid))
            str_token = token.user_token(
                userid, str(self.config['server']['fingerprint']))
            return c2s.ValidationResponse.STATUS_SUCCESS, str_token

        else:
            return c2s.ValidationResponse.STATUS_FAILED, None
Пример #2
0
    def login(self,
              tx_id,
              auth_token,
              client_protocol=None,
              client_version=None,
              flags=0):
        '''Client is trying to login.'''
        # check protocol version
        if client_protocol < version.CLIENT_PROTOCOL:
            return c2s.LoginResponse.STATUS_PROTOCOL_MISMATCH, None

        if client_protocol:
            self.client_protocol = client_protocol
        self.flags = flags

        try:
            userid = token.verify_user_token(
                auth_token, self.broker.keyring,
                str(self.config['server']['fingerprint']))
        except:
            import traceback
            traceback.print_exc()
            log.debug("[%s] token verification failed: %s" %
                      (tx_id, auth_token))
            userid = None

        if userid:
            log.debug("[%s] user %s logged in." % (tx_id, userid))
            self.userid = userid
            self.broker.register_user_consumer(userid, self,
                                               self.can_broadcast_presence(),
                                               self.supports_mailbox())
            return c2s.LoginResponse.STATUS_LOGGED_IN, self.userid

        return c2s.LoginResponse.STATUS_AUTH_FAILED, None
Пример #3
0
 def conflict(self):
     '''Called on resource conflict.'''
     log.debug("resource conflict for %s" % self.userid)
     # the zombie flag prevents the disconnected() method to unregister from the broker
     # since any descriptor will be replaced by the new client connection
     self.zombie = True
     self.protocol.transport.loseConnection()
Пример #4
0
    def login(self, tx_id, auth_token, client_protocol = None, client_version = None, flags = 0):
        '''Client is trying to login.'''
        # check protocol version
        if client_protocol < version.CLIENT_PROTOCOL:
            return c2s.LoginResponse.STATUS_PROTOCOL_MISMATCH, None

        if client_protocol:
            self.client_protocol = client_protocol
        self.flags = flags

        try:
            userid = token.verify_user_token(auth_token, self.broker.keyring, str(self.config['server']['fingerprint']))
        except:
            import traceback
            traceback.print_exc()
            log.debug("[%s] token verification failed: %s" % (tx_id, auth_token))
            userid = None

        if userid:
            log.debug("[%s] user %s logged in." % (tx_id, userid))
            self.userid = userid
            self.broker.register_user_consumer(userid, self, self.can_broadcast_presence(), self.supports_mailbox())
            return c2s.LoginResponse.STATUS_LOGGED_IN, self.userid

        return c2s.LoginResponse.STATUS_AUTH_FAILED, None
Пример #5
0
    def render_GET(self, request):
        #log.debug("request from %s: %s" % (self.userid, request.args))
        if 'f' in request.args:
            fn = request.args['f'][0]
            info = self.fileserver.storage.get_extra(fn, self.userid)
            if info:
                (filename, mime, md5sum) = info
                log.debug("sending file type %s, path %s, md5sum %s" % (mime, filename, md5sum))
                genfilename = utils.generate_filename(mime)
                request.setHeader('content-type', mime)
                request.setHeader('content-length', os.path.getsize(filename))
                request.setHeader('content-disposition', 'attachment; filename="%s"' % (genfilename))
                request.setHeader('x-md5sum', md5sum)

                # stream file to the client
                fp = open(filename, 'rb')
                d = FileSender().beginFileTransfer(fp, request)
                def finished(ignored):
                    fp.close()
                    request.finish()
                d.addErrback(err).addCallback(finished)
                return server.NOT_DONE_YET

            # file not found in extra storage
            else:
                return self.not_found(request)

        return self.bad_request(request)
Пример #6
0
 def conflict(self):
     '''Called on resource conflict.'''
     log.debug("resource conflict for %s" % self.userid)
     # the zombie flag prevents the disconnected() method to unregister from the broker
     # since any descriptor will be replaced by the new client connection
     self.zombie = True
     self.protocol.transport.loseConnection()
Пример #7
0
    def validate(self, request):
        '''Check a validation code and generates a user token to login with.'''
        code = request.args['c'][0]
        if not code or len(code) != utils.VALIDATION_CODE_LENGTH:
            return utils.bad_request(request)

        # lookup the verification code
        valdb = database.validations(self.broker.db)

        userid = valdb.get_userid(code)
        if userid:
            # damn unicode!
            userid = str(userid)

            # delete verification entry in validations table
            valdb.delete(code)
            # touch user so we get a first presence
            self.broker.usercache.touch_user(userid)

            # here is your token
            log.debug("generating token for %s" % (userid, ))
            str_token = token.user_token(
                userid, str(self.broker.config['server']['fingerprint']))
            return {'auth': str_token, 'userid': userid}

        else:
            return utils.not_found(request)
Пример #8
0
    def validate(self, request):
        '''Check a validation code and generates a user token to login with.'''
        code = request.args['c'][0]
        if not code or len(code) != utils.VALIDATION_CODE_LENGTH:
            return utils.bad_request(request)

        # lookup the verification code
        valdb = database.validations(self.broker.db)

        userid = valdb.get_userid(code)
        if userid:
            # damn unicode!
            userid = str(userid)

            # delete verification entry in validations table
            valdb.delete(code)
            # touch user so we get a first presence
            self.broker.usercache.touch_user(userid)

            # here is your token
            log.debug("generating token for %s" % (userid, ))
            str_token = token.user_token(userid,
                str(self.broker.config['server']['fingerprint']))
            return {'auth': str_token, 'userid': userid }

        else:
            return utils.not_found(request)
Пример #9
0
    def validate_user(self, tx_id, code):
        if not code or len(code) != utils.VALIDATION_CODE_LENGTH:
            return c2s.ValidationResponse.STATUS_FAILED, None

        # lookup the verification code
        valdb = database.validations(self.broker.db)

        userid = valdb.get_userid(code)
        if userid:
            # damn unicode!
            userid = str(userid)

            # delete verification entry in validations table
            valdb.delete(code)
            # touch user so we get a first presence
            self.broker.usercache.touch_user(userid)

            # here is your token
            log.debug("[%s] generating token for %s" % (tx_id, userid))
            str_token = token.user_token(userid,
                str(self.config['server']['fingerprint']))
            return c2s.ValidationResponse.STATUS_SUCCESS, str_token

        else:
            return c2s.ValidationResponse.STATUS_FAILED, None
Пример #10
0
 def disconnected(self):
     if self.userid:
         addr = self.protocol.transport.getPeer()
         log.debug("user %s (%s) disconnected." % (self.userid, addr.host))
         if not self.zombie:
             self.broker.unregister_user_consumer(self.userid, self.can_broadcast_presence())
     else:
         log.debug("disconnected.")
Пример #11
0
 def revalidate(self):
     valdb = database.validations(self.broker.db)
     userid = self.userid[:utils.USERID_LENGTH] + utils.rand_str(8, utils.CHARSBOX_AZN_UPPERCASE)
     log.debug("revalidating user %s as %s" % (self.userid, userid))
     ret = valdb.update(userid)
     if ret[0] > 0:
         return ret[1]
     else:
         return False
Пример #12
0
 def data_uptime(self, context, data):
     uptime = long(self.broker.uptime())
     mins, secs = divmod(uptime, 60)
     hours, mins = divmod(mins, 60)
     days = long(hours / 24)
     log.debug((days, hours, mins))
     hours = hours % 24
     return '%d:%02d:%02d:%02d' % \
         (days, hours, mins, secs)
Пример #13
0
 def data_uptime(self, context, data):
     uptime = long(self.broker.uptime())
     mins, secs = divmod(uptime, 60)
     hours, mins = divmod(mins, 60)
     days = long(hours / 24)
     log.debug((days, hours, mins))
     hours = hours % 24
     return '%d:%02d:%02d:%02d' % \
         (days, hours, mins, secs)
Пример #14
0
 def disconnected(self):
     if self.userid:
         addr = self.protocol.transport.getPeer()
         log.debug("user %s (%s) disconnected." % (self.userid, addr.host))
         if not self.zombie:
             self.broker.unregister_user_consumer(
                 self.userid, self.can_broadcast_presence())
     else:
         log.debug("disconnected.")
Пример #15
0
 def notify(self, userid):
     if userid not in self._notify_cache:
         self._notify_cache[userid] = 0
         server = self._push_server(userid)
         if server:
             log.debug("pushing notification to %s" % userid)
             return server.notify()
     else:
         self._notify_cache[userid] += 1
Пример #16
0
 def notify(self, userid):
     if userid not in self._notify_cache:
         self._notify_cache[userid] = 0
         server = self._push_server(userid)
         if server:
             log.debug("pushing notification to %s" % userid)
             return server.notify()
     else:
         self._notify_cache[userid] += 1
Пример #17
0
    def startService(self):
        service.Service.startService(self)
        log.debug("HTTP endpoint init")
        self.storage = self.broker.storage

        # create http service
        factory = server.Site(Endpoint(self.config, self.broker))
        fs_service = internet.TCPServer(port=self.config['server']['endpoint.bind'][1],
            factory=factory, interface=self.config['server']['endpoint.bind'][0])
        fs_service.setServiceParent(self.parent)
Пример #18
0
 def broadcast(self, box, tx_id=None):
     # TODO handle shutdown: self.protocol.trasport is null!!
     jobs = []
     for fp in self.broker.keyring:
         # do not send to local server
         if self.protocol.fingerprint != fp:
             tx_id, d = self.protocol.sendBox(fp, box, tx_id)
             log.debug("sent broadcast to %s (%s)" % (fp, tx_id))
             jobs.append(d)
     return defer.gatherResults(jobs)
Пример #19
0
 def revalidate(self):
     valdb = database.validations(self.broker.db)
     userid = self.userid[:utils.USERID_LENGTH] + utils.rand_str(
         8, utils.CHARSBOX_AZN_UPPERCASE)
     log.debug("revalidating user %s as %s" % (self.userid, userid))
     ret = valdb.update(userid)
     if ret[0] > 0:
         return ret[1]
     else:
         return False
Пример #20
0
 def broadcast(self, box, tx_id = None):
     # TODO handle shutdown: self.protocol.trasport is null!!
     jobs = []
     for fp in self.broker.keyring:
         # do not send to local server
         if self.protocol.fingerprint != fp:
             tx_id, d = self.protocol.sendBox(fp, box, tx_id)
             log.debug("sent broadcast to %s (%s)" % (fp, tx_id))
             jobs.append(d)
     return defer.gatherResults(jobs)
Пример #21
0
 def notify(self):
     params = urllib.urlencode(
         {"registration_id": self.regid, "collapse_key": "new", "data.action": "org.kontalk.CHECK_MESSAGES"}
     )
     headers = {"Authorization": "key=" + self.token}
     req = urllib2.Request(self.url, params, headers)
     fd = urllib2.urlopen(req)
     # TODO what do we do with the output??
     data = fd.read()
     log.debug("data from gcm: %s" % (data,))
     fd.close()
     return data
Пример #22
0
 def __init__(self, path):
     log.debug("init dict-based storage on %s" % path)
     self._path = path
     try:
         os.makedirs(self._path)
     except:
         pass
     self._extra_path = os.path.join(path, 'extra')
     try:
         os.makedirs(self._extra_path)
     except:
         pass
Пример #23
0
    def __init__(self, path, db = None):
        log.debug("init MySQL storage")
        '''User messages cache.'''
        self._cache = {}
        self._extra_path = path
        try:
            os.makedirs(self._extra_path)
        except:
            pass

        self._db = db
        self._update_ds()
Пример #24
0
    def __init__(self, path, db=None):
        log.debug("init MySQL storage")
        '''User messages cache.'''
        self._cache = {}
        self._extra_path = path
        try:
            os.makedirs(self._extra_path)
        except:
            pass

        self._db = db
        self._update_ds()
Пример #25
0
    def startService(self):
        service.Service.startService(self)
        log.debug("HTTP endpoint init")
        self.storage = self.broker.storage

        # create http service
        factory = server.Site(Endpoint(self.config, self.broker))
        fs_service = internet.TCPServer(
            port=self.config['server']['endpoint.bind'][1],
            factory=factory,
            interface=self.config['server']['endpoint.bind'][0])
        fs_service.setServiceParent(self.parent)
Пример #26
0
 def __init__(self, path):
     log.debug("init dict-based storage on %s" % path)
     self._path = path
     try:
         os.makedirs(self._path)
     except:
         pass
     self._extra_path = os.path.join(path, 'extra')
     try:
         os.makedirs(self._extra_path)
     except:
         pass
Пример #27
0
 def _push_init(self):
     '''Sends push messages on startup for incoming messages.'''
     # FIXME this might trigger notifications even when it's not needed
     msglist = self.storage.load(None)
     for uhash, count in msglist.items():
         log.debug("push notifying user %s" % uhash)
         try:
             self.push_manager.notify_all(uhash)
         except:
             # TODO notify errors
             import traceback
             traceback.print_exc()
Пример #28
0
 def _push_init(self):
     '''Sends push messages on startup for incoming messages.'''
     # FIXME this might trigger notifications even when it's not needed
     msglist = self.storage.load(None)
     for uhash, count in msglist.items():
         log.debug("push notifying user %s" % uhash)
         try:
             self.push_manager.notify_all(uhash)
         except:
             # TODO notify errors
             import traceback
             traceback.print_exc()
Пример #29
0
    def startService(self):
        service.Service.startService(self)
        self.print_version()
        log.debug("broker init")

        self.storage = storage.__dict__[self.config['broker']['storage'][0]](*self.config['broker']['storage'][1:])
        self.usercache = usercache.__dict__[self.config['broker']['usercache'][0]](*self.config['broker']['usercache'][1:])

        # estabilish a connection to the database
        self.db = database.connect_config(self.config)
        # datasource it will not be used if not needed
        self.storage.set_datasource(self.db)
        self.usercache.set_datasource(self.db)

        # setup keyring
        sdb = database.servers(self.db)
        self.keyring = keyring.Keyring(sdb, self.fingerprint)

        # create push notifications manager
        if self.config['server']['push_notifications']:
            log.debug("enabling push notifications support")
            from push_notifications import PushNotifications
            self.push_manager = PushNotifications(self.config, self.db)

        # create listening service for clients
        factory = InternalServerFactory(C2SServerProtocol, C2SChannel, self, self.config)
        c2s_service = internet.TCPServer(port=self.config['server']['c2s.bind'][1],
            factory=factory, interface=self.config['server']['c2s.bind'][0])
        c2s_service.setServiceParent(self.parent)

        # create listening service for servers (messages only)
        factory = InternalServerFactory(S2SMessageServerProtocol, S2SMessageChannel, self, self.config)
        s2s_service = internet.TCPServer(port=self.config['server']['s2s.bind'][1],
            factory=factory, interface=self.config['server']['s2s.bind'][0])
        s2s_service.setServiceParent(self.parent)

        # create listening service for servers (notifications and requests)
        protocol = S2SRequestServerProtocol(self.config)
        self.network = S2SRequestChannel(protocol, self)
        s2s_service = internet.UDPServer(port=self.config['server']['s2s.bind'][1],
            protocol=protocol, interface=self.config['server']['s2s.bind'][0])
        s2s_service.setServiceParent(self.parent)

        if self.push_manager:
            self._push_init()

        # old usercache entries purger
        self._loop(self.config['broker']['usercache_purger.delay'], self._purge_usercache)
        # expired/unknown messages purger
        self._loop(self.config['broker']['message_purger.delay'], self._purge_messages, True)
        # old validations entries purger
        self._loop(self.config['broker']['validations.expire'], self._purge_validations, True)
Пример #30
0
    def register_user(self, tx_id, username):
        # hiding username for privacy reasons
        log.debug("[%s] registering user via %s" % (tx_id, self.config['registration']['type']))
        if self.config['registration']['type'] == 'sms':
            res = self._register_sms(username)
            d = { 'status' : res }
            if res == c2s.RegistrationResponse.STATUS_CONTINUE:
                    d['sms_from'] = self.config['registration']['from']
            return d

        else:
            # TODO support for other registration types
            return { 'status' : c2s.RegistrationResponse.STATUS_ERROR }
Пример #31
0
    def startService(self):
        service.Service.startService(self)
        log.debug("monitor init")
        self.storage = self.broker.storage
        self.db = self.broker.db

        # some static resources
        self.putChild('favicon.ico', static.File('monitor/favicon.ico'))

        # create http service
        factory = appserver.NevowSite(self)
        fs_service = internet.TCPServer(port=self.config['server']['monitor.bind'][1],
            factory=factory, interface=self.config['server']['monitor.bind'][0])
        fs_service.setServiceParent(self.parent)
Пример #32
0
 def notify(self):
     params = urllib.urlencode({
         'registration_id': self.regid,
         'collapse_key': 'new',
         'data.action': 'org.kontalk.CHECK_MESSAGES'
     })
     headers = {'Authorization': 'key=' + self.token}
     req = urllib2.Request(self.url, params, headers)
     fd = urllib2.urlopen(req)
     # TODO what do we do with the output??
     data = fd.read()
     log.debug("data from gcm: %s" % (data, ))
     fd.close()
     return data
Пример #33
0
    def render_POST(self, request):
        #log.debug("request from %s: %s" % (self.userid, request.requestHeaders))
        a = c2s.FileUploadResponse()

        # check mime type
        mime = request.getHeader('content-type')
        if mime not in self.config['fileserver']['accept_content']:
            a.status = c2s.FileUploadResponse.STATUS_NOTSUPPORTED
        else:
            # check length
            length = request.getHeader('content-length')
            if length != None:
                length = long(length)
                if length <= self.config['fileserver']['max_size']:
                    # store file to storage
                    # TODO convert to file-object management for lighter memory consumption
                    data = request.content.read()
                    if len(data) == length:
                        (filename, fileid) = self.fileserver.storage.extra_storage(('', ), mime, data)
                        log.debug("file stored to disk (filename=%s, fileid=%s)" % (filename, fileid))
                        a.status = c2s.FileUploadResponse.STATUS_SUCCESS
                        a.file_id = fileid
                    else:
                        log.debug("file length not matching content-length header (%d/%d)" % (len(data), length))
                        a.status = c2s.FileUploadResponse.STATUS_ERROR
                else:
                    log.debug("file too big (%d bytes)" % length)
                    a.status = c2s.FileUploadResponse.STATUS_BIG
            else:
                log.debug("content-length header not found")
                a.status = c2s.FileUploadResponse.STATUS_ERROR

        request.setHeader('content-type', 'application/x-google-protobuf')
        return a.SerializeToString()
Пример #34
0
    def register_user(self, tx_id, username):
        # hiding username for privacy reasons
        log.debug("[%s] registering user via %s" %
                  (tx_id, self.config['registration']['type']))
        if self.config['registration']['type'] == 'sms':
            res = self._register_sms(username)
            d = {'status': res}
            if res == c2s.RegistrationResponse.STATUS_CONTINUE:
                d['sms_from'] = self.config['registration']['from']
            return d

        else:
            # TODO support for other registration types
            return {'status': c2s.RegistrationResponse.STATUS_ERROR}
Пример #35
0
    def startService(self):
        service.Service.startService(self)
        log.debug("monitor init")
        self.storage = self.broker.storage
        self.db = self.broker.db

        # some static resources
        self.putChild('favicon.ico', static.File('monitor/favicon.ico'))

        # create http service
        factory = appserver.NevowSite(self)
        fs_service = internet.TCPServer(
            port=self.config['server']['monitor.bind'][1],
            factory=factory,
            interface=self.config['server']['monitor.bind'][0])
        fs_service.setServiceParent(self.parent)
Пример #36
0
    def post_message(self,
                     tx_id,
                     recipient=None,
                     mime=None,
                     flags=None,
                     content=None):
        '''User posted a message.'''
        #log.debug("[%s] posting message for: %s (mime=%s, flags=%s)" % (tx_id, str(recipient), mime, str(flags)))

        # are we sending an attachment message?
        attachment = 'attachment' in flags
        if attachment and mime in self.config['fileserver']['accept_content']:
            fileid = str(content)
            # TODO check for errors
            (filename, _mime,
             _md5sum) = self.broker.storage.get_extra(fileid, '')
            # update userids
            self.broker.storage.update_extra_storage(fileid, recipient)
            # TODO risking thumbnail larger than the max allowed size
            content = utils.generate_preview_content(filename, mime)
        else:
            filename = None

        res = {}
        for rcpt in recipient:
            u = str(rcpt)
            length = len(content)
            mime_supported = mime in self.config['fileserver']['accept_content'] \
                if attachment else mime in self.config['broker']['accept_content']
            if not mime_supported:
                log.debug("[%s] mime type not supported: %s - dropping" % \
                    (tx_id, mime))
                res[u] = c2s.MessagePostResponse.MessageSent.STATUS_NOTSUPPORTED
            elif length > self.config['broker']['max_size']:
                log.debug("[%s] message too big (%d bytes) - dropping" % \
                    (tx_id, length))
                res[u] = c2s.MessagePostResponse.MessageSent.STATUS_BIG
            else:
                misc = {'mime': mime, 'flags': flags}
                if filename:
                    misc['filename'] = fileid

                res[u] = self.broker.publish_user(self.userid, u, misc,
                                                  content,
                                                  broker.MSG_ACK_BOUNCE)

        return res
Пример #37
0
    def lookup_users(self, fingerprint, users):
        '''Lookup users connected locally.'''
        log.debug("request lookup from %s for %s" % (fingerprint, users))
        ret = []
        for u in users:
            nstat = {'userid' : u}
            stat = self.broker.usercache.get_user_data(u)
            if stat:
                if stat['status']:
                    nstat['status'] = stat['status']

                if not self.broker.user_online(u):
                    nstat['timestamp'] = stat['timestamp']

            ret.append(nstat)
        log.debug("lookup will return %s" % (ret, ))
        return ret
Пример #38
0
    def lookup_users(self, fingerprint, users):
        '''Lookup users connected locally.'''
        log.debug("request lookup from %s for %s" % (fingerprint, users))
        ret = []
        for u in users:
            nstat = {'userid': u}
            stat = self.broker.usercache.get_user_data(u)
            if stat:
                if stat['status']:
                    nstat['status'] = stat['status']

                if not self.broker.user_online(u):
                    nstat['timestamp'] = stat['timestamp']

            ret.append(nstat)
        log.debug("lookup will return %s" % (ret, ))
        return ret
Пример #39
0
    def login(self, request, data):
        '''Create a channel for the requested userid.'''
        try:
            auth = data['auth']
            userid = token.verify_user_token(auth, self.broker.keyring, self.broker.fingerprint)
        except:
            import traceback
            traceback.print_exc()
            log.debug("token verification failed!")
            return utils.unauthorized(request)

        sid = utils.rand_str(40, utils.CHARSBOX_AZN_LOWERCASE)
        ch = EndpointChannel(self, sid, userid)
        self.broker.register_user_consumer(userid, ch, supports_mailbox=True, pending=False)
        log.debug("user %s logged in." % (userid, ))

        self.channels[sid] = ch
        return { 'id' : sid }
Пример #40
0
    def post_message(self, tx_id, recipient = None, mime = None, flags = None, content = None):
        '''User posted a message.'''
        #log.debug("[%s] posting message for: %s (mime=%s, flags=%s)" % (tx_id, str(recipient), mime, str(flags)))

        # are we sending an attachment message?
        attachment = 'attachment' in flags
        if attachment and mime in self.config['fileserver']['accept_content']:
            fileid = str(content)
            # TODO check for errors
            (filename, _mime, _md5sum) = self.broker.storage.get_extra(fileid, '')
            # update userids
            self.broker.storage.update_extra_storage(fileid, recipient)
            # TODO risking thumbnail larger than the max allowed size
            content = utils.generate_preview_content(filename, mime)
        else:
            filename = None

        res = {}
        for rcpt in recipient:
            u = str(rcpt)
            length = len(content)
            mime_supported = mime in self.config['fileserver']['accept_content'] \
                if attachment else mime in self.config['broker']['accept_content']
            if not mime_supported:
                log.debug("[%s] mime type not supported: %s - dropping" % \
                    (tx_id, mime))
                res[u] = c2s.MessagePostResponse.MessageSent.STATUS_NOTSUPPORTED
            elif length > self.config['broker']['max_size']:
                log.debug("[%s] message too big (%d bytes) - dropping" % \
                    (tx_id, length))
                res[u] = c2s.MessagePostResponse.MessageSent.STATUS_BIG
            else:
                misc = {
                    'mime' : mime,
                    'flags' : flags
                }
                if filename:
                    misc['filename'] = fileid

                res[u] = self.broker.publish_user(self.userid, u, misc, content, broker.MSG_ACK_BOUNCE)

        return res
Пример #41
0
    def startService(self):
        service.Service.startService(self)
        if self.broker:
            # daemon mode - print init message
            log.debug("fileserver init")
            self.storage = self.broker.storage
            self.db = self.broker.db
            self.keyring = self.broker.keyring
        else:
            # standalone - print version
            self.print_version()
            # create storage and database connection on our own
            self.storage = storage.__dict__[self.config['broker']['storage'][0]](*self.config['broker']['storage'][1:])
            self.db = database.connect_config(self.config)
            self.storage.set_datasource(self.db)
            self.keyring = keyring.Keyring(database.servers(self.db), str(self.config['server']['fingerprint']))

        credFactory = utils.AuthKontalkTokenFactory(str(self.config['server']['fingerprint']), self.keyring)

        # setup upload endpoint
        portal = Portal(FileUploadRealm(self), [utils.AuthKontalkToken()])
        resource = HTTPAuthSessionWrapper(portal, [credFactory])
        self.putChild('upload', resource)

        # setup download endpoint
        portal = Portal(FileDownloadRealm(self), [utils.AuthKontalkToken()])
        resource = HTTPAuthSessionWrapper(portal, [credFactory])
        self.putChild('download', resource)

        # setup serverlist endpoint
        self.putChild('serverlist', ServerlistDownload(self))

        # create http service
        factory = server.Site(self)
        fs_service = internet.TCPServer(port=self.config['server']['fileserver.bind'][1],
            factory=factory, interface=self.config['server']['fileserver.bind'][0])
        fs_service.setServiceParent(self.parent)

        # old attachments entries purger
        self._loop(self.config['fileserver']['attachments_purger.delay'], self._purge_attachments, True)
Пример #42
0
    def login(self, request, data):
        '''Create a channel for the requested userid.'''
        try:
            auth = data['auth']
            userid = token.verify_user_token(auth, self.broker.keyring,
                                             self.broker.fingerprint)
        except:
            import traceback
            traceback.print_exc()
            log.debug("token verification failed!")
            return utils.unauthorized(request)

        sid = utils.rand_str(40, utils.CHARSBOX_AZN_LOWERCASE)
        ch = EndpointChannel(self, sid, userid)
        self.broker.register_user_consumer(userid,
                                           ch,
                                           supports_mailbox=True,
                                           pending=False)
        log.debug("user %s logged in." % (userid, ))

        self.channels[sid] = ch
        return {'id': sid}
Пример #43
0
    def _register_sms(self, n):
        # validate phone number syntax
        if not n or len(n.strip()) == 0:
            log.debug("number empty - %s" % n)
            return c2s.RegistrationResponse.STATUS_INVALID_USERNAME

        phone = phone_num = n.strip()
        # exclude the initial plus to verify the digits
        if (phone[0] == '+'):
            phone_num = phone[1:]

        # not all digits...
        if not phone_num.isdigit():
            log.debug("number is not all-digits - %s" % phone_num)
            return c2s.RegistrationResponse.STATUS_INVALID_USERNAME

        # replace double-zero with plus
        if phone[0:2] == '00':
            phone = '+' + phone[2:]

        # insert validation record
        # TODO do not use directly - let the storage module do it
        valdb = database.validations(self.broker.db)
        userid = utils.sha1(phone)

        # throttling :P
        if valdb.get_code(userid, True):
            return c2s.RegistrationResponse.STATUS_THROTTLING

        userid += utils.rand_str(8, utils.CHARSBOX_AZN_UPPERCASE)
        ret = valdb.update(userid)
        if ret[0] > 0:
            # send SMS
            code = ret[1]
            sms_from = self.config['registration']['from']

            if self.config['registration']['android_emu']:
                # android emulation
                import os
                os.system('adb emu sms send %s %s' % (sms_from, code))
            else:
                # send sms
                from nexmomessage import NexmoMessage
                msg = {
                    'reqtype' : 'json',
                    'username' : self.config['registration']['nx.username'],
                    'password': self.config['registration']['nx.password'],
                    'from': sms_from,
                    'to': phone
                }
                sms = NexmoMessage(msg)
                # FIXME send just the code for now
                sms.set_text_info(code)
                js = sms.send_request()
                log.debug("sms sent [response=%s]" % js)

            return c2s.RegistrationResponse.STATUS_CONTINUE
        else:
            return c2s.RegistrationResponse.STATUS_ERROR
Пример #44
0
    def _register_sms(self, n):
        # validate phone number syntax
        if not n or len(n.strip()) == 0:
            log.debug("number empty - %s" % n)
            return c2s.RegistrationResponse.STATUS_INVALID_USERNAME

        phone = phone_num = n.strip()
        # exclude the initial plus to verify the digits
        if (phone[0] == '+'):
            phone_num = phone[1:]

        # not all digits...
        if not phone_num.isdigit():
            log.debug("number is not all-digits - %s" % phone_num)
            return c2s.RegistrationResponse.STATUS_INVALID_USERNAME

        # replace double-zero with plus
        if phone[0:2] == '00':
            phone = '+' + phone[2:]

        # insert validation record
        # TODO do not use directly - let the storage module do it
        valdb = database.validations(self.broker.db)
        userid = utils.sha1(phone)

        # throttling :P
        if valdb.get_code(userid, True):
            return c2s.RegistrationResponse.STATUS_THROTTLING

        userid += utils.rand_str(8, utils.CHARSBOX_AZN_UPPERCASE)
        ret = valdb.update(userid)
        if ret[0] > 0:
            # send SMS
            code = ret[1]
            sms_from = self.config['registration']['from']

            if self.config['registration']['android_emu']:
                # android emulation
                import os
                os.system('adb emu sms send %s %s' % (sms_from, code))
            else:
                # send sms
                from nexmomessage import NexmoMessage
                msg = {
                    'reqtype': 'json',
                    'username': self.config['registration']['nx.username'],
                    'password': self.config['registration']['nx.password'],
                    'from': sms_from,
                    'to': phone
                }
                sms = NexmoMessage(msg)
                # FIXME send just the code for now
                sms.set_text_info(code)
                js = sms.send_request()
                log.debug("sms sent [response=%s]" % js)

            return c2s.RegistrationResponse.STATUS_CONTINUE
        else:
            return c2s.RegistrationResponse.STATUS_ERROR
Пример #45
0
    def message(self, request, data):
        '''Send a message.'''
        log.debug("sending message: %s" % (data, ))

        # TODO check for missing keys
        content = base64.b64decode(data['content'])
        mime = data['mime']

        # TODO attachments & flags
        attachment = False
        filename = None
        flags = []

        res = {}
        for rcpt in data['to']:
            u = str(rcpt)
            length = len(content)
            mime_supported = mime in self.broker.config['fileserver']['accept_content'] \
                if attachment else mime in self.broker.config['broker']['accept_content']
            if not mime_supported:
                log.debug("[%s] mime type not supported: %s - dropping" % \
                    (tx_id, mime))
                res[u] = c2s.MessagePostResponse.MessageSent.STATUS_NOTSUPPORTED
            elif length > self.broker.config['broker']['max_size']:
                log.debug("[%s] message too big (%d bytes) - dropping" % \
                    (tx_id, length))
                res[u] = c2s.MessagePostResponse.MessageSent.STATUS_BIG
            else:
                misc = {
                    'mime' : mime,
                    'flags' : flags
                }
                if filename:
                    misc['filename'] = fileid

                res[u] = self.broker.publish_user(self.userid, u, misc, content, broker.MSG_ACK_BOUNCE)

        log.debug("message sent! %s" % (res, ))
        return res
Пример #46
0
    def message(self, request, data):
        '''Send a message.'''
        log.debug("sending message: %s" % (data, ))

        # TODO check for missing keys
        content = base64.b64decode(data['content'])
        mime = data['mime']

        # TODO attachments & flags
        attachment = False
        filename = None
        flags = []

        res = {}
        for rcpt in data['to']:
            u = str(rcpt)
            length = len(content)
            mime_supported = mime in self.broker.config['fileserver']['accept_content'] \
                if attachment else mime in self.broker.config['broker']['accept_content']
            if not mime_supported:
                log.debug("[%s] mime type not supported: %s - dropping" % \
                    (tx_id, mime))
                res[u] = c2s.MessagePostResponse.MessageSent.STATUS_NOTSUPPORTED
            elif length > self.broker.config['broker']['max_size']:
                log.debug("[%s] message too big (%d bytes) - dropping" % \
                    (tx_id, length))
                res[u] = c2s.MessagePostResponse.MessageSent.STATUS_BIG
            else:
                misc = {'mime': mime, 'flags': flags}
                if filename:
                    misc['filename'] = fileid

                res[u] = self.broker.publish_user(self.userid, u, misc,
                                                  content,
                                                  broker.MSG_ACK_BOUNCE)

        log.debug("message sent! %s" % (res, ))
        return res
Пример #47
0
    def authenticate(self, tx_id, auth_token):
        '''Client tried to authenticate.'''
        log.debug("[%s] deprecated authentication mode" % (tx_id, ))
        try:
            userid = token.verify_user_token(auth_token, self.broker.keyring, str(self.config['server']['fingerprint']))
        except:
            import traceback
            traceback.print_exc()
            log.debug("[%s] token verification failed: %s" % (tx_id, auth_token))
            userid = None

        if userid:
            log.debug("[%s] user %s logged in." % (tx_id, userid))
            self.userid = userid
            self.broker.register_user_consumer(userid, self)
            return True

        return False
Пример #48
0
    def authenticate(self, tx_id, auth_token):
        '''Client tried to authenticate.'''
        log.debug("[%s] deprecated authentication mode" % (tx_id, ))
        try:
            userid = token.verify_user_token(
                auth_token, self.broker.keyring,
                str(self.config['server']['fingerprint']))
        except:
            import traceback
            traceback.print_exc()
            log.debug("[%s] token verification failed: %s" %
                      (tx_id, auth_token))
            userid = None

        if userid:
            log.debug("[%s] user %s logged in." % (tx_id, userid))
            self.userid = userid
            self.broker.register_user_consumer(userid, self)
            return True

        return False
Пример #49
0
 def _error(result, local_users, deferred):
     log.debug("error in lookup: %s / %s / %s" % (result, local_users, deferred))
     deferred.callback(local_users)
Пример #50
0
    def ack_user(self, sender, msgid_list):
        '''Manually acknowledge a message.'''

        # result returned to the confirming client
        res = {}
        # message receipts grouped by recipient
        rcpt_list = {}

        # retrieve messages that needs to be acknowledged
        # FIXME this is totally inefficient - this call will select all user
        # messages everytime an ack request is sent by the client!!!
        db = self.storage.load(sender)

        for msgid in msgid_list:
            try:
                # search message in list
                msg = None
                for entry in db:
                    if entry['messageid'] == msgid:
                        msg = entry
                        break
                if not msg:
                    raise KeyError

                if msg['need_ack'] == MSG_ACK_BOUNCE:
                    #log.debug("found message to be acknowledged - %s" % msgid)

                    # group receipts by user so we can batch send
                    backuser = msg['sender']
                    if backuser not in rcpt_list:
                        rcpt_list[backuser] = []

                    e = {
                        'messageid' : msgid if 'originalid' not in msg else msg['originalid'],
                        'storageid' : msgid,
                        'status' : c2s.ReceiptMessage.Entry.STATUS_SUCCESS,
                        'timestamp' : datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')
                    }
                    rcpt_list[backuser].append(e)

                res[msgid] = True

            except:
                log.debug("message not found - %s" % msgid)
                res[msgid] = False

        # push the receipts back to the senders
        for backuser, msglist in rcpt_list.iteritems():
            r = c2s.ReceiptMessage()
            for m in msglist:
                e = r.entry.add()
                e.message_id = m['messageid']
                e.status = m['status']
                e.timestamp = m['timestamp']

            if not self.publish_user(sender, backuser, { 'mime' : MIME_RECEIPT, 'flags' : [] }, r.SerializeToString(), MSG_ACK_MANUAL):
                # mark the messages NOT SAFE to delete
                for m in msglist:
                    res[m['storageid']] = False

        # it's safe to delete the messages now
        for msgid, safe in res.iteritems():
            if safe:
                self.storage.delete(sender, msgid)

        return res
Пример #51
0
    def startService(self):
        service.Service.startService(self)
        self.print_version()
        log.debug("broker init")

        self.storage = storage.__dict__[self.config['broker']['storage'][0]](
            *self.config['broker']['storage'][1:])
        self.usercache = usercache.__dict__[
            self.config['broker']['usercache'][0]](
                *self.config['broker']['usercache'][1:])

        # estabilish a connection to the database
        self.db = database.connect_config(self.config)
        # datasource it will not be used if not needed
        self.storage.set_datasource(self.db)
        self.usercache.set_datasource(self.db)

        # setup keyring
        sdb = database.servers(self.db)
        self.keyring = keyring.Keyring(sdb, self.fingerprint)

        # create push notifications manager
        if self.config['server']['push_notifications']:
            log.debug("enabling push notifications support")
            from push_notifications import PushNotifications
            self.push_manager = PushNotifications(self.config, self.db)

        # create listening service for clients
        factory = InternalServerFactory(C2SServerProtocol, C2SChannel, self,
                                        self.config)
        c2s_service = internet.TCPServer(
            port=self.config['server']['c2s.bind'][1],
            factory=factory,
            interface=self.config['server']['c2s.bind'][0])
        c2s_service.setServiceParent(self.parent)

        # create listening service for servers (messages only)
        factory = InternalServerFactory(S2SMessageServerProtocol,
                                        S2SMessageChannel, self, self.config)
        s2s_service = internet.TCPServer(
            port=self.config['server']['s2s.bind'][1],
            factory=factory,
            interface=self.config['server']['s2s.bind'][0])
        s2s_service.setServiceParent(self.parent)

        # create listening service for servers (notifications and requests)
        protocol = S2SRequestServerProtocol(self.config)
        self.network = S2SRequestChannel(protocol, self)
        s2s_service = internet.UDPServer(
            port=self.config['server']['s2s.bind'][1],
            protocol=protocol,
            interface=self.config['server']['s2s.bind'][0])
        s2s_service.setServiceParent(self.parent)

        if self.push_manager:
            self._push_init()

        # old usercache entries purger
        self._loop(self.config['broker']['usercache_purger.delay'],
                   self._purge_usercache)
        # expired/unknown messages purger
        self._loop(self.config['broker']['message_purger.delay'],
                   self._purge_messages, True)
        # old validations entries purger
        self._loop(self.config['broker']['validations.expire'],
                   self._purge_validations, True)
Пример #52
0
 def _incoming(self, data):
     # TODO
     log.debug("incoming message:", data)
Пример #53
0
 def disconnected(self):
     log.debug("disconnected.")
     if self.fingerprint:
         self.broker.unregister_server_queue(self.fingerprint)
Пример #54
0
 def _error(result, local_users, deferred):
     log.debug("error in lookup: %s / %s / %s" %
               (result, local_users, deferred))
     deferred.callback(local_users)
Пример #55
0
 def conflict(self):
     '''Called on resource conflict.'''
     log.debug("resource conflict for %s" % self.userid)
     self.zombie = True
     self.endpoint.destroy(self.sessionid)
Пример #56
0
    def ack_user(self, sender, msgid_list):
        '''Manually acknowledge a message.'''

        # result returned to the confirming client
        res = {}
        # message receipts grouped by recipient
        rcpt_list = {}

        # retrieve messages that needs to be acknowledged
        # FIXME this is totally inefficient - this call will select all user
        # messages everytime an ack request is sent by the client!!!
        db = self.storage.load(sender)

        for msgid in msgid_list:
            try:
                # search message in list
                msg = None
                for entry in db:
                    if entry['messageid'] == msgid:
                        msg = entry
                        break
                if not msg:
                    raise KeyError

                if msg['need_ack'] == MSG_ACK_BOUNCE:
                    #log.debug("found message to be acknowledged - %s" % msgid)

                    # group receipts by user so we can batch send
                    backuser = msg['sender']
                    if backuser not in rcpt_list:
                        rcpt_list[backuser] = []

                    e = {
                        'messageid':
                        msgid
                        if 'originalid' not in msg else msg['originalid'],
                        'storageid':
                        msgid,
                        'status':
                        c2s.ReceiptMessage.Entry.STATUS_SUCCESS,
                        'timestamp':
                        datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')
                    }
                    rcpt_list[backuser].append(e)

                res[msgid] = True

            except:
                log.debug("message not found - %s" % msgid)
                res[msgid] = False

        # push the receipts back to the senders
        for backuser, msglist in rcpt_list.iteritems():
            r = c2s.ReceiptMessage()
            for m in msglist:
                e = r.entry.add()
                e.message_id = m['messageid']
                e.status = m['status']
                e.timestamp = m['timestamp']

            if not self.publish_user(sender, backuser, {
                    'mime': MIME_RECEIPT,
                    'flags': []
            }, r.SerializeToString(), MSG_ACK_MANUAL):
                # mark the messages NOT SAFE to delete
                for m in msglist:
                    res[m['storageid']] = False

        # it's safe to delete the messages now
        for msgid, safe in res.iteritems():
            if safe:
                self.storage.delete(sender, msgid)

        return res
Пример #57
0
 def logout(self, request):
     log.debug("user %s logged out." % (self.userid))
     if not self.zombie:
         self.broker.unregister_user_consumer(self.userid)
     # destroy session
     self.endpoint.destroy(self.sessionid)