async def __send_user_account(**in_data): """ """ inputs = [ addresser.user_address( public=in_data["txn_key"].get_public_key().as_hex(), index=0), ] outputs = [ addresser.user_address( public=in_data["txn_key"].get_public_key().as_hex(), index=0), ] account = payload_pb2.CreateUserAccount( role=in_data["role"], phone_number=in_data["phone_number"], pancard=in_data["pancard"], first_name=in_data["first_name"], last_name=in_data["last_name"], user_id=in_data["user_id"], email=in_data["email"], time=in_data["time"], indian_time=in_data["indian_time"], deactivate=in_data["deactivate"], deactivate_on=in_data["deactivate_on"], ) logging.info(account) logging.info(f"THe address for the user on blockchain {inputs[0]}") payload = payload_pb2.TransactionPayload( payload_type=payload_pb2.TransactionPayload.CREATE_USER_ACCOUNT, create_user_account=account) logging.info(payload) transaction_ids, batches, batch_id, batch_list_bytes = make_header_and_batch( payload=payload, inputs=inputs, outputs=outputs, txn_key=in_data["txn_key"], batch_key=in_data["batch_key"]) logging.info(f"This is the batch_id {batch_id}") rest_api_response = await messaging.send(batch_list_bytes, in_data["config"]) try: result = await messaging.wait_for_status(batch_id, in_data["config"]) except (ApiBadRequest, ApiInternalError) as err: #await auth_query.remove_auth_entry(request.app.config.DB_CONN, request.json.get('email')) raise err return False, False return transaction_ids, batch_id
def get_user(self, public_key): try: address = addresser.user_address(public=public_key, index=0) except Exception as e: logging.error(e) raise InvalidTransaction("get_user error =={}".format(e)) ##entries will be a weird list of the form ##[address: "318c9fa5d39e9ccd2769115795e384b8e83b3267172ae518136ac49ddc5adf71d87814" ##data: "\nB02dbf0f4a3defef38df754122ef7c10fee6a4bb363312367524f86d230e205d459\022$b6de5d5b-7870-49df-971e-0885986bfa96\032 ##\006seller\"\021978-0-9956537-6-4*\0161-191-790-04532\r1-932866-82-5:\001\000"] entries = self._context.get_state(addresses=[address], timeout=self._timeout) logging.info("ENtries correspoding to user account address \ {} are {}".format(address, entries)) try: entry = entries[0] except Exception as e: logging.info( "No user account with address {} and publickey {} can be \ found".format(address, public_key)) return False account = empty_user() account.ParseFromString(entry.data) logging.info("This is the account at {} stored on blockchain \ {}".format(address, account)) return account
def set_user(self, public_key, payload): if "" in [ payload.first_name, payload.last_name, payload.email, payload.phone_number ]: raise InvalidTransaction('shouldnt be left empty') address = addresser.user_address(public_key, 0) logging.info("THis is the user address {}".format(address)) user = empty_user() user.public = public_key user.role = payload.role user.phone_number = payload.phone_number user.pancard = payload.pancard user.user_id = payload.user_id user.email = payload.email user.first_name = payload.first_name user.last_name = payload.last_name user.time = payload.time user.indian_time = payload.indian_time user.deactivate = payload.deactivate user.deactivate_on = payload.deactivate_on logging.info("User before serialization %s", user) return self._context.set_state({address: user.SerializeToString()}, self._timeout)
async def user_details(self, public): user_address = addresser.user_address(public, 0) user_state = await deserialize_state.deserialize_user( self.app.config.REST_API_URL, user_address) user_db = await accounts_query.find_on_key(self.app, "user_id", user_state["user_id"]) return user_address, user_state, user_db
async def forgot_password(request): """ This api will be used when the user forgot their password and they have chosed the second option where they have stored their mnemonic with other users on the blockchain. """ required_fields = ["email", "otp_email", "phone_number", "otp_mobile", "new_password"] validate_fields(required_fields, request.json) required_pattern = re.compile('(?=.{6,})(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[@#$%^&*()])') if not required_pattern.match(request.json["new_password"]) or \ len(request.json["new_password"]) <= 8: raise errors.PasswordStrengthError() account_db = await accounts_query.find_user(request.app, request.json["phone_number"], request.json["email"]) if not account_db: raise CustomError("This user doesnt exists, Please register first") otp_email = int(request.json["otp_email"]) otp_mobile = int(request.json["otp_mobile"]) await verify_otp(request.app, otp_email, request.json["email"], otp_mobile, request.json["phone_number"]) if account_db["role"] == "USER": address = addresser.user_address(account_db["acc_zero_pub"], 0) state = await deserialize_state.deserialize_user( request.app.config.REST_API_URL, address) logging.info(state) await activate_secret_batch_submit(request.app, account_db, request.json["new_password"]) elif account_db["role"] == "ORGANIZATION": address = addresser.organization_address(account_db["acc_zero_pub"], 0) elif account_db["role"] == "CHILD": ##TODO pass else: raise CustomError("Undefined role for this user") logging.info(state) return response.json( { 'error': False, 'success': True, 'message': "Success", })
async def share_secret_batch_submit(app, requester, receive_secrets, nth_keys_data): """ Args: requester(dict): db entry of the user who is sharing the Menmonic receive_secrets(list of dictionaies): The recieve_secret transactions present on the the blockchain with whom the user wants to share the mnemonic, this has three addtional keys salt (hex encoded): THe salt used, while encrypting mnemonic share with scrypt ket generated from user email address(string): address of the receive secret on blockchain secret(hex encoded): hex encoded encrypted secret nth_keys_data(dict with keys as random indexes): The Pub/Priv key pairs generated from the random indexes generated from the user mnemonic who wants to share his/her mnemonic, the pub/priv keys are ecc keys fetched from go_api All the trasactions will be packaged into a batch and then will be submitted to the ledger, If one transaction fails, All transaction will fail as per the property of hyperledger sawtooth Output: True if all the trasactions in a batch will be submitted False if there is any error """ if requester["role"] == "USER": requester_address = addresser.user_address(requester["acc_zero_pub"], 0) else: logging.error("NOt implemented yet") async with aiohttp.ClientSession() as session: transactions = await asyncio.gather(*[ submit_share_secret( app, requester, requester_address, receive_secret, int( index), nth_keys_data[index]["private_key"]) for (receive_secret, index) in zip(receive_secrets, list(nth_keys_data.keys())) ]) batch_id, batch_bytes = multi_transactions_batch( [e["transaction"] for e in transactions], app.config.SIGNER) """ for e in [e["transaction"] for e in transactions]: logging.info(e) """ instance = await SendTransactions(app.config.REST_API_URL, app.config.TIMEOUT) await instance.push_n_wait(batch_bytes, batch_id) return batch_id, transactions
async def all_share_secrets(request, requester): """ Result will have two keys, floated and received, floated will have all the shared_secret addresses that this user have floated and have his encryptes mnemonic distribution the received is all the shared_Secret_addresses that have shared with him, This information can only be pulled from database right now but sawtooth events will be used later """ if requester["role"] == "USER": address = addresser.user_address(requester["acc_zero_pub"], 0) account = await deserialize_state.deserialize_user(request.app.config.REST_API_URL, address) else: logging.error("Not implemented yet") raise errors.ApiInternalError("This functionality is not implemented yet") logging.info(account) floated = account.get("share_secret_addresses") floated_result = [] if floated: #implies that user has already have created shared_secrets contracts and ##this array have the addresses of the shared_secrets async with aiohttp.ClientSession() as session: floated_result= await asyncio.gather(*[ deserialize_state.deserialize_share_secret( request.app.config.REST_API_URL, address) for address in floated ]) received_result =await get_addresses_on_ownership(request.app, address) return response.json( { 'error': False, 'success': True, "data": {"floated": floated_result, "received": [received_result]}, })
async def _address_account(self): """ Find address and account of the requester based on their role, the address and their blockchain state will be different for the user and organization role. """ if self.requester["role"] == "USER": account_address = addresser.user_address( self.requester["acc_zero_pub"], 0) account_state = await deserialize_state.deserialize_user( self.app.config.REST_API_URL, account_address) else: logger.error("Not implemented yet") raise errors.ApiInternalError("This functionality is not implemented yet") return account_address, account_state
async def receive_secret(request, requester): """ Wheneve a user shares their secret with other users, the user must have a receive_secret address, which must be generated from his mnemonic at some random index, this index will then be appended to users receive_secret_idxs array """ if requester["role"] == "USER": requester_address = addresser.user_address(requester["acc_zero_pub"], 0) else: ##handle case for organization pass ##resolving account for the requester to get his decrypted menmonic user = await ResolveAccount(requester, request.app) logging.info(user.decrypted_mnemonic) if user.org_state.get("receive_secret_idxs"): if len(user.org_state.get("receive_secret_idxs")) >= \ request.app.config.MAX_RECEIVE_SECRET: raise errors.ApiInternalError("Maximum amount of rceive_secret \ addresses limit reached") data = await submit_receive_secret(request.app, requester["user_id"], user.org_state, requester_address, user.decrypted_mnemonic) return response.json( { 'error': False, 'success': True, "data": data })
async def activate_secret_batch_submit(app, requester, password): ##the share_secret transaction were floated, depending upon the ##number of other users, our user has chosen who will have the secret shares ##of our users mnemonic #every share_secret transaction have ownership, address of other user account ## secret hash, hash of the secret_share ##key, particular key that was originally created to encrypt a particular share ## of particuar user, this key will be different for every user with whom ## secret share of menmonic was shared ##Now, the user has forgotten their password , Now based on their email address, ## the user will generate different AES keys, depending upon the number of users ##with whom he has shared their menmonic """ Steps: Retrive number of users account addresses in the shared_secret array of the user, Generate that numbers of Scrypt keys from the password wth different salts these salts will then be stored in the user accounts, just using these salts admin cant decrypt the mnemonic """ ##must be intialized db_instance = await DBSecrets( app, table_name="share_secret", array_name="share_secret_addresses", ) requester_address = addresser.user_address(requester["acc_zero_pub"], 0) ##get user account from the blokchain, its shared_secret will have all share_secret ##addresses requester_state = await deserialize_state.deserialize_user( app.config.REST_API_URL, requester_address) ##allt he shared_secret_addresses for the user share_secret_addresses = requester_state["share_secret_addresses"] ##Deserializing all the shared_secret transaction present on the blockchain ## i.e all the data corresponding to the share_secret_addresses list of addresses async with aiohttp.ClientSession() as session: share_secret_transactions = await asyncio.gather(*[ deserialize_state.deserialize_share_secret(app.config.REST_API_URL, address) for address in share_secret_addresses ]) ##now every share_Secret transaction as a key called as ownership which is ##actually an addresss of the receive_Secret transaction, Now appending ##public key of that receive_Secret transaction to the transaction data for transaction in share_secret_transactions: receive_secret = await deserialize_state.deserialize_receive_secret( app.config.REST_API_URL, transaction["ownership"]) transaction.update({"owner_public": receive_secret["public"]}) async with aiohttp.ClientSession() as session: transactions = await asyncio.gather(*[ submit_activate_secret(app, transaction, password) for transaction in share_secret_transactions ]) instance = await SendActivateSecret(app.config.REST_API_URL, app.config.TIMEOUT) batch_id, batch_list_bytes = await instance.push_batch( [e["transaction"] for e in transactions], app.config.SIGNER) try: for transaction in transactions: transaction.update({ "batch_id": batch_id, "user_id": requester["user_id"] }) await db_instance.update_reset_key(app, transaction) except Exception as e: logging.error(e) raise CustomError(e) return True
async def conclude_secret_batch_submit(app, requester, mnemonic): ##the share_secret transaction were floated, depending upon the ##number of other users, our user has chosen who will have the secret shares ##of our users mnemonic #every share_secret transaction have ownership, address of other user account ## secret hash, hash of the secret_share ##key, particular key that was originally created to encrypt a particular share ## of particuar user, this key will be different for every user with whom ## secret share of menmonic was shared ##Now, the user has forgotten their password , Now based on their email address, ## the user will generate different AES keys, depending upon the number of users ##with whom he has shared their menmonic """ Steps: Retrive number of users account addresses in the shared_secret array of the user, Generate that numbers of Scrypt keys from the password wth different salts these salts will then be stored in the user accounts, just using these salts admin cant decrypt the mnemonic """ ##must be intialized requester_address = addresser.user_address(requester["acc_zero_pub"], 0) ##get user account from the blokchain, its shared_secret will have all share_secret ##addresses requester_state = await deserialize_state.deserialize_user( app.config.REST_API_URL, requester_address) ##allt he shared_secret_addresses for the user share_secret_addresses = requester_state["share_secret_addresses"] ##Deserializing all the shared_secret transaction present on the blockchain ## i.e all the data corresponding to the share_secret_addresses list of addresses async with aiohttp.ClientSession() as session: share_secret_transactions = await asyncio.gather(*[ deserialize_state.deserialize_share_secret(app.config.REST_API_URL, address) for address in share_secret_addresses ]) indexes = [e["idx"] for e in share_secret_transactions] indexes.append(0) nth_keys = await remote_calls.key_index_keys(app, mnemonic, indexes) zeroth_priv, zeroth_pub = nth_keys[str(0)]["private_key"], nth_keys[str( 0)]["public_key"] for share_secret_state in share_secret_transactions: logger.info(nth_keys[str(share_secret_state["idx"])]["private_key"]) async with aiohttp.ClientSession() as session: transactions = await asyncio.gather(*[ submit_conclude_secret( app, requester_address, share_secret_state, zeroth_priv, nth_keys[str(share_secret_state["idx"])]["private_key"]) for share_secret_state in share_secret_transactions ]) logger.info(nth_keys) instance = await SendConcludeSecret(app.config.REST_API_URL, app.config.TIMEOUT) batch_id, batch_list_bytes = await instance.push_batch( [e["transaction"] for e in transactions], app.config.SIGNER) return batch_id