def systest_auth(requesting_app, providing_app, user):
    """
    Ensuring that an incorrectly signed request is rejected.

    """
    def broken(d, field):
        d[field] = 'unlucky' + d[field][7:]
        return d

    log.info(f'{requesting_app} is requesting data from {providing_app}')

    body = {'users': [user], 'data_id': 'request_hash'}

    app_config = demo_config['demo_apps'][providing_app]
    port = app_config['rpc_server_port']

    eos_client = get_eos_rpc_client()
    mother = UnificationMother(eos_client, providing_app, get_cleos(),
                               get_ipfs_client())
    provider_obj = Provider(providing_app, 'https', mother)

    encoded_password = demo_config['system'][requesting_app]['password']

    ks = UnificationKeystore(encoded_password,
                             app_name=requesting_app,
                             keystore_path=Path('data/keys'))
    payload = bundle(ks, requesting_app, provider_obj.name, body, 'Success')
    payload = broken(payload, 'signature')

    r = provider_obj.post('data_request', payload)
    assert r.status_code == 401
    def run_test_mother(self, app, demo_apps):
        print("Contacting MOTHER FOR: ", app)

        eos_client = Client(nodes=[self.cleos.get_nodeos_url()])
        um = UnificationMother(eos_client, app, get_cleos(), get_ipfs_client())
        print("Valid app: ", um.valid_app())
        assert um.valid_app() is True

        print("UApp SC Hash in MOTHER: ", um.get_hash_in_mother())
        print("Deployed UApp SC hash: ", um.get_deployed_contract_hash())
        assert um.get_hash_in_mother() == um.get_deployed_contract_hash()

        print("Valid Code: ", um.valid_code())
        assert um.valid_code() is True

        print("Signed by MOTHER: ", um.signed_by_mother())
        assert um.signed_by_mother() is True

        print("RPC IP: ", um.get_haiku_rpc_ip())
        assert um.get_haiku_rpc_ip() == demo_apps[app]['rpc_server']

        print("RPC Port: ", um.get_haiku_rpc_port())
        assert int(um.get_haiku_rpc_port()) == int(
            demo_apps[app]['rpc_server_port'])

        print("RPC Server: ", um.get_haiku_rpc_server())
        print("-----------------------------------")
Пример #3
0
def view(provider, request_hash):
    """
    Read data stored locally from an Data Provider for a particular user.

    \b
    :param provider: The app name of the data provider.
    :param request_hash: The particular piece of data in concern.
    :return:
    """
    requesting_app = os.environ['app_name']
    password = os.environ['keystore']

    eos_client = get_eos_rpc_client()
    mother = UnificationMother(eos_client, provider, get_cleos(),
                               get_ipfs_client())

    provider_obj = Provider(provider, 'https', mother)
    req_hash = f'request-{request_hash}'

    click.echo(f'App {requesting_app} is reading ingested data from '
               f'{provider_obj.name}')

    encoded_password = str.encode(password)
    keystore = UnificationKeystore(encoded_password)

    client = HaikuDataClient(keystore)
    data = client.read_data_from_store(provider_obj, req_hash)

    click.echo(json.loads(data))
Пример #4
0
    def __init__(self, eos_client, uapp_contract_acc, requesting_app, users):
        """
        :param users: A list of users we want to obtain data for. If an empty
        list is provided, then data for all permissible users are provided.
        """
        self.__uapp_contract_acc = uapp_contract_acc
        self.__requesting_app = requesting_app
        self.__haiku_conf = UnificationConfig()

        self.__my_mother = UnificationMother(eos_client, uapp_contract_acc,
                                             get_cleos(), get_ipfs_client())
        self.__my_uapp_sc = UnificationUapp(eos_client, uapp_contract_acc)
        self.__my_lookup = UnificationLookup(default_lookup_db())
        self.__users = None if len(users) == 0 else users

        self.__my_db_schemas = self.__my_uapp_sc.get_all_db_schemas()
        self.__db_schema_maps = {}
        self.__granted = []
        self.__granted_field_lookup = {}
        self.__revoked = []
        self.__raw_data = None

        self.__native_user_meta = self.__my_lookup.get_native_user_meta()

        for pkey, db_schema in self.__my_db_schemas.items():
            schema_map = self.__my_lookup.get_schema_map(pkey)
            self.__db_schema_maps[pkey] = schema_map

        self.__generate_data()
Пример #5
0
    def __check_app_is_valid(self):
        """
        Call the MOTHER Smart Contract, and check if the requesting_app is both
        a verified app, and that it's smart contract code is valid (by checking
        the code's hash).
        """

        um = UnificationMother(self.__eosClient, self.__app_to_validate,
                               get_cleos(), get_ipfs_client())
        self.__is_valid_app = um.valid_app()
        self.__is_valid_code = um.valid_code()
        self.__signed_by_mother = um.signed_by_mother()
Пример #6
0
def balance(user, password):
    """
    Get UND balance for an account

    \b
    :param user: The EOS user account name.
    :param password: The EOS user account's wallet password.
    """
    cleos = get_cleos()
    cleos.unlock_wallet(user, password)
    my_balance = get_balance(user)
    cleos.lock_wallet(user)

    click.echo(bold(f'{user} Balance: {my_balance}'))
Пример #7
0
def fetch(provider, request_hash, user):
    """
    Fetch data from an App to this App in an Enterprise/DSP/B2B environment,
    where data request is agreed external to the UApp Store.

    \b
    :param provider: The app name of the data provider.
    :param request_hash: The particular piece of data in concern.
    :param user: Obtain data for a specific user EOS user account.
    :return:
    """
    requesting_app = os.environ['app_name']
    password = os.environ['keystore']

    # Write the data request to the Consumer's UApp smart contract
    eos_client = get_eos_rpc_client()
    mother = UnificationMother(eos_client, provider, get_cleos(),
                               get_ipfs_client())

    provider = Provider(provider, 'https', mother)
    req_hash = f'request-{request_hash}'

    suffix = 'for all users' if user is None else f'for {user}'
    click.echo(f'App {requesting_app} is requesting data from {provider}'
               f' {suffix}')

    encoded_password = str.encode(password)
    keystore = UnificationKeystore(encoded_password)

    # tmp - get the price for the transfer from Schema[0] in provider's UApp SC
    # This will possibly be determined externally as part of the B2B agreement
    provider_uapp_sc = UnificationUapp(eos_client, provider.name)
    db_schema = provider_uapp_sc.get_db_schema_by_pkey(
        0)  # tmp - only 1 schema
    sched_price = db_schema['price_sched']

    # initiate request in Consumer's UApp SC
    consumer_uapp_sc = UnificationUapp(eos_client, requesting_app)
    latest_req_id = consumer_uapp_sc.init_data_request(provider.name, "0", "0",
                                                       sched_price)

    client = HaikuDataClient(keystore)
    data_path = client.make_data_request(requesting_app, provider, user,
                                         req_hash, latest_req_id)

    click.echo(f'Data written to: {data_path}')
    click.echo(f'View using: haiku view {provider.name} {request_hash}')
Пример #8
0
    def __init__(self, eos_rpc_client, uapp_contract_acc):
        """
        :param eos_rpc_client: EOS RPC Client
        :param uapp_contract_acc: the eos account name of the app for which the
               class will retrieve data from the UApp smart contract

        """
        self.__ipfs_perm_table = "userperms"
        self.__rsa_pub_key_table = "rsapubkey"
        self.__db_schema_table = "dataschemas"
        self.__data_requests_table = "datareqs"

        self.__uapp_contract_acc = uapp_contract_acc
        self.__eos_rpc_client = eos_rpc_client

        # Todo: Migrate from cleos command line to EOS RPC API
        self.__cleos = get_cleos()
def systest_smart_contract_mother():
    log.info('Running systest smart contract MOTHER')
    d_conf = json.loads(Path('data/demo_config.json').read_text())
    appnames = ['app1', 'app2', 'app3']
    d_apps = d_conf['demo_apps']
    conf = UnificationConfig()
    eos_client = Client(
        nodes=[f"http://{conf['eos_rpc_ip']}:{conf['eos_rpc_port']}"])

    for appname in appnames:
        log.info("------------------------------------------")
        app_data = d_apps[appname]
        log.info(f"Contacting MOTHER for {app_data['eos_sc_account']}")
        mother = UnificationMother(eos_client, app_data['eos_sc_account'],
                                   get_cleos(), get_ipfs_client())

        log.info("App is Valid")
        log.info("Expecting: True")
        log.info(f"Actual - MOTHER: {mother.valid_app()}")
        assert mother.valid_app() is True

        log.info("App Code is Valid")
        log.info("Expecting: True")
        log.info(f"Actual - MOTHER: {mother.valid_code()}")
        assert mother.valid_app() is True

        log.info("Code Hash")
        log.info(
            f"Expecting - config.json: {mother.get_deployed_contract_hash()}")
        log.info(f"Actual - MOTHER: {mother.get_hash_in_mother()}")
        assert (mother.get_deployed_contract_hash()
                == mother.get_hash_in_mother()) is True

        log.info("RPC IP")
        log.info(f"Expecting - config.json: {app_data['rpc_server']}")
        log.info(f"Actual - MOTHER: {mother.get_haiku_rpc_ip()}")
        assert (app_data['rpc_server'] == mother.get_haiku_rpc_ip()) is True

        log.info("RPC Port")
        log.info(f"Expecting - config.json: {app_data['rpc_server_port']}")
        log.info(f"Actual - MOTHER: {mother.get_haiku_rpc_port()}")
        assert (int(app_data['rpc_server_port']) == int(
            mother.get_haiku_rpc_port())) is True

        log.info("------------------------------------------")
Пример #10
0
def transfer(from_acc, to_acc, amount, password):
    """
    Quick UND transfer method.

    \b
    :param from_acc: The EOS user account name SENDING the UNDs.
    :param to_acc: The EOS user account name RECEIVING the UNDs.
    :param amount: amount to send.
    :param password: The SENDING EOS user account's wallet password.
    """
    # TODO: need to make the babel client initialised, and locked to a user

    amt = "{0:.4f}".format(round(float(amount), 4))

    click.echo(f"{bold(from_acc)} is transferring {bold(amt)} UND"
               f"to {bold(to_acc)}:")

    my_balance = get_balance(from_acc)
    click.echo(bold(f'{from_acc} Old Balance: {my_balance}'))
    their_balance = get_balance(to_acc)
    click.echo(bold(f'{to_acc} Old Balance: {their_balance}'))

    cleos = get_cleos()
    cleos.unlock_wallet(from_acc, password)

    d = {
        'from': from_acc,
        'to': to_acc,
        'quantity': f'{amt} UND',
        'memo': 'UND transfer'
    }

    ret = cleos.run(
        ['push', 'action', 'unif.token', 'transfer', json.dumps(d),
         '-p', from_acc])

    cleos.lock_wallet(from_acc)

    stripped = ret.stdout.strip()
    click.echo(bold(f'Transfer result: {stripped}'))

    my_balance = get_balance(from_acc)
    click.echo(bold(f'{from_acc} New Balance: {my_balance}'))
    their_balance = get_balance(to_acc)
    click.echo(bold(f'{to_acc} New Balance: {their_balance}'))
    def __init__(self, uapp_acc: str, und_amt: int):
        """

        :param uapp_acc: The account name of the payer.
        :param und_amt: The amount of UND to be processed
        """
        self.__my_uapp_acc = uapp_acc
        self.__cleos = get_cleos()

        #TODO: I think I can deprecate the following
        conf = UnificationConfig()
        self.__eos_client_pre = [
            "/opt/eosio/bin/cleos", "--url",
            f"http://{conf['eos_rpc_ip']}:{conf['eos_rpc_port']}",
            "--wallet-url",
            f"http://{conf['eos_wallet_ip']}:{conf['eos_wallet_port']}"
        ]

        self.__und_amt = und_amt
Пример #12
0
def __request_from_uapp_store(data_request):
    """
    Receives a data request from the UApp Store, and
    processes the request

    \b
    :param data_request: Dict containing request parameters
    """
    requesting_app = os.environ['app_name']
    password = os.environ['keystore']

    click.echo("Processing request from UApp Store:")
    click.echo(data_request)

    eos_client = get_eos_rpc_client()

    # Write the data request to the Consumer's smart contract
    uapp_sc = UnificationUapp(eos_client, requesting_app)
    latest_req_id = uapp_sc.init_data_request(data_request['provider'],
                                              data_request['schema_pkey'], "0",
                                              data_request['price'])

    request_hash = f"{data_request['provider']}-{data_request['schema_pkey']}" \
                   f"-{latest_req_id}.dat"

    provider_name = data_request['provider']
    mother = UnificationMother(eos_client, provider_name, get_cleos(),
                               get_ipfs_client())
    provider_obj = Provider(provider_name, 'https', mother)
    req_hash = f'request-{request_hash}'

    click.echo(f'App {requesting_app} is requesting data from '
               f'{provider_obj.name}')

    encoded_password = str.encode(password)
    keystore = UnificationKeystore(encoded_password)

    client = HaikuDataClient(keystore)
    data_path = client.make_data_request(requesting_app, provider_obj, None,
                                         req_hash, latest_req_id)

    click.echo(f'Data written to: {data_path}')
    click.echo(f'View using: haiku view {provider_obj.name} {request_hash}')
def systest_ingest(requesting_app, providing_app, user, balances):
    log.info(f'Testing Fetch ingestion: {requesting_app} '
             f'is requesting data from {providing_app}')
    request_hash = f'data-request-{providing_app}-{requesting_app}'

    app_config = demo_config['demo_apps'][providing_app]
    port = app_config['rpc_server_port']

    eos_client = get_eos_rpc_client()
    mother = UnificationMother(eos_client, providing_app, get_cleos(),
                               get_ipfs_client())
    provider_obj = Provider(providing_app, 'https', mother)

    password = demo_config['system'][requesting_app]['password']
    encoded_password = str.encode(password)
    keystore = UnificationKeystore(encoded_password,
                                   app_name=requesting_app,
                                   keystore_path=Path('data/keys'))

    conf = UnificationConfig()
    eos_client = Client(
        nodes=[f"http://{conf['eos_rpc_ip']}:{conf['eos_rpc_port']}"])
    consumer_uapp_sc = UnificationUapp(eos_client, requesting_app)

    price_sched = demo_config['demo_apps'][providing_app]['db_schemas'][0][
        'price_sched']

    latest_req_id = consumer_uapp_sc.init_data_request(provider_obj.name, "0",
                                                       "0", price_sched)

    client = HaikuDataClient(keystore)
    client.make_data_request(requesting_app, provider_obj, user, request_hash,
                             latest_req_id)
    client.read_data_from_store(provider_obj, request_hash)

    # Update the system test record of the balances
    balances[requesting_app] = balances[requesting_app] - price_sched
    und_rewards = UndRewards(providing_app, price_sched)
    balances[providing_app] = (balances[providing_app] +
                               und_rewards.calculate_reward(is_user=False))

    return balances
def systest_process_permission_batches():
    appnames = ['app1', 'app2', 'app3']

    for app_name in appnames:
        log.debug(f'run systest_process_permission_batches for {app_name}')
        mother = UnificationMother(get_eos_rpc_client(), app_name, get_cleos(),
                                   get_ipfs_client())
        provider_obj = Provider(app_name, 'https', mother)

        password = demo_config['system'][app_name]['password']
        encoded_password = str.encode(password)
        keystore = UnificationKeystore(encoded_password,
                                       app_name=app_name,
                                       keystore_path=Path('data/keys'))

        client = HaikuDataClient(keystore)
        try:
            client.process_permissions_batch(provider_obj)
        except Exception as e:
            log.error(f'systest_process_permission_batches failed: {e}')
    def request_permission_change(self, user, app_permission_list,
                                  private_key):
        log.info(f"Process {user} permission change requests")
        for consumer, providers in app_permission_list.items():
            for provider, permissions in providers.items():
                granted = permissions['granted']
                if granted:
                    fields = permissions['fields']
                else:
                    fields = ''
                schema_id = int(permissions['schema_id'])

                log.debug(f'request_permission_change '
                          f'{user} requesting {provider} '
                          f'update perms for {consumer} '
                          f'in schema {schema_id}: {granted} {fields}')

                payload, p_nonce, p_sig = generate_payload(
                    user, private_key, provider, consumer, fields, 'active',
                    schema_id)

                log.debug(f'request_permission_change payload: '
                          f'{json.dumps(payload)}')

                mother = UnificationMother(get_eos_rpc_client(), provider,
                                           get_cleos(), get_ipfs_client())
                provider_obj = Provider(provider, 'https', mother)

                r = provider_obj.post('modify_permission', payload)
                d = r.json()

                if r.status_code != 200:
                    raise Exception(d['message'])

                proc_id = d['proc_id']
                ret_app = d['app']

                log.debug(f"request_permission_change success: "
                          f"{ret_app}: Process ID {proc_id}")
Пример #16
0
def modify_permission():
    conf = app.unification_config

    try:
        d = flask.request.get_json()

        eos_perm = d['eos_perm']
        req_sender = d['user']
        jwt = d['jwt']

        cleos = get_cleos()
        eos_rpc_client = get_eos_rpc_client()

        # ToDo: find better way to get public key from EOS account
        public_key = cleos.get_public_key(req_sender, eos_perm)

        unif_jwt = UnifJWT(jwt, public_key)
        issuer = unif_jwt.get_issuer()
        audience = unif_jwt.get_audience()

        if audience != conf['uapp_contract']:
            return error_request_not_me()

        if req_sender != issuer:
            return error_request_not_you()

        payload = unif_jwt.get_payload()

        # Check field list sent matches fields in metadata schema
        if len(payload['perms']) > 0:
            field_list = payload['perms'].split(',')

            uapp_sc = UnificationUapp(eos_rpc_client, conf['uapp_contract'])
            db_schema = uapp_sc.get_db_schema_by_pkey(int(
                payload['schema_id']))

            if not db_schema:
                return generic_error(
                    f"Invalid Metadata Schema ID: {payload['schema_id']}")

            valid_fields = [f['name'] for f in db_schema['schema']['fields']]
            for pf in field_list:
                if pf not in valid_fields:
                    return generic_error(
                        f"Invalid field list: {payload['perms']}")

        batcher = PermissionBatcher(pb_default_db())

        rowid = batcher.add_to_queue(issuer, payload['consumer'],
                                     payload['schema_id'], payload['perms'],
                                     payload['p_nonce'], payload['p_sig'],
                                     public_key)

        d = {'app': conf['uapp_contract'], 'proc_id': rowid}

        return flask.jsonify(d), 200

    except InvalidJWT as e:
        return invalid_jwt(e)

    except InvalidPublicKey as e:
        return invalid_jwt(e)

    except JWTSignatureMismatch as e:
        return invalid_jwt(e)

    except InvalidSignature:
        return invalid_response()

    except Exception as e:
        logger.exception(e)
        return generic_error()