def heartbeat(self, method, id, **kwargs): """ .. py:func:: heartbeat(method, id, **kwargs) Registers a kiosks IP address, software version and uptime in the datastore. :param method: The name of the requested json method (should be equal to 'heartbeat') :param id: Unused :param **kwargs: Keyword arguments to the function. Should have non-unicode keys. :rtype dict: The response object. Expects the following in kwargs: kiosk-id : The unique kiosk identifier uptime: A string representing the time elapsed since the script executed. sw_version: Version of the datalogger software running on the device. time: The UTC time on the datalogger. Expects the following headers: X-eko-signature: RSA signed hash of request body. """ # extract arguments dieid = kwargs['kiosk-id'] logging.debug('Device with id : %s has a pulse from %s.' % (dieid, self.request.remote_addr)) uptime = kwargs['uptime'] sw_version = kwargs['sw-version'] local_inetadr = kwargs['rwanda-ip'] time = kwargs['time'] # find the kiosk from the kiosk id kiosk = Kiosk.kiosk_from_dieid(dieid) if not kiosk: logging.warn('Unrecognised kiosk attempted %s (IP: %s, sw_version: %s, dieid: %s).' % (method, self.request.remote_addr, sw_version, dieid)) return self._standard_error_response(method, id, 'Not recognised', 20, 'Kiosk not registered with system.') # log this event logging.info('Receiving kiosk heartbeat from kiosk %s at IP %s' % (kiosk.name, self.request.remote_addr)) hash, signature = self._extract_signature_hdr() if not signature[0]: # prepare error response return self._standard_error_response(method, id, 'Signature Absent', 10, 'Verification signature not present.') pubkey = self._get_public_key(kiosk) if not pubkey: return self._standard_error_response(method, id, 'Signature Fail', 11, 'Unable to create public key from config.') if pubkey and signature: if pubkey.verify(hash, signature): #message is authentic self._create_heartbeat(kiosk, uptime, sw_version, time, self.request.remote_addr, local_inetadr) data = {} data['result'] = 'Success' data['error'] = None data['id'] = id return data else: return self._standard_error_response(method, id, 'Signature Incorrect', 12, 'Verification signature failed check.')
def post(self): logging.debug('Running File Upload Handler') bconv = BaseConverter('0123456789abcdef') dieid = self.request.get('kiosk-id') if not dieid: self.error(403) self.response.write('No device id provided.\n') logger.warn('Device attempted contact without die id from ip %s.' % self.request.remote_addr) return logging.info("File upload incoming from kiosk : %s" % dieid) kiosk = Kiosk.kiosk_from_dieid(dieid) if not kiosk: self.error(400) self.response.write('Kiosk is unregistered on system.\n') logging.warn('Unregistered kiosk on ip %s with dieid %s.' % (self.request.remote_addr, dieid)) return logging.debug("Encoded sig: %s." % self.request.headers['X-eko-signature']) # look for the signature try: signature = bconv.to_decimal(self.request.headers['X-eko-signature']) logging.debug("Decoded sig: %s." % str(signature)) challenge = self.request.headers['X-eko-challenge'] logging.debug("Challenge: %s." % challenge) # signature should be uuid we sent kiosk signed with the public key verify = self._verify_client(kiosk, signature, challenge) except: logging.exception("Authentication signature not found.\n") verify = False # auth failed if not verify: logging.error("Kiosk id %s did not pass id check." % dieid) self.response.write('Unable to verify identity of kiosk.\n') return # a uuid that identifies this data packet on the remote device client_ref = self.request.headers['X-eko-challenge'] if not client_ref: logging.error("No client reference provided.") self.response.write('Client Error: No reference provided.') return # the type of data being sent (logs, readings, etc...) type = self.request.get('type') # version of the client software_version = self.request.get('software_version') # manifest try: manifest = self.get_uploads(field_name='manifest')[0] logging.debug("Manifest uploaded, size: %s" % str(manifest.size)) except: logging.exception("Manifest missing from upload data.") self.response.write('Manifest Not Found\n') # payload try: payload = self.get_uploads(field_name='payload')[0] except: logging.exception("Payload missing from upload data.") self.response.write('Payload Not Found\n') sync = SyncSession.get_by_clientref(client_ref) if not sync: logging.error("Upload attempt without requesting sync session.") self.response.write('Upload request improperly handled.') return sync.kiosk = kiosk sync.data_type = type sync.payload_size = 0 # payload size + manifest size if payload: sync.payload_size += payload.size if manifest: sync.payload_size += manifest.size sync.payload = payload sync.manifest = manifest sync.software_version = software_version #sync.client_ip = self.request.remote_addr sync.end_date = datetime.utcnow() try: sync.put() logging.debug("Sync packet succesfully added to datastore") self.response.write('Success\n') except: logging.exception("Adding sync packet failed.") self.response.write('Failure\n') return
def testUpdatingCachedEntityFromDb(self): """Get a entity from db, change it and put back. Then get it from cache and compare.""" aq = db.GqlQuery("SELECT * FROM Kiosk WHERE dieid = :1", 'A') a = aq.get() ## we set the value in memcache memcache.set(a.dieid, a, namespace="kiosks") a.name = "Baz" a.put() b = Kiosk.kiosk_from_dieid('A') self.assertEqual(a.name, b.name) self.assertEqual(1, aq.count())
def get_messages(self, method, id, **kwargs): """ .. py:func:: get_messages(method, id, **kwargs) Returns all server messages that are pending for the kiosk. :param method: The name of the requested json method (should be equal to 'get_messages') :param id: Unused :param **kwargs: Keyword arguments to the function. Should have non-unicode keys. :rtype dict: The response object. Expects the following in kwargs: kiosk-id : The unique kiosk identifier Expects the following headers: X-eko-signature: RSA signed hash of request body. """ dieid = kwargs['kiosk-id'] logging.debug('device with id : %s is requesting incoming messages.' % dieid) # grab kiosk, internally utilises memcache kiosk = Kiosk.kiosk_from_dieid(dieid) if not kiosk: logging.warn('Unrecognised kiosk attempted to fetch server messages (IP: %s, dieid %s).' % (self.request.remote_addr, dieid)) return self._standard_error_response(method, id, 'Not recognised', 20, 'Kiosk not registered with system.') logging.info('Receiving message fetch request from kiosk %s at IP %s' % (kiosk.name, self.request.remote_addr)) hash, signature = self._extract_signature_hdr() if not signature[0]: # prepare error response return self._standard_error_response(method, id, 'Signature Absent', 10, 'Verification signature not present.') pubkey = self._get_public_key(kiosk) if not pubkey: return self._standard_error_response(method, id, 'Signature Fail', 11, 'Unable to create public key from config.') if pubkey and signature[0]: if pubkey.verify(hash, signature): #message is authentic messages = self._get_server_messages(kiosk) data = {} data['result'] = messages data['error'] = None data['id'] = id return data else: return self._standard_error_response(method, id, 'Signature Incorrect', 12, 'Verification signature failed check.')
def get(self): upload_url = blobstore.create_upload_url('/api/upload') challenge = str(uuid1().get_hex()) self.response.headers['X-eko-challenge'] = challenge dieid = self.request.get('kiosk-id') kiosk = Kiosk.kiosk_from_dieid(dieid) # we create a sync session sess = SyncSession() sess.client_ref = challenge sess.client_ip = self.request.remote_addr sess.kiosk = kiosk sess.start_date = datetime.utcnow() sess.put() self.response.headers['client-ip'] = self.request.remote_addr self.response.write(upload_url) return
def get(self, dieid): user = users.get_current_user() ctx = self.get_ctx(user) if user: kiosk = Kiosk.kiosk_from_dieid(dieid) if not kiosk: self.error(404) return ctx['kiosk'] = kiosk helper = KioskFeedHelper(user) ctx['heartbeat'] = helper.getMostRecentHeartbeat(kiosk) twomonthsago = datetime.utcnow() - timedelta(days=60) logging.debug("SyncSessions since %s." % (twomonthsago.strftime("%d%b%Y"))) syncsessions = memcache.get(dieid, namespace='syncsessions') if not syncsessions: syncsessions = kiosk.syncsession_set.fetch(100) logging.debug("%d syncsessions fetched." % len(syncsessions)) memcache.set(dieid, syncsessions, 60*60, namespace="syncsessions") ctx['sync_sessions'] = syncsessions else: self.redirect(users.create_login_url(self.request.uri)) self.render_response('sync_list.html', **ctx)
def _commit_to_store(self, data): k = Kiosk() k.populate_from_dict(data) k.put() self.session.add_flash('Kiosk record created for %s at %s' % (data['name'], data['loc']), 'ok')
def create_dummy_kiosk(self): user = users.get_current_user() k = Kiosk() k.dieid = "A" k.name = "Foo" k.hardware = "Bar" k.admin = user k.put() # self.a = k k1 = Kiosk() k1.dieid = "B" k1.name = "Foo" k1.hardware = "Bar" k1.admin = user k1.put() self.b = k1 return (k, k1)
def post_messages(self, method, id, **kwargs): """ .. py:func:: post_messages(method, id, **kwargs) Registers a message from a kiosk in the datastore. :param method: The name of the requested json method (should be equal to 'post_messages') :param id: Unused :param **kwargs: Keyword arguments to the function. Should have non-unicode keys. :rtype dict: The response object. Expects the following in kwargs: kiosk-id : The unique kiosk identifier message: A text message. origin: The origin of the message (subsystem). date: The UTC time on the datalogger that the message originated. [session-ref] : An optional reference to a upload session. Expects the following headers: X-eko-signature: RSA signed hash of request body. """ # extract arguments dieid = kwargs['kiosk-id'] logging.debug('Device with id : %s has a pulse from %s.' % (dieid, self.request.remote_addr)) messages = kwargs['messages'] # find the kiosk from the kiosk id logging.debug('device with id : %s has a pulse.' % dieid) kiosk = Kiosk.kiosk_from_dieid(dieid) if not kiosk: logging.warn('Unrecognised kiosk attempted %s (IP: %s, dieid: %s).' % (method, self.request.remote_addr, dieid)) return self._standard_error_response(method, id, 'Not recognised', 20, 'Kiosk not registered with system.') # log this event logging.info('Receiving %d kiosk messages from kiosk %s at IP %s' % (len(messages), kiosk.name, self.request.remote_addr)) hash, signature = self._extract_signature_hdr() if not signature[0]: # prepare error response return self._standard_error_response(method, id, 'Signature Absent', 10, 'Verification signature not present.') pubkey = self._get_public_key(kiosk) if not pubkey: return self._standard_error_response(method, id, 'Signature Fail', 11, 'Unable to create public key from config.') if pubkey and signature: if pubkey.verify(hash, signature): #message is authentic for message in messages: self._create_clientmsg(kiosk, message, self.request.remote_addr) data = {} data['result'] = 'Success' data['error'] = None data['id'] = id return data else: return self._standard_error_response(method, id, 'Signature Incorrect', 12, 'Verification signature failed check.')