diff --git a/CHANGELOG.md b/CHANGELOG.md index a283e5a..30e3254 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# 0.3.0 +* Add delete_key action +* Add default network fee on config.yml for operations that need fees +* Add .props in unprotected headers to offer metadatas about the cointained data (MD5, message size in bytes, modified timestamp) for COSE Encodings +* Other minor fixes + # 0.2.0 * Add Read from file and write to file capability diff --git a/README.md b/README.md index 22db0ed..a3cff31 100644 --- a/README.md +++ b/README.md @@ -72,17 +72,17 @@ If you want to store or read your encrypted data, you need to set the correct HM ## Arguments ```bash -usage: dataplayer datastore [-h] --id ID [--codec {hex,cose}] --action {update_key,read_key,list_keys} [--key KEY] [--value VALUE] - [--cose-ph COSE_PH [COSE_PH ...]] [--cose-uh COSE_UH [COSE_UH ...]] +usage: dataplayer datastore [-h] --id ID [--codec {hex,cose}] --action {update_key,read_key,list_keys,delete_key} [--key KEY] [--value VALUE] + [--value-from-file VALUE_FROM_FILE] [--value-to-file VALUE_TO_FILE] [--cose-ph COSE_PH [COSE_PH ...]] [--cose-uh COSE_UH [COSE_UH ...]] optional arguments: -h, --help show this help message and exit --id ID, -i ID Datastore ID --codec {hex,cose}, -c {hex,cose} Encoding type for reading or updating (default hex) - --action {update_key,read_key,list_keys}, -a {update_key,read_key,list_keys} + --action {update_key,read_key,list_keys,delete_key}, -a {update_key,read_key,list_keys,delete_key} Action to execute over datastore (required) - --key KEY, -k KEY Key of selection (required for read_key, update_key actions) + --key KEY, -k KEY Key of selection (required for read_key, update_key, delete_key actions) --value VALUE, -v VALUE Value for update_key action (optional) --value-from-file VALUE_FROM_FILE, -vff VALUE_FROM_FILE diff --git a/config.yaml b/config.yaml index f5dbf1d..50f53fc 100644 --- a/config.yaml +++ b/config.yaml @@ -1,6 +1,6 @@ --- rpc_connector: - host: "localhost" + host: "127.0.0.1" private_wallet_cert_path: "~/.chia/mainnet/config/ssl/wallet/private_wallet.crt" private_wallet_key_path: "~/.chia/mainnet/config/ssl/wallet/private_wallet.key" service_ports: @@ -9,5 +9,6 @@ rpc_connector: service_wallets: chia: 1 datalayer: 2 + default_network_fee: 1000 log_level: "WARNING" diff --git a/dataplayer b/dataplayer index ed5c18e..d084492 100755 --- a/dataplayer +++ b/dataplayer @@ -45,10 +45,16 @@ def default_routine(datahandler): store_key = args_datastore.key )) elif args_datastore.action == "list_keys": - logging.info(f"Listing Keys: {args_datastore.key} for Store: {args_datastore.id}") + logging.info(f"Listing Keys for Store: {args_datastore.id}") print(datahandler.datastore_list_keys( store_id = args_datastore.id - )) + )) + elif args_datastore.action == "delete_key": + logging.info(f"Deleting key: {args_datastore.key} for Store: {args_datastore.id}") + print(datahandler.datastore_delete_key( + store_id = args_datastore.id, + store_key = args_datastore.key + )) def check_only_routine(): wallet_rpc.check_available_wallets() @@ -68,13 +74,15 @@ if __name__ == "__main__": host=config["rpc_connector"]["host"], port=int(config["rpc_connector"]["service_ports"]["wallet"]), private_wallet_cert_path=config["rpc_connector"]["private_wallet_cert_path"], - private_wallet_key_path=config["rpc_connector"]["private_wallet_key_path"]) + private_wallet_key_path=config["rpc_connector"]["private_wallet_key_path"], + network_fee=config["rpc_connector"]["default_network_fee"]) datalayer_rpc = RemoteProcedureCall( host=config["rpc_connector"]["host"], port=int(config["rpc_connector"]["service_ports"]["datalayer"]), private_wallet_cert_path=config["rpc_connector"]["private_wallet_cert_path"], - private_wallet_key_path=config["rpc_connector"]["private_wallet_key_path"]) + private_wallet_key_path=config["rpc_connector"]["private_wallet_key_path"], + network_fee=config["rpc_connector"]["default_network_fee"]) datahandler = Handler(datalayer_rpc) diff --git a/lib/cli/cli.py b/lib/cli/cli.py index 24f9f28..192f5c0 100644 --- a/lib/cli/cli.py +++ b/lib/cli/cli.py @@ -31,8 +31,8 @@ def printText(args): datastores = subparser.add_parser('datastore') datastores.add_argument('--id', '-i', type=str, help='Datastore ID', required=True) datastores.add_argument('--codec', '-c', type=str, help='Encoding type for reading or updating (default hex)', choices=['hex', 'cose'], default='hex', required=False) - datastores.add_argument('--action', '-a', type=str, help='Action to execute over datastore (required)', choices=['update_key', 'read_key', 'list_keys'], required=True) - datastores.add_argument('--key', '-k', type=str, help='Key of selection (required for read_key, update_key actions)', required=False) + datastores.add_argument('--action', '-a', type=str, help='Action to execute over datastore (required)', choices=['update_key', 'read_key', 'list_keys', 'delete_key'], required=True) + datastores.add_argument('--key', '-k', type=str, help='Key of selection (required for read_key, update_key, delete_key actions)', required=False) datastores.add_argument('--value', '-v', type=str, help='Value for update_key action (optional)', required=False) datastores.add_argument('--value-from-file', '-vff', type=str, help='Read a file from path for update_key action if specified (optional)', required=False) datastores.add_argument('--value-to-file', '-vtf', type=str, help='Write value to a file path for read_key action if specified specified (optional)', required=False) diff --git a/lib/datalayer/handle.py b/lib/datalayer/handle.py index 999b52f..dbcc443 100644 --- a/lib/datalayer/handle.py +++ b/lib/datalayer/handle.py @@ -5,7 +5,7 @@ class Handler(): def __init__(self, rpc_datalayer_instance): if os.getenv('COSE_KEY') is None: - logging.warning("COSE_KEY environment variable not defined, USING A DEFAULT KEY for hex encodings") + logging.warning("COSE_KEY environment variable not defined, USING A DEFAULT KEY for COSE ciphering") cose_key = "03d4f7f0611f28563a318c64f8b0852b" else: logging.info("COSE_KEY environment variable defined, using it") @@ -57,6 +57,9 @@ def datastore_list_keys(self, store_id=str): keys["keys"] = keys_ascii return(json.dumps(keys, sort_keys=True, indent=2)) + def datastore_delete_key(self, store_id=str, store_key=str): + return(json.dumps(self.rpc_instance.datalayer_delete_key(store_id=store_id, key=self.serial.hex_encode(message=store_key)), sort_keys=True, indent=2)) + def read_local_file(self, filepath=str): with open(filepath, mode="rb") as rawfile: b64_file = self.serial.base64_bencode(message=rawfile.read()) diff --git a/lib/datalayer/serial.py b/lib/datalayer/serial.py index c65558b..e08d162 100644 --- a/lib/datalayer/serial.py +++ b/lib/datalayer/serial.py @@ -1,4 +1,4 @@ -import logging, base64 +import logging, base64, sys, hashlib from binascii import unhexlify, hexlify from cose.messages import Mac0Message, CoseMessage from cose.keys import CoseKey @@ -7,6 +7,7 @@ from cose.keys.keyparam import KpKty, SymKpK, KpKeyOps from cose.keys.keytype import KtySymmetric from cose.keys.keyops import MacCreateOp, MacVerifyOp +from datetime import datetime,timezone class Serializer(): @@ -19,10 +20,11 @@ def __init__(self, cose_key=str): }) def cose_encode(self, message, protected_headers={}, unprotected_headers={}): + message_utf8 = message.encode('utf-8') msg = Mac0Message( phdr = {Algorithm: HMAC256, **protected_headers}, - uhdr = {**unprotected_headers}, - payload = message.encode('utf-8') + uhdr = {**unprotected_headers, ".props": {"size.bytes": sys.getsizeof(message), "checksum.md5": hashlib.md5(message_utf8).hexdigest(), "modified.iso8601.utc": datetime.now(timezone.utc).isoformat()}}, + payload = message_utf8 ) msg.key = self.cose_key @@ -43,11 +45,13 @@ def cose_decode(self, message): if decoded.verify_tag(): ph = decoded.phdr + uh = decoded.uhdr for k, v in ph.items(): if "abc.ABCMeta" in str(type(k)): del ph[k] break - return({"payload": str(decoded.payload.decode('ascii')), "protected_headers": ph, "unprotected_headers": decoded.uhdr}) + #return({"payload": str(decoded.payload.decode('ascii')), "protected_headers": ph, "unprotected_headers": uh}) + return({"protected_headers": ph, "unprotected_headers": uh}) else: pass diff --git a/lib/rpc/xchrpc.py b/lib/rpc/xchrpc.py index a915601..de60848 100644 --- a/lib/rpc/xchrpc.py +++ b/lib/rpc/xchrpc.py @@ -5,13 +5,14 @@ class RemoteProcedureCall(): - def __init__(self, host="localhost", port=9256, private_wallet_cert_path="~/.chia/mainnet/config/ssl/wallet/private_wallet.crt", private_wallet_key_path="~/.chia/mainnet/config/ssl/wallet/private_wallet.key"): + def __init__(self, host="127.0.0.1", port=9256, private_wallet_cert_path="~/.chia/mainnet/config/ssl/wallet/private_wallet.crt", private_wallet_key_path="~/.chia/mainnet/config/ssl/wallet/private_wallet.key", network_fee=1000): requests.packages.urllib3.disable_warnings(InsecureRequestWarning) self.default_rpc_headers = {'Content-Type': 'application/json'} self.default_wallet_certs = (expanduser(private_wallet_cert_path), expanduser(private_wallet_key_path)) self.host = host self.port = port + self.network_fee = network_fee logging.debug(f"RPC connector set to {self.host}:{str(self.port)} using certs {str(self.default_wallet_certs)}") @@ -93,7 +94,8 @@ def datalayer_update_owned_store(self, store_id=str, change_list=list): request_data = { "id": str(store_id), - "changelist": list(change_list) + "changelist": list(change_list), + "fee": int(self.network_fee) } try: @@ -134,6 +136,31 @@ def datalayer_get_value(self, store_id=str, key=str): logging.error(f"Cannot found Key. Desc: {str(loaded_json)}") return(False) + def datalayer_delete_key(self, store_id=str, key=str): + logging.debug(f"Deleting Key: {key} for Store: {store_id}") + + request_data = { + "id": str(store_id), + "key": str(key), + "fee": int(self.network_fee) + } + + try: + response = requests.post(f"https://{self.host}:{str(self.port)}/delete_key", headers=self.default_rpc_headers, json=request_data, cert=self.default_wallet_certs, verify=False) + response.raise_for_status() + except Exception as e: + logging.error(str(e)) + return(False) + else: + loaded_json = json.loads(response.text) + print(loaded_json) + if loaded_json["success"]: + logging.info("Succesfull") + return(loaded_json) + else: + logging.error(f"Cannot delete key. Desc: {str(loaded_json)}") + return(False) + def datalayer_get_keys(self, store_id=str): logging.debug(f"Listing Keys for Store: {store_id}")