def __process_worker_update(self, worker_id, input_json_str, response): """ Function to update the worker details. Parameters: - worker_id is the worker id specified in the input json str. - input_json_str is a worker request json as per TCF API 5.3.2 Worker Update JSON Payload - response is the response object to be returned to client. """ jrpc_id = json.loads(input_json_str)["id"] # value retrieved is 'result' field as per Spec 5.3.8 Worker Retrieve Response Payload value = self.kv_helper.get("workers", worker_id) if value is not None: json_dict = json.loads(value) input_value = json.loads(input_json_str) worker_details = input_value["params"]["details"] for item in worker_details: json_dict["details"][item] = worker_details[item] value = json.dumps(json_dict) self.kv_helper.set("workers", worker_id, value) response = utility.create_error_response(WorkerError.SUCCESS, jrpc_id, "Successfully Updated") else: response = utility.create_error_response( WorkerError.INVALID_PARAMETER_FORMAT_OR_VALUE, jrpc_id, "Worker Id not found in the database. \ Hence invalid parameter") return response
def __process_work_order_get_result(self, wo_id, jrpc_id, response): """ Function to process work order get result This API corresponds to TCF API 6.1.4 Work Order Pull Request Payload Parameters: - wo_id is work order id - jrpc_id is JRPC id of response - response is the response object to be returned """ # Work order is processed if it is in wo-response table value = self.kv_helper.get("wo-responses", wo_id) if value: input_value = json.loads(value) if 'result' in value: response['result'] = input_value['result'] else: response['result'] = input_value['error'] else: if (self.kv_helper.get("wo-timestamps", wo_id) is not None): # work order is yet to be processed response = utility.create_error_response( WorkorderError.PENDING, jrpc_id, "Work order result is yet to be updated") else: # work order not in 'wo-timestamps' table response = utility.create_error_response( WorkorderError.INVALID_PARAMETER_FORMAT_OR_VALUE, jrpc_id, "Work order Id not found in the database. \ Hence invalid parameter") return response
def __process_worker_set_status(self, worker_id, input_json_str, response): """ Function to set the status of worker Parameters: - worker_id is the worker id specified in the input json str. - input_json_str is a worker request json as per TCF API 5.3.3 Worker Set Status JSON Payload - response is the response object to be returned to client. """ #status can be one of active, offline, decommissioned, or compromised input_value = json.loads(input_json_str) jrpc_id = input_value["id"] value = self.kv_helper.get("workers", worker_id) if value: json_dict = json.loads(value) json_dict['status'] = input_value['params']['status'] value = json.dumps(json_dict) self.kv_helper.set("workers", worker_id, value) response = utility.create_error_response( WorkerError.SUCCESS, jrpc_id, "Successfully Set Status") else: response = utility.create_error_response( WorkerError.INVALID_PARAMETER_FORMAT_OR_VALUE, jrpc_id, "Worker Id not found in the database. \ Hence invalid parameter") return response
def __process_worker_register(self, worker_id, input_json_str, response): """ Function to register a new worker to the enclave Parameters: - worker_id is the worker id specified in the input json str. - input_json_str is a worker request json as per TCF API 5.3.1 Worker Register JSON Payload. - response is the response object to be returned to client. """ input_value_json = json.loads(input_json_str) jrpc_id = input_value_json["id"] if (self.kv_helper.get("workers", worker_id) is None): input_value = {} input_value = input_value_json['params'] # Worker Initial Status is set to Active input_value["status"] = WorkerStatus.ACTIVE input_json_str = json.dumps(input_value) self.kv_helper.set("workers", worker_id, input_json_str) response = utility.create_error_response( WorkerError.SUCCESS, jrpc_id, "Successfully Registered") else: response = utility.create_error_response( WorkerError.INVALID_PARAMETER_FORMAT_OR_VALUE, jrpc_id, "Worker Id already exists in the database. \ Hence invalid parameter") return response
def render_POST(self, request): response = {} logger.info('Received a new request from the client') try: # process the message encoding encoding = request.getHeader('Content-Type') data = request.content.read() if encoding == 'application/json': try: input_json_str = json.loads(data.decode('utf-8')) input_json = json.loads(input_json_str) jrpc_id = input_json["id"] response = self._process_request(input_json_str) except AttributeError: logger.error("Error while loading input json") response = utility.create_error_response( WorkorderError.UNKNOWN_ERROR, jrpc_id, "UNKNOWN_ERROR: Error while loading the input JSON file" ) return response else: # JRPC response with 0 as id is returned because id can't be fecthed # from a request with unknown encoding response = utility.create_error_response( WorkorderError.UNKNOWN_ERROR, 0, "UNKNOWN_ERROR: unknown message encoding") return response except: logger.exception('exception while decoding http request %s', request.path) # JRPC response with 0 as id is returned because id can't be # fetched from improper request response = utility.create_error_response( WorkorderError.UNKNOWN_ERROR, 0, "UNKNOWN_ERROR: unable to decode incoming request") return response # send back the results try: if encoding == 'application/json': response = json.dumps(response) logger.info('response[%s]: %s', encoding, response) request.setHeader('content-type', encoding) request.setResponseCode(http.OK) return response.encode('utf8') except: logger.exception('unknown exception while processing request %s', request.path) response = utility.create_error_response( WorkorderError.UNKNOWN_ERROR, jrpc_id, "UNKNOWN_ERROR: unknown exception processing http \ request {0}".format(request.path)) return response
def __process_workorder_receipt_retrieve(self,wo_id, jrpc_id, response): """ Function to retrieve the details of worker Parameters: - worker_id is the worker id specified in worker request json as per TCF API 7.2.4 Receipt Retrieve Request Payload - response is the response object to be returned to client - jrpc_id is the jrpc id of response object to be returned to client """ # value retrieved is 'result' field as per Spec 7.2.5 Receipt Retrieve Response Payload value = self.kv_helper.get("wo-receipts", wo_id) if value: input_value = json.loads(value) response['result'] = {} if 'result' in value : response['result'] = input_value['result'] else: #Need to revisit code when actual receipts are created response['result'] = input_value['error'] else : response = utility.create_error_response( WorkorderError.INVALID_PARAMETER_FORMAT_OR_VALUE, jrpc_id, "Work order id not found in the database. \ Hence invalid parameter") return response return response
def __process_worker_retrieve(self, worker_id, response): """ Function to retrieve the details of worker Parameters: - worker_id is the worker id specified in worker request json as per TCF API 5.3.7 Worker Retrieve JSON Payload - response is the response object to be returned to client. """ # value retrieved is 'result' field as per Spec 5.3.8 Worker Retrieve Response Payload value = self.kv_helper.get("workers", worker_id) if value is not None: json_dict = json.loads(value) response["result"] = {} response["result"]["workerType"] = json_dict["workerType"] response["result"]["organizationId"] = json_dict["organizationId"] response["result"]["applicationTypeId"] = json_dict[ "applicationTypeId"] response["result"]["details"] = json_dict["details"] response["result"]["status"] = json_dict["status"] else: jrpc_id = json.loads(response)["id"] response = utility.create_error_response( WorkerError.INVALID_PARAMETER_FORMAT_OR_VALUE, jrpc_id, "Worker Id not found in the database. Hence invalid parameter") return response
def __process_workorder_receipt_update(self, wo_id, input_json_str, response): """ Function to process update work order request Parameters: - wo_id is work order id - input_json_str is work order receipt update json as per TCF API 7.2.6 Receipt Update Retrieve Request Payload - response is the response object to be returned to client """ input_value = json.loads(input_json_str) jrpc_id = input_value["id"] # value retrieved is 'result' field as per Spec 7.2.5 Receipt Retrieve Response Payload value = self.kv_helper.get("wo-receipts", wo_id) response['error'] = {} if value : updater_value = input_value['params'] # WorkorderId already a part of receipt. And will be not change for a given receipt. Hence it's not stored in updater param. del updater_value['workOrderId'] json_dict = json.loads(value) updater_objects = json_dict['result']['updater'] if len(updater_objects)>0 : # Updater Object is sorted based on index and then last index is chosen index = int(sorted(updater_objects.keys())[-1]) + 1 else : index = 0 updater_objects[index] = updater_value json_dict['result']['receiptCurrentStatus'] = updater_value['updateType'] json_dict['result']['updater'] = updater_objects value = json.dumps(json_dict) self.kv_helper.set("wo-receipts", wo_id, value) response = utility.create_error_response( WorkorderError.SUCCESS, jrpc_id, "Receipt Successfully Updated") else: response = utility.create_error_response( WorkorderError.INVALID_PARAMETER_FORMAT_OR_VALUE, jrpc_id, "Work order id not found in the database. \ Hence invalid parameter") return response
def render_GET(self, request): # JRPC response with id 0 is returned because id parameter # will not be found in GET request response = utility.create_error_response( WorkorderError.INVALID_PARAMETER_FORMAT_OR_VALUE, "0", "Only POST request is supported") logger.error( "GET request is not supported. Only POST request is supported") return response
def __process_encryption_key_set(self, input_json_str, response): """ Function to process set encryption key request. Parameters: - input_json_str is a work order request json as per TCF API 6.1.11 Set Encryption Key Request Payload - response is the response object to be returned """ input_json = json.loads(input_json_str) jrpc_id = input_json["id"] response = utility.create_error_response( WorkerError.INVALID_PARAMETER_FORMAT_OR_VALUE, jrpc_id, "Operation is not supported. Hence invalid parameter") return response
def __process_store_workorder_receipt(self, wo_id, input_json_str, response): """ Function to process work order request Parameters: - wo_id is work order id - input_json_str is create work order receipt json as per TCF API 7.2.2 Receipt Create Request Payload - response is the response object to be returned to client """ input_value_json = json.loads(input_json_str) jrpc_id = input_value_json["id"] input_value = {} input_value['result'] = input_value_json['params'] input_value['result']['receiptCurrentStatus'] = ReceiptCreateStatus.PENDING #Updater is introduced to maintain multiple update details on a receipt input_value['result']['updater'] = {} input_json_str = json.dumps(input_value) if(self.kv_helper.get("wo-receipts",wo_id) is None): value = self.kv_helper.get("wo-requests", wo_id) if value: self.kv_helper.set("wo-receipts",wo_id,input_json_str) response = utility.create_error_response( WorkorderError.SUCCESS, jrpc_id, "Receipt created successfully") else: response = utility.create_error_response( WorkorderError.INVALID_PARAMETER_FORMAT_OR_VALUE, jrpc_id, "Work order does not exists. Hence invalid parameter") else: response = utility.create_error_response( WorkorderError.INVALID_PARAMETER_FORMAT_OR_VALUE, jrpc_id, "Work order receipt already exist in the database. Hence invalid parameter") return response
def __process_workorder_receipt_update_retrieve(self,wo_id, input_json_str, response): """ Function to process work order receipt update retrieve Parameters: - wo_id is work order id - input_json_str is work order receipt update json as per TCF API 7.2.6 Receipt Update Retrieve Request Payload - response is the response object to be returned to client """ input_value = json.loads(input_json_str) jrpc_id = input_value["id"] # value retrieved is 'result' field as per Spec 7.2.5 Receipt Retrieve Response Payload value = self.kv_helper.get("wo-receipts",wo_id) if value : updater_id = input_value["params"]['updaterId'] update_index = input_value["params"]['updateIndex'] json_dict = json.loads(value) updater_objects = json_dict['result']['updater'] update_count = 0 result_item = {} for item in updater_objects: id = updater_objects[item]['updaterId'] if id == updater_id : #Considering Index 0 as first update if update_count == update_index : result_item = updater_objects[item] #the total number of updates made by the updaterId. update_count = update_count+1 response['result'] = {} response['result'] = result_item response['result']['updateCount'] = update_count else: response = utility.create_error_response( WorkorderError.INVALID_PARAMETER_FORMAT_OR_VALUE, jrpc_id, "Work order id not found in the database. \ Hence invalid parameter") return response
def __process_encryption_key_get(self, input_json_str, response): """ Function to process get encryption key request. Parameters: - input_json_str is a work order request json as per TCF API 6.1.10 Get Encryption Key Request Payload - response is the response object to be returned """ input_json = json.loads(input_json_str) jrpc_id = input_json["id"] worker_id = str(input_json['params']['workerId']) value = self.kv_helper.get("workers", worker_id) if value is not None: json_dict = json.loads(value) response["result"] = {} response["result"]["workerId"] = worker_id encryptionKey = json_dict["details"]["workerTypeData"]["encryptionKey"] try : encryptionKeyNonce = json_dict["details"]["workerTypeData"]["encryptionKeyNonce"] except : encryptionKeyNonce = crypto.random_bit_string(NO_OF_BYTES) tag = "" response["result"]["encryptionKey"] = encryptionKey response["result"]["encryptionKeyNonce"] = encryptionKeyNonce response["result"]["tag"] = tag #calculate signature concat_string = worker_id.encode('UTF-8') + encryptionKey.encode('UTF-8') + encryptionKeyNonce.encode('UTF-8') + tag.encode('UTF-8') concat_hash = bytes() concat_hash = bytes(concat_string) hash_1 = crypto.compute_message_hash(concat_hash) s1 = crypto.byte_array_to_base64(hash_1) # Requires worker private key to sign. # signature = self.PrivateKey.SignMessage(hash) response["result"]["signature"] = s1 else : # Workorder id already exists response = utility.create_error_response( WorkerError.INVALID_PARAMETER_FORMAT_OR_VALUE, jrpc_id, "Worker id not found in the database. Hence invalid parameter") return response
def worker_registry_handler(self, input_json_str): """ Function to process worker request Parameters: - input_json_str is a worker request json as per TCF API 5.3 Off-Chain Worker Registry JSON RPC API """ input_json = json.loads(input_json_str) response = {} response['jsonrpc'] = '2.0' response['id'] = input_json['id'] logger.info("Received Worker request : %s", input_json['method']) if (input_json['method'] == "WorkerLookUp"): return self.__process_worker_lookup(input_json_str, response) elif (input_json['method'] == "WorkerLookUpNext"): return self.__process_worker_lookup_next(input_json_str, response) if 'workerId' in input_json_str: worker_id = str(input_json['params']['workerId']) else: return utility.create_error_response( WorkerError.INVALID_PARAMETER_FORMAT_OR_VALUE, input_json["id"], "Worker Id not found in the database. \ Hence invalid parameter") if (input_json['method'] == "WorkerRegister"): return self.__process_worker_register(worker_id, input_json_str, response) elif (input_json['method'] == "WorkerSetStatus"): return self.__process_worker_set_status(worker_id, input_json_str, response) elif (input_json['method'] == "WorkerRetrieve"): return self.__process_worker_retrieve(worker_id, response) elif (input_json['method'] == "WorkerUpdate"): return self.__process_worker_update(worker_id, input_json_str, response)
def workorder_receipt_handler(self, input_json_str): """ Function to process work order receipt request Parameters: - input_json_str is a work order receipt request json as per TCF API 7.2 Direct Model Receipt Handling """ input_json = json.loads(input_json_str) response = {} response['jsonrpc'] = input_json['jsonrpc'] response['id'] = input_json['id'] logger.info("Received Work order Receipt request : %s",input_json['method']) if(input_json['method'] == "WorkOrderReceiptLookUp") : return self.__process_workorder_receipt_lookup(input_json_str, response) elif(input_json['method'] == "WorkOrderReceiptLookUpNext") : return self.__process_workorder_receipt_lookup_next(input_json_str, response) if 'workOrderId' in input_json_str: wo_id = str(input_json['params']['workOrderId']) else : response = utility.create_error_response( WorkorderError.INVALID_PARAMETER_FORMAT_OR_VALUE, input_json['id'], "Work order id not found in the database. \ Hence invalid parameter") return response jrpc_id = input_json['id'] if(input_json['method'] == "WorkOrderReceiptCreate") : return self.__process_store_workorder_receipt(wo_id, input_json_str, response) elif(input_json['method'] == "WorkOrderReceiptUpdate") : return self.__process_workorder_receipt_update(wo_id, input_json_str, response) elif(input_json['method'] == "WorkOrderReceiptRetrieve") : return self.__process_workorder_receipt_retrieve(wo_id, jrpc_id, response) elif(input_json['method'] == "WorkOrderReceiptUpdateRetrieve") : return self.__process_workorder_receipt_update_retrieve(wo_id,input_json_str, response)
def __process_work_order_submission(self, wo_id, input_json_str, response): """ Function to process work order request Parameters: - wo_id is work order id - input_json_str is a work order request json as per TCF API 6.1.1 Work Order Request Payload - response is the response object to be returned to client """ input_value_json = json.loads(input_json_str) jrpc_id = input_value_json["id"] if ((self.workorder_count + 1) > self.max_workorder_count): #if max count reached clear a processed entry work_orders = self.kv_helper.lookup("wo-timestamps") for id in work_orders: # If work order is processed then remove from table if (self.kv_helper.get("wo-processed", id) is not None): self.kv_helper.remove("wo-processed", id) self.kv_helper.remove("wo-requests", id) self.kv_helper.remove("wo-responses", id) self.kv_helper.remove("wo-receipts", id) self.kv_helper.remove("wo-timestamps", id) self.workorder_list.remove(id) self.workorder_count -= 1 break # If no work order is processed then return busy if ((self.workorder_count + 1) > self.max_workorder_count): response = utility.create_error_response( WorkorderError.BUSY, jrpc_id, "Work order handler is busy updating the result") return response if (self.kv_helper.get("wo-timestamps", wo_id) is None): # Create a new work order entry. Dont change the order of table updation. # The order is important for clean up if the TCS is restarted in middle epoch_time = str(time.time()) # Update the tables self.kv_helper.set("wo-timestamps", wo_id, epoch_time) self.kv_helper.set("wo-requests", wo_id, input_json_str) self.kv_helper.set("wo-scheduled", wo_id, input_json_str) #Add to the internal FIFO self.workorder_list.append(wo_id) self.workorder_count += 1 response = utility.create_error_response( WorkorderError.PENDING, jrpc_id, "Work order is computing. Please query for WorkOrderGetResult \ to view the result") else: # Workorder id already exists response = utility.create_error_response( WorkorderError.INVALID_PARAMETER_FORMAT_OR_VALUE, jrpc_id, "Work order id already exists in the database. \ Hence invalid parameter") return response