def systest_smart_contract_uapp():
    log.info('Running systest smart contract UApp')
    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]
        conf_db_schemas = app_data['db_schemas']
        uapp_sc = UnificationUapp(eos_client, app_data['eos_sc_account'])
        log.info("Check DB Schemas are correctly configured")

        for schema_obj in conf_db_schemas:
            log.info(f"Check schema {schema_obj['schema_name']}")
            conf_schema = schema_obj['schema']
            log.info(f"Expecting - config.json: {conf_schema}")

            # version set to 1, since that's the hard coded version used in
            # accounts.validate_with_mother
            uapp_contract_schema = uapp_sc.get_db_schema_by_pkey(0)
            log.info(f"Actual - UApp Smart Contract: "
                     f"{uapp_contract_schema['schema']}")
            assert (conf_schema == uapp_contract_schema['schema']) is True
Exemple #2
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()
Exemple #3
0
def get_public_key(app_name):
    eos_client = get_eos_rpc_client()
    uapp_sc = UnificationUapp(eos_client, app_name)
    public_key_hash = uapp_sc.get_public_key_hash(app_name)

    store = get_ipfs_client()
    public_key = store.cat_file(public_key_hash)

    return serialization.load_pem_public_key(public_key,
                                             backend=default_backend())
    def run_test_uapp(self, app):
        print("Loading UApp Contract for: ", app)

        eos_client = Client(nodes=[self.cleos.get_nodeos_url()])
        u_uapp = UnificationUapp(eos_client, app)

        print("Data Schemas:")
        print(u_uapp.get_all_db_schemas())

        print("-----------------------------------")
def obtain_data(keystore,
                eos_account_name,
                eos_client,
                uapp_contract_acc,
                users,
                request_id=None):
    """
    :param eos_account_name: The account name of the
                             requesting App (Data Consumer).
    :param eos_client: EOS RPC Client
    :param uapp_contract_acc: The account name of
                              the providing App (Data Provider).
    :param users: The users to obtain data for. None to get all available users
    :param request_id: Primary Key for the data request
                       held in the Consumer's UApp smart contract
    """

    data_factory = UnificationDataFactory(eos_client, uapp_contract_acc,
                                          eos_account_name, users)
    body = {'data': data_factory.get_raw_data()}

    d = bundle(keystore, uapp_contract_acc, eos_account_name, body, 'Success')

    # load UApp SC for requesting app
    uapp_sc = UnificationUapp(eos_client, eos_account_name)
    # generate checksum
    data_hash = hashlib.sha224(str(d['payload']).encode('utf-8')).hexdigest()

    # temporarily allow uapp_contract_acc@modreq to
    # interact with consumer's contract
    eosio_cleos = EosioCleos(False)
    eosio_cleos.run([
        "set", "action", "permission", uapp_contract_acc, eos_account_name,
        'updatereq', 'modreq', '-p', f'{uapp_contract_acc}@active'
    ])

    # write to Consumer's smart contract
    transaction_id = uapp_sc.update_data_request(request_id, uapp_contract_acc,
                                                 data_hash, "test")

    # Remove permission association for action in consumer's contract
    eosio_cleos.run([
        "set", "action", "permission", uapp_contract_acc, eos_account_name,
        'updatereq', 'NULL', '-p', f'{uapp_contract_acc}@active'
    ])

    # check transaction has been processed
    if transaction_id is not None:
        return flask.jsonify(d), 200
    else:
        return bc_transaction_error()
Exemple #6
0
def uapp_store():
    """
    Display a list of valid apps, and their schemas.
    Allow option to initiate and process a data transfer
    \b
    """
    requesting_app = os.environ['app_name']

    click.echo(bold("UApp Store"))

    eos_client = get_eos_rpc_client()
    valid_apps = eos_client.get_table_rows("unif.mother", "unif.mother",
                                           "validapps", True, 0, -1, -1)

    uapp_store_dict = {}
    store_key = 1

    for va in valid_apps['rows']:
        data_provider = eosio_account.name_to_string(
            int(va['uapp_contract_acc']))
        if int(va['is_valid']) == 1 and data_provider != requesting_app:
            uapp_sc = UnificationUapp(eos_client, data_provider)
            db_schemas = uapp_sc.get_all_db_schemas()
            click.echo(bold(f"Data Provider: {data_provider}"))
            for schema_pkey, db_schema in db_schemas.items():
                schema = db_schema['schema']
                click.echo(bold(f"Option {store_key}:"))
                click.echo("    Data available:")
                for field in schema['fields']:
                    click.echo(f"        {field['name']}, {field['type']}")
                click.echo(
                    f"    Scheduled Price: {db_schema['price_sched']} UND")
                click.echo(f"    Ad-hoc Price: {db_schema['price_adhoc']} UND")
                click.echo("    Availability: daily")

                d = {
                    'provider': data_provider,
                    'schema_pkey': schema_pkey,
                    'price': db_schema['price_sched']
                }
                uapp_store_dict[store_key] = d
                store_key += 1

    request_id = int(
        input(f"Select option 1 - {(store_key - 1)} to generate "
              f"a data request, or '0' to exit:"))
    if 0 < request_id <= store_key:
        data_request = uapp_store_dict[request_id]
        __request_from_uapp_store(data_request)
    else:
        click.echo("Exit Uapp Store")
def get_proof():
    conf = app.unification_config
    d = flask.request.get_json()
    user = d['user']
    consumer = d['consumer']
    ipfs_hash = d['ipfs_hash']
    schema_id = d['schema_id']

    provider_uapp = UnificationUapp(get_eos_rpc_client(),
                                    conf['uapp_contract'])

    permission_db = PermissionBatchDatabase(pb_default_db())

    permissions = UnifPermissions(get_ipfs_client(), provider_uapp,
                                  permission_db)

    if ipfs_hash is not None:
        permissions.load_perms_from_ipfs(ipfs_hash)
    else:
        permissions.load_consumer_perms(consumer)

    proof = permissions.get_proof(user, schema_id=schema_id)

    # ToDo: send as JWT
    return_d = {'proof': proof}

    return flask.jsonify(return_d), 200
Exemple #8
0
def schemas(app_name):
    """
    Obtain data source information about an App.

    \b
    :param app_name: The EOS app account name to query.
    """
    eos_client = get_eos_rpc_client()

    uapp_sc = UnificationUapp(eos_client, app_name)

    click.echo(f"{app_name} has the following Schemas:\n")

    for key, schema in uapp_sc.get_all_db_schemas().items():
        click.echo(f"Schema ID {schema['pkey']}:")
        click.echo(schema['schema'])
def systest_merkle_proof_permissions():
    ipfs = get_ipfs_client()
    users, consumers, providers = compile_actors()

    for provider in providers:
        log.debug(f'run systest_merkle_proof_'
                  f'permissions for Provider {provider}')

        provider_uapp = UnificationUapp(get_eos_rpc_client(), provider)

        permission_db = PermissionBatchDatabase(pb_default_db())
        permissions = UnifPermissions(ipfs, provider_uapp, permission_db)

        for consumer in consumers:
            if consumer != provider:
                log.debug(f'Provider {provider}: load '
                          f'permissions for Consumer {consumer}')
                permissions.load_consumer_perms(consumer)

                permissions_obj = permissions.get_all_perms()

                tree = MerkleTree()

                for user, perm in permissions_obj['permissions'].items():
                    for schema_id, schema_perm in perm.items():
                        tree.add_leaf(json.dumps(schema_perm))

                tree.grow_tree()

                log.debug(f"Generated merkle root: {tree.get_root_str()}")
                log.debug(f"Recorded merkle root: "
                          f"{permissions_obj['merkle_root']}")

                for user, perm in permissions_obj['permissions'].items():
                    for schema_id, schema_perm in perm.items():
                        requested_leaf = json.dumps(schema_perm)
                        proof_chain = tree.get_proof(requested_leaf,
                                                     is_hashed=False)
                        log.debug(f'Permission leaf for {user}:'
                                  f' {requested_leaf}')
                        log.debug(f'Proof chain for {user} - '
                                  f'Schema {schema_id} '
                                  f'permission leaf: '
                                  f'{json.dumps(proof_chain)}')

                        # simulate only having access to leaf,
                        # root and proof chain for leaf
                        verify_tree = MerkleTree()

                        is_good = verify_tree.verify_leaf(
                            requested_leaf,
                            permissions_obj['merkle_root'],
                            proof_chain,
                            is_hashed=False)

                        log.debug(f'Leaf is valid: {is_good}')

                        assert is_good
Exemple #10
0
def permissions(user):
    """
    Display user permissions.

    \b
    :param user: The EOS user account name to query.
    """
    eos_rpc_client = get_eos_rpc_client()
    ipfs_client = get_ipfs_client()

    apps = []

    valid_apps = eos_rpc_client.get_table_rows(
        "unif.mother", "unif.mother", "validapps", True, 0, -1,
        -1)

    for va in valid_apps['rows']:
        apps.append(eosio_account.name_to_string(int(va['uapp_contract_acc'])))

    click.echo(f"{bold(user)} Permissions overview:")

    for provider in apps:
        click.echo(f'Provider: {bold(provider)}')
        for consumer in apps:
            if consumer != provider:
                click.echo(f'  Consumer: {bold(consumer)}')
                uapp_sc = UnificationUapp(eos_rpc_client, provider)
                ipfs_hash, merkle_root = uapp_sc.get_ipfs_perms_for_req_app(
                    consumer)

                if ipfs_hash is not None and ipfs_hash != ZERO_MASK:
                    permissions_str = ipfs_client.get_json(ipfs_hash)
                    permissions_json = json.loads(permissions_str)
                    user_perms = permissions_json[user]
                    for schema_id, perms in user_perms.items():
                        click.echo(f'    Schema ID: {schema_id}')
                        if perms['perms'] == '':
                            click.echo('      Granted: False')
                        else:
                            click.echo('      Granted: True')
                            click.echo(f"      Fields: {perms['perms']}")
                else:
                    click.echo('Nothing set')
Exemple #11
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_check_permission_requests():

    ipfs = get_ipfs_client()
    users, consumers, providers = compile_actors()

    for provider in providers:
        log.debug(f'run systest_check_permission_requests'
                  f' for Provider {provider}')

        provider_uapp = UnificationUapp(get_eos_rpc_client(), provider)

        permission_db = PermissionBatchDatabase(pb_default_db())
        permissions = UnifPermissions(ipfs, provider_uapp, permission_db)

        for consumer in consumers:
            if consumer != provider:
                log.debug(f'Provider {provider}: load permissions '
                          f'for Consumer {consumer}')
                permissions.load_consumer_perms(consumer)
                for user in users:
                    user_permissions = permissions.get_user_perms_for_all_schemas(
                        user)
                    for schema_id, user_perms in user_permissions.items():
                        log.debug(f'User {user}, '
                                  f'Schema {schema_id}: {user_perms}')
                        is_valid = permissions.verify_permission(user_perms)
                        log.debug(f'Perm sig valid: {is_valid}')

                        assert is_valid

                        demo_conf_check = demo_config['demo_permissions'][
                            user][consumer][provider]

                        demo_conf_fields = demo_conf_check['fields']
                        demo_conf_granted = demo_conf_check['granted']
                        demo_conf_schema_id = demo_conf_check['schema_id']

                        assert int(demo_conf_schema_id) == int(schema_id)

                        if demo_conf_granted:
                            log.debug("Permission granted")
                            log.debug(f"Demo fields: {demo_conf_fields}, "
                                      f"recorded fields: "
                                      f"{user_perms['perms']}")
                            assert demo_conf_fields == user_perms['perms']
                        else:
                            log.debug("Permission not granted. Recorded "
                                      "perms should be empty")
                            log.debug(f"Recorded fields: "
                                      f"{user_perms['perms']}")
                            assert user_perms['perms'] == ''
def data_request():
    try:
        d = flask.request.get_json()

        # Validate requesting app against smart contracts
        # config is this Haiku Node's config fle, containing its UApp
        # Smart Contract account/address and the EOS RPC server/port used for
        # communicating with the blockchain.
        conf = app.unification_config

        sender = d['eos_account_name']
        recipient = conf['uapp_contract']

        if sender == recipient:
            return error_request_self()

        bundle_d = unbundle(app.keystore, sender, d)

        eos_client = get_eos_rpc_client()

        # Init the validation class for THIS Haiku, and validate the
        # REQUESTING APP.
        v = UnificationAppScValidation(eos_client, d['eos_account_name'])

        # If the REQUESTING APP is valid according to MOTHER, then we can
        # generate the data. If not, return an invalid_app response
        if v.valid():
            users = bundle_d.get('users')
            request_id = bundle_d.get('request_id')

            # before processing data, check for any stashed permissions
            ipfs = get_ipfs_client()
            provider_uapp = UnificationUapp(eos_client, conf['uapp_contract'])

            permission_db = PermissionBatchDatabase(pb_default_db())
            permissions = UnifPermissions(ipfs, provider_uapp, permission_db)
            permissions.check_and_process_stashed(sender)

            return obtain_data(app.keystore, sender, eos_client,
                               conf['uapp_contract'], users, request_id)
        else:
            return invalid_app()

    except InvalidSignature:
        return invalid_response()

    except Exception as e:
        logger.exception(e)
        return generic_error()
Exemple #15
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}')
    def make_data_request(self, requesting_app, providing_app: Provider, user,
                          request_hash, request_id):
        # Check if the providing app is valid according to MOTHER
        eos_client = get_eos_rpc_client()
        v = UnificationAppScValidation(eos_client, providing_app.name)

        if not v.valid():
            raise Exception(f"Providing App {providing_app.name} is "
                            f"NOT valid according to MOTHER")

        body = self.transform_request_id(user, request_hash, request_id)
        payload = bundle(self.keystore, requesting_app, providing_app.name,
                         body, 'Success')

        r = providing_app.post('data_request', payload)
        d = r.json()

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

        bundle_d = unbundle(self.keystore, providing_app.name, d)
        decrypted_body = bundle_d['data']

        # log.info(f'"In the air" decrypted content is: {decrypted_body}')

        checksum_ok = False

        # Computationally validate the received data the checksum of the payload
        data_hash = hashlib.sha224(str(
            d['payload']).encode('utf-8')).hexdigest()

        uapp_sc = UnificationUapp(eos_client, requesting_app)
        data_request = uapp_sc.get_data_request_by_pkey(request_id)
        und_reward = UndRewards(requesting_app, data_request['price'])
        if data_request['hash'] == data_hash:
            print("Data computationally valid")
            checksum_ok = True

        json_obj = json.loads(decrypted_body)

        if 'no-data' not in json_obj and checksum_ok:
            users_to_pay = json_obj['unification_users']
            print("users_to_pay")
            print(users_to_pay)
            num_users = len(users_to_pay)
            print(f"Pay {num_users} users")

            for username in users_to_pay:
                print(f'pay {username}')
                ret = und_reward.send_reward(username,
                                             is_user=True,
                                             num_users=num_users)
                log.debug(ret)

            log.debug(f"Pay provider {providing_app.name}")
            ret = und_reward.send_reward(providing_app.name, False)
            log.debug(ret)

            log.debug(f"Pay Unification")
            ret = und_reward.pay_unif()
            log.debug(ret)

        return self.persist_data(providing_app.name, request_hash, d)
Exemple #17
0
class UnificationDataFactory:
    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()

    def get_raw_data(self):
        return self.__raw_data

    def __build_permissions(self):
        granted = []
        revoked = []
        granted_field_lookup = {}
        pbdb = PermissionBatchDatabase(default_pb_db())
        permissions = UnifPermissions(get_ipfs_client(), self.__my_uapp_sc,
                                      pbdb)
        permissions.load_consumer_perms(self.__requesting_app)

        permission_obj = permissions.get_all_perms()
        # schema_id = self.__my_db_schemas[0]['pkey']  # tmp - only 1 db schema

        for user, perms in permission_obj['permissions'].items():
            log.debug(perms)
            schema_perms = perms['0']  # tmp - only 1 db schema
            if schema_perms['perms'] == '':
                revoked.append(eosio_account.string_to_name(user))
            else:
                granted.append(eosio_account.string_to_name(user))
                native_id = self.__my_lookup.get_native_user_id(user)
                granted_field_lookup[native_id] = schema_perms['perms'].split(
                    ',')
                # required
                granted_field_lookup[native_id].append('account_name')

        return granted, revoked, granted_field_lookup

    def __generate_user_list(self):
        native_user_ids = []

        if self.__users is None:
            for i in self.__granted:
                native_user_ids.append(
                    self.__my_lookup.get_native_user_id(
                        eosio_account.name_to_string(i)))
        else:
            for u in self.__users:
                user_acc_uint64 = eosio_account.string_to_name(u)
                if user_acc_uint64 in self.__granted:
                    native_user_ids.append(
                        self.__my_lookup.get_native_user_id(u))

        return native_user_ids

    def __generate_data(self):

        self.__granted, self.__revoked, self.__granted_field_lookup = self.__build_permissions(
        )

        native_user_ids = self.__generate_user_list()

        # temporary - there's only 1 db schema per app at the moment
        sc_schema_pkey = self.__my_db_schemas[0]['pkey']
        db_schema = self.__my_db_schemas[0]['schema']
        db_schema_map = self.__db_schema_maps[sc_schema_pkey]
        db_connection = self.__haiku_conf['db_conn']["0"]

        cols_to_include = []
        base64_encode_cols = []
        for items in db_schema['fields']:
            if items['table'] != 'unification_lookup':
                real_table_data = self.__my_lookup.get_real_table_info(
                    sc_schema_pkey, items['table'])
                items['table'] = real_table_data['real_table_name']
                cols_to_include.append(items['name'])
                if items['type'] == 'base64_mime_image':
                    base64_encode_cols.append(items['name'])
            else:
                real_table_data = self.__my_lookup.get_real_table_info(
                    sc_schema_pkey, 'data_1')
                items['table'] = real_table_data['real_table_name']
                cols_to_include.append(real_table_data['user_id_column'])

        # temp
        user_table_info =\
            self.__my_lookup.get_real_table_info(sc_schema_pkey, 'users')
        data_table_info = \
            self.__my_lookup.get_real_table_info(sc_schema_pkey, 'data_1')

        # generate db params for ETL
        data_source_parms = {
            'database': db_schema_map['db_name'],
            'filename': db_connection['filename'],
            'userTable': user_table_info['real_table_name'],  # temp
            'dataTable': data_table_info['real_table_name'],  # temp
            'userIdentifier': user_table_info['user_id_column'],  # temp
            'dataUserIdentifier': data_table_info['user_id_column'],  # temp
            'dataColumnsToInclude': cols_to_include,
            'native_user_ids': native_user_ids,
            'base64_encode_cols': base64_encode_cols,
            'providing_app': self.__uapp_contract_acc,
            'db_schema': db_schema,
            'granted_field_lookup': self.__granted_field_lookup
        }

        # grab list of EOS account names
        if len(native_user_ids) > 0:
            unification_ids = {}
            for n_id in native_user_ids:
                unification_ids[n_id] = self.__my_lookup.get_eos_account(n_id)

            data_source_parms['unification_id_map'] = unification_ids
            data_transform_json = TransformDataJSON(data_source_parms)

            j = data_transform_json.transform()
            self.__raw_data = j

        else:
            d = {"no-data": True}
            self.__raw_data = json.dumps(d)
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()