async def admin_delete(ini_path: str, ident: str) -> int: """ Set configuration from file, open node pool and anchor, and request deletion from tails file server of tails files that identifier specifies. :param ini_path: path to configuration file :param ident: identifier to specify in deletion request :return: 0 for OK, 1 for failure. """ config = inis2dict(ini_path) pool_data = NodePoolData( config['Node Pool']['name'], config['Node Pool'].get('genesis.txn.path', None) or None) # nudge empty value from '' to None tsan_data = AnchorData( Role.USER, config['VON Anchor']['name'], config['VON Anchor'].get('seed', None) or None, None, config['VON Anchor'].get('wallet.create', '0').lower() in ['1', 'true', 'yes'], config['VON Anchor'].get('wallet.type', None) or None, config['VON Anchor'].get('wallet.access', None) or None) # Set up node pool ledger config and wallet manager = NodePoolManager() if pool_data.name not in await manager.list(): if pool_data.genesis_txn_path: await manager.add_config(pool_data.name, pool_data.genesis_txn_path) else: logging.error( 'Node pool %s has no ledger configuration but %s specifies no genesis transaction path', pool_data.name, ini_path) return 1 wallet = await get_wallet(tsan_data) async with wallet, ( manager.get(pool_data.name)) as pool, ( NominalAnchor(wallet, pool)) as noman: host = config['Tails Server']['host'] port = config['Tails Server']['port'] epoch = int(time()) url = 'http://{}:{}/tails/{}/{}'.format(host, port, quote(ident), epoch) signature = await noman.sign('{}||{}'.format(epoch, ident)) try: resp = requests.delete(url, data=signature) logging.info('DELETE: url %s status %s', url, resp.status_code) if resp.status_code != requests.codes.ok: return 1 except RequestsConnectionError: logging.error('DELETE connection refused: %s', url) return 1
def set_config() -> dict: """ Read configuration file content into memory cache. :return: configuration dict """ ini_path = join(dirname(realpath(__file__)), 'config', 'config.ini') do_wait(MEM_CACHE.set('config.ini', ini_path)) do_wait(MEM_CACHE.delete('config')) do_wait(MEM_CACHE.set('config', inis2dict(ini_path))) return do_wait(MEM_CACHE.get('config'))
async def test_von_tails(pool_ip, genesis_txn_file, path_cli_ini, cli_ini, path_setnym_ini, setnym_ini): print( Ink.YELLOW('\n\n== Testing tails server vs. IP {} =='.format(pool_ip))) # Set config for tails clients config = {} i = 0 for profile in path_cli_ini: cli_config = inis2dict(str(path_cli_ini[profile])) config[profile] = cli_config with open(path_cli_ini[profile], 'r') as fh_cfg: print('\n\n== 0.{} == {} tails sync configuration:\n{}'.format( i, profile, fh_cfg.read())) i += 1 # Start tails server print('\n\n== 1 == Starting tails server on port {}'.format( config['issuer']['Tails Server']['port'])) tsrv = TailsServer(config['issuer']['Tails Server']['port']) started = tsrv.start() if not started: print( '\n\n== X == Server already running - stop it to run test from scratch' ) assert False assert tsrv.is_up() print( '\n\n== 2 == Started tails server, docker-compose port-forwarded via localhost:{}' .format(tsrv.port)) atexit.register(shutdown) # Set nyms (operation creates pool if need be) i = 0 setnym_config = {} for profile in path_setnym_ini: cli_config = inis2dict(str(path_setnym_ini[profile])) if profile == 'admin': # tails server anchor on ledger a priori continue setnym_config[profile] = cli_config with open(path_setnym_ini[profile], 'r') as fh_cfg: print('\n\n== 3.{} == {} setnym configuration:\n{}'.format( i, profile, fh_cfg.read())) sub_proc = subprocess.run( ['von_anchor_setnym', str(path_setnym_ini[profile])], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL) assert not sub_proc.returncode i += 1 print('\n\n== 4 == Setnym ops completed OK') # wallets = {profile: Wallet(setnym_config[profile]['VON Anchor']['name']) for profile in setnym_config} # wallets['admin'] = Wallet(config['admin']['VON Anchor']['name']) wallets = await get_wallets( { **{ profile: setnym_config[profile]['VON Anchor'] for profile in setnym_config }, 'admin': config['admin']['VON Anchor'] }, open_all=False) # Open pool and anchors, issue creds to create tails files async with wallets['issuer'] as w_issuer, ( wallets['prover']) as w_prover, (NodePool( config['issuer']['Node Pool']['name'])) as pool, (RegistrarAnchor( w_issuer, pool)) as ian, (OrgBookAnchor(w_prover, pool)) as pan: # Get nyms from ledger for display i = 0 for an in (ian, pan): print('\n\n== 5.{} == {} nym on ledger: {}'.format( i, an.wallet.name, ppjson(await an.get_nym()))) i += 1 # Publish schema to ledger S_ID = schema_id(ian.did, 'rainbow', '{}.0'.format(int(time()))) schema_data = { 'name': schema_key(S_ID).name, 'version': schema_key(S_ID).version, 'attr_names': ['numeric', 'sha256'] } S_KEY = schema_key(S_ID) try: await ian.get_schema(S_KEY) # may exist (almost certainly not) except AbsentSchema: await ian.send_schema(json.dumps(schema_data)) schema_json = await ian.get_schema(S_KEY) schema = json.loads(schema_json) print('\n\n== 6 == SCHEMA [{} v{}]: {}'.format(S_KEY.name, S_KEY.version, ppjson(schema))) assert schema # should exist now # Setup link secret for creation of cred req or proof await pan.create_link_secret('LinkSecret') # Issuer anchor create, store, publish cred definitions to ledger; create cred offers await ian.send_cred_def(S_ID, revo=True) cd_id = cred_def_id(S_KEY.origin_did, schema['seqNo'], pool.protocol) assert ((not Tails.unlinked(ian.dir_tails)) and [f for f in Tails.links(ian.dir_tails, ian.did) if cd_id in f]) cred_def_json = await ian.get_cred_def(cd_id) # ought to exist now cred_def = json.loads(cred_def_json) print('\n\n== 7.0 == Cred def [{} v{}]: {}'.format( S_KEY.name, S_KEY.version, ppjson(json.loads(cred_def_json)))) assert cred_def.get('schemaId', None) == str(schema['seqNo']) cred_offer_json = await ian.create_cred_offer(schema['seqNo']) cred_offer = json.loads(cred_offer_json) print('\n\n== 7.1 == Credential offer [{} v{}]: {}'.format( S_KEY.name, S_KEY.version, ppjson(cred_offer_json))) (cred_req_json, cred_req_metadata_json) = await pan.create_cred_req( cred_offer_json, cd_id) cred_req = json.loads(cred_req_json) print('\n\n== 8 == Credential request [{} v{}]: metadata {}, cred {}'. format(S_KEY.name, S_KEY.version, ppjson(cred_req_metadata_json), ppjson(cred_req_json))) assert json.loads(cred_req_json) # Issuer anchor issues creds and stores at HolderProver: get cred req, create cred, store cred cred_data = [] CREDS = 450 # enough to build 4 rev regs print('\n\n== 9 == creating and storing {} credentials:'.format(CREDS)) for number in range(CREDS): (cred_json, _) = await ian.create_cred( cred_offer_json, cred_req_json, { 'numeric': str(number), 'sha256': sha256(str(number).encode()).hexdigest(), }) cred_id = await pan.store_cred(cred_json, cred_req_metadata_json) print('.', end='' if (number + 1) % 100 else '{}\n'.format(number + 1), flush=True) # Exercise list view, least to most specific for tails_list_path in ('all', ian.did, cd_id): url = url_for(tsrv.port, 'tails/list/{}'.format(tails_list_path)) r = requests.get(url) assert r.status_code == 200 assert not r.json() rr_ids_up = { basename(link) for link in Tails.links(ian.dir_tails, ian.did) } for rr_id in rr_ids_up: url = url_for(tsrv.port, 'tails/list/{}'.format(rr_id)) r = requests.get(url) assert r.status_code == 200 assert not r.json() print( '\n\n== 10 == All listing views at server come back OK and empty as expected' ) rv = pexpect.run('python ../src/sync/sync.py {}'.format( path_cli_ini['issuer'])) print('\n\n== 11 == Issuer sync uploaded local tails files') for tails_list_path in ('all', ian.did, cd_id): url = url_for(tsrv.port, 'tails/list/{}'.format(tails_list_path)) r = requests.get(url) assert r.status_code == 200 assert {rr for rr in r.json()} == rr_ids_up for rr_id in rr_ids_up: url = url_for(tsrv.port, 'tails/list/{}'.format(rr_id)) r = requests.get(url) assert r.status_code == 200 assert r.json() == [rr_id] # list with one rr_id should come back # Exercise list view, least to most specific for tails_list_path in ('all', ian.did, cd_id): url = url_for(tsrv.port, 'tails/list/{}'.format(tails_list_path)) r = requests.get(url) assert r.status_code == 200 assert len(r.json()) == len(rr_ids_up) print( '\n\n== 12 == All listing views at server come back OK with {} uploaded files' .format(len(rr_ids_up))) rv = pexpect.run('python ../src/sync/sync.py {}'.format( path_cli_ini['prover'])) print('\n\n== 13 == Prover sync downloaded remote tails files') rr_ids_down = { basename(link) for link in Tails.links( config['prover']['Tails Client']['tails.dir'], ian.did) } assert rr_ids_down == rr_ids_up # Exercise admin-delete rv = pexpect.run('python ../src/admin/delete.py {} all'.format( path_cli_ini['admin'])) print('\n\n== 14 == Admin called for deletion at tails server') # Check tails server deletion url = url_for(tsrv.port, 'tails/list/all') r = requests.get(url) assert r.status_code == 200 assert not r.json() print( '\n\n== 15 == All listing views at server come back OK and empty as expected' ) rv = pexpect.run('python ../src/sync/multisync.py 1 {}'.format( path_cli_ini['issuer'])) print( '\n\n== 16 == Issuer multisync on 1 sync iteration uploaded local tails files' ) for tails_list_path in ('all', ian.did, cd_id): url = url_for(tsrv.port, 'tails/list/{}'.format(tails_list_path)) r = requests.get(url) assert r.status_code == 200 assert {rr for rr in r.json()} == rr_ids_up for rr_id in rr_ids_up: url = url_for(tsrv.port, 'tails/list/{}'.format(rr_id)) r = requests.get(url) assert r.status_code == 200 assert r.json() == [rr_id] # list with one rr_id should come back # Exercise list view, least to most specific for tails_list_path in ('all', ian.did, cd_id): url = url_for(tsrv.port, 'tails/list/{}'.format(tails_list_path)) r = requests.get(url) assert r.status_code == 200 assert len(r.json()) == len(rr_ids_up) print( '\n\n== 17 == All listing views at server come back OK with {} uploaded files' .format(len(rr_ids_up))) # Remove tails server anchor wallet await wallets['admin'].remove() print('\n\n== 18 == Removed admin (tails server anchor {}) wallet'. format(wallets['admin'].name))
async def test_setnym(pool_ip, pool_name, pool_genesis_txn_data, seed_trustee1, path_setnym_ini, setnym_ini_file): print( Ink.YELLOW('\n\n== Testing setnym operation on node pool {} =='.format( pool_ip))) with open(path_setnym_ini, 'r') as cfg_fh: print('\n\n== 1 == Initial configuration:\n{}'.format(cfg_fh.read())) cfg = inis2dict(str(path_setnym_ini)) # Set up node pool ledger config and wallets, open pool, init anchors p_mgr = NodePoolManager() if pool_name not in await p_mgr.list(): await p_mgr.add_config(pool_name, pool_genesis_txn_data) wallets = await get_wallets( { 'trustee-anchor': { 'seed': seed_trustee1 }, cfg['VON Anchor']['name']: { 'seed': cfg['VON Anchor']['seed'] }, 'x-anchor': { 'seed': 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' } }, open_all=True) try: async with NominalAnchor(wallets['x-anchor']) as xan: await xan.get_nym() except AbsentPool: pass wallets.pop('x-anchor') # Open pool, check if nym already present pool = p_mgr.get(pool_name) await pool.open() assert pool.handle tan = TrusteeAnchor(wallets['trustee-anchor'], pool) await tan.open() noman = NominalAnchor(wallets[cfg['VON Anchor']['name']], pool) nym = json.loads(await noman.get_nym(noman.did)) print('\n\n== 2 == Nym {} on ledger for anchor {} on DID {}'.format( '{} already'.format(ppjson(nym)) if nym else 'not yet', noman.wallet.name, noman.did)) await tan.close() await pool.close() # Run setnym on initial configuration, check ledger sub_proc = subprocess.run([ 'python', join(dirname(dirname(dirname(realpath(__file__)))), 'von_anchor', 'op', 'setnym.py'), str(path_setnym_ini) ], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL) assert not sub_proc.returncode print('\n\n== 3 == Set nym with TRUST_ANCHOR role on {} for {}'.format( noman.did, noman.wallet.name)) await pool.open() await noman.open() nym = json.loads(await noman.get_nym(noman.did)) assert nym and Role.get(nym['role']) == Role.TRUST_ANCHOR print('\n\n== 4 == Got nym transaction from ledger for DID {} ({}): {}'. format(noman.did, noman.wallet.name, ppjson(nym))) await noman.close() await pool.close() # Run setnym on configuration with DID and explicit storage type, check ledger with open(path_setnym_ini, 'w+') as ini_fh: for section in cfg: print('[{}]'.format(section), file=ini_fh) for (key, value) in cfg[section].items(): if section == 'VON Anchor': if key == 'seed': print('did={}'.format(noman.did), file=ini_fh) elif key == 'wallet.type': print('wallet.type=default', file=ini_fh) else: print('{}={}'.format(key, value), file=ini_fh) else: print('{}={}'.format(key, value), file=ini_fh) print(file=ini_fh) with open(path_setnym_ini, 'r') as cfg_fh: print( '\n\n== 5 == Next configuration, on DID instead of seed and explicit wallet type:\n{}' .format(cfg_fh.read())) sub_proc = subprocess.run([ 'python', join(dirname(dirname(dirname(realpath(__file__)))), 'von_anchor', 'op', 'setnym.py'), str(path_setnym_ini) ], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL) assert not sub_proc.returncode print('\n\n== 6 == Set nym with TRUST_ANCHOR role on {} for {}'.format( noman.did, noman.wallet.name)) await pool.open() await noman.open() nym = json.loads(await noman.get_nym(noman.did)) assert nym and Role.get(nym['role']) == Role.TRUST_ANCHOR last_nym_seqno = nym['seqNo'] print('\n\n== 7 == Got nym transaction from ledger for DID {} ({}): {}'. format(noman.did, noman.wallet.name, ppjson(nym))) await noman.close() await pool.close() # Run setnym on configuration with no seeds nor VON Anchor role, check ledger with open(path_setnym_ini, 'w+') as ini_fh: for section in cfg: print('[{}]'.format(section), file=ini_fh) for (key, value) in cfg[section].items(): if key in ('seed', 'genesis.txn.path'): continue print('{}={}'.format( key, '${X_ROLE:-}' if key == 'role' else value), file=ini_fh) # exercise default print(file=ini_fh) with open(path_setnym_ini, 'r') as cfg_fh: print( '\n\n== 8 == Next configuration, no seeds, no VON Anchor role:\n{}' .format(cfg_fh.read())) sub_proc = subprocess.run([ 'python', join(dirname(dirname(dirname(realpath(__file__)))), 'von_anchor', 'op', 'setnym.py'), str(path_setnym_ini) ], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL) assert not sub_proc.returncode print('\n\n== 9 == Set nym with USER role on {} for {}'.format( noman.did, noman.wallet.name)) await pool.open() await noman.open() nym = json.loads(await noman.get_nym(noman.did)) assert nym and Role.get(nym['role']) == Role.USER last_nym_seqno = nym['seqNo'] print('\n\n== 10 == Got nym transaction from ledger for DID {} ({}): {}'. format(noman.did, noman.wallet.name, ppjson(nym))) await noman.close() await pool.close() # Run again to check idempotence sub_proc = subprocess.run([ 'python', join(dirname(dirname(dirname(realpath(__file__)))), 'von_anchor', 'op', 'setnym.py'), str(path_setnym_ini) ], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL) assert not sub_proc.returncode print('\n\n== 11 == Set nym again with default role on {} for {}'.format( noman.did, noman.wallet.name)) await pool.open() await noman.open() nym = json.loads(await noman.get_nym(noman.did)) last_nym_seqno = nym['seqNo'] print( '\n\n== 12 == Got (same) nym transaction from ledger for DID {} ({}): {}' .format(noman.did, noman.wallet.name, ppjson(nym))) await noman.close() await pool.close() # Run setnym on configuration with no seeds and bad VON Anchor role, check ledger with open(path_setnym_ini, 'w+') as ini_fh: for section in cfg: print('[{}]'.format(section), file=ini_fh) for (key, value) in cfg[section].items(): if key in ('seed', 'genesis.txn.path'): continue print('{}={}'.format(key, 'BAD_ROLE' if key == 'role' else value), file=ini_fh) print(file=ini_fh) with open(path_setnym_ini, 'r') as cfg_fh: print( '\n\n== 13 == Next configuration, no seeds, bad VON Anchor role:\n{}' .format(cfg_fh.read())) sub_proc = subprocess.run([ 'python', join(dirname(dirname(dirname(realpath(__file__)))), 'von_anchor', 'op', 'setnym.py'), str(path_setnym_ini) ], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL) assert sub_proc.returncode assert str(int(ErrorCode.BadRole)) in sub_proc.stdout.decode() print( '\n\n== 14 == Called to set bad role for {}, got error text {}'.format( noman.wallet.name, sub_proc.stdout.decode())) await pool.open() await noman.open() nym = json.loads(await noman.get_nym(noman.did)) noman_role = await noman.get_nym_role() assert nym and nym['seqNo'] == last_nym_seqno await noman.close() await pool.close() print('\n\n== 15 == Got nym transaction from ledger for DID {} ({}): {}'. format(noman.did, noman.wallet.name, ppjson(nym))) # Exercise reseed, ensure no side effect to role on ledger await pool.open() pan = ProctorAnchor(wallets[cfg['VON Anchor']['name']], pool, rrbx=False) await pan.open() next_seed = '{}000000000000VonAnchor1'.format(int(time()) + 1) await pan.reseed(next_seed) nym = json.loads(await pan.get_nym(noman.did)) pan_role = await pan.get_nym_role() await pool.close() assert nym and nym['seqNo'] != last_nym_seqno assert pan_role == noman_role print( '\n\n== 16 == As Proctor Anchor, reseeded, then got nym transaction from ledger for DID {} ({}): {}' .format(pan.did, pan.wallet.name, ppjson(nym))) last_nym_seqno = nym['seqNo'] # Run setnym on configuration with same wallet for trustee and VON anchor with open(path_setnym_ini, 'w+') as ini_fh: for section in cfg: print('[{}]'.format(section), file=ini_fh) for (key, value) in cfg[section].items(): if section == 'VON Anchor' and key == 'name': print('{}={}'.format(key, cfg['Trustee Anchor']['name']), file=ini_fh) else: print('{}={}'.format(key, value), file=ini_fh) print(file=ini_fh) with open(path_setnym_ini, 'r') as cfg_fh: print( '\n\n== 17 == Next configuration, same wallet for trustee anchor and VON anchor:\n{}' .format(cfg_fh.read())) sub_proc = subprocess.run([ 'python', join(dirname(dirname(dirname(realpath(__file__)))), 'von_anchor', 'op', 'setnym.py'), str(path_setnym_ini) ], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL) assert sub_proc.returncode assert str(int(ErrorCode.ExtantWallet)) in sub_proc.stdout.decode() print( '\n\n== 18 == Called with same wallet for trustee anchor and VON anchor, got error text {}' .format(sub_proc.stdout.decode())) # Run setnym on configuration with new ledger node pool configuration genesis_tmp = NamedTemporaryFile(mode='w+b', buffering=0, delete=False) with genesis_tmp: genesis_tmp.write(pool_genesis_txn_data.encode()) pool_copy = '{}.{}'.format(cfg['Node Pool']['name'], int(time())) with open(path_setnym_ini, 'w+') as ini_fh: for section in cfg: print('[{}]'.format(section), file=ini_fh) for (key, value) in cfg[section].items(): if section == 'Node Pool': if key == 'name': print('name={}'.format(pool_copy), file=ini_fh) elif key == 'genesis.txn.path': print('genesis.txn.path={}'.format(genesis_tmp.name), file=ini_fh) # includes /tmp/ path else: print('{}={}.xxx'.format(key, value), file=ini_fh) else: print('{}={}'.format(key, value), file=ini_fh) print(file=ini_fh) with open(path_setnym_ini, 'r') as cfg_fh: print( '\n\n== 19 == Next configuration, calling for copy of node pool ledger config:\n{}' .format(cfg_fh.read())) sub_proc = subprocess.run([ 'python', join(dirname(dirname(dirname(realpath(__file__)))), 'von_anchor', 'op', 'setnym.py'), str(path_setnym_ini) ], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL) assert not sub_proc.returncode print('\n\n== 20 == Called for new copy {} of node pool ledger config'. format(pool_copy)) unlink(genesis_tmp.name) await p_mgr.remove(pool_copy) await pool.open() await pan.open() nym = json.loads(await pan.get_nym(pan.did)) assert nym and Role.get(nym['role']) == Role.TRUST_ANCHOR assert nym and nym['seqNo'] != last_nym_seqno print('\n\n== 21 == Got nym transaction from ledger for DID {} ({}): {}'. format(pan.did, pan.wallet.name, ppjson(nym))) await pan.close() await pool.close() # Run setnym on configuration with wrong genesis transaction path with open(path_setnym_ini, 'w+') as ini_fh: for section in cfg: print('[{}]'.format(section), file=ini_fh) for (key, value) in cfg[section].items(): if section == 'Node Pool': print('{}={}.xxx'.format(key, value), file=ini_fh) else: print('{}={}'.format(key, value), file=ini_fh) print(file=ini_fh) with open(path_setnym_ini, 'r') as cfg_fh: print( '\n\n== 22 == Next configuration, missing pool and bad genesis txn path:\n{}' .format(cfg_fh.read())) sub_proc = subprocess.run([ 'python', join(dirname(dirname(dirname(realpath(__file__)))), 'von_anchor', 'op', 'setnym.py'), str(path_setnym_ini) ], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL) assert sub_proc.returncode assert str(int(ErrorCode.AbsentPool)) in sub_proc.stdout.decode() print( '\n\n== 23 == Called with missing pool and bad genesis txn path, got error text {}' .format(sub_proc.stdout.decode())) # Run setnym on configuration with no node pool ledger configuration with open(path_setnym_ini, 'w+') as ini_fh: for section in cfg: print('[{}]'.format(section), file=ini_fh) for (key, value) in cfg[section].items(): if section == 'Node Pool': if key == 'name': print('{}={}.xxx'.format(key, value), file=ini_fh) elif key == 'genesis.txn.path': print('genesis.txn.path=', file=ini_fh) else: print('{}={}'.format(key, value), file=ini_fh) else: print('{}={}'.format(key, value), file=ini_fh) print(file=ini_fh) with open(path_setnym_ini, 'r') as cfg_fh: print( '\n\n== 24 == Next configuration, missing pool and no genesis txn path:\n{}' .format(cfg_fh.read())) sub_proc = subprocess.run([ 'python', join(dirname(dirname(dirname(realpath(__file__)))), 'von_anchor', 'op', 'setnym.py'), str(path_setnym_ini) ], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL) assert sub_proc.returncode assert str(int(ErrorCode.AbsentPool)) in sub_proc.stdout.decode() print( '\n\n== 25 == Called with missing pool and no genesis txn path, got error text {}' .format(sub_proc.stdout.decode())) # Run again without trustee anchor wallet present await wallets['trustee-anchor'].close() await wallets['trustee-anchor'].remove() wallets.pop('trustee-anchor') noman = NominalAnchor(wallets[cfg['VON Anchor']['name']], pool) with open(path_setnym_ini, 'w+') as ini_fh: for section in cfg: print('[{}]'.format(section), file=ini_fh) for (key, value) in cfg[section].items(): print('{}={}'.format(key, value), file=ini_fh) print(file=ini_fh) with open(path_setnym_ini, 'r') as cfg_fh: print( '\n\n== 26 == Set VON anchor configuration, no Trustee anchor wallet a priori:\n{}' .format(cfg_fh.read())) sub_proc = subprocess.run([ 'python', join(dirname(dirname(dirname(realpath(__file__)))), 'von_anchor', 'op', 'setnym.py'), str(path_setnym_ini) ], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL) assert not sub_proc.returncode print('\n\n== 27 == Set nym with TRUST_ANCHOR role on {} for {}'.format( noman.did, noman.wallet.name)) await pool.open() await noman.open() nym = json.loads(await noman.get_nym(noman.did)) assert nym and Role.get(nym['role']) == Role.TRUST_ANCHOR print('\n\n== 28 == Got nym transaction from ledger for DID {} ({}): {}'. format(noman.did, noman.wallet.name, ppjson(nym))) await noman.close() await pool.close() await pan.close() for name in wallets: await wallets[name].close()
async def setnym(ini_path: str) -> int: """ Set configuration. Open pool, trustee anchor, and wallet of anchor whose nym to send. Register exit hooks to close pool and trustee anchor. Engage trustee anchor to send nym for VON anchor, if it differs on the ledger from configuration. :param ini_path: path to configuration file :return: 0 for OK, 1 for failure """ config = inis2dict(ini_path) if config['Trustee Anchor']['name'] == config['VON Anchor']['name']: raise ExtantWallet( 'Wallet names must differ between VON Anchor and Trustee Anchor') cfg_van_role = config['VON Anchor'].get( 'role', None) or None # nudge empty value from '' to None if not ok_role(cfg_van_role): raise BadRole('Configured role {} is not valid'.format(cfg_van_role)) pool_data = NodePoolData( config['Node Pool']['name'], config['Node Pool'].get('genesis.txn.path', None) or None) an_data = { 'tan': AnchorData( Role.TRUSTEE, config['Trustee Anchor']['name'], config['Trustee Anchor'].get('seed', None) or None, config['Trustee Anchor'].get('did', None) or None, config['Trustee Anchor'].get('wallet.create', '0').lower() in ['1', 'true', 'yes'], config['Trustee Anchor'].get('wallet.type', None) or None, config['Trustee Anchor'].get('wallet.access', None) or None), 'van': AnchorData( Role.get(cfg_van_role), config['VON Anchor']['name'], config['VON Anchor'].get('seed', None) or None, config['VON Anchor'].get('did', None) or None, config['VON Anchor'].get('wallet.create', '0').lower() in ['1', 'true', 'yes'], config['VON Anchor'].get('wallet.type', None) or None, config['VON Anchor'].get('wallet.access', None) or None) } an_wallet = await _set_wallets(an_data) p_mgr = NodePoolManager() if pool_data.name not in await p_mgr.list(): if pool_data.genesis_txn_path: await p_mgr.add_config(pool_data.name, pool_data.genesis_txn_path) else: raise AbsentPool( 'Node pool {} has no ledger configuration, but {} specifies no genesis txn path' .format(pool_data.name, ini_path)) async with an_wallet['tan'] as w_tan, (an_wallet['van']) as w_van, ( p_mgr.get(pool_data.name)) as pool, (TrusteeAnchor( w_tan, pool)) as tan, (NominalAnchor(w_van, pool)) as van: send_verkey = van.verkey try: nym_role = await tan.get_nym_role(van.did) if an_data['van'].role == nym_role: return 0 # ledger is as per configuration send_verkey = None # only owner can touch verkey if nym_role != Role.USER: # only remove role when it is not already None on the ledger await tan.send_nym(van.did, send_verkey, van.wallet.name, Role.ROLE_REMOVE) except AbsentNym: pass # cryptonym not there yet, fall through await tan.send_nym(van.did, send_verkey, van.wallet.name, an_data['van'].role) return 0
async def setnym(ini_path: str) -> int: """ Set configuration. Open pool, trustee anchor, and wallet of anchor whose nym to send. Register exit hooks to close pool and trustee anchor. Engage trustee anchor to send nym for VON anchor, if it differs on the ledger from configuration. :param ini_path: path to configuration file :return: 0 for OK, 1 for failure """ config = inis2dict(ini_path) cfg_van_role = config['VON Anchor'].get( 'role', None) or None # nudge empty value from '' to None if not ok_role(cfg_van_role): raise BadRole('Configured role {} is not valid'.format(cfg_van_role)) if config['Trustee Anchor']['wallet.name'] == config['VON Anchor'][ 'wallet.name']: raise ExtantWallet( 'Wallet names must differ between VON Anchor and Trustee Anchor') pool_data = NodePoolData( config['Node Pool']['name'], config['Node Pool'].get('genesis.txn.path', None) or None) an_data = { 'tan': AnchorData(Role.TRUSTEE, config['Trustee Anchor'].get('seed', None) or None, config['Trustee Anchor']['wallet.name'], config['Trustee Anchor'].get('wallet.type', None) or None, config['Trustee Anchor'].get('wallet.key', None) or None), 'van': AnchorData(Role.get(cfg_van_role), config['VON Anchor'].get('seed', None) or None, config['VON Anchor']['wallet.name'], config['VON Anchor'].get('wallet.type', None) or None, config['VON Anchor'].get('wallet.key', None) or None) } an_wallet = { an: Wallet(an_data[an].wallet_name, an_data[an].wallet_type, None, {'key': an_data[an].wallet_key} if an_data[an].wallet_key else None) for an in an_data } for anchor in an_data: # create wallet if seed configured, silently continue if extant if an_data[anchor].seed: try: await an_wallet[anchor].create(an_data[anchor].seed) except ExtantWallet: pass manager = NodePoolManager() if pool_data.name not in await manager.list(): if pool_data.genesis_txn_path: await manager.add_config(pool_data.name, pool_data.genesis_txn_path) else: raise AbsentPool( 'Node pool {} has no ledger configuration, but {} specifies no genesis txn path' .format(pool_data.name, ini_path)) async with an_wallet['tan'] as w_tan, (an_wallet['van']) as w_van, ( manager.get(pool_data.name)) as pool, (TrusteeAnchor( w_tan, pool)) as tan, (NominalAnchor(w_van, pool)) as van: send_verkey = van.verkey try: nym_role = await tan.get_nym_role(van.did) if an_data['van'].role == nym_role: return 0 # ledger is as per configuration send_verkey = None # only owner can touch verkey await tan.send_nym(van.did, send_verkey, van.wallet.name, Role.ROLE_REMOVE) except AbsentNym: pass # cryptonym not there yet, fall through await tan.send_nym(van.did, send_verkey, van.wallet.name, an_data['van'].role) return 0
async def setup(ini_path: str) -> tuple: """ Set configuration from file. If configured profile is issuer, open and return node pool and anchor, then register both for shutdown at program exit. :param ini_path: path to configuration file :return: tuple (profile, issuer anchor) for issuer or (profile, None) for prover. """ global CONFIG CONFIG = inis2dict(ini_path) profile = Profile.get(CONFIG['Tails Client']['profile']) if profile != Profile.ISSUER: return (profile, None) pool_data = NodePoolData(CONFIG['Node Pool']['name'], CONFIG['Node Pool'].get('genesis.txn.path', None) or None) # nudge empty value from '' to None # Set up node pool ledger config and wallet manager = NodePoolManager() if pool_data.name not in await manager.list(): if pool_data.genesis_txn_path: await manager.add_config(pool_data.name, pool_data.genesis_txn_path) else: logging.error( 'Node pool %s has no ledger configuration but %s specifies no genesis txn path', pool_data.name, ini_path) return (None, None) pool = manager.get(pool_data.name) await pool.open() atexit.register(close_pool, pool) noman_data = AnchorData( Role.USER, CONFIG['VON Anchor']['name'], CONFIG['VON Anchor'].get('seed', None) or None, None, CONFIG['VON Anchor'].get('wallet.create', '0').lower() in ['1', 'true', 'yes'], CONFIG['VON Anchor'].get('wallet.type', None) or None, CONFIG['VON Anchor'].get('wallet.access', None) or None) w_mgr = WalletManager() wallet = None wallet_config = {'id': noman_data.name} if noman_data.wallet_type: wallet_config['storage_type'] = noman_data.wallet_type if noman_data.wallet_create: if noman_data.seed: wallet_config['seed'] = noman_data.seed try: wallet = await w_mgr.create(wallet_config, access=noman_data.wallet_access) logging.info('Created wallet %s', noman_data.name) except ExtantWallet: wallet = w_mgr.get(wallet_config, access=noman_data.wallet_access) logging.warning( 'Wallet %s already exists: remove seed and wallet.create from config file', noman_data.name) else: wallet = w_mgr.get(wallet_config, access=noman_data.wallet_access) await wallet.open() noman = NominalAnchor(wallet, pool) await noman.open() atexit.register(close_anchor, noman) return (profile, noman)
async def test_setnym(pool_ip, pool_name, pool_genesis_txn_data, seed_trustee1, path_setnym_ini, setnym_ini_file): print( Ink.YELLOW('\n\n== Testing setnym operation on node pool {} =='.format( pool_ip))) with open(path_setnym_ini, 'r') as cfg_fh: print('\n\n== 1 == Initial configuration:\n{}'.format(cfg_fh.read())) cfg = inis2dict(str(path_setnym_ini)) # Set up node pool ledger config and wallets, open pool, init anchors manager = NodePoolManager() if pool_name not in await manager.list(): await manager.add_config(pool_name, pool_genesis_txn_data) seeds = { 'trustee-anchor': seed_trustee1, cfg['VON Anchor']['wallet.name']: cfg['VON Anchor']['seed'], 'x-anchor': 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' } wallets = await get_wallets(seeds, True) try: async with NominalAnchor(wallets['x-anchor']) as xan: await xan.get_nym() except AbsentPool: pass wallets.pop('x-anchor') # Open pool, check if nym already present pool = manager.get(pool_name) await pool.open() assert pool.handle tan = TrusteeAnchor(wallets['trustee-anchor'], pool) await tan.open() noman = NominalAnchor(wallets[cfg['VON Anchor']['wallet.name']], pool) nym = json.loads(await noman.get_nym(noman.did)) print('\n\n== 2 == Nym {} on ledger for anchor {} on DID {}'.format( '{} already'.format(ppjson(nym)) if nym else 'not yet', noman.wallet.name, noman.did)) await tan.close() await pool.close() sub_proc = subprocess.run([ 'python', join(dirname(dirname(dirname(realpath(__file__)))), 'von_anchor', 'op', 'setnym.py'), str(path_setnym_ini) ], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL) assert not sub_proc.returncode print('\n\n== 3 == Set nym with TRUST_ANCHOR role on {} for {}'.format( noman.did, noman.wallet.name)) await pool.open() await noman.open() nym = json.loads(await noman.get_nym(noman.did)) assert nym and Role.get(nym['role']) == Role.TRUST_ANCHOR print('\n\n== 4 == Got nym transaction from ledger for DID {} ({}): {}'. format(noman.did, noman.wallet.name, ppjson(nym))) await noman.close() await pool.close() with open(path_setnym_ini, 'w+') as ini_fh: for section in cfg: print('[{}]'.format(section), file=ini_fh) for (key, value) in cfg[section].items(): if key in ('seed', 'genesis.txn.path'): continue print('{}={}'.format( key, '${X_ROLE:-}' if key == 'role' else value), file=ini_fh) # exercise default print(file=ini_fh) with open(path_setnym_ini, 'r') as cfg_fh: print( '\n\n== 5 == Next configuration, no seeds, no VON Anchor role:\n{}' .format(cfg_fh.read())) sub_proc = subprocess.run([ 'python', join(dirname(dirname(dirname(realpath(__file__)))), 'von_anchor', 'op', 'setnym.py'), str(path_setnym_ini) ], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL) assert not sub_proc.returncode print('\n\n== 6 == Set nym with default role on {} for {}'.format( noman.did, noman.wallet.name)) await pool.open() await noman.open() nym = json.loads(await noman.get_nym(noman.did)) assert nym and Role.get(nym['role']) == Role.USER last_nym_seqno = nym['seqNo'] print('\n\n== 7 == Got nym transaction from ledger for DID {} ({}): {}'. format(noman.did, noman.wallet.name, ppjson(nym))) await noman.close() await pool.close() sub_proc = subprocess.run( # do it again [ 'python', join(dirname(dirname(dirname(realpath(__file__)))), 'von_anchor', 'op', 'setnym.py'), str(path_setnym_ini) ], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL) assert not sub_proc.returncode print('\n\n== 8 == Set nym again with default role on {} for {}'.format( noman.did, noman.wallet.name)) await pool.open() await noman.open() nym = json.loads(await noman.get_nym(noman.did)) last_nym_seqno = nym['seqNo'] print( '\n\n== 9 == Got (same) nym transaction from ledger for DID {} ({}): {}' .format(noman.did, noman.wallet.name, ppjson(nym))) await noman.close() await pool.close() with open(path_setnym_ini, 'w+') as ini_fh: for section in cfg: print('[{}]'.format(section), file=ini_fh) for (key, value) in cfg[section].items(): if key in ('seed', 'genesis.txn.path'): continue print('{}={}'.format(key, 'BAD_ROLE' if key == 'role' else value), file=ini_fh) print(file=ini_fh) with open(path_setnym_ini, 'r') as cfg_fh: print( '\n\n== 10 == Next configuration, no seeds, bad VON Anchor role:\n{}' .format(cfg_fh.read())) sub_proc = subprocess.run([ 'python', join(dirname(dirname(dirname(realpath(__file__)))), 'von_anchor', 'op', 'setnym.py'), str(path_setnym_ini) ], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL) assert sub_proc.returncode print( '\n\n== 11 == Called to set bad role for {}, got error text {}'.format( noman.wallet.name, sub_proc.stdout.decode())) await pool.open() await noman.open() nym = json.loads(await noman.get_nym(noman.did)) noman_role = await noman.get_nym_role() assert nym and nym['seqNo'] == last_nym_seqno await noman.close() await pool.close() print('\n\n== 12 == Got nym transaction from ledger for DID {} ({}): {}'. format(noman.did, noman.wallet.name, ppjson(nym))) await pool.open() san = SRIAnchor(wallets[cfg['VON Anchor']['wallet.name']], pool) await san.open() next_seed = "{}000000000000VonAnchor1".format(int(time()) + 1) await san.reseed(next_seed) nym = json.loads(await san.get_nym(noman.did)) san_role = await san.get_nym_role() assert nym and nym['seqNo'] != last_nym_seqno assert san_role == noman_role # ensure that reseed does not side-effect role on ledger print( '\n\n== 13 == As SRI Anchor, reseeded, then got nym transaction from ledger for DID {} ({}): {}' .format(san.did, san.wallet.name, ppjson(nym))) await san.close() await pool.close() for name in wallets: await wallets[name].close()