def fulfill_escrow_reward_condition(event, agreement_id, service_agreement, price, consumer_address, publisher_account, condition_ids): """ :param event: AttributeDict with the event data. :param agreement_id: id of the agreement, hex str :param service_agreement: ServiceAgreement instance :param price: Asset price, int :param consumer_address: ethereum account address of consumer, hex str :param publisher_account: Account instance of the publisher :param condition_ids: is a list of bytes32 content-addressed Condition IDs, bytes32 :return: """ logger.debug(f"release reward after event {event}.") access_id, lock_id = condition_ids[:2] assert price == service_agreement.get_price(), 'price mismatch.' try: tx_hash = Keeper.get_instance().escrow_reward_condition.fulfill( agreement_id, price, publisher_account.address, consumer_address, lock_id, access_id, publisher_account) process_tx_receipt( tx_hash, Keeper.get_instance().escrow_reward_condition.FULFILLED_EVENT, 'EscrowReward.Fulfilled') except Exception as e: # logger.error(f'Error when doing escrow_reward_condition.fulfills: {e}') raise e
def init_ocn_tokens(ocn, account, amount=100): ocn.accounts.request_tokens(account, amount) Keeper.get_instance().token.token_approve( Keeper.get_instance().dispenser.address, amount, account )
def get_contract_dict_by_name(contract_name): """ Retrieve the Contract instance for a given contract name. :param contract_name: str :return: the smart contract's definition from the json abi file, dict """ network_name = Keeper.get_network_name(Keeper.get_network_id()).lower() artifacts_path = ConfigProvider.get_config().keeper_path # file_name = '{}.{}.json'.format(contract_name, network_name) # path = os.path.join(keeper.artifacts_path, file_name) path = ContractHandler._get_contract_file_path(artifacts_path, contract_name, network_name) if not (path and os.path.exists(path)): path = ContractHandler._get_contract_file_path( artifacts_path, contract_name, network_name.lower()) if not (path and os.path.exists(path)): path = ContractHandler._get_contract_file_path( artifacts_path, contract_name, Keeper.DEFAULT_NETWORK_NAME) if not (path and os.path.exists(path)): raise FileNotFoundError(f'Keeper contract {contract_name} file ' f'not found in {artifacts_path} ' f'using network name {network_name}') with open(path) as f: contract_dict = json.loads(f.read()) return contract_dict
def fulfill_access_secret_store_condition(event, agreement_id, did, service_agreement, consumer_address, publisher_account): """ Fulfill the access condition. :param event: AttributeDict with the event data. :param agreement_id: id of the agreement, hex str :param did: DID, str :param service_agreement: ServiceAgreement instance :param consumer_address: ethereum account address of consumer, hex str :param publisher_account: Account instance of the publisher """ logger.debug(f"release reward after event {event}.") name_to_parameter = { param.name: param for param in service_agreement.condition_by_name['accessSecretStore'].parameters } document_id = add_0x_prefix(name_to_parameter['_documentId'].value) asset_id = add_0x_prefix(did_to_id(did)) assert document_id == asset_id, f'document_id {document_id} <=> asset_id {asset_id} mismatch.' try: tx_hash = Keeper.get_instance().access_secret_store_condition.fulfill( agreement_id, document_id, consumer_address, publisher_account) process_tx_receipt( tx_hash, Keeper.get_instance().access_secret_store_condition. FULFILLED_EVENT, 'AccessSecretStoreCondition.Fulfilled') except Exception as e: # logger.error(f'Error when calling grantAccess condition function: {e}') raise e
def verify_contracts(): """ Verify that the contracts are deployed correctly in the network. :raise Exception: raise exception if the contracts are not deployed correctly. """ artifacts_path = ConfigProvider.get_config().keeper_path logger.info( f'Keeper contract artifacts (JSON abi files) at: {artifacts_path}') if os.environ.get('KEEPER_NETWORK_NAME'): logger.warning( f'The `KEEPER_NETWORK_NAME` env var is set to ' f'{os.environ.get("KEEPER_NETWORK_NAME")}. ' f'This enables the user to override the method of how the network name ' f'is inferred from network id.') # try to find contract with this network name contract_name = Diagnostics.TEST_CONTRACT_NAME network_id = Keeper.get_network_id() network_name = Keeper.get_network_name(network_id) logger.info(f'Using keeper contracts from network {network_name}, ' f'network id is {network_id}') logger.info( f'Looking for keeper contracts ending with ".{network_name}.json", ' f'e.g. "{contract_name}.{network_name}.json".') existing_contract_names = os.listdir(artifacts_path) try: ContractHandler.get(contract_name) except Exception as e: logger.error(e) logger.error( f'Cannot find the keeper contracts. \n' f'Current network id is {network_id} and network name is {network_name}.' f'Expected to find contracts ending with ".{network_name}.json",' f' e.g. "{contract_name}.{network_name}.json"') raise OceanKeeperContractsNotFound( f'Keeper contracts for keeper network {network_name} were not found ' f'in {artifacts_path}. \n' f'Found the following contracts: \n\t{existing_contract_names}' ) keeper = Keeper.get_instance() contracts = [ keeper.dispenser, keeper.token, keeper.did_registry, keeper.agreement_manager, keeper.template_manager, keeper.condition_manager, keeper.access_secret_store_condition, keeper.sign_condition, keeper.lock_reward_condition, keeper.escrow_access_secretstore_template, keeper.escrow_reward_condition, keeper.hash_lock_condition ] addresses = '\n'.join([f'\t{c.name}: {c.address}' for c in contracts]) logging.info('Finished loading keeper contracts:\n' '%s', addresses)
def process_agreement_events_publisher(publisher_account, agreement_id, did, service_agreement, price, consumer_address, condition_ids): """ Process the agreement events during the register of the service agreement for the publisher side :param publisher_account: Account instance of the publisher :param agreement_id: id of the agreement, hex str :param did: DID, str :param service_agreement: ServiceAgreement instance :param price: Asset price, int :param consumer_address: ethereum account address of consumer, hex str :param condition_ids: is a list of bytes32 content-addressed Condition IDs, bytes32 :return: """ conditions_dict = service_agreement.condition_by_name keeper = Keeper.get_instance() keeper.lock_reward_condition.subscribe_condition_fulfilled( agreement_id, conditions_dict['lockReward'].timeout, access_secret_store_condition.fulfillAccessSecretStoreCondition, (agreement_id, did, service_agreement, consumer_address, publisher_account)) keeper.access_secret_store_condition.subscribe_condition_fulfilled( agreement_id, conditions_dict['accessSecretStore'].timeout, escrow_reward_condition.fulfillEscrowRewardCondition, (agreement_id, service_agreement, price, consumer_address, publisher_account, condition_ids)) keeper.escrow_reward_condition.subscribe_condition_fulfilled( agreement_id, conditions_dict['escrowReward'].timeout, verify_reward_condition.verifyRewardTokens, (agreement_id, did, service_agreement, price, consumer_address, publisher_account))
def lock_reward(ocean, account, agreement_id): keeper = Keeper.get_instance() ocean_conditions = OceanConditions(keeper) amount = int(get_agreement_from_id(ocean, agreement_id).get_price()) keeper.token.token_approve(keeper.lock_reward_condition.address, amount, account) return ocean_conditions.lock_reward(agreement_id, amount, account)
def fulfill_lock_reward_condition(event, agreement_id, price, consumer_account): """ Fulfill the lock reward condition. :param event: AttributeDict with the event data. :param agreement_id: id of the agreement, hex str :param price: Asset price, int :param consumer_account: Account instance of the consumer """ logger.debug(f"about to lock reward after event {event}.") keeper = Keeper.get_instance() tx_hash = None try: keeper.token.token_approve(keeper.lock_reward_condition.address, price, consumer_account) tx_hash = keeper.lock_reward_condition.fulfill( agreement_id, keeper.escrow_reward_condition.address, price, consumer_account ) process_tx_receipt( tx_hash, keeper.lock_reward_condition.FULFILLED_EVENT, 'LockRewardCondition.Fulfilled' ) except Exception as e: logger.debug(f'error locking reward: {e}') if not tx_hash: raise e
def test_ec_recover(): test_values = [ ('0xe2DD09d719Da89e5a3D0F2549c7E24566e947260', 'c80996119e884cb38599bcd96a22ad3eea3a4734bcfb47959a5d41ecdcbdfe67', '0xa50427a9d5beccdea3eeabecfc1014096b35cd05965e772e8ea32477d2f217' 'c30d0ec5dbf6b14de1d6eeff45011d17490fe5126576b20d2cbada828cb068c9f801' ), ('0x00Bd138aBD70e2F00903268F3Db08f2D25677C9e', 'd77c3a84cafe4cb8bc28bf41a99c63fd530c10da33a54acf94e8d1369d09fbb2', '0x9076b561e554cf657af333d9680ba118d556c5b697622636bce4b02f4d5632' '5a0ea6a474ca85291252c8c1b8637174ee32072bef357bb0c21b0db4c25b379e781b' ), ('0xe2DD09d719Da89e5a3D0F2549c7E24566e947260', '8d5c1065a9c74da59fbb9e41d1f196e40517e92d81b14c3a8143d6887f3f4438', '0x662f6cffd96ada4b6ce5497d444c92126bd053ab131915332edf0dbba716ba' '82662275670c95eb2a4d65245cac70313c25e34f594d7c0fbca5232c3d5701a57e00' ) ] for expected_address, document_id, signed_document_id in test_values: rec_address = Keeper.get_instance().ec_recover(document_id, signed_document_id) print( f'recovered address: {rec_address}, original address {expected_address}' ) assert expected_address.lower() == rec_address.lower()
def test_keeper_networks(): keeper = Keeper() assert isinstance(keeper.get_network_id(), int) assert keeper.get_network_name(1) == Keeper._network_name_map.get(1) assert keeper.get_network_name(2) == Keeper._network_name_map.get(2) assert keeper.get_network_name(3) == Keeper._network_name_map.get(3) assert keeper.get_network_name(4) == Keeper._network_name_map.get(4) assert keeper.get_network_name(42) == Keeper._network_name_map.get(42) assert keeper.get_network_name(77) == Keeper._network_name_map.get(77) assert keeper.get_network_name(99) == Keeper._network_name_map.get(99) assert keeper.get_network_name(8995) == Keeper._network_name_map.get(8995) assert keeper.get_network_name(8996) == Keeper._network_name_map.get(8996) assert keeper.get_network_name(0) == 'development'
def get(did): register_values = Keeper.get_instance().did_registry.contract_concise\ .getDIDRegister(did_to_id(did)) response = [] if register_values and len(register_values) == 5: response = DIDRegisterValues(*register_values)._asdict() response['last_checksum'] = Web3Provider.get_web3()\ .toHex(response['last_checksum']) return response
def buy_asset(): """ Requires all ocean services running. """ ConfigProvider.set_config(ExampleConfig.get_config()) config = ConfigProvider.get_config() # make ocean instance ocn = Ocean() acc = get_publisher_account(config) if not acc: acc = ([acc for acc in ocn.accounts.list() if acc.password] or ocn.accounts.list())[0] # Register ddo ddo = ocn.assets.create(Metadata.get_example(), acc, providers=[acc.address]) logging.info(f'registered ddo: {ddo.did}') # ocn here will be used only to publish the asset. Handling the asset by the publisher # will be performed by the Brizo server running locally keeper = Keeper.get_instance() if 'TEST_LOCAL_NILE' in os.environ and os.environ['TEST_LOCAL_NILE'] == '1': provider = keeper.did_registry.to_checksum_address( '0x413c9ba0a05b8a600899b41b0c62dd661e689354' ) keeper.did_registry.add_provider(ddo.asset_id, provider, acc) logging.debug(f'is did provider: ' f'{keeper.did_registry.is_did_provider(ddo.asset_id, provider)}') cons_ocn = Ocean() consumer_account = get_account_from_config(config, 'parity.address1', 'parity.password1') # sign agreement using the registered asset did above service = ddo.get_service(service_type=ServiceTypes.ASSET_ACCESS) # This will send the purchase request to Brizo which in turn will execute the agreement on-chain cons_ocn.accounts.request_tokens(consumer_account, 100) sa = ServiceAgreement.from_service_dict(service.as_dictionary()) agreement_id = cons_ocn.assets.order( ddo.did, sa.service_definition_id, consumer_account) logging.info('placed order: %s, %s', ddo.did, agreement_id) i = 0 while ocn.agreements.is_access_granted( agreement_id, ddo.did, consumer_account.address) is not True and i < 30: time.sleep(1) i += 1 assert ocn.agreements.is_access_granted(agreement_id, ddo.did, consumer_account.address) ocn.assets.consume( agreement_id, ddo.did, sa.service_definition_id, consumer_account, config.downloads_path) logging.info('Success buying asset.')
def test_consume(client, publisher_ocean_instance, consumer_ocean_instance): Brizo.set_http_client(client) endpoint = BaseURLs.ASSETS_URL + '/consume' pub_acc = get_publisher_account(ConfigProvider.get_config()) cons_acc = get_consumer_account(ConfigProvider.get_config()) asset = get_registered_ddo(publisher_ocean_instance, pub_acc, providers=[pub_acc.address]) metadata = Metadata.get_example() files = metadata['base']['files'] urls = [_file_dict['url'] for _file_dict in files] # This is a trick to give access to provider through the secretstore publisher_ocean_instance.assets.order(asset.did, 'Access', pub_acc, auto_consume=False) # initialize an agreement agreement_id = consumer_ocean_instance.assets.order(asset.did, 'Access', cons_acc, auto_consume=False) payload = dict({ 'serviceAgreementId': agreement_id, 'consumerAddress': cons_acc.address }) signature = Keeper.get_instance().sign_hash(agreement_id, cons_acc) index = 2 # Consume using decrypted url payload['url'] = urls[index] request_url = endpoint + '?' + '&'.join( [f'{k}={v}' for k, v in payload.items()]) i = 0 while i < 30 and not consumer_ocean_instance.agreements.is_access_granted( agreement_id, asset.did, cons_acc.address): time.sleep(1) i += 1 response = client.get(request_url) assert response.status == '200 OK' # Consume using url index and signature (let brizo do the decryption) payload.pop('url') payload['signature'] = signature payload['index'] = index request_url = endpoint + '?' + '&'.join( [f'{k}={v}' for k, v in payload.items()]) response = client.get(request_url) assert response.status == '200 OK'
def release_reward(ocn, account, agreement_id): if agreement_id == 'all': response = False for _agreement_id in list_agreements(ocn, account, account.address): try: response = release_reward(ocn, account, _agreement_id) except Exception as e: print(e) return response amount = int(get_agreement_from_id(ocn, agreement_id).get_price()) ocean_conditions = OceanConditions(Keeper.get_instance()) return ocean_conditions.release_reward(agreement_id, amount, account)
def consume_service(service_agreement_id, service_endpoint, account, files, destination_folder): """ Call the brizo endpoint to get access to the different files that form the asset. :param service_agreement_id: Service Agreement Id, str :param service_endpoint: Url to consume, str :param account: Account instance of the consumer signing this agreement, hex-str :param files: List containing the files to be consumed, list :param destination_folder: Path, str """ signature = Keeper.get_instance().sign_hash(service_agreement_id, account) for i, _file in enumerate(files): if 'url' in _file: url = _file['url'] if url.startswith('"') or url.startswith("'"): url = url[1:-1] file_name = os.path.basename(url) consume_url = (f'{service_endpoint}' f'?url={url}' f'&serviceAgreementId={service_agreement_id}' f'&consumerAddress={account.address}') else: file_name = f'file.{i}' consume_url = (f'{service_endpoint}' f'?signature={signature}' f'&serviceAgreementId={service_agreement_id}' f'&consumerAddress={account.address}' f'&index={i}') logger.info( f'invoke consume endpoint with this url: {consume_url}') response = Brizo._http_client.get(consume_url, stream=True) total_size = response.headers.get('content-length', 0) logger.info(f'Total size of {file_name}: {total_size} bytes.') bar = tqdm(total=int(total_size), unit='KB', leave=False, smoothing=0.1) if response.status_code == 200: with open(os.path.join(destination_folder, file_name), 'wb') as f: for chunk in response.iter_content(): f.write(chunk) bar.update(len(chunk)) logger.info(f'Saved downloaded file in {f.name}') else: logger.warning(f'consume failed: {response.reason}')
def refund_reward(event, agreement_id, did, service_agreement, price, consumer_account, publisher_address, condition_ids): """ Refund the reward to the publisher address. :param event: AttributeDict with the event data. :param agreement_id: id of the agreement, hex str :param did: DID, str :param service_agreement: ServiceAgreement instance :param price: Asset price, int :param consumer_account: Account instance of the consumer :param publisher_address: ethereum account address of publisher, hex str :param condition_ids: is a list of bytes32 content-addressed Condition IDs, bytes32 """ logger.debug(f"trigger refund after event {event}.") access_id, lock_id = condition_ids[:2] name_to_parameter = { param.name: param for param in service_agreement.condition_by_name['escrowReward'].parameters } document_id = add_0x_prefix(name_to_parameter['_documentId'].value) asset_id = add_0x_prefix(did_to_id(did)) assert document_id == asset_id, f'document_id {document_id} <=> asset_id {asset_id} mismatch.' assert price == service_agreement.get_price(), 'price mismatch.' # logger.info(f'About to do grantAccess: account {account.address}, # saId {service_agreement_id}, ' # f'documentKeyId {document_key_id}') try: tx_hash = Keeper.get_instance().escrow_reward_condition.fulfill( agreement_id, price, publisher_address, consumer_account.address, lock_id, access_id, consumer_account) process_tx_receipt( tx_hash, Keeper.get_instance().escrow_reward_condition.FULFILLED_EVENT, 'EscrowReward.Fulfilled') except Exception as e: # logger.error(f'Error when doing escrow_reward_condition.fulfills: {e}') raise e
def handle_lock_reward(agreement_id=None, agreement=None, ocean=None, *args, **kwargs): ocean_conditions = OceanConditions(Keeper.get_instance()) consumer = agreement['consumer'] did = agreement['did'] print( f'Access: {agreement_id} for {consumer}', ocean_conditions.grant_access(agreement_id, did, consumer, ocean.account)) print(f'Release: {agreement_id}', release_reward(agreement_id, ocean=ocean))
def access(ocn, account, agreement_id, consumer): if agreement_id == 'all': response = False for _agreement_id in list_agreements(ocn, account, account.address): try: response = access(ocn, account, _agreement_id, consumer) except Exception as e: print(e) return response ocean_conditions = OceanConditions(Keeper.get_instance()) agreement = ocn.agreements.get(agreement_id) return ocean_conditions.grant_access(agreement_id, id_to_did(agreement.did), consumer, account)
def ocean_agreements(): keeper = Keeper.get_instance() w3 = Web3Provider.get_web3() did_resolver = Mock() ddo = get_ddo_sample() service = ddo.get_service(ServiceTypes.ASSET_ACCESS) service.update_value( ServiceAgreementTemplate.TEMPLATE_ID_KEY, w3.toChecksumAddress("0x00bd138abd70e2f00903268f3db08f2d25677c9e")) did_resolver.resolve = MagicMock(return_value=ddo) consumer_class = Mock consumer_class.download = MagicMock(return_value='') return OceanAgreements(keeper, did_resolver, AssetConsumer, ConfigProvider.get_config())
def get_account_from_config(config, config_account_key, config_account_password_key): address = None if config.has_option('keeper-contracts', config_account_key): address = config.get('keeper-contracts', config_account_key) if not address: return None password = None address = Web3Provider.get_web3().toChecksumAddress(address) if address else None if (address and address in Keeper.get_instance().accounts and config.has_option('keeper-contracts', config_account_password_key)): password = config.get('keeper-contracts', config_account_password_key) return Account(address, password)
def execute_pending_service_agreements(storage_path, account, actor_type, did_resolver_fn): """ Iterates over pending service agreements recorded in the local storage, fetches their service definitions, and subscribes to service agreement events. :param storage_path: storage path for the internal db, str :param account: :param actor_type: :param did_resolver_fn: :return: """ keeper = Keeper.get_instance() # service_agreement_id, did, service_definition_id, price, files, start_time, status for (agreement_id, did, _, price, files, start_time, _) in get_service_agreements(storage_path): ddo = did_resolver_fn(did) for service in ddo.services: if service.type != 'Access': continue consumer_provider_tuple = keeper.escrow_access_secretstore_template.get_agreement_data( agreement_id) if not consumer_provider_tuple: continue consumer, provider = consumer_provider_tuple did = ddo.did service_agreement = ServiceAgreement.from_service_dict( service.as_dictionary()) condition_ids = service_agreement.generate_agreement_condition_ids( agreement_id, did, consumer, provider, keeper) if actor_type == 'consumer': assert account.address == consumer process_agreement_events_consumer(provider, agreement_id, did, service_agreement, price, account, condition_ids, None) else: assert account.address == provider process_agreement_events_publisher(account, agreement_id, did, service_agreement, price, consumer, condition_ids)
def process_agreement_events_consumer(publisher_address, agreement_id, did, service_agreement, price, consumer_account, condition_ids, consume_callback): """ Process the agreement events during the register of the service agreement for the consumer side. :param publisher_address: ethereum account address of publisher, hex str :param agreement_id: id of the agreement, hex str :param did: DID, str :param service_agreement: ServiceAgreement instance :param price: Asset price, int :param consumer_account: Account instance of the consumer :param condition_ids: is a list of bytes32 content-addressed Condition IDs, bytes32 :param consume_callback: :return: """ conditions_dict = service_agreement.condition_by_name keeper = Keeper.get_instance() keeper.escrow_access_secretstore_template.subscribe_agreement_created( agreement_id, 60, lock_reward_condition.fulfillLockRewardCondition, (agreement_id, price, consumer_account)) if consume_callback: def _refund_callback(_price, _publisher_address, _condition_ids): def do_refund(_event, _agreement_id, _did, _service_agreement, _consumer_account, *_): escrow_reward_condition.refund_reward( _event, _agreement_id, _did, _service_agreement, _price, _consumer_account, _publisher_address, _condition_ids) return do_refund keeper.access_secret_store_condition.subscribe_condition_fulfilled( agreement_id, conditions_dict['accessSecretStore'].timeout, escrow_reward_condition.consume_asset, (agreement_id, did, service_agreement, consumer_account, consume_callback), _refund_callback(price, publisher_address, condition_ids))
def build_access_service(did, price, purchase_endpoint, service_endpoint, timeout, template_id): """ Build the access service. :param did: DID, str :param price: Asset price, int :param purchase_endpoint: url of the service provider, str :param service_endpoint: identifier of the service inside the asset DDO, str :param timeout: amount of time in seconds before the agreement expires, int :param template_id: id of the template use to create the service, str :return: ServiceAgreement """ # TODO fill all the possible mappings param_map = { '_documentId': did_to_id(did), '_amount': price, '_rewardAddress': Keeper.get_instance().escrow_reward_condition.address, } sla_template_path = get_sla_template_path() sla_template = ServiceAgreementTemplate.from_json_file( sla_template_path) sla_template.template_id = template_id conditions = sla_template.conditions[:] for cond in conditions: for param in cond.parameters: param.value = param_map.get(param.name, '') if cond.timeout > 0: cond.timeout = timeout sla_template.set_conditions(conditions) sa = ServiceAgreement(1, sla_template, purchase_endpoint, service_endpoint, ServiceTypes.ASSET_ACCESS) sa.set_did(did) return sa
def test_publish(client, publisher_ocean_instance): ocn = publisher_ocean_instance endpoint = BaseURLs.ASSETS_URL + '/publish' did = DID.did() asset_id = did_to_id(did) account = get_provider_account(ocn) test_urls = ['url 0', 'url 1', 'url 2'] urls_json = json.dumps(test_urls) signature = Keeper.get_instance().sign_hash(asset_id, account) address = Web3Provider.get_web3().personal.ecRecover(asset_id, signature) assert address.lower() == account.address.lower() payload = { 'documentId': asset_id, 'signedDocumentId': signature, 'document': urls_json, 'publisherAddress': account.address } post_response = client.post(endpoint, data=json.dumps(payload), content_type='application/json') encrypted_url = post_response.data.decode('utf-8') assert encrypted_url.startswith('0x')
def setup_things(): config = ConfigProvider.get_config() consumer_acc = get_consumer_account(config) publisher_acc = get_publisher_account(config) keeper = Keeper.get_instance() service_definition_id = 'Access' ddo = get_ddo_sample() ddo._did = DID.did() keeper.did_registry.register(ddo.did, checksum=Web3Provider.get_web3().sha3( text=ddo.metadata['base']['checksum']), url='aquarius:5000', account=publisher_acc, providers=None) registered_ddo = ddo asset_id = registered_ddo.asset_id service_agreement = ServiceAgreement.from_ddo(service_definition_id, ddo) agreement_id = ServiceAgreement.create_new_agreement_id() price = service_agreement.get_price() access_cond_id, lock_cond_id, escrow_cond_id = \ service_agreement.generate_agreement_condition_ids( agreement_id, asset_id, consumer_acc.address, publisher_acc.address, keeper ) return ( keeper, publisher_acc, consumer_acc, agreement_id, asset_id, price, service_agreement, (lock_cond_id, access_cond_id, escrow_cond_id), )
def consume_asset(event, agreement_id, did, service_agreement, consumer_account, consume_callback): """ Consumption of an asset after get the event call. :param event: AttributeDict with the event data. :param agreement_id: id of the agreement, hex str :param did: DID, str :param service_agreement: ServiceAgreement instance :param consumer_account: Account instance of the consumer :param consume_callback: """ logger.debug(f"consuming asset after event {event}.") if consume_callback: config = ConfigProvider.get_config() secret_store = SecretStoreProvider.get_secret_store( config.secret_store_url, config.parity_url, consumer_account) brizo = BrizoProvider.get_brizo() consume_callback( agreement_id, service_agreement.service_definition_id, DIDResolver(Keeper.get_instance().did_registry).resolve(did), consumer_account, ConfigProvider.get_config().downloads_path, brizo, secret_store)
def get_consumer_account(config): acc = get_account_from_config(config, 'parity.address1', 'parity.password1') if acc is None: acc = Account(Keeper.get_instance().accounts[1]) return acc
def publish(): """Encrypt document using the SecretStore and keyed by the given documentId. This can be used by the publisher of an asset to encrypt the urls of the asset data files before publishing the asset ddo. The publisher to use this service is one that is using a front-end with a wallet app such as MetaMask. In such scenario the publisher is not able to encrypt the urls using the SecretStore interface and this service becomes necessary. tags: - services consumes: - application/json parameters: - in: body name: body required: true description: Asset urls encryption. schema: type: object required: - documentId - signedDocumentId - document - publisherAddress: properties: documentId: description: Identifier of the asset to be registered in ocean. type: string example: 'did:op:08a429b8529856d59867503f8056903a680935a76950bb9649785cc97869a43d' signedDocumentId: description: Publisher signature of the documentId type: string example: '' document: description: document type: string example: '/some-url' publisherAddress: description: Publisher address. type: string example: '0x00a329c0648769A73afAc7F9381E08FB43dBEA72' responses: 201: description: document successfully encrypted. 500: description: Error return: the encrypted document (hex str) """ required_attributes = [ 'documentId', 'signedDocumentId', 'document', 'publisherAddress' ] data = request.json msg, status = check_required_attributes(required_attributes, data, 'publish') if msg: return msg, status provider_acc = get_provider_account(ocn) did = data.get('documentId') signed_did = data.get('signedDocumentId') document = data.get('document') publisher_address = data.get('publisherAddress') try: address = Keeper.get_instance().ec_recover(did, signed_did) if address.lower() != publisher_address.lower(): msg = f'Invalid signature {signed_did} for ' \ f'publisherAddress {publisher_address} and documentId {did}.' raise ValueError(msg) encrypted_document = ocn.secret_store.encrypt(did, document, provider_acc) logger.info(f'encrypted urls {encrypted_document}, ' f'publisher {publisher_address}, ' f'documentId {did}') return encrypted_document, 201 except Exception as e: logger.error( f'Error encrypting document: {e}. \nPayload was: documentId={did}, ' f'publisherAddress={publisher_address}', exc_info=1) return "Error: " + str(e), 500
def get_publisher_account(config): acc = get_account_from_config(config, 'parity.address', 'parity.password') if acc is None: acc = Account(Keeper.get_instance().accounts[0]) return acc
def consume(): """Allows download of asset data file. --- tags: - services consumes: - application/json parameters: - name: consumerAddress in: query description: The consumer address. required: true type: string - name: serviceAgreementId in: query description: The ID of the service agreement. required: true type: string - name: url in: query description: This URL is only valid if Brizo acts as a proxy. Consumer can't download using the URL if it's not through Brizo. required: true type: string responses: 200: description: Redirect to valid asset url. 400: description: One of the required attributes is missing. 401: description: Invalid asset data. 500: description: Error """ data = request.args required_attributes = ['serviceAgreementId', 'consumerAddress'] msg, status = check_required_attributes(required_attributes, data, 'consume') if msg: return msg, status if not (data.get('url') or (data.get('signature') and data.get('index'))): return f'Either `url` or `signature and index` are required in the call to "consume".', 400 try: provider_account = get_provider_account(ocn) agreement_id = data.get('serviceAgreementId') consumer_address = data.get('consumerAddress') asset_id = ocn.agreements.get(agreement_id).did did = id_to_did(asset_id) if ocn.agreements.is_access_granted(agreement_id, did, consumer_address): logger.info('Connecting through Osmosis to generate the sign url.') url = data.get('url') try: if not url: signature = data.get('signature') index = int(data.get('index')) address = Keeper.get_instance().ec_recover( agreement_id, signature) if address.lower() != consumer_address.lower(): msg = f'Invalid signature {signature} for ' \ f'consumerAddress {consumer_address} and documentId {did}.' raise ValueError(msg) asset = ocn.assets.resolve(did) urls_str = ocn.secret_store.decrypt( asset_id, asset.encrypted_files, provider_account) urls = json.loads(urls_str) if index >= len(urls): raise ValueError(f'url index "{index}"" is invalid.') url = urls[index]['url'] osm = Osmosis(url, config_file) download_url = osm.data_plugin.generate_url(url) logger.debug("Osmosis generate the url: %s", download_url) try: if request.range: headers = {"Range": request.headers.get('range')} response = requests_session.get(download_url, headers=headers, stream=True) else: headers = { "Content-Disposition": f'attachment;filename={url.split("/")[-1]}' } response = requests_session.get(download_url, headers=headers, stream=True) return Response(io.BytesIO(response.content).read(), response.status_code, headers=headers) except Exception as e: logger.error(e) return "Error getting the url content: %s" % e, 401 except Exception as e: logger.error(e) return "Error generating url: %s" % e, 401 else: msg = "Invalid consumer address and/or service agreement id, " \ "or consumer address does not have permission to consume this asset." logger.warning(msg) return msg, 401 except Exception as e: logger.error("Error- " + str(e)) return "Error : " + str(e), 500