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
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
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()
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
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)
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)
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)
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
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.")
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
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)
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.")
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
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)
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)
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
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)
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
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
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()
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()
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)
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()
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)
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 }
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)
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
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()
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}
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)
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
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
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
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 }
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
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)
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}
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
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
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
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
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
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
def _error(result, local_users, deferred): log.debug("error in lookup: %s / %s / %s" % (result, local_users, deferred)) deferred.callback(local_users)
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
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)
def _incoming(self, data): # TODO log.debug("incoming message:", data)
def disconnected(self): log.debug("disconnected.") if self.fingerprint: self.broker.unregister_server_queue(self.fingerprint)
def conflict(self): '''Called on resource conflict.''' log.debug("resource conflict for %s" % self.userid) self.zombie = True self.endpoint.destroy(self.sessionid)
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
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)