def execute_compute_job(): """Call the execution of a workflow. Method deprecated, it will be replaced by `/execute` in further versions swagger_from_file: docs/execute_compute_job.yml """ data = request.args required_attributes = [ 'serviceAgreementId', 'consumerAddress', 'signature', 'workflowDID' ] msg, status = check_required_attributes(required_attributes, data, 'consume') if msg: return msg, status if not (data.get('signature')): return f'`signature is required in the call to "consume".', 400 try: agreement_id = data.get('serviceAgreementId') consumer_address = data.get('consumerAddress') asset_id = keeper_instance().agreement_manager.get_agreement( agreement_id).did did = id_to_did(asset_id) if not was_compute_triggered(agreement_id, did, consumer_address, keeper_instance()): msg = ( 'Checking if the compute was triggered failed. Either consumer address does not ' 'have permission to executre this workflow or consumer address and/or service ' 'agreement id is invalid.') logger.warning(msg) return msg, 401 workflow = DIDResolver(keeper_instance().did_registry).resolve( data.get('workflowDID')) body = { "serviceAgreementId": agreement_id, "workflow": workflow.as_dictionary() } response = requests_session.post( get_config().compute_api_url + '/api/v1/nevermined-compute-api/init', data=json.dumps(body), headers={'content-type': 'application/json'}) return jsonify({"workflowId": response.content.decode('utf-8')}) except Exception as e: logger.error(f'Error- {str(e)}', exc_info=1) return f'Error : {str(e)}', 500
def get_external_contracts(): keeper = keeper_instance() return { name: contract.address for (name, contract) in keeper.external_contract_name_to_instance.items() }
def test_nft_access_no_agreement(client, provider_account, consumer_account): ddo = get_nft_ddo(provider_account, providers=[provider_account.address]) nft_amounts = 1 keeper = keeper_instance() keeper.nft_upgradeable.transfer_nft(ddo.asset_id, consumer_account.address, nft_amounts, provider_account) no_agreement_id = '0x' # generate the grant token grant_token = generate_access_grant_token(consumer_account, no_agreement_id, ddo.did, uri="/nft-access") # request access token response = client.post("/api/v1/gateway/services/oauth/token", data={ "grant_type": NeverminedJWTBearerGrant.GRANT_TYPE, "assertion": grant_token }) access_token = response.get_json()["access_token"] index = 0 endpoint = BaseURLs.ASSETS_URL + '/nft-access/%s/%d' % (no_agreement_id, index) response = client.get(endpoint, headers={"Authorization": f"Bearer {access_token}"}) assert response.status == '200 OK' assert len( keeper.did_registry.get_provenance_method_events( 'USED', did_bytes=did_to_id_bytes(ddo.did))) >= 1
def test_consume(client, provider_account, consumer_account): endpoint = BaseURLs.ASSETS_URL + '/consume' for method in constants.ConfigSections.DECRYPTION_METHODS: print('Testing Consume with Authorization Method: ' + method) ddo = get_registered_ddo(provider_account, providers=[provider_account.address], auth_service=method) # initialize an agreement agreement_id = place_order(provider_account, ddo, consumer_account, ServiceTypes.ASSET_ACCESS) payload = dict({ 'serviceAgreementId': agreement_id, 'consumerAddress': consumer_account.address }) print('Provider: ' + provider_account.address) print('Consumer: ' + consumer_account.address) keeper = keeper_instance() agr_id_hash = add_ethereum_prefix_and_hash_msg(agreement_id) signature = keeper.sign_hash(agr_id_hash, consumer_account) index = 0 event = keeper.access_template.subscribe_agreement_created( agreement_id, 15, None, (), wait=True, from_block=0) assert event, "Agreement event is not found, check the keeper node's logs" consumer_balance = keeper.token.get_token_balance( consumer_account.address) if consumer_balance < 50: keeper.dispenser.request_tokens(50 - consumer_balance, consumer_account) sa = ServiceAgreement.from_ddo(ServiceTypes.ASSET_ACCESS, ddo) lock_payment(agreement_id, ddo.asset_id, sa, amounts, receivers, consumer_account) event = keeper.lock_payment_condition.subscribe_condition_fulfilled( agreement_id, 15, None, (), wait=True, from_block=0) assert event, "Lock reward condition fulfilled event is not found, check the keeper " \ "node's logs" grant_access(agreement_id, ddo, consumer_account, provider_account) event = keeper.access_condition.subscribe_condition_fulfilled( agreement_id, 15, None, (), wait=True, from_block=0) assert event or keeper.access_condition.check_permissions( ddo.asset_id, consumer_account.address ), f'Failed to get access permission: agreement_id={agreement_id}, ' \ f'did={ddo.did}, consumer={consumer_account.address}' # Consume using url index and signature (let the gateway do the decryption) 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 test_info_contracts(client): keeper = keeper_instance() expected_contracts = { name: contract.address for (name, contract) in keeper.contract_name_to_instance.items() } response = client.get('/') assert response.status_code == 200 assert response.json['contracts'] == expected_contracts
def test_nft_access(client, provider_account, consumer_account): keeper = keeper_instance() ddo = get_nft_ddo(provider_account, providers=[provider_account.address]) asset_id = ddo.asset_id nft_amounts = 1 keeper.nft_upgradeable.transfer_nft(asset_id, consumer_account.address, nft_amounts, provider_account) assert keeper.nft_upgradeable.balance(consumer_account.address, asset_id) >= nft_amounts nft_access_service_agreement = ServiceAgreement.from_ddo( ServiceTypes.NFT_ACCESS, ddo) agreement_id = ServiceAgreement.create_new_agreement_id() (nft_access_cond_id, nft_holder_cond_id ) = nft_access_service_agreement.generate_agreement_condition_ids( agreement_id, asset_id, consumer_account.address, keeper) print('NFT_ACCESS_DID: ' + asset_id) keeper.nft_access_template.create_agreement( agreement_id, asset_id, [nft_holder_cond_id, nft_access_cond_id], nft_access_service_agreement.conditions_timelocks, nft_access_service_agreement.conditions_timeouts, consumer_account.address, consumer_account) event = keeper.nft_access_template.subscribe_agreement_created( agreement_id, 15, None, (), wait=True, from_block=0) assert event, "Agreement event is not found, check the keeper node's logs" # generate the grant token grant_token = generate_access_grant_token(consumer_account, agreement_id, ddo.did, uri="/nft-access") # request access token response = client.post("/api/v1/gateway/services/oauth/token", data={ "grant_type": NeverminedJWTBearerGrant.GRANT_TYPE, "assertion": grant_token }) access_token = response.get_json()["access_token"] index = 0 endpoint = BaseURLs.ASSETS_URL + '/nft-access/%s/%d' % (agreement_id, index) response = client.get(endpoint, headers={"Authorization": f"Bearer {access_token}"}) assert response.status == '200 OK' assert len( keeper.did_registry.get_provenance_method_events( 'USED', did_bytes=did_to_id_bytes(ddo.did))) >= 1
def validate_access(self, agreement_id, did, consumer_address): keeper = keeper_instance() if not is_access_granted( agreement_id, did, consumer_address, keeper): # 3. If not granted, verification of agreement and conditions agreement = keeper.agreement_manager.get_agreement(agreement_id) cond_ids = agreement.condition_ids asset = DIDResolver(keeper.did_registry).resolve(did) asset_id = f'0x{did.replace(NEVERMINED_PREFIX, "")}' self.check_ddo(did, agreement_id, asset_id, consumer_address, keeper, cond_ids, ServiceTypes.ASSET_ACCESS) access_condition_status = keeper.condition_manager.get_condition_state(cond_ids[0]) lock_condition_status = keeper.condition_manager.get_condition_state(cond_ids[1]) escrow_condition_status = keeper.condition_manager.get_condition_state( cond_ids[2]) logger.debug('AccessCondition: %d' % access_condition_status) logger.debug('LockPaymentCondition: %d' % lock_condition_status) logger.debug('EscrowPaymentCondition: %d' % escrow_condition_status) if lock_condition_status != ConditionState.Fulfilled.value: logger.debug('ServiceAgreement %s was not paid. Forbidden' % agreement_id) raise InvalidClientError( f"ServiceAgreement {agreement_id} was not paid, LockPaymentCondition status is {lock_condition_status}") fulfilled = fulfill_access_condition(keeper, agreement_id, cond_ids, asset_id, consumer_address, self.provider_account) if not fulfilled: raise InvalidClientError('Server error fulfilling access condition') fulfill_escrow_payment_condition(keeper, agreement_id, cond_ids, asset, self.provider_account) iteration = 0 access_granted = False while iteration < ConfigSections.PING_ITERATIONS: iteration = iteration + 1 logger.debug('Checking if access was granted. Iteration %d' % iteration) if not is_access_granted(agreement_id, did, consumer_address, keeper): time.sleep(ConfigSections.PING_SLEEP / 1000) else: access_granted = True break if not access_granted: msg = ('Checking access permissions failed. Either consumer address does not have ' 'permission to consume this asset or consumer address and/or service ' 'agreement ' 'id is invalid.') logger.warning(msg) raise InvalidClientError(msg)
def execute(agreement_id): """Call the execution of a workflow. swagger_from_file: docs/execute.yml """ consumer_address = current_token["client_id"] workflow_did = current_token["did"] agreement_id = current_token["sub"] try: keeper = keeper_instance() asset_id = keeper_instance().agreement_manager.get_agreement( agreement_id).did did = id_to_did(asset_id) signature = '0x00' workflow = DIDResolver( keeper_instance().did_registry).resolve(workflow_did) body = { "serviceAgreementId": agreement_id, "workflow": workflow.as_dictionary() } response = requests_session.post( get_config().compute_api_url + '/api/v1/nevermined-compute-api/init', data=json.dumps(body), headers={'content-type': 'application/json'}) if response.status_code != 200: msg = f'The compute API was not able to create the workflow. {response.content}' logger.warning(msg) return msg, 401 used_by(generate_random_id(), did, consumer_address, 'compute', signature, 'compute', provider_acc, keeper) return jsonify({"workflowId": response.content.decode('utf-8')}) except Exception as e: logger.error(f'Error- {str(e)}', exc_info=1) return f'Error : {str(e)}', 500
def validate_nft_access(self, agreement_id, did, consumer_address): keeper = keeper_instance() asset = DIDResolver(keeper.did_registry).resolve(did) # check which nft access service type is on the ddo service_type = ServiceTypes.NFT_ACCESS if asset.get_service(ServiceTypes.NFT721_ACCESS) is not None: service_type = ServiceTypes.NFT721_ACCESS sa = ServiceAgreement.from_ddo(service_type, asset) return self._validate_nft_access(agreement_id, did, consumer_address, sa, service_type)
def validate_owner(self, did, consumer_address): keeper = keeper_instance() if not is_owner_granted( did, consumer_address, keeper): msg = ('Checking access permissions failed. Consumer address does not have ' 'permission to download this asset or consumer address and/or did ' 'is invalid.') logger.warning(msg) raise InvalidClientError(msg)
def _validate_nft_access(self, agreement_id, did, consumer_address, service_agreement, service_type): keeper = keeper_instance() asset = DIDResolver(keeper.did_registry).resolve(did) asset_id = asset.asset_id sa_name = service_agreement.main['name'] erc721_address = service_agreement.get_param_value_by_name('_contractAddress') access_granted = False if agreement_id is None or agreement_id == '0x': if sa_name == 'nftAccessAgreement': access_granted = is_nft_holder(keeper, asset_id, service_agreement.get_number_nfts(), consumer_address) elif sa_name == 'nft721AccessAgreement': access_granted = is_nft721_holder(keeper, asset_id, consumer_address, erc721_address) else: agreement = keeper.agreement_manager.get_agreement(agreement_id) cond_ids = agreement.condition_ids access_cond_id = cond_ids[1] ddo = DIDResolver(keeper.did_registry).resolve(did) nft_access_service_agreement = ServiceAgreement.from_ddo(service_type, ddo) (nft_access_cond_id, nft_holder_cond_id) = nft_access_service_agreement.generate_agreement_condition_ids(agreement_id, asset_id, consumer_address, keeper) if [nft_holder_cond_id, nft_access_cond_id] != cond_ids: raise InvalidClientError(f"ServiceAgreement {agreement_id} doesn't match ddo") if not is_nft_access_condition_fulfilled( agreement_id, access_cond_id, consumer_address, keeper): # If not granted, verification of agreement and conditions and fulfill # access_granted = is_nft_holder(keeper, asset_id, sa.get_number_nfts(), consumer_address) access_granted = fulfill_nft_holder_and_access_condition( keeper, agreement_id, cond_ids, asset_id, service_agreement.get_number_nfts(), consumer_address, self.provider_account ) if not access_granted: msg = ('Checking access permissions failed. Either consumer address does not have ' 'permission to consume this NFT or consumer address and/or service ' 'agreement ' 'id is invalid.') logger.warning(msg) raise InvalidClientError(msg)
def validate_execute(self, agreement_id, workflow_did, consumer_address): keeper = keeper_instance() asset_id = keeper.agreement_manager.get_agreement(agreement_id).did did = id_to_did(asset_id) asset = DIDResolver(keeper.did_registry).resolve(did) if not was_compute_triggered(agreement_id, did, consumer_address, keeper): agreement = keeper.agreement_manager.get_agreement(agreement_id) cond_ids = agreement.condition_ids self.check_ddo(did, agreement_id, asset_id, consumer_address, keeper, cond_ids, ServiceTypes.CLOUD_COMPUTE) compute_condition_status = keeper.condition_manager.get_condition_state(cond_ids[0]) lock_condition_status = keeper.condition_manager.get_condition_state(cond_ids[1]) escrow_condition_status = keeper.condition_manager.get_condition_state( cond_ids[2]) logger.debug('ComputeExecutionCondition: %d' % compute_condition_status) logger.debug('LockPaymentCondition: %d' % lock_condition_status) logger.debug('EscrowPaymentCondition: %d' % escrow_condition_status) if lock_condition_status != ConditionState.Fulfilled.value: logger.debug('ServiceAgreement %s was not paid. Forbidden' % agreement_id) raise InvalidClaimError( f"ServiceAgreement {agreement_id} was not paid, LockPaymentCondition status is {lock_condition_status}") fulfill_compute_condition(keeper, agreement_id, cond_ids, asset_id, consumer_address, self.provider_account) fulfill_escrow_payment_condition(keeper, agreement_id, cond_ids, asset, self.provider_account, ServiceTypes.CLOUD_COMPUTE) iteration = 0 access_granted = False while iteration < ConfigSections.PING_ITERATIONS: iteration = iteration + 1 logger.debug('Checking if compute was granted. Iteration %d' % iteration) if not was_compute_triggered(agreement_id, did, consumer_address, keeper): time.sleep(ConfigSections.PING_SLEEP / 1000) else: access_granted = True break if not access_granted: msg = ( 'Scheduling the compute execution failed. Either consumer address does not ' 'have permission to execute this workflow or consumer address and/or service ' 'agreement id is invalid.') logger.warning(msg) raise InvalidClientError(msg)
def validate_access_proof(self, agreement_id, did, eth_address, consumer_address, jubjub_sig): consumer_pub = ['0x'+consumer_address[0:64], '0x'+consumer_address[64:128]] provider_pub = [self.provider_key.x, self.provider_key.y] if not keytransfer.verify([int(consumer_pub[0],16), int(consumer_pub[1],16)], int(eth_address,16), jubjub_sig): raise InvalidClientError( f"ServiceAgreement {agreement_id}: babyjubjub signature doesn't match") keeper = keeper_instance() agreement = keeper.agreement_manager.get_agreement(agreement_id) cond_ids = agreement.condition_ids asset = DIDResolver(keeper.did_registry).resolve(did) asset_id = did.replace(NEVERMINED_PREFIX, "") self.check_ddo(did, agreement_id, asset_id, consumer_pub, keeper, cond_ids, ServiceTypes.ASSET_ACCESS_PROOF) access_condition_status = keeper.condition_manager.get_condition_state(cond_ids[0]) lock_condition_status = keeper.condition_manager.get_condition_state(cond_ids[1]) escrow_condition_status = keeper.condition_manager.get_condition_state( cond_ids[2]) logger.info('AccessProofCondition: %d' % access_condition_status) logger.info('LockPaymentCondition: %d' % lock_condition_status) logger.info('EscrowPaymentCondition: %d' % escrow_condition_status) if lock_condition_status != ConditionState.Fulfilled.value: logger.debug('ServiceAgreement %s was not paid. Forbidden' % agreement_id) raise InvalidClientError( f"ServiceAgreement {agreement_id} was not paid, LockPaymentCondition status is {lock_condition_status}") if escrow_condition_status != ConditionState.Fulfilled.value: # compute the proof auth_method = asset.authorization.main['service'] url = '0x' + get_asset_url_at_index(0, asset, self.provider_account, auth_method) res = call_prover(consumer_pub, self.provider_key.secret, url) # check that the condition ID is correct cond_id = keeper.access_proof_condition.generate_id( agreement_id, ['bytes32', 'bytes32', 'bytes32', 'bytes32', 'bytes32'], [res['hash'], consumer_pub[0], consumer_pub[1], provider_pub[0], provider_pub[1]] ) if cond_ids[0] != cond_id.hex(): raise InvalidClientError( f"ServiceAgreement {agreement_id}: public key doesn't match {consumer_address}") fulfill_access_proof_condition(keeper, agreement_id, cond_ids, res['hash'], consumer_pub, provider_pub, res['cipher'], res['proof'], self.provider_account) fulfill_escrow_payment_condition(keeper, agreement_id, cond_ids, asset, self.provider_account, ServiceTypes.ASSET_ACCESS_PROOF)
def test_access_endpoint_bad_signature(client, provider_account, consumer_account): # The provider_account will place the order and consumer_account # will try to request access to it # order access keeper = keeper_instance() ddo = get_registered_ddo(provider_account, providers=[provider_account.address]) agreement_id = place_order(provider_account, ddo, provider_account) event = keeper.access_template.subscribe_agreement_created(agreement_id, 15, None, (), wait=True, from_block=0) assert event, "Agreement event is not found, check the keeper node's logs" consumer_balance = keeper.token.get_token_balance(consumer_account.address) if consumer_balance < 50: keeper.dispenser.request_tokens(50 - consumer_balance, consumer_account) sa = ServiceAgreement.from_ddo(ServiceTypes.ASSET_ACCESS, ddo) lock_payment(agreement_id, ddo.asset_id, sa, amounts, receivers, consumer_account) event = keeper.lock_payment_condition.subscribe_condition_fulfilled( agreement_id, 15, None, (), wait=True, from_block=0) assert event, "Lock reward condition fulfilled event is not found, check the keeper node's logs" # create jwt bearer grant jwk = account_to_jwk(consumer_account) assertion = NeverminedJWTBearerGrant.sign(jwk, issuer=consumer_account.address, audience=BaseURLs.ASSETS_URL + '/access', subject=agreement_id, claims={"did": ddo.did}, header={"alg": "ES256K"}) response = client.post("/api/v1/gateway/services/oauth/token", data={ "grant_type": NeverminedJWTBearerGrant.GRANT_TYPE, "assertion": assertion }) assert response.status_code == 400 assert response.get_json()["error"] == "invalid_client"
def test_execute_endpoint(client, provider_account, consumer_account): ddo_compute = get_registered_compute_ddo( provider_account, providers=[provider_account.address]) ddo_algorithm = get_registered_algorithm_ddo( consumer_account, providers=[provider_account.address]) ddo_workflow = get_registered_workflow_ddo( consumer_account, ddo_compute.did, ddo_algorithm.did, providers=[provider_account.address]) # initialize agreement agreement_id = place_order(provider_account, ddo_compute, consumer_account, service_type=ServiceTypes.CLOUD_COMPUTE) sa = ServiceAgreement.from_ddo(ServiceTypes.CLOUD_COMPUTE, ddo_compute) lock_payment(agreement_id, ddo_compute.asset_id, sa, amounts, receivers, consumer_account) keeper = keeper_instance() event = keeper.lock_payment_condition.subscribe_condition_fulfilled( agreement_id, 60, None, (), wait=True) assert event is not None, "Reward condition is not found" # create jwt bearer grant jwk = account_to_jwk(consumer_account) assertion = NeverminedJWTBearerGrant.sign(jwk, issuer=consumer_account.address, subject=agreement_id, audience=BaseURLs.ASSETS_URL + '/execute', claims={"did": ddo_workflow.did}, header={"alg": "ES256K"}) response = client.post("/api/v1/gateway/services/oauth/token", data={ "grant_type": NeverminedJWTBearerGrant.GRANT_TYPE, "assertion": assertion }) assert response.status_code == 200 # use jwt access token to execute the compute access_token = response.get_json()["access_token"] response = client.post(f"/api/v1/gateway/services/execute/{agreement_id}", headers={"Authorization": f"Bearer {access_token}"}) assert response.status_code == 200
def test_publish(client): keeper = keeper_instance() account = get_provider_account() endpoint = BaseURLs.ASSETS_URL + '/publish' did_seed = generate_new_id() asset_id = keeper.did_registry.hash_did(did_seed, account.address) # did = DID.did({"0": str(uuid.uuid4())}) # asset_id = did_to_id(did) test_urls = ['url 00', 'url 11', 'url 22'] urls_json = json.dumps(test_urls) asset_id_hash = add_ethereum_prefix_and_hash_msg(asset_id) signature = keeper.sign_hash(asset_id_hash, account) address = web3().eth.account.recoverHash(asset_id_hash, signature=signature) assert address.lower() == account.address.lower() address = keeper.personal_ec_recover(asset_id, signature) assert address.lower() == account.address.lower() payload = { 'documentId': asset_id, 'signature': 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') # publish using auth token signature = generate_token(account) payload['signature'] = signature # did = DID.did({"0": str(uuid.uuid4())}) # asset_id = did_to_id(did) did_seed = generate_new_id() asset_id = keeper.did_registry.hash_did(did_seed, account.address) payload['documentId'] = add_0x_prefix(asset_id) 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 publish(): """Encrypt document using the SecretStore and keyed by the given documentId. swagger_from_file: docs/publish.yml """ required_attributes = [ 'documentId', 'signature', 'document', 'publisherAddress' ] data = request.json if 'signedDocumentId' in data and 'signature' not in data: data['signature'] = data['signedDocumentId'] msg, status = check_required_attributes(required_attributes, data, 'publish') if msg: return msg, status did = data.get('documentId') signature = data.get('signature') document = json.dumps(json.loads(data.get('document')), separators=(',', ':')) publisher_address = data.get('publisherAddress') try: if not verify_signature(keeper_instance(), publisher_address, signature, did): msg = f'Invalid signature {signature} for ' \ f'publisherAddress {publisher_address} and documentId {did}.' raise ValueError(msg) print('Document: ' + document) print('DID: ' + remove_0x_prefix(did)) encrypted_document, public_key = rsa_encryption_from_file( document, get_rsa_public_key_file()) logger.debug(f'encrypted urls {encrypted_document}, ' f'publisher {publisher_address}, ' f'documentId {did}') return encrypted_document, 201 except (RPCError, Exception) as e: logger.error( f'Encryption Error: {e}. \n' f'providerAddress={provider_acc.address}\n' f'Payload was: documentId={did}, ' f'publisherAddress={publisher_address},' f'signature={signature}', exc_info=1) return f'Error: {str(e)}', 500
def test_auth_token(): token = "0x1d2741dee30e64989ef0203957c01b14f250f5d2f6ccb0" \ "c88c9518816e4fcec16f84e545094eb3f377b7e214ded226" \ "76fbde8ca2e41b4eb1b3565047ecd9acf300-1568372035" pub_address = "0x62C092047B01630FC7ABAf3Ab07f4b8aDa5EeB35" doc_id = "663516d306904651bbcf9fe45a00477c215c7303d8a24c5bad6005dd2f95e68e" assert is_token_valid(token), f'cannot recognize auth-token {token}' address = check_auth_token(token) assert address and address.lower() == pub_address.lower(), f'address mismatch, got {address}, ' \ f'' \ f'' \ f'' \ f'' \ f'' \ f'expected {pub_address}' good = verify_signature(keeper_instance(), pub_address, token, doc_id) assert good, f'invalid signature/auth-token {token}, {pub_address}, {doc_id}'
def lock_payment(agreement_id, did, service_agreement, amounts, receivers, consumer_account, token_address=None): keeper = keeper_instance() if token_address is None: token_address = keeper.token.address price = service_agreement.get_price() keeper.token.token_approve(keeper.lock_payment_condition.address, price, consumer_account) tx_hash = keeper.lock_payment_condition.fulfill( agreement_id, did, keeper.escrow_payment_condition.address, token_address, amounts, receivers, consumer_account) keeper.lock_payment_condition.get_tx_receipt(tx_hash)
def access(agreement_id, index=0): """Allows to get access to an asset data file. swagger_from_file: docs/access.yml """ consumer_address = current_token["client_id"] did = current_token["did"] agreement_id = current_token["sub"] logger.info( 'Parameters:\nAgreementId: %s\nIndex: %d\nConsumerAddress: %s\n' 'DID: %s\n' % (agreement_id, index, consumer_address, did)) try: keeper = keeper_instance() asset = DIDResolver(keeper.did_registry).resolve(did) logger.debug('AgreementID :' + agreement_id) file_attributes = asset.metadata['main']['files'][index] content_type = file_attributes.get('contentType', None) try: auth_method = asset.authorization.main['service'] except Exception: auth_method = constants.ConfigSections.DEFAULT_DECRYPTION_METHOD if auth_method not in constants.ConfigSections.DECRYPTION_METHODS: msg = ( 'The Authorization Method defined in the DDO is not part of the available ' 'methods supported' 'by the Gateway: ' + auth_method) logger.warning(msg) return msg, 400 url = get_asset_url_at_index(index, asset, provider_acc, auth_method) used_by(generate_random_id(), did, consumer_address, 'access', '0x00', 'access', provider_acc, keeper) return get_asset(request, requests_session, content_type, url, app.config['CONFIG_FILE']) except (ValueError, Exception) as e: logger.error(f'Error- {str(e)}', exc_info=1) return f'Error : {str(e)}', 500
def place_order(provider_account, ddo, consumer_account, service_type=ServiceTypes.ASSET_ACCESS): keeper = keeper_instance() agreement_id = ServiceAgreement.create_new_agreement_id() if service_type == ServiceTypes.ASSET_ACCESS: agreement_template = keeper.access_template elif service_type == ServiceTypes.ASSET_ACCESS_PROOF: agreement_template = keeper.access_proof_template elif service_type == ServiceTypes.NFT_SALES: agreement_template = keeper.nft_sales_template elif service_type == ServiceTypes.CLOUD_COMPUTE: agreement_template = keeper.escrow_compute_execution_template else: raise NotImplementedError( "The agreement template could not be created.") publisher_address = provider_account.address service_agreement = ServiceAgreement.from_ddo(service_type, ddo) if service_type == ServiceTypes.ASSET_ACCESS_PROOF: consumer_pub = get_buyer_public_key() condition_ids = service_agreement.generate_agreement_condition_ids( agreement_id, ddo.asset_id, consumer_pub, keeper) else: condition_ids = service_agreement.generate_agreement_condition_ids( agreement_id, ddo.asset_id, consumer_account.address, keeper) time_locks = service_agreement.conditions_timelocks time_outs = service_agreement.conditions_timeouts agreement_template.create_agreement(agreement_id, ddo.asset_id, condition_ids, time_locks, time_outs, consumer_account.address, consumer_account) return agreement_id
def root_info(): config = Config(filename=app.config['CONFIG_FILE']) keeper = keeper_instance() key = get_provider_babyjub_key() url_keeper = urlparse(config.keeper_url) info = { 'software': Metadata.TITLE, 'version': version.__version__, 'keeper-url': url_keeper.scheme + '://' + url_keeper.netloc, 'network': keeper.network_name, 'contracts': get_contracts(), 'external-contracts': get_external_contracts(), 'keeper-version': keeper.did_registry.version, 'provider-address': get_provider_account().address, 'ecdsa-public-key': get_ecdsa_public_key_from_file(get_provider_key_file(), get_provider_password()), 'babyjub-public-key': { 'x': key.x, 'y': key.y } } try: info['rsa-public-key'] = get_content_keyfile_from_path( get_rsa_public_key_file()) except Exception as e: logger.warning(f'Unable to load RSA Public Key: {e}. ', exc_info=1) return jsonify(info)
def is_allowed_read_compute(agreement_id, execution_id, consumer_address, signature, has_bearer_token=False): keeper = keeper_instance() ## Access check if not has_bearer_token: if not verify_signature(keeper, consumer_address, signature, execution_id): msg = (f'Invalid signature {signature} for ' f'consumerAddress {consumer_address} and executionId {execution_id}.') logger.error(msg) return msg, False asset_id = keeper.agreement_manager.get_agreement(agreement_id).did did = id_to_did(asset_id) if not was_compute_triggered(agreement_id, did, consumer_address, keeper): msg = ( 'Getting access failed. Either consumer address does not ' 'have permission to execute this agreement or consumer address and/or service ' 'agreement id is invalid.') logger.warning(msg) return msg, False return 'OK', True
def test_access_proof(client, provider_account, consumer_account): for method in constants.ConfigSections.DECRYPTION_METHODS: ddo = get_proof_ddo(provider_account, providers=[provider_account.address], auth_service=method) # initialize an agreement agreement_id = place_order(provider_account, ddo, consumer_account, ServiceTypes.ASSET_ACCESS_PROOF) print(ddo.did) keeper = keeper_instance() index = 0 event = keeper.access_proof_template.subscribe_agreement_created( agreement_id, 15, None, (), wait=True, from_block=0) assert event, "Agreement event is not found, check the keeper node's logs" consumer_balance = keeper.token.get_token_balance( consumer_account.address) if consumer_balance < 50: keeper.dispenser.request_tokens(50 - consumer_balance, consumer_account) sa = ServiceAgreement.from_ddo(ServiceTypes.ASSET_ACCESS_PROOF, ddo) lock_payment(agreement_id, ddo.asset_id, sa, amounts, receivers, consumer_account) event = keeper.lock_payment_condition.subscribe_condition_fulfilled( agreement_id, 15, None, (), wait=True, from_block=0) assert event, "Lock reward condition fulfilled event is not found, check the keeper node's logs" # Consume using url index # generate the grant token grant_token = generate_access_proof_grant_token( consumer_account, agreement_id, ddo.did, get_buyer_secret_key(), "/access-proof") # request access token response = client.post("/api/v1/gateway/services/oauth/token", data={ "grant_type": NeverminedJWTBearerGrant.GRANT_TYPE, "assertion": grant_token }) access_token = response.get_json()["access_token"] agreement = keeper.agreement_manager.get_agreement(agreement_id) cond_ids = agreement.condition_ids assert keeper.condition_manager.get_condition_state( cond_ids[0]) == ConditionState.Fulfilled.value assert keeper.condition_manager.get_condition_state( cond_ids[1]) == ConditionState.Fulfilled.value assert keeper.condition_manager.get_condition_state( cond_ids[2]) == ConditionState.Fulfilled.value endpoint = BaseURLs.ASSETS_URL + '/access-proof/%s/%d' % (agreement_id, index) response = client.get( endpoint, headers={"Authorization": f"Bearer {access_token}"}) assert response.status == '200 OK' assert len( keeper.did_registry.get_provenance_method_events( 'USED', did_bytes=did_to_id_bytes(ddo.did))) == 1
def test_nft_transfer(client, provider_account, consumer_account, publisher_account): print('PROVIDER_ACCOUNT= ' + provider_account.address) print('PUBLISHER_ACCOUNT= ' + publisher_account.address) print('CONSUMER_ACCOUNT= ' + consumer_account.address) keeper = keeper_instance() ddo = get_nft_ddo(publisher_account, providers=[provider_account.address]) asset_id = ddo.asset_id nft_amounts = 1 agreement_id = ServiceAgreement.create_new_agreement_id() print('NFT_SALES_DID: ' + asset_id) nft_sales_service_agreement = ServiceAgreement.from_ddo( ServiceTypes.NFT_SALES, ddo) (transfer_nft_condition_id, lock_payment_condition_id, escrow_payment_condition_id ) = nft_sales_service_agreement.generate_agreement_condition_ids( agreement_id, asset_id, consumer_account.address, keeper) keeper.nft_sales_template.create_agreement( agreement_id, asset_id, [ lock_payment_condition_id, transfer_nft_condition_id, escrow_payment_condition_id ], nft_sales_service_agreement.conditions_timelocks, nft_sales_service_agreement.conditions_timeouts, consumer_account.address, consumer_account) event = keeper.nft_sales_template.subscribe_agreement_created(agreement_id, 15, None, (), wait=True, from_block=0) assert event, "Agreement event is not found, check the keeper node's logs" agreement = keeper.agreement_manager.get_agreement(agreement_id) cond_ids = agreement.condition_ids keeper.token.token_approve(keeper.lock_payment_condition.address, nft_sales_service_agreement.get_price(), consumer_account) keeper.dispenser.request_tokens(50, consumer_account) lock_payment(agreement_id, ddo.asset_id, nft_sales_service_agreement, nft_sales_service_agreement.get_amounts_int(), nft_sales_service_agreement.get_receivers(), consumer_account) event = keeper.lock_payment_condition.subscribe_condition_fulfilled( agreement_id, 15, None, (), wait=True, from_block=0) assert event, "Lock reward condition fulfilled event is not found, check the keeper " \ "node's logs" keeper.nft_upgradeable.set_approval_for_all(get_provider_account().address, True, publisher_account) time.sleep(10) is_approved = keeper.nft_upgradeable.is_approved_for_all( publisher_account.address, provider_account.address) assert is_approved is True response = client.post(BaseURLs.ASSETS_URL + '/nft-transfer', json={ 'agreementId': agreement_id, 'nftHolder': publisher_account.address, 'nftReceiver': consumer_account.address, 'nftAmount': nft_amounts }) assert response.status_code == 200 assert keeper.condition_manager.get_condition_state( cond_ids[0]) == ConditionState.Fulfilled.value assert keeper.condition_manager.get_condition_state( cond_ids[1]) == ConditionState.Fulfilled.value assert keeper.condition_manager.get_condition_state( cond_ids[2]) == ConditionState.Fulfilled.value
def nft_transfer(): """Allows the provider transfer and release the rewards. swagger_from_file: docs/nft_transfer.yml """ required_attributes = [ 'agreementId', 'nftHolder', 'nftReceiver', 'nftAmount' ] data = request.json msg, status = check_required_attributes(required_attributes, data, 'nft-transfer') if msg: return msg, status agreement_id = data.get('agreementId') nft_holder_address = data.get('nftHolder') nft_receiver_address = data.get('nftReceiver') nft_amount = data.get('nftAmount') keeper = keeper_instance() agreement = keeper.agreement_manager.get_agreement(agreement_id) did = id_to_did(agreement.did) ddo = DIDResolver(keeper.did_registry).resolve(did) try: ServiceAgreement.from_ddo(ServiceTypes.NFT_SALES, ddo) except ValueError as e: logger.error('nft-sales service not found on ddo for %s', did) return str(e), 400 (lock_payment_condition_id, nft_transfer_condition_id, escrow_payment_condition_id) = agreement.condition_ids if not is_nft_holder(keeper, agreement.did, nft_amount, nft_holder_address): msg = f'Holder {nft_holder_address} does not have enough NFTs to transfer' logger.warning(msg) return msg, 406 if not is_lock_payment_condition_fulfilled(lock_payment_condition_id, keeper): msg = f'lockPayment condition for agreement_id={agreement_id} is not fulfilled' logger.warning(msg) return msg, 402 if not is_nft_transfer_approved(nft_holder_address, get_provider_account().address, keeper): msg = f'Gateway ({get_provider_account().address}) is not approved to transfer nfts from {nft_holder_address}' logger.warning(msg) return msg, 405 # fulfill transferNFT condition if not is_nft_transfer_condition_fulfilled(nft_transfer_condition_id, keeper): logger.debug('NFTTransfer condition not fulfilled') result = fulfill_for_delegate_nft_transfer_condition( agreement_id, agreement.did, Web3.toChecksumAddress(nft_holder_address), Web3.toChecksumAddress(nft_receiver_address), nft_amount, lock_payment_condition_id, keeper) if result is False: msg = f'There was an error fulfilling the NFTTransfer condition for agreement_id={agreement_id}' logger.error(msg) return msg, 500 # fulfill escrowPayment condition if not is_escrow_payment_condition_fulfilled(escrow_payment_condition_id, keeper): logger.debug('EscrowPayment condition not fulfilled') result = fulfill_escrow_payment_condition( keeper, agreement_id, [ nft_transfer_condition_id, lock_payment_condition_id, escrow_payment_condition_id ], ddo, get_provider_account(), service_type=ServiceTypes.NFT_SALES) if result is False: msg = f'There was an error fulfilling the EscrowPayment condition for agreement_id={agreement_id}' logger.error(msg) return msg, 500 return 'success', 200
def grant_access(agreement_id, ddo, consumer_account, provider_account): keeper = keeper_instance() tx_hash = keeper.access_condition.fulfill(agreement_id, ddo.asset_id, consumer_account.address, provider_account) keeper.access_condition.get_tx_receipt(tx_hash)
def consume(): """Allows download of asset data file. Method deprecated, it will be replaced by `/access` in further versions swagger_from_file: docs/consume.yml """ data = request.args required_attributes = [ 'serviceAgreementId', 'consumerAddress', 'signature', 'index' ] msg, status = check_required_attributes(required_attributes, data, 'consume') if msg: return msg, status try: keeper = keeper_instance() agreement_id = data.get('serviceAgreementId') consumer_address = data.get('consumerAddress') asset_id = keeper.agreement_manager.get_agreement(agreement_id).did did = id_to_did(asset_id) if not is_access_granted(agreement_id, did, consumer_address, keeper): msg = ( 'Checking access permissions failed. Either consumer address does not have ' 'permission to consume this asset or consumer address and/or service agreement ' 'id is invalid.') logger.warning(msg) return msg, 401 asset = DIDResolver(keeper.did_registry).resolve(did) signature = data.get('signature') index = int(data.get('index')) if not verify_signature(keeper, consumer_address, signature, agreement_id): msg = f'Invalid signature {signature} for ' \ f'publisherAddress {consumer_address} and documentId {agreement_id}.' raise ValueError(msg) file_attributes = asset.metadata['main']['files'][index] content_type = file_attributes.get('contentType', None) try: auth_method = asset.authorization.main['service'] except Exception: auth_method = constants.ConfigSections.DEFAULT_DECRYPTION_METHOD if auth_method not in constants.ConfigSections.DECRYPTION_METHODS: msg = ( 'The Authorization Method defined in the DDO is not part of the available ' 'methods supported' 'by the Gateway: ' + auth_method) logger.warning(msg) return msg, 400 url = get_asset_url_at_index(index, asset, provider_acc, auth_method) return get_asset(request, requests_session, content_type, url, app.config['CONFIG_FILE']) except (ValueError, Exception) as e: logger.error(f'Error- {str(e)}', exc_info=1) return f'Error : {str(e)}', 500
def register_ddo(metadata, account, providers, auth_service, additional_service_descriptors, royalties=None, cap=None, mint=0): keeper = keeper_instance() metadata_api = Metadata('http://172.17.0.1:5000') ddo = DDO() ddo_service_endpoint = metadata_api.get_service_endpoint() metadata_service_desc = ServiceDescriptor.metadata_service_descriptor( metadata, ddo_service_endpoint) authorization_service_attributes = { "main": { "service": auth_service, "publicKey": "0xd7" } } service_descriptors = [ ServiceDescriptor.authorization_service_descriptor( authorization_service_attributes, 'http://localhost:12001') ] service_descriptors += [metadata_service_desc] service_descriptors += additional_service_descriptors services = ServiceFactory.build_services(service_descriptors) checksums = dict() for service in services: try: checksums[str(service.index)] = checksum(service.main) except Exception as e: pass # Adding proof to the ddo. ddo.add_proof(checksums, account) did_seed = checksum(ddo.proof['checksum']) asset_id = keeper.did_registry.hash_did(did_seed, account.address) ddo._did = DID.did(asset_id) did = ddo._did for service in services: if service.type == ServiceTypes.ASSET_ACCESS or service.type == ServiceTypes.NFT_ACCESS or service.type == ServiceTypes.ASSET_ACCESS_PROOF: access_service = ServiceFactory.complete_access_service( did, service.service_endpoint, service.attributes, keeper.access_template.address, keeper.escrow_payment_condition.address, service.type) ddo.add_service(access_service) elif service.type == ServiceTypes.CLOUD_COMPUTE: compute_service = ServiceFactory.complete_compute_service( did, service.service_endpoint, service.attributes, keeper.compute_execution_condition.address, keeper.escrow_payment_condition.address) ddo.add_service(compute_service) elif service.type == ServiceTypes.NFT_SALES: nft_sales_service = ServiceFactory.complete_nft_sales_service( did, service.service_endpoint, service.attributes, keeper.nft_sales_template.address, keeper.escrow_payment_condition.address, service.type) ddo.add_service(nft_sales_service) else: ddo.add_service(service) ddo.proof['signatureValue'] = keeper.sign_hash(did_to_id_bytes(did), account) ddo.add_public_key(did, account.address) ddo.add_authentication(did, PUBLIC_KEY_TYPE_RSA) try: _oldddo = metadata_api.get_asset_ddo(ddo.did) if _oldddo: metadata_api.retire_asset_ddo(ddo.did) except ValueError: pass if 'files' in metadata['main']: if auth_service == ServiceAuthorizationTypes.SECRET_STORE: encrypted_files = do_secret_store_encrypt( remove_0x_prefix(ddo.asset_id), json.dumps(metadata['main']['files']), account, get_config()) elif auth_service == ServiceAuthorizationTypes.PSK_RSA: encrypted_files, public_key = rsa_encryption_from_file( json.dumps(metadata['main']['files']), get_rsa_public_key_file()) else: encrypted_files, public_key = ecdsa_encryption_from_file( json.dumps(metadata['main']['files']), get_provider_key_file(), get_provider_password()) _files = metadata['main']['files'] # only assign if the encryption worked if encrypted_files: index = 0 for file in metadata['main']['files']: file['index'] = index index = index + 1 del file['url'] metadata['encryptedFiles'] = encrypted_files ddo_with_did = DDO(did, json_text=ddo.as_text().replace('/{did}', '/' + did)) ddo_service_endpoint = ddo_service_endpoint.replace('/{did}', '/' + did) if mint > 0 or royalties is not None or cap is not None: keeper.did_registry.register_mintable_did( did_seed, checksum=web3().toBytes(hexstr=ddo.asset_id), url=ddo_service_endpoint, cap=cap, royalties=royalties, account=account, providers=providers) if mint > 0: keeper.did_registry.mint(ddo.asset_id, mint, account=account) else: keeper_instance().did_registry.register( did_seed, checksum=web3().toBytes(hexstr=ddo.asset_id), url=ddo_service_endpoint, account=account, providers=providers) metadata_api.publish_asset_ddo(ddo_with_did) return ddo_with_did