Пример #1
0
def computeStop():
    """Stop the execution of a workflow.

    ---
    tags:
      - services
    consumes:
      - application/json
    parameters:
      - name: signature
        in: query
        description: Signature of (consumerAddress+jobId+documentId) to verify the consumer of
            this compute job/asset. The signature uses ethereum based signing method
            (see https://github.com/ethereum/EIPs/pull/683)
        type: string
      - name: documentId
        in: query
        description: The ID of the asset. If not provided, all currently running compute
            jobs will be stopped for the specified consumerAddress
        required: true
        type: string
      - name: consumerAddress
        in: query
        description: The consumer ethereum address.
        required: true
        type: string
      - name: jobId
        in: query
        description: The ID of the compute job. If not provided, all running compute jobs of
            the specified consumerAddress/documentId are suspended
        type: string
    responses:
      200:
        description: Call to the operator-service was successful.
      400:
        description: One of the required attributes is missing.
      401:
        description: Consumer signature is invalid or failed verification.
      500:
        description: General server error
    """
    data = get_request_data(request)
    try:
        body = process_compute_request(data)
        response = requests_session.put(
            get_compute_endpoint(),
            params=body,
            headers={"content-type": "application/json"},
        )
        increment_nonce(body["owner"])
        return Response(
            response.content,
            response.status_code,
            headers={"content-type": "application/json"},
        )
    except (ValueError, Exception) as e:
        logger.error(f"Error- {str(e)}", exc_info=1)
        return jsonify(error=f"Error : {str(e)}"), 500
Пример #2
0
def computeDelete():
    """Deletes a workflow.

    ---
    tags:
      - services
    consumes:
      - application/json
    parameters:
      - name: signature
        in: query
        description: Signature of the documentId to verify that the consumer has rights to download the asset.
        type: string
      - name: documentId
        in: query
        description: The ID of the asset
        required: true
        type: string
      - name: consumerAddress
        in: query
        description: The consumer address.
        required: true
        type: string
      - name: jobId
        in: query
        description: JobId.
        type: string
    responses:
      200:
        description: Call to the operator-service was successful.
      400:
        description: One of the required attributes is missing.
      401:
        description: Invalid asset data.
      500:
        description: Error
    """
    data = get_request_data(request)
    try:
        body = process_compute_request(data)
        response = requests_session.delete(
            get_compute_endpoint(),
            params=body,
            headers={"content-type": "application/json"},
        )
        increment_nonce(body["owner"])
        return Response(
            response.content,
            response.status_code,
            headers={"content-type": "application/json"},
        )
    except (ValueError, Exception) as e:
        logger.error(f"Error- {str(e)}", exc_info=1)
        return jsonify(error=f"Error : {str(e)}"), 500
Пример #3
0
def download():
    """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: documentId
        in: query
        description: The ID of the asset/document (the DID).
        required: true
        type: string
      - name: url
        in: query
        description: This URL is only valid if Provider acts as a proxy.
                     Consumer can't download using the URL if it's not through the Provider.
        required: true
        type: string
      - name: signature
        in: query
        description: Signature of the documentId to verify that the consumer has rights to download the asset.
      - name: index
        in: query
        description: Index of the file in the array of files.
    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 = get_request_data(request)
    try:
        (
            asset,
            service,
            did,
            consumer_address,
            token_address,
        ) = process_consume_request(data)
        service_id = data.get("serviceId")
        service_type = data.get("serviceType")
        tx_id = data.get("transferTxId")
        if did.startswith("did:"):
            did = add_0x_prefix(did_to_id(did))

        _tx, _order_log, _transfer_log = validate_order(
            consumer_address,
            token_address,
            float(service.get_cost()),
            tx_id,
            did,
            service_id,
        )
        validate_transfer_not_used_for_other_service(did, service_id, tx_id,
                                                     consumer_address,
                                                     token_address)
        record_consume_request(did, service_id, tx_id, consumer_address,
                               token_address, service.get_cost())

        assert service_type == ServiceTypes.ASSET_ACCESS

        file_index = int(data.get("fileIndex"))
        file_attributes = asset.metadata["main"]["files"][file_index]
        content_type = file_attributes.get("contentType", None)
        url = get_asset_url_at_index(file_index, asset, provider_wallet)
        if not url:
            return jsonify(error="Cannot decrypt files for this asset."), 400

        download_url = get_download_url(url, app.config["CONFIG_FILE"])
        logger.info(f"Done processing consume request for asset {did}, "
                    f" url {download_url}")
        increment_nonce(consumer_address)
        return build_download_response(request, requests_session, url,
                                       download_url, content_type)

    except Exception as e:
        logger.error(
            f"Error: {e}. \n"
            f"Payload was: documentId={data.get('did')}, "
            f"consumerAddress={data.get('consumerAddress')},"
            f"serviceId={data.get('serviceId')}"
            f"serviceType={data.get('serviceType')}",
            exc_info=1,
        )
        return jsonify(error=str(e)), 500
Пример #4
0
def encrypt():
    """Encrypt document using the Provider's own symmetric key (symmetric encryption).
    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.
    The `urls` are encrypted by the provider so that the provider will be able
    to decrypt at time of providing the service later on.

    ---
    tags:
      - services
    consumes:
      - application/json
    parameters:
      - in: body
        name: body
        required: true
        description: Asset urls encryption.
        schema:
          type: object
          required:
            - documentId
            - document
            - publisherAddress:
          properties:
            documentId:
              description: Identifier of the asset to be registered in ocean.
              type: string
              example: 'did:op:08a429b8529856d59867503f8056903a680935a76950bb9649785cc97869a43d'
            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)
    """
    data = get_request_data(request)
    did = data.get("documentId")
    document = json.dumps(json.loads(data.get("document")),
                          separators=(",", ":"))
    publisher_address = data.get("publisherAddress")

    try:
        encrypted_document = do_encrypt(document, provider_wallet)
        logger.info(f"encrypted urls {encrypted_document}, "
                    f"publisher {publisher_address}, "
                    f"documentId {did}")
        increment_nonce(publisher_address)
        return Response(
            json.dumps({"encryptedDocument": encrypted_document}),
            201,
            headers={"content-type": "application/json"},
        )

    except Exception as e:
        logger.error(
            f"Error: {e}. \n"
            f"providerAddress={provider_wallet.address}\n"
            f"Payload was: documentId={did}, "
            f"publisherAddress={publisher_address}",
            exc_info=1,
        )
        return jsonify(error=str(e)), 500
Пример #5
0
def computeStart():
    """Call the execution of a workflow.

    ---
    tags:
      - services
    consumes:
      - application/json
    parameters:
      - name: signature
        in: query
        description: Signature of (consumerAddress+jobId+documentId) to verify the consumer of
            this asset/compute job. The signature uses ethereum based signing method
            (see https://github.com/ethereum/EIPs/pull/683)
        type: string
      - name: consumerAddress
        in: query
        description: The consumer ethereum address.
        required: true
        type: string

      - name: algorithmDid
        in: query
        description: The DID of the algorithm Asset to be executed
        required: false
        type: string
      - name: algorithmMeta
        in: query
        description: json object that define the algorithm attributes and url or raw code
        required: false
        type: json string
      - name: output
        in: query
        description: json object that define the output section
        required: true
        type: json string
    responses:
      200:
        description: Call to the operator-service was successful.
      400:
        description: One of the required attributes is missing.
      401:
        description: Consumer signature is invalid or failed verification
      500:
        description: General server error
    """
    data = get_request_data(request)

    try:
        consumer_address = data.get("consumerAddress")
        validator = WorkflowValidator(consumer_address, provider_wallet, data)

        status = validator.validate()
        if not status:
            return jsonify(error=validator.error), 400

        workflow = validator.workflow
        # workflow is ready, push it to operator
        logger.info("Sending: %s", workflow)

        tx_id = data.get("transferTxId")
        did = data.get("documentId")

        msg_to_sign = f"{provider_wallet.address}{did}"
        msg_hash = add_ethereum_prefix_and_hash_msg(msg_to_sign)

        payload = {
            "workflow": workflow,
            "providerSignature": Web3Helper.sign_hash(msg_hash, provider_wallet),
            "documentId": did,
            "agreementId": tx_id,
            "owner": consumer_address,
            "providerAddress": provider_wallet.address,
        }
        response = requests_session.post(
            get_compute_endpoint(),
            data=json.dumps(payload),
            headers={"content-type": "application/json"},
        )
        increment_nonce(consumer_address)
        return Response(
            response.content,
            response.status_code,
            headers={"content-type": "application/json"},
        )
    except (ValueError, KeyError, Exception) as e:
        logger.error(f"Error- {str(e)}", exc_info=1)
        return jsonify(error=f"Error : {str(e)}"), 500
Пример #6
0
def computeStatus():
    """Get status for a specific jobId/documentId/owner

    ---
    tags:
      - services
    consumes:
      - application/json
    parameters:
      - name: signature
        in: query
        description: Signature of (consumerAddress+jobId+documentId) to verify the consumer of
            this asset/compute job. The signature uses ethereum based signing method
            (see https://github.com/ethereum/EIPs/pull/683)
        type: string
      - name: documentId
        in: query
        description: The ID of the asset. If not provided, the status of all
            currently running and old compute jobs for the specified consumerAddress will be returned.
        required: true
        type: string
      - name: consumerAddress
        in: query
        description: The consumer ethereum address.
        required: true
        type: string
      - name: jobId
        in: query
        description: The ID of the compute job. If not provided, all running compute jobs of
            the specified consumerAddress/documentId are suspended
        type: string

    responses:
      200:
        description: Call to the operator-service was successful.
      400:
        description: One of the required attributes is missing.
      401:
        description: Consumer signature is invalid or failed verification.
      500:
        description: General server error
    """
    data = get_request_data(request)
    try:
        body = process_compute_request(data)

        response = requests_session.get(
            get_compute_endpoint(),
            params=body,
            headers={"content-type": "application/json"},
        )

        _response = response.content

        signed_request = bool(data.get("signature"))
        if signed_request:
            owner = data.get("consumerAddress")
            did = data.get("documentId")
            jobId = data.get("jobId")
            original_msg = f"{owner}{jobId}{did}"
            try:
                verify_signature(
                    owner, data.get("signature"), original_msg, get_nonce(owner)
                )
            except InvalidSignatureError:
                signed_request = False
            increment_nonce(owner)

        # Filter status info if signature is not given or failed validation
        if not signed_request:
            resp_content = json.loads(response.content.decode("utf-8"))
            if not isinstance(resp_content, list):
                resp_content = [resp_content]
            _response = []
            keys_to_filter = ["resultsUrl", "algorithmLogUrl", "resultsDid", "owner"]
            for job_info in resp_content:
                for k in keys_to_filter:
                    job_info.pop(k)
                _response.append(job_info)

            _response = json.dumps(_response)

        return Response(
            _response,
            response.status_code,
            headers={"content-type": "application/json"},
        )

    except (ValueError, Exception) as e:
        logger.error(f"Error- {str(e)}", exc_info=1)
        return jsonify(error=f"Error : {str(e)}"), 500