Exemple #1
0
def test_build_download_response():
    request = Mock()
    request.range = None

    class Dummy:
        pass

    mocked_response = Dummy()
    mocked_response.content = b'asdsadf'
    mocked_response.status_code = 200
    mocked_response.headers = {}

    requests_session = Dummy()
    requests_session.get = MagicMock(return_value=mocked_response)

    filename = '<<filename>>.xml'
    content_type = mimetypes.guess_type(filename)[0]
    url = f'https://source-lllllll.cccc/{filename}'
    response = build_download_response(request, requests_session, url, url, None)
    assert response.headers["content-type"] == content_type
    assert response.headers.get_all('Content-Disposition')[0] == f'attachment;filename={filename}'

    filename = '<<filename>>'
    url = f'https://source-lllllll.cccc/{filename}'
    response = build_download_response(request, requests_session, url, url, None)
    assert response.headers["content-type"] == get_content_type(response.default_mimetype, response.charset)
    assert response.headers.get_all('Content-Disposition')[0] == f'attachment;filename={filename}'

    filename = '<<filename>>'
    url = f'https://source-lllllll.cccc/{filename}'
    response = build_download_response(request, requests_session, url, url, content_type)
    assert response.headers["content-type"] == content_type
    assert response.headers.get_all('Content-Disposition')[0] == f'attachment;filename={filename+mimetypes.guess_extension(content_type)}'

    mocked_response_with_attachment = deepcopy(mocked_response)
    attachment_file_name = 'test.xml'
    mocked_response_with_attachment.headers = {'content-disposition': f'attachment;filename={attachment_file_name}'}

    requests_session_with_attachment = Dummy()
    requests_session_with_attachment.get = MagicMock(return_value=mocked_response_with_attachment)

    url = 'https://source-lllllll.cccc/not-a-filename'
    response = build_download_response(request, requests_session_with_attachment, url, url, None)
    assert response.headers["content-type"] == mimetypes.guess_type(attachment_file_name)[0]
    assert response.headers.get_all('Content-Disposition')[0] == f'attachment;filename={attachment_file_name}'

    mocked_response_with_content_type = deepcopy(mocked_response)
    response_content_type = 'text/csv'
    mocked_response_with_content_type.headers = {'content-type': response_content_type}

    requests_session_with_content_type = Dummy()
    requests_session_with_content_type.get = MagicMock(return_value=mocked_response_with_content_type)

    filename = 'filename.txt'
    url = f'https://source-lllllll.cccc/{filename}'
    response = build_download_response(request, requests_session_with_content_type, url, url, None)
    assert response.headers["content-type"] == response_content_type
    assert response.headers.get_all('Content-Disposition')[0] == f'attachment;filename={filename}'
Exemple #2
0
def test_download_ipfs_file(client):
    cid = 'QmQfpdcMWnLTXKKW9GPV7NgtEugghgD6HgzSF6gSrp2mL9'
    url = f'ipfs://{cid}'
    download_url = get_download_url(url, None)
    requests_session = get_requests_session()

    request = Mock()
    request.range = None

    print(f'got ipfs download url: {download_url}')
    assert download_url and download_url.endswith(f'ipfs/{cid}')
    response = build_download_response(request, requests_session, download_url, download_url, None)
    assert response.data, f'got no data {response.data}'
Exemple #3
0
def simple_flow_consume():
    required_attributes = [
        'consumerAddress',
        'dataToken',
        'transferTxId'
    ]
    data = get_request_data(request)

    msg, status = check_required_attributes(
        required_attributes, data, 'simple_flow_consume')
    if msg:
        return jsonify(error=msg), status

    consumer = data.get('consumerAddress')
    dt_address = data.get('dataToken')
    tx_id = data.get('transferTxId')

    dt_map = None
    dt_map_str = os.getenv('CONFIG', '')
    if dt_map_str:
        dt_map = json.loads(dt_map_str)

    if not (dt_map_str and dt_map):  # or dt not in dt_map:
        return jsonify(error='This request is not supported.'), 400

    try:
        dt = DataToken(dt_address)
        # TODO: Verify that the datatoken is owned by this provider's account

        # TODO: Enable this check for the token transfer.
        # validate_order(
        #     consumer,
        #     dt_address,
        #     1,
        #     tx_id
        # )

        url = list(dt_map.values())[0]  # [dt_address]
        download_url = get_download_url(url, app.config['CONFIG_FILE'])
        logger.info(f'Done processing consume request for data token {dt_address}, '
                    f' url {download_url}')
        return build_download_response(request, requests_session, url, download_url)

    except Exception as e:
        logger.error(
            f'Error: {e}. \n'
            f'Payload was: dataToken={dt_address}, '
            f'consumerAddress={consumer}',
            exc_info=1
        )
        return jsonify(error=e), 500
Exemple #4
0
def simple_flow_consume():
    data = get_request_data(request)
    consumer = data.get("consumerAddress")
    dt_address = data.get("dataToken")

    dt_map = None
    dt_map_str = os.getenv("CONFIG", "")
    if dt_map_str:
        dt_map = json.loads(dt_map_str)

    if not (dt_map_str and dt_map):  # or dt not in dt_map:
        return jsonify(error="This request is not supported."), 400

    try:
        _ = DataToken(dt_address)
        # TODO: verify that the datatoken is owned by this provider's account

        # TODO: Enable this check for the token transfer.
        # validate_order(
        #     consumer,
        #     dt_address,
        #     1,
        #     tx_id
        # )

        url = list(dt_map.values())[0]  # [dt_address]
        download_url = get_download_url(url, app.config["CONFIG_FILE"])
        logger.info(
            f"Done processing consume request for data token {dt_address}, "
            f" url {download_url}")
        return build_download_response(request, requests_session, url,
                                       download_url)

    except Exception as e:
        logger.error(
            f"Error: {e}. \n"
            f"Payload was: dataToken={dt_address}, "
            f"consumerAddress={consumer}",
            exc_info=1,
        )
        return jsonify(error=str(e)), 500
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(  # noqa
            data,
            'download',
            user_nonce=user_nonce,
            additional_params=["transferTxId", "fileIndex"])
        service_id = data.get('serviceId')
        service_type = data.get('serviceType')
        signature = data.get('signature')
        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)

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

    except InvalidSignatureError as e:
        msg = f'Consumer signature failed verification: {e}'
        logger.error(msg, exc_info=1)
        return jsonify(error=msg), 401

    except Exception as e:
        logger.error(
            f'Error: {e}. \n'
            f'Payload was: documentId={did}, '
            f'consumerAddress={consumer_address},'
            f'signature={signature}'
            f'serviceId={service_id}'
            f'serviceType={service_type}',
            exc_info=1)
        return jsonify(error=str(e)), 500
Exemple #6
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
Exemple #7
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: 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 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, 'download', additional_params=["transferTxId", "fileIndex"])
        service_id = data.get('serviceId')
        service_type = data.get('serviceType')
        signature = data.get('signature')
        tx_id = data.get("transferTxId")
        validate_token_transfer(
            consumer_address,
            provider_acc.address,
            token_address,
            # FIXME: Replace this constant price number
            5,  #service.get_price(),
            tx_id)

        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_acc)

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

    except InvalidSignatureError as e:
        msg = f'Consumer signature failed verification: {e}'
        logger.error(msg, exc_info=1)
        return jsonify(error=msg), 401

    except Exception as e:
        logger.error(
            f'Error: {e}. \n'
            f'Payload was: documentId={did}, '
            f'consumerAddress={consumer_address},'
            f'signature={signature}'
            f'serviceId={service_id}'
            f'serviceType={service_type}',
            exc_info=1)
        return jsonify(error=e), 500
Exemple #8
0
def download():
    return asset_access(request, lambda req, session, url, download_url,
                               content_type: build_download_response(req, session, url, content_type))
Exemple #9
0
def test_build_download_response():
    request = Mock()
    request.range = None

    class Dummy:
        pass

    mocked_response = Dummy()
    mocked_response.content = b"asdsadf"
    mocked_response.status_code = 200
    mocked_response.headers = {}

    requests_session = Dummy()
    requests_session.get = MagicMock(return_value=mocked_response)

    filename = "<<filename>>.xml"
    content_type = mimetypes.guess_type(filename)[0]
    url = f"https://source-lllllll.cccc/{filename}"
    response = build_download_response(request, requests_session, url, url,
                                       None)
    assert response.headers["content-type"] == content_type
    assert (response.headers.get_all("Content-Disposition")[0] ==
            f"attachment;filename={filename}")

    filename = "<<filename>>"
    url = f"https://source-lllllll.cccc/{filename}"
    response = build_download_response(request, requests_session, url, url,
                                       None)
    assert response.headers["content-type"] == get_content_type(
        response.default_mimetype, response.charset)
    assert (response.headers.get_all("Content-Disposition")[0] ==
            f"attachment;filename={filename}")

    filename = "<<filename>>"
    url = f"https://source-lllllll.cccc/{filename}"
    response = build_download_response(request, requests_session, url, url,
                                       content_type)
    assert response.headers["content-type"] == content_type

    matched_cd = (
        f"attachment;filename={filename+mimetypes.guess_extension(content_type)}"
    )
    assert response.headers.get_all("Content-Disposition")[0] == matched_cd

    mocked_response_with_attachment = deepcopy(mocked_response)
    attachment_file_name = "test.xml"
    mocked_response_with_attachment.headers = {
        "content-disposition": f"attachment;filename={attachment_file_name}"
    }

    requests_session_with_attachment = Dummy()
    requests_session_with_attachment.get = MagicMock(
        return_value=mocked_response_with_attachment)

    url = "https://source-lllllll.cccc/not-a-filename"
    response = build_download_response(request,
                                       requests_session_with_attachment, url,
                                       url, None)
    assert (response.headers["content-type"] == mimetypes.guess_type(
        attachment_file_name)[0])  # noqa

    matched_cd = f"attachment;filename={attachment_file_name}"
    assert response.headers.get_all("Content-Disposition")[0] == matched_cd

    mocked_response_with_content_type = deepcopy(mocked_response)
    response_content_type = "text/csv"
    mocked_response_with_content_type.headers = {
        "content-type": response_content_type
    }

    requests_session_with_content_type = Dummy()
    requests_session_with_content_type.get = MagicMock(
        return_value=mocked_response_with_content_type)

    filename = "filename.txt"
    url = f"https://source-lllllll.cccc/{filename}"
    response = build_download_response(request,
                                       requests_session_with_content_type, url,
                                       url, None)
    assert response.headers["content-type"] == response_content_type
    assert (response.headers.get_all("Content-Disposition")[0] ==
            f"attachment;filename={filename}")