async def submit_conclude_secret(app, requester_address, share_secret_state, zeroth_priv, private_key): """ Args: share_secret_address: desrialize share_secret transaction data on share_secret address created from the random index for the user """ acc_signer = create_signer(zeroth_priv) nonce = random.randint(2**20, 2**30) ##nonce signed by zerothprivate key and in hex format signed_nonce = ecdsa_signature(private_key, nonce) user_signed_nonce = ecdsa_signature(zeroth_priv, nonce) nonce_hash = hashlib.sha512(str(nonce).encode()).hexdigest() ##ON the processor side, signed_nonce will be checked against admin account ##public key ##this is required as this will add to the confidence that this tramsaction ##was signed by the database owners or The ADMIN transaction_data = { "user_address": requester_address, "share_secret_address": share_secret_state["address"], "active": False, "timestamp": indian_time_stamp(), "nonce": nonce, "nonce_hash": nonce_hash, "signed_nonce": signed_nonce, "user_signed_nonce": user_signed_nonce, } ##transaction["address"] is actually an address of the shared_secret_transaction inputs = [requester_address, share_secret_state["address"]] outputs = [share_secret_state["address"]] payload = payload_pb2.CreateConcludeSecret(**transaction_data) instance = await SendConcludeSecret(app.config.REST_API_URL, app.config.TIMEOUT) transaction_id, transaction = await instance.create_conclude_secret( txn_key=acc_signer, batch_key=app.config.SIGNER, inputs=inputs, outputs=outputs, payload=payload) transaction_data.update({ "transaction_id": transaction_id, "transaction": transaction, }) logger.info(transaction_data) return transaction_data
async def submit_receive_secret(app, requester_user_id, requester_state, requester_address, requester_mnemonic): """ Args: requester_state(str): The user state present on the blockchain who wants to create a new receive secret address requester_mnemonic: decrypted mnemonic of the user """ index = await generate_key_index(requester_state.get("receive_secret_idxs") ) logging.info(index) nth_keys = await remote_calls.key_index_keys(app, requester_mnemonic, [index, 0]) nth_priv, nth_pub = nth_keys[str(index)]["private_key"], \ nth_keys[str(index)]["public_key"] zeroth_priv, zeroth_pub = nth_keys[str(0)]["private_key"], \ nth_keys[str(0)]["public_key"] ##to prove that this receive_secret has been created by the user himself, ##nonce must be signed by the zeroth private of the account nonce = random.randint(2**20, 2**30) ## nonce signed by zerothprivate key and in hex format signed_nonce = ecdsa_signature(zeroth_priv, nonce) nonce_hash = hashlib.sha512(str(nonce).encode()).hexdigest() acc_signer = create_signer(nth_priv) transaction_data = { "role": requester_state["role"], "active": True, "created_on": indian_time_stamp(), "nonce": nonce, "signed_nonce": signed_nonce, "nonce_hash": nonce_hash, "requester_address": requester_address, "idx": index, } receive_secret_address = addresser.receive_secret_address( acc_signer.get_public_key().as_hex(), index) ##both the inputs and outputs addresses will be the same ##requester addresss will be fetched from blockchain and checked if its exists, ##The receive_secret idx will be appended to the array fo account addresses = [requester_address, receive_secret_address] logging.info(f"addresses are {addresses}") payload = payload_pb2.CreateReceiveSecret(**transaction_data) instance = await SendReceiveSecret(app.config.REST_API_URL, app.config.TIMEOUT) transaction_id, transaction = await instance.push_receive_secret( txn_key=acc_signer, batch_key=app.config.SIGNER, inputs=addresses, outputs=addresses, payload=payload) transaction_data.update({ "transaction_id": transaction_id, "transaction": transaction, "signed_nonce": signed_nonce.decode() }) db_instance = await DBReceiveSecret(app, app.config.DATABASE["receive_secret"], "receive_secret_idxs") await db_instance.store_receive_secrets(requester_user_id, transaction_data) await db_instance.update_user_receive_secret(requester_user_id, index) return transaction_data
async def submit_execute_share_secret(app, requester, receive_secret_address, shared_secret_state, private, public): """ app(dict): configuration of the whole application requester(dict): database entry of the user who requested this api, i.e who tries to execute a share_Secret transactions shared with him on his receive_secret transaction share_secret_state(dict): Blcokchain state of the share_secret tansaction which will be executed by this user private(hex encoded string): Private key of the requester with whom the receive secret transaction was created, this private was generaed from the idx mentioned in the receive_secret transaction from the requester mnemonic public(hex encoded string): corresponding public of the private Process: share_secret transaction has three keys , key: hex encoded AES key encrypted with the public key of the requester secret: hex encoded shamir secret share encrypted with the AES key mentioned above reset_key: The new hex encoded key generated from the users new_password this is also encrypted with requester public key. Step1: decrypt hex encoded KEY (AES) with private key Step2: decrypt unhexlified secret with AES key from step1. Step3: decrypt unhexlified reset_key with private_key Step4: Encrypt Secret with reset_key """ secret = shared_secret_state[ "secret"] ##encrypted secret with AES key i.e key reset_key = shared_secret_state["reset_key"] ##new aes key which will be #used to encrypt the secret after decryption key = shared_secret_state[ "key"] #THE aes key which was oriniginally used to encrypt secret ##the key is hex encoed but this function will first dehexlify it and then ## decrypt with private key de_org_key = decrypt_w_privkey(key, private) #this orginal AES key de_org_key will be in bytes unhexlified_secret = binascii.unhexlify(secret) ##This is the bare secret which was originally shared with this user de_org_secret = aes_decrypt(de_org_key, unhexlified_secret) ##Now we have to decrypt the new aes key which user has updated as reset_key ##in this contract ##It was also encrypted with the public key of the account address de_reset_key = priv_decrypt(binascii.unhexlify(reset_key), private) ##now encypting orginila share with new reset key ciphertext, tag, nonce = aes_encrypt(de_reset_key, de_org_secret) secret = b"".join([tag, ciphertext, nonce]) ##encrypting the shared mnemonic with users account public key ##the return will also be in bytes i.e encrypted_secret_share #encrypted_secret_share = pub_encrypt(secret_share, account["public"]) #logging.info(encrypted_secret_share) #secret_share = binascii.hexlify(encrypted_secret_share) nonce = random.randint(2**20, 2**30) ##nonce signed by zerothprivate key and in hex format signed_nonce = ecdsa_signature(private, nonce) nonce_hash = hashlib.sha512(str(nonce).encode()).hexdigest() acc_signer = create_signer(private) transaction_data = { "share_secret_address": shared_secret_state["address"], "reset_secret": binascii.hexlify(secret), "timestamp": indian_time_stamp(), "nonce": nonce, "nonce_hash": nonce_hash, "signed_nonce": signed_nonce, } addresses = [shared_secret_state["address"], receive_secret_address] logging.info(f"addresses are {addresses}") payload = payload_pb2.CreateExecuteShareSecret(**transaction_data) instance = await SendExecuteSecret(app.config.REST_API_URL, app.config.TIMEOUT) transaction_id, batch_id = await instance.push_receive_secret( txn_key=acc_signer, batch_key=app.config.SIGNER, inputs=addresses, outputs=addresses, payload=payload) logging.info(transaction_data) #transaction_ids, batch_id = await __send_execute_share_mnemonic(**transaction_data) """ if transaction_ids: logging.info("Execute share secret Transaction has been created successfully") ##which imlies the transaction has been submitted successfully, ##now all the changes that are required to be done on the databse can ##be done ##Update users create_asset_idxs key on users entry will be updated by ## whomever will call this, because update can happend on pending_users share_asset_address = addresser.share_asset_address( share_asset_pub, key_index) account_signature = account_hex_signature.decode() asset_signature=asset_hex_signature.decode() transaction_data.update({"transaction_id": transaction_ids[0], "batch_id": batch_id, "account_signature": account_signature, "asset_signature": asset_signature, "address": share_asset_address }) [transaction_data.pop(field) for field in ["config", "txn_key", "batch_key"]] await share_assets_query.store_share_asset(app, transaction_data) ##now asset must be update with share_with key await assets_query.update_issuer_asset_shared( app, asset_address, key_index) ##TOFO update receiver_address asset and issuer_asset_Address in DB await accounts_query.update_share_asset_idxs( app, org_state["user_id"], key_index) if child_user_id: await accounts_query.update_share_asset_idxs( app, child_user_id, key_index) return share_asset_address else: return False """ return
async def submit_receive_asset(app, requester, _id_, name, description, at_which_asset_expires): """ """ f = await userapis.SolveAccount(requester, app) decrypted_mnemonic = f.decrypted_mnemonic logging.info(f"THis is the decrypted mnemonic {decrypted_mnemonic}") org_db_entry = f.org_db receive_asset_idxs = f.org_state.get("receive_asset_idxs") child_user_id = f.child_user_id child_zero_pub = f.child_zero_pub account_zero_pub = f.zero_pub key_index = await ledger_utils.generate_key_index(array=receive_asset_idxs) nth_keys = await remote_calls.key_index_keys(app, decrypted_mnemonic, [key_index, 0]) nth_priv, nth_pub = nth_keys[str(key_index)]["private_key"], \ nth_keys[str(key_index)]["public_key"] org_priv, org_pub = nth_keys[str(0)]["private_key"], \ nth_keys[str(0)]["public_key"] org_account_address = addresser.create_organization_account_address( account_id=account_zero_pub, index=0) instance = await userapis.SolveAddress(org_account_address, app.config.REST_API_URL) org_state = instance.data ##the transaction will be signed by users nth private key create_asset_signer = ledger_utils.create_signer(nth_priv) ##we havent included the child_nth_pub in this transaction because it ## can be calculated from txn_key on the processor side ##for added security we will send a nonce signed by issuer account ##private key nonce = random.randint(2**20, 2**30) nonce_hash = hashlib.sha224(str(nonce).encode()).hexdigest() ##nonce signed by zerothprivate key and in hex format hex_signatures = signatures.ecdsa_signature(org_priv, nonce) receive_asset_address = addresser.receive_asset_address(asset_id=nth_pub, index=key_index) unique_code = int("".join(map(str, random.choices(list(range(1, 10)), k=5)))) unique_code_hash = hashlib.sha224(str(unique_code).encode()).hexdigest() encrypted_unique_code = encryption_utils.encrypt_w_pubkey( str(unique_code).encode(), nth_pub) encrypted_admin_unique_code = encryption_utils.encrypt_w_pubkey( str(unique_code).encode(), app.config.ADMIN_ZERO_PUB) transaction_data = { "config": app.config, "txn_key": create_asset_signer, "batch_key": app.config.SIGNER, "_id_": _id_, "time": int(time.time()), "indiantime": upload_utils.indian_time_stamp(), "idx": key_index, "at_which_asset_expires": at_which_asset_expires, "org_name": org_state["org_name"], "org_address": org_account_address, "org_zero_pub": org_pub, "org_role": org_state["role"], "receive_asset_details": { "name": name, "description": description }, "child_zero_pub": child_zero_pub, "signed_nonce": hex_signatures, "nonce": nonce, "nonce_hash": nonce_hash, "unique_code_hash": unique_code_hash, "encrypted_unique_code": encrypted_unique_code, "encrypted_admin_unique_code": encrypted_admin_unique_code } logging.info(f"THis is the transaction data in receive_asset") logging.info(pprint(transaction_data)) transaction_ids, batch_id = await send_receive_asset(**transaction_data) if batch_id: [ transaction_data.pop(field) for field in ["config", "txn_key", "batch_key"] ] signed_nonce = transaction_data["signed_nonce"].decode() transaction_data.update({ "user_id": requester["user_id"], "public": nth_pub, "transaction_id": transaction_ids[0], "batch_id": batch_id, "signed_nonce": signed_nonce, "unique_code": unique_code }) await receive_assets_query.store_receive_assets(app, transaction_data) await accounts_query.update_receive_assets_idxs( app, org_db_entry["user_id"], key_index) ##if this receive_asset is created by child of the organization ##then update the child account receive_asset_idxs array also if child_user_id: await accounts_query.update_receive_assets_idxs( app, child_user_id, key_index) #await accounts_query.update_create_asst_idxs_pending(app, #requester["user_id"], key_index) return nth_pub, key_index, receive_asset_address else: logging.error("Create asset Faied, GO to hell Dude!!!!,\ Kabhi kabhi lagta hai ki bhagwan hone ka bhi kya fayda") return
async def submit_activate_secret(app, transaction, password): """ Args: transaction: desrialize share_secret transaction data on share_secret address created from the random index for the user """ key, salt = generate_scrypt_key(password, 1, None) ##the encrypted scrypt key will also be in bytes. this is the scrypt key ##which will be encrypted with other users public key, ##The other user will decrypt with their account private key ##and also the secret stored on shasred address, ##now he will encrypt the unencrypted original secret with this new scrypt ##key encrypted_key = pub_encrypt(key, transaction["owner_public"]) acc_signer = create_signer(app.config.ADMIN_ZERO_PRIV) nonce = random.randint(2**20, 2**30) ##nonce signed by zerothprivate key and in hex format signed_nonce = ecdsa_signature(app.config.ADMIN_ZERO_PRIV, nonce) nonce_hash = hashlib.sha512(str(nonce).encode()).hexdigest() ##ON the processor side, signed_nonce will be checked against admin account ##public key ##this is required as this will add to the confidence that this tramsaction ##was signed by the database owners or The ADMIN admin_address = addresser.organization_address(app.config.ADMIN_ZERO_PUB, 0) transaction_data = { "share_secret_address": transaction["address"], "reset_key": binascii.hexlify(encrypted_key), "nonce": nonce, "nonce_hash": nonce_hash, "signed_nonce": signed_nonce, "admin_address": admin_address, "timestamp": indian_time_stamp() } ##transaction["address"] is actually an address of the shared_secret_transaction inputs = [transaction["address"], admin_address] outputs = [transaction["address"], admin_address] payload = payload_pb2.CreateActivateSecret(**transaction_data) instance = await SendActivateSecret(app.config.REST_API_URL, app.config.TIMEOUT) transaction_id, transaction = await instance.create_activate_secret( txn_key=acc_signer, batch_key=app.config.SIGNER, inputs=inputs, outputs=outputs, payload=payload) transaction_data.update({ "transaction_id": transaction_id, "transaction": transaction, "key": binascii.hexlify(key).decode(), "salt": binascii.hexlify(salt).decode(), }) return transaction_data
async def submit_share_asset(app, requester, asset_address, receive_asset_address, unique_code, revoked_on, comments): """ 1.check whether asset_address is valid asset address or not 2. check whether the asset is empty or not 3.check whether the asset has been transsefred the ownership to someother empty asset 4.check whether the requester is the owner of this asset or not 5.check whether the receiver_asset_address is a valid receive_asset_address or not 6.check whether at_which_asset_expires is stil valid or hasnt expired 7.cheque whether the sha_2224 hash of unique code matches with receiver_asset """ f = await userapis.SolveAccount(requester, app) decrypted_mnemonic = f.decrypted_mnemonic org_state = f.org_state logging.info(f"THis is the decrypted mnemonic {decrypted_mnemonic}") share_asset_idxs = f.org_state.get("share_asset_idxs") child_user_id = f.child_user_id child_zero_pub = f.child_zero_pub account_zero_pub = f.zero_pub unique_code_hash = hashlib.sha224(str(unique_code).encode()).hexdigest() if await share_assets_query.find_share_asset(app, asset_address, receive_asset_address): raise ApiInternalError("This shared asset has already been done") ##checking point 5 receive_asset_instance = await userapis.SolveAddress( receive_asset_address, app.config.REST_API_URL) if receive_asset_instance.type != "RECEIVE_ASSET": raise AssetError("receive_asset_address is notreceive asset address") if not receive_asset_instance.data[ "at_which_asset_expires"] > upload_utils.now_time_stamp(): raise errors.InvalidValidityPeriod("The time to share asset with this \ address has been expired") if receive_asset_instance.data["unique_code_hash"] !=\ unique_code_hash: raise AssetError( "Unique code provided is either wrong or meant for different receiver_address" ) asset_instance = await userapis.SolveAddress(asset_address, app.config.REST_API_URL) if asset_instance.type != "CREATE_ASSET": raise AssetError("asset_address is not asset address") ##check point 2 if not asset_instance.data["file_name"] or not asset_instance.data[ "file_hash"]: raise AssetError("Empty assets cannot be shared") ##decrypting issuer mnemonic requester_account_address = addresser.create_organization_account_address( account_id=org_state["public"], index=0) ##Check if the asset had been transffered to the issuer i.e issets which were ###not created by the issuer cant be transffered to other users if asset_instance.data.get("ownership_transfer"): message = f"This asset which already have been transffered to \ {issuer_asset.get('ownership_transfer')} can be shared" logging.error(message) raise AssetError(message) key_index = await ledger_utils.generate_key_index(share_asset_idxs) logging.info(f"THis is the key index for issuer {key_index}") ##at which the asset was created asset_index = asset_instance.data["idx"] nth_keys = await remote_calls.key_index_keys(app, decrypted_mnemonic, [0, key_index, asset_index]) ##account kets for the issuer requester_zeroth_priv, requester_zeroth_pub = \ nth_keys[str(0)]["private_key"], \ nth_keys[str(0)]["public_key"] ##keys at which teh asset which needs to be shared was floated create_asset_priv, create_asset_pub = nth_keys[str(asset_index)]["private_key"], \ nth_keys[str(asset_index)]["public_key"] ##keys at which the shared asset index will be floated share_asset_priv, share_asset_pub = nth_keys[str(key_index)]["private_key"], \ nth_keys[str(key_index)]["public_key"] ##check if issuer n th public key is exactly the public key mentioned in the ##asset transaction present on the blockchain, this also checks whether ##the requester is actually the owner of the asset if create_asset_pub != asset_instance.data.get("public"): logging.error("This asset address is not owned by the issuer") raise AssetError("This asset address is not owned by the issuer") ##decrypting file data stored ob the issuer asset address, this can be ##done by issuer private key present on the nth index data = await asset_utils.decrypt_file_data( asset_instance.data["key"], asset_instance.data["url"], asset_instance.data["file_hash"], create_asset_priv) ##TODO: check file_hash file_data = { "data": data, "file_name": asset_instance.data["file_name"], "file_hash": asset_instance.data["file_hash"] } ##encrypting again with the public key present at the receiver_asset_address key, encrypted_key, s3_url, encrypted_s3_url = \ await asset_utils.encrypt_file_data(None, receive_asset_instance.data["public"], app.config, file_data) logging.info(f"This is the key {key} , encrypted_key{encrypted_key} \ and the s3_url {s3_url}") master_key, master_url = await asset_utils.master_url_n_key( app.config.ADMIN_ZERO_PUB, key, s3_url) ##Now this transaction should be signed by user create_asset_signer = ledger_utils.create_signer(share_asset_priv) ##for added security we will send a nonce signed by issuer account ##private key nonce = random.randint(2**20, 2**30) nonce_hash = hashlib.sha224(str(nonce).encode()).hexdigest() account_hex_signature = signatures.ecdsa_signature(requester_zeroth_priv, nonce) ##nonce must also be signed with the private key at random index at which ##create asset is present asset_hex_signature = signatures.ecdsa_signature(create_asset_priv, nonce) transaction_data = { "config": app.config, "txn_key": create_asset_signer, "batch_key": app.config.SIGNER, "key": encrypted_key, "url": encrypted_s3_url, "master_key": master_key, "master_url": master_url, "time": int(time.time()), "indiantime": upload_utils.indian_time_stamp(), "file_name": asset_instance.data["file_name"], "file_hash": asset_instance.data["file_hash"], "original_asset_address": asset_address, "revoked_on": revoked_on, "comments": comments, "idx": key_index, "account_signature": account_hex_signature, "asset_signature": asset_hex_signature, "nonce": nonce, "nonce_hash": nonce_hash, "to_org_name": receive_asset_instance.data["org_name"], "to_org_address": receive_asset_instance.data["org_address"], "issuer_account_address": requester_account_address, "receive_asset_address": receive_asset_address, "child_zero_pub": child_zero_pub, "unique_code_hash": unique_code_hash, } transaction_ids, batch_id = await send_share_asset(**transaction_data) if transaction_ids: logging.info("Share Transaction has been created successfully") ##which imlies the transaction has been submitted successfully, ##now all the changes that are required to be done on the databse can ##be done ##Update users create_asset_idxs key on users entry will be updated by ## whomever will call this, because update can happend on pending_users share_asset_address = addresser.share_asset_address( share_asset_pub, key_index) account_signature = account_hex_signature.decode() asset_signature = asset_hex_signature.decode() transaction_data.update({ "transaction_id": transaction_ids[0], "batch_id": batch_id, "account_signature": account_signature, "asset_signature": asset_signature, "address": share_asset_address }) [ transaction_data.pop(field) for field in ["config", "txn_key", "batch_key"] ] await share_assets_query.store_share_asset(app, transaction_data) ##now asset must be update with share_with key await assets_query.update_issuer_asset_shared(app, asset_address, key_index) ##TOFO update receiver_address asset and issuer_asset_Address in DB await accounts_query.update_share_asset_idxs(app, org_state["user_id"], key_index) if child_user_id: await accounts_query.update_share_asset_idxs( app, child_user_id, key_index) return share_asset_address else: return False return
async def submit_share_secret(app, requester, requester_address, receive_secret, index, private_key): """ Args: requester(dict): The db entry of the user who wants to share the mnemonic receive_secret(dict): The blockchain state of the receive_secret addr to whom this user wants to share the mnemonic {'role': 'USER', 'active': True, 'created_on': '2018-12-28 19:59:14 IST+0530', 'nonce': 802584806, 'signed_nonce': '304402204b79ebf02b7.........', 'nonce_hash': '87b4e684b071956e5598b.........', 'idx': 1044988318, 'public': '026f914d49e6321f668139e75.........', 'address': 'a9d5c23e49419e21d9f5a2ef.........', "salt": "secret": the part of the mnemonic share shared with this receive_secret} address is added by deserialize_receive_secret function secret_share (str): One share of the encrypted mnemonic of the user out of many others which will be shared with the user represented by account. index(int): ranom index generated from the user mnemonic at which a new shared_mnemonic address will be generated at which this share of the mnemonic will be stored after encrypting it with a random AES key and encrypting AES key with the public key of the user represented but the account. private_key(str): private key of the requested generated from its mnemonic present at the index. """ acc_signer = create_signer(private_key) ##encrypting the shared mnemonic with users account public key ##the return will also be in bytes i.e encrypted_secret_share #encrypted_secret_share = pub_encrypt(secret_share, account["public"]) #logging.info(encrypted_secret_share) #secret_share = binascii.hexlify(encrypted_secret_share) key = generate_aes_key(16) ##this is in bytes ciphertext, tag, nonce = aes_encrypt(key, receive_secret["secret"]) ciphertext = b"".join([tag, ciphertext, nonce]) ##The AES_GCM encrypted file content encryptes_secret_share = binascii.hexlify(ciphertext).decode() ##Encrypting AES key with the public key present at the receive_secret transaction, ##output will ne hex encoded encryted AES key encrypted_key = encrypt_w_pubkey(key, receive_secret["public"]) nonce = random.randint(2**20, 2**30) ##nonce signed by zerothprivate key and in hex format signed_nonce = ecdsa_signature(requester["zeroth_private"], nonce) nonce_hash = hashlib.sha512(str(nonce).encode()).hexdigest() transaction_data = { "ownership": receive_secret["address"], "active": False, "secret": encryptes_secret_share, "key": encrypted_key, "secret_hash": hashlib.sha512(receive_secret["secret"]).hexdigest(), "role": "USER", "idx": index, "created_on": route_utils.indian_time_stamp(), "nonce": nonce, "signed_nonce": signed_nonce, "nonce_hash": nonce_hash, "user_address": requester_address #because at the processing side ##user state needs to be appended with ##shared_asecret_address on their share_secret_addresses } share_secret_address = addresser.shared_secret_address( acc_signer.get_public_key().as_hex(), index) ##both the inputs and outputs addresses will be the same ##requester addresss will be fetched from blockchain and checked if its exists ##and the shared_secret_addresses will be appended to its inputs = [ requester_address, share_secret_address, receive_secret["address"] ] outputs = [requester_address, share_secret_address] payload = payload_pb2.CreateShareSecret(**transaction_data) instance = await SendTransactions(app.config.REST_API_URL, app.config.TIMEOUT) transaction_id, transaction = await instance.share_mnemonic_transaction( txn_key=acc_signer, batch_key=app.config.SIGNER, inputs=inputs, outputs=outputs, payload=payload) transaction_data.update({ "transaction_id": transaction_id, "transaction": transaction, "share_secret_address": share_secret_address, "signed_nonce": signed_nonce.decode(), "public": acc_signer.get_public_key().as_hex() }) return transaction_data
async def submit_transfer_asset(app, requester, issuer_address, receiver_address, expired_on): ##decrypting issuer mnemonic logging.info("Enter into Transfer asset") f = await userapis.SolveAccount(requester, app) decrypted_mnemonic = f.decrypted_mnemonic logging.info(f"Requester Mnemonic is {decrypted_mnemonic}") instance = await userapis.SolveAddress(issuer_address, app.config.REST_API_URL) ##getting issuer public key and the index at which this asset was created if instance.type != "CREATE_ASSET": raise AssetError("Not a valid issuer address") issuer_asset = instance.data issuer_asset_public_key, issuer_asset_idx = \ issuer_asset["public"], issuer_asset["idx"] instance = await userapis.SolveAddress(receiver_address, app.config.REST_API_URL) if instance.type != "CREATE_ASSET": raise AssetError("Not a valid receiver address") receiver_asset = instance.data logging.info(f"Deserialized receiver asset <<{issuer_asset}>>") ##checking is issuer asset is empty or not, empty assets cant be transffered if not issuer_asset["file_name"] or not issuer_asset["file_hash"]: logging.error("Empty assets cannot be transffered") raise AssetError("Empty assets cannot be transffered") ##Check if the asset had been transffered to the issuer i.e issets which were ###not created by the issuer cant be transffered to other users if issuer_asset.get("ownership_received"): message = f"This asset is not owned by the user but \ received from {issuer_asset['parent_address']}" logging.error(message) raise AssetError(message) ##checking if receiver_asset is empty or not, non empty assets couldnt receive ##assets if receiver_asset.get("file_name") or receiver_asset.get("file_hash"): logging.error("Non empty assets cannot be a receiver") raise AssetError("Non empty assets cannot be a receiver") ##get issuer keys from the GOAPI_URL, private key corresponding to the ##random index public key at which the asset was floated issuer_keys = await remote_calls.key_index_keys(app, decrypted_mnemonic, [issuer_asset_idx, 0]) issuer_zeroth_priv, issuer_zeroth_pub = \ issuer_keys[str(0)]["private_key"], \ issuer_keys[str(0)]["public_key"] issuer_nth_priv, issuer_nth_pub = issuer_keys[str(issuer_asset_idx)]["private_key"], \ issuer_keys[str(issuer_asset_idx)]["public_key"] ##check if issuer n th public key is exactly the public key mentioned in the ##asset transaction present on the blockchain, this also checks whether ##the requester is actually the owner of the asset if issuer_nth_pub != issuer_asset_public_key: logging.error("This asset address is not owned by the issuer") raise AssetError("This asset address is not owned by the issuer") ##decrypting file data stored ob the issuer asset address, this can be ##done by issuer private key present on the nth index data = await asset_utils.decrypt_file_data(issuer_asset["key"], issuer_asset["url"], issuer_asset["file_hash"], issuer_nth_priv) ##TODO: check file_hash file_data = { "data": data, "file_name": issuer_asset["file_name"], "file_hash": issuer_asset["file_hash"] } ##encrypting again with the public key present at the receiver_asset_address key, encrypted_key, s3_url, encrypted_s3_url = \ await asset_utils.encrypt_file_data(None, receiver_asset["public"], app.config, file_data) logging.info(f"This is the key {key} , encrypted_key{encrypted_key} \ and the s3_url {s3_url}") master_key, master_url = await asset_utils.master_url_n_key( app.config.ADMIN_ZERO_PUB, key, s3_url) ##Now this transaction should be signed by user create_asset_signer = ledger_utils.create_signer(issuer_nth_priv) ##for added security we will send a nonce signed by issuer account ##private key nonce = random.randint(2**20, 2**30) ##nonce signed by zerothprivate key and in hex format hex_signatures = signatures.ecdsa_signature(issuer_zeroth_priv, nonce) transaction_data = { "config": app.config, "txn_key": create_asset_signer, "batch_key": app.config.SIGNER, "key": encrypted_key, "url": encrypted_s3_url, "time": int(time.time()), "indiantime": upload_utils.indian_time_stamp(), "file_name": issuer_asset["file_name"], "file_hash": issuer_asset["file_hash"], "expired_on": expired_on, "master_key": master_key, "master_url": master_url, "scope": issuer_asset["scope"], "receiver_address": receiver_address, "issuer_address": issuer_address, "issuer_pub": issuer_nth_pub, "issuer_zero_pub": issuer_zeroth_pub, "signed_nonce": hex_signatures, "nonce": nonce, "issuer_child_zero_pub": issuer_asset.get("child_zero_pub"), } logging.info(transaction_data) transaction_ids, batch_id = await send_transfer_asset(**transaction_data) if transaction_ids: ##just because signatures are in bytes signed_nonce = transaction_data["signed_nonce"].decode() logging.info("Create Transaction has been created successfully") ##which imlies the transaction has been submitted successfully, ##now all the changes that are required to be done on the databse can ##be done ##Update users create_asset_idxs key on users entry will be updated by ## whomever will call this, because update can happend on pending_users transaction_data.update({ "transaction_id": transaction_ids[0], "batch_id": batch_id, "signed_nonce": signed_nonce }) [ transaction_data.pop(field) for field in ["config", "txn_key", "batch_key"] ] await transfer_assets_query.store_transfer_assets( app, transaction_data) await assets_query.update_issuer_asset(app, issuer_address, transaction_data) await assets_query.update_receiver_asset(app, receiver_address, transaction_data) ##TOFO update receiver_address asset and issuer_asset_Address in DB return True else: return False return
async def submit_child_account(app, parent_org, child): """ Decrypt parent_org menmonic with the ADMIN private key Get orgnization account for parent_org Generate a random index at the child_account_idxs array of the Get Public/Private key pair at random_indexfrom parent_org mnemonic Generate child_address from this pair and index Signed nonce with zeroth public key of the parent_org """ decrypted_mnemonic = await ledger_utils.decrypted_user_mnemonic( app, parent_org["encrypted_admin_mnemonic"], parent_org["role"]) logging.info(decrypted_mnemonic) org_address = addresser.create_organization_account_address( parent_org["acc_zero_pub"], 0) org_account = await deserialize_state.deserialize_org_account( app.config.REST_API_URL, org_address) logging.info(org_account) ##lets chaeck if the parent user_i child_account_idxs = org_account.get("child_account_idxs") ##This will generate a new key which doesnt exists in the flt_acc_idxs array key_index = await ledger_utils.generate_key_index(child_account_idxs) logging.info(f"THis is the key index for parent {key_index}") nth_keys = await remote_calls.key_index_keys(app, decrypted_mnemonic, [key_index, 0]) org_nth_priv, org_nth_pub = nth_keys[str(key_index)]["private_key"], \ nth_keys[str(key_index)]["public_key"] ##getting zeroth private key to be used later org_zeroth_priv, org_zeroth_pub = nth_keys[str(0)]["private_key"], \ nth_keys[str(0)]["public_key"] ##signer created from the parent key signer = upload_utils.create_signer(org_nth_priv) ##sending signatures, A nonce signed by zeroth_private_key nonce = random.randint(2**20, 2**31) nonce_hash = hashlib.sha224(str(nonce).encode()).hexdigest() hex_signatures = signatures.ecdsa_signature(org_zeroth_priv, nonce) ##import from ledger.account import float_account, other then create_asset_idxs ## wil be emprty for the float_account, if we push empty list on blockchain ##it wil hsow an error, its better to not to send them at the first place transaction_data = { "config": app.config, "txn_key": signer, "batch_key": app.config.SIGNER, "parent_idx": key_index, "parent_zero_pub": org_zeroth_pub, "parent_role": parent_org["role"], "first_name": child["first_name"], "last_name": child["last_name"], "org_name": child["org_name"], "user_id": child["user_id"], "pancard": child["pancard"], "gst_number": child["gst_number"], "tan_number": child["tan_number"], "phone_number": child["phone_number"], "email": child["email"], "time": int(time.time()), "indian_time": upload_utils.indian_time_stamp(), "role": "CHILD", "deactivate": False, "deactivate_on": None, "nonce": nonce, "nonce_hash": nonce_hash, "signed_nonce": hex_signatures } transaction_ids, batch_id = await send_child_account(**transaction_data) logging.info(batch_id) if batch_id: ##if successful, insert this user in pending_users table child.update({ "parent_idx": key_index, "public": org_nth_pub, "transaction_id": transaction_ids[0], "batch_id": batch_id, "parent_zero_pub": org_zeroth_pub, "parent_role": parent_org["role"], "nonce": nonce, "nonce_hash": nonce_hash, "signed_nonce": hex_signatures.decode(), "time": transaction_data["time"], "indian_time": transaction_data["indian_time"], "role": "CHILD", "deactivate": False, "deactivate_on": None, }) logging.debug(child) await accounts_query.insert_account(app, child) ##update child_account_idxs array of the parent_org await accounts_query.update_child_account_idxs(app, parent_org["user_id"], key_index) return child
async def submit_float_account(app, requester, user): ##retrive float_account from parent ## handle if the parent is actually a child account, then the flt_acc_idxs ## of the parent must be used ##elseif organization is directly creating another org account then its ## own flt_account_idxs must be used ##a junk entry needs to be sent which is A once signed by the parent orgnisation of the ## child or the organization itself zeroth_private_key, which that the float_account is ## actually being sent by the concerned authority, otherwise anyone can generate any ## random keys and then make a float_transaction because we are not checking any other details ## for cros checking if requester["role"] == "CHILD": ##now find the parent pub of this child to track the parent ##organization account ##child will get the flt_acc_idxs of the parent organization org_address = addresser.create_organization_account_address( requester["parent_zero_pub"], 0) org_account = await deserialize_state.deserialize_org_account( app.config.REST_API_URL, org_address) logging.info(org_account) ##lets chaeck if the parent user_id hash matched with the child parent_id if requester["parent_idx"] not in org_account["child_account_idxs"]: raise Exception("Child parent_idx not in parent org child_account_idxs") if requester["org_name"] != org_account["org_name"]: raise Exception("Child org_name is different from parent") ##since child was created from the PUblic key present at parent_idx at the ##parent org mnemonic, We need to get that so that we can generated child ##adddress, Remember, child_account_addresses generates from parent_org ##not with the zeroth key of the child mnemonic ##TODO: you can also check whether the child address generated from #parent org public key pair at requester parent_idx is same as requester ## address ##float_account_idxs array of the child's parent organisation flt_acc_idxs = org_account.get("float_account_idxs") ##now we need to decrypt the parent mnemonic so that we can get the Public/private key ##pair corresponding to the the random index parent_id = org_account["user_id"] logging.info(f"Parent id for the child is {parent_id} and\ float_account_idxs are {flt_acc_idxs}") org_db = await accounts_query.find_on_key(app, "user_id", parent_id) logging.info(org_db) if org_db["role"] != "ADMIN": decrypted_mnemonic = await ledger_utils.decrypted_user_mnemonic( app, org_db["encrypted_admin_mnemonic"], org_db["role"]) else: decrypted_mnemonic = app.config.ADMIN_MNEMONIC logging.info(decrypted_mnemonic) nth_keys = await remote_calls.key_index_keys(app, decrypted_mnemonic, [requester["parent_idx"]]) nth_priv, nth_pub = nth_keys[str(requester["parent_idx"])]["private_key"], \ nth_keys[str(requester["parent_idx"])]["public_key"] zero_pub = org_db["acc_zero_pub"] parent_role = org_db["role"] child_zero_pub = nth_pub else: #orgnisation itself is creating this float_account logging.info(requester) ##float_account_idxs array of the orgnization itself flt_acc_idxs = await accounts_query.get_field(app, requester["user_id"], "float_account_idxs") flt_acc_idxs = flt_acc_idxs.get("float_account_idxs") logging.info(f"Float account indxs for the orgnization {flt_acc_idxs}") decrypted_mnemonic = await ledger_utils.decrypted_user_mnemonic(app, requester["encrypted_admin_mnemonic"], requester["role"]) logging.info(decrypted_mnemonic) zero_pub = requester["acc_zero_pub"] parent_role = requester["role"] child_zero_pub = None logging.info(f"This is the decrypted mnemonic for parent {decrypted_mnemonic}") ##This will generate a new key which doesnt exists in the flt_acc_idxs array key_index = await ledger_utils.generate_key_index(flt_acc_idxs) logging.info(f"THis is the key index for parent {key_index}") nth_keys = await remote_calls.key_index_keys(app, decrypted_mnemonic, [key_index, 0]) nth_priv, nth_pub = nth_keys[str(key_index)]["private_key"], \ nth_keys[str(key_index)]["public_key"] ##getting zeroth private key to be used later zeroth_priv, zeroth_pub = nth_keys[str(0)]["private_key"], \ nth_keys[str(0)]["public_key"] flt_acc_address = addresser.float_account_address(nth_pub, key_index) logging.info(f"This is the flt acc addressfor user {flt_acc_address}") logging.info(f"Checking if valid account address has been generated\ {addresser.address_is(flt_acc_address)}") ##signer created from the parent key flt_acc_signer=upload_utils.create_signer(nth_priv) ##sending signatures, A nonce signed by zeroth_private_key nonce = random.randint(2**20, 2**31) nonce_hash = hashlib.sha224(str(nonce).encode()).hexdigest() hex_signatures = signatures.ecdsa_signature(zeroth_priv, nonce) ##hashing gst number and tan number if present if user.get("gst_number"): gst_number = hashlib.sha224(user["gst_number"].encode()).hexdigest() else: gst_number = None if user.get("tan_number"): tan_number = hashlib.sha224(user["tan_number"]\ .encode()).hexdigest() else: tan_number = None ##import from ledger.account import float_account transaction_data= {"config": app.config, "txn_key": flt_acc_signer, "batch_key": app.config.SIGNER, "org_name": user["org_name"], "pancard": hashlib.sha224(user["pancard"]\ .encode()).hexdigest(), "gst_number": gst_number, "tan_number": tan_number, "phone_number": user["phone_number"], "email": user["email"], "claimed": False, "claimed_by": None, "create_asset_idxs": [], "parent_pub": nth_pub, "parent_idx": key_index, "time": int(time.time()), "indian_time": upload_utils.indian_time_stamp(), "parent_zero_pub": zero_pub, "parent_role": parent_role, "role": user["role"], "claimed_on": None, "nonce": nonce, "nonce_hash": nonce_hash, "signed_nonce": hex_signatures, "child_zero_pub": child_zero_pub } transaction_ids, batch_id = await send_float_account(**transaction_data) if batch_id: logging.debug(user) ##if successful, insert this user in pending_users table user.update({"parent_pub": nth_pub, "parent_idx": key_index, "time": transaction_data["time"], "indian_time": transaction_data["indian_time"], "parent_zero_pub": transaction_data["parent_zero_pub"], "parent_role": transaction_data["parent_role"], "transaction_id": transaction_ids[0], "batch_id": batch_id, "child_zero_pub": child_zero_pub, }) logging.debug(f"User after submitting float_Account trasaction {user}") await accounts_query.insert_pending_account(app, user) if requester["role"] == "CHILD": ##update parent create_flt_idcs array await accounts_query.update_flt_acc_idxs(app, org_db["user_id"], key_index) ##update float_account_idxs of the child also, so that we would ##know which child created which float_account_idxs await accounts_query.update_flt_acc_idxs(app, requester["user_id"], key_index) else: await accounts_query.update_flt_acc_idxs(app, requester["user_id"], key_index) ##return new user data whose float_account has just been created return user