def generate_config(self, emitter, config_root): opts = self.config_options if opts.dev: raise click.BadArgumentUsage( "Cannot create a persistent development character") if not opts.provider_uri and not opts.federated_only: raise click.BadOptionUsage( option_name='--provider', message= "--provider is required to create a new decentralized alice.") pay_with = opts.pay_with if not pay_with and not opts.federated_only: pay_with = select_client_account(emitter=emitter, provider_uri=opts.provider_uri, show_eth_balance=True) return AliceConfiguration.generate( password=get_nucypher_password(confirm=True), config_root=config_root, checksum_address=pay_with, domains=opts.domains, federated_only=opts.federated_only, provider_uri=opts.provider_uri, signer_uri=opts.signer_uri, provider_process=opts.eth_node, registry_filepath=opts.registry_filepath, poa=self.poa, light=self.light, m=self.m, n=self.n, duration_periods=self.duration_periods)
def generate_config(self, emitter: StdoutEmitter, config_root: Path, key_material: str) -> AliceConfiguration: opts = self.config_options if opts.dev: raise click.BadArgumentUsage("Cannot create a persistent development character") if not opts.provider_uri and not opts.federated_only: raise click.BadOptionUsage( option_name='--provider', message="--provider is required to create a new decentralized alice.") pay_with = opts.pay_with if not pay_with and not opts.federated_only: pay_with = select_client_account(emitter=emitter, provider_uri=opts.provider_uri, signer_uri=opts.signer_uri, show_eth_balance=True, network=opts.domain) return AliceConfiguration.generate( password=get_nucypher_password(emitter=emitter, confirm=True), key_material=bytes.fromhex(key_material) if key_material else None, config_root=config_root, checksum_address=pay_with, domain=opts.domain, federated_only=opts.federated_only, provider_uri=opts.provider_uri, signer_uri=opts.signer_uri, registry_filepath=opts.registry_filepath, poa=self.poa, light=self.light, threshold=self.threshold, shares=self.shares, payment_periods=self.payment_periods)
def alice( click_config, action, # Mode dev, force, dry_run, # Network teacher_uri, min_stake, federated_only, network, discovery_port, controller_port, # Filesystem config_root, config_file, # Blockchain pay_with, provider_uri, geth, sync, poa, registry_filepath, hw_wallet, # Alice bob_encrypting_key, bob_verifying_key, label, m, n, value, rate, duration_periods, expiration, message_kit, ): """ "Alice the Policy Authority" management commands. \b Actions ------------------------------------------------- \b init Create a brand new persistent Alice view View existing Alice's configuration. run Start Alice's controller. destroy Delete existing Alice's configuration. public-keys Obtain Alice's public verification and encryption keys. derive-policy-pubkey Get a policy public key from a policy label. grant Create and enact an access policy for some Bob. revoke Revoke a policy. decrypt Decrypt data encrypted under an Alice's policy public key. """ # # Validate # if federated_only and geth: raise click.BadOptionUsage( option_name="--geth", message="Federated only cannot be used with the --geth flag") # Banner emitter = click_config.emitter emitter.clear() emitter.banner(ALICE_BANNER) # # Managed Ethereum Client # ETH_NODE = NO_BLOCKCHAIN_CONNECTION if geth: ETH_NODE = actions.get_provider_process() provider_uri = ETH_NODE.provider_uri(scheme='file') # # Eager Actions (No Authentication Required) # if action == 'init': """Create a brand-new persistent Alice""" if dev: raise click.BadArgumentUsage( "Cannot create a persistent development character") if not provider_uri and not federated_only: raise click.BadOptionUsage( option_name='--provider', message= "--provider is required to create a new decentralized alice.") if not config_root: # Flag config_root = click_config.config_file # Envvar if not pay_with and not federated_only: pay_with = select_client_account(emitter=emitter, provider_uri=provider_uri) new_alice_config = AliceConfiguration.generate( password=get_nucypher_password(confirm=True), config_root=config_root, checksum_address=pay_with, domains={network} if network else None, federated_only=federated_only, registry_filepath=registry_filepath, provider_process=ETH_NODE, poa=poa, provider_uri=provider_uri, m=m, n=n, duration_periods=duration_periods, rate=rate) painting.paint_new_installation_help( emitter, new_configuration=new_alice_config) return # Exit elif action == "view": """Paint an existing configuration to the console""" configuration_file_location = config_file or AliceConfiguration.default_filepath( ) response = AliceConfiguration._read_configuration_file( filepath=configuration_file_location) return emitter.ipc( response=response, request_id=0, duration=0) # FIXME: what are request_id and duration here? # # Get Alice Configuration # if dev: alice_config = AliceConfiguration( dev_mode=True, network_middleware=click_config.middleware, domains={network}, provider_process=ETH_NODE, provider_uri=provider_uri, federated_only=True) else: try: alice_config = AliceConfiguration.from_configuration_file( dev_mode=False, filepath=config_file, domains={network} if network else None, network_middleware=click_config.middleware, rest_port=discovery_port, checksum_address=pay_with, provider_process=ETH_NODE, provider_uri=provider_uri, registry_filepath=registry_filepath) except FileNotFoundError: return actions.handle_missing_configuration_file( character_config_class=AliceConfiguration, config_file=config_file) if action == "destroy": """Delete all configuration files from the disk""" if dev: message = "'nucypher alice destroy' cannot be used in --dev mode" raise click.BadOptionUsage(option_name='--dev', message=message) return actions.destroy_configuration(emitter, character_config=alice_config, force=force) # # Produce Alice # # TODO: OH MY. client_password = None if not alice_config.federated_only: if (not hw_wallet or not dev) and not click_config.json_ipc: client_password = get_client_password( checksum_address=alice_config.checksum_address) try: ALICE = actions.make_cli_character(character_config=alice_config, click_config=click_config, dev=dev, teacher_uri=teacher_uri, min_stake=min_stake, client_password=client_password) except NucypherKeyring.AuthenticationFailed as e: emitter.echo(str(e), color='red', bold=True) click.get_current_context().exit(1) # TODO: Exit codes (not only for this, but for other exceptions) # # Admin Actions # if action == "run": """Start Alice Controller""" try: # RPC if click_config.json_ipc: rpc_controller = ALICE.make_rpc_controller() _transport = rpc_controller.make_control_transport() rpc_controller.start() return # HTTP else: emitter.message( f"Alice Verifying Key {bytes(ALICE.stamp).hex()}", color="green", bold=True) controller = ALICE.make_web_controller( crash_on_error=click_config.debug) ALICE.log.info('Starting HTTP Character Web Controller') emitter.message( f'Running HTTP Alice Controller at http://localhost:{controller_port}' ) return controller.start(http_port=controller_port, dry_run=dry_run) # Handle Crash except Exception as e: alice_config.log.critical(str(e)) emitter.message(f"{e.__class__.__name__} {e}", color='red', bold=True) if click_config.debug: raise # Crash :-( return # # Alice API # elif action == "public-keys": response = ALICE.controller.public_keys() return response elif action == "derive-policy-pubkey": # Validate if not label: raise click.BadOptionUsage( option_name='label', message= "--label is required for deriving a policy encrypting key.") # Request return ALICE.controller.derive_policy_encrypting_key(label=label) elif action == "grant": # Validate if not all((bob_verifying_key, bob_encrypting_key, label)): raise click.BadArgumentUsage( message= "--bob-verifying-key, --bob-encrypting-key, and --label are " "required options to grant (optionally --m, --n, and --expiration)." ) # Request grant_request = { 'bob_encrypting_key': bob_encrypting_key, 'bob_verifying_key': bob_verifying_key, 'label': label, 'm': m, 'n': n, 'expiration': expiration, } if not ALICE.federated_only: grant_request.update({'value': value}) return ALICE.controller.grant(request=grant_request) elif action == "revoke": # Validate if not label and bob_verifying_key: raise click.BadArgumentUsage( message= f"--label and --bob-verifying-key are required options for revoke." ) # Request revoke_request = { 'label': label, 'bob_verifying_key': bob_verifying_key } return ALICE.controller.revoke(request=revoke_request) elif action == "decrypt": # Validate if not all((label, message_kit)): input_specification, output_specification = ALICE.controller.get_specifications( interface_name=action) required_fields = ', '.join(input_specification) raise click.BadArgumentUsage( f'{required_fields} are required flags to decrypt') # Request request_data = {'label': label, 'message_kit': message_kit} response = ALICE.controller.decrypt(request=request_data) return response else: raise click.BadArgumentUsage(f"No such argument {action}")
def alice( click_config, action, # Mode dev, force, dry_run, # Network teacher_uri, min_stake, federated_only, network, discovery_port, controller_port, # Filesystem config_root, config_file, # Blockchain pay_with, provider_uri, geth, sync, poa, no_registry, registry_filepath, # Alice bob_encrypting_key, bob_verifying_key, label, m, n, value, rate, duration, expiration, message_kit): # # Validate # if federated_only and geth: raise click.BadOptionUsage( option_name="--geth", message="Federated only cannot be used with the --geth flag") # Banner click.clear() if not click_config.json_ipc and not click_config.quiet: click.secho(ALICE_BANNER) # # Managed Ethereum Client # ETH_NODE = NO_BLOCKCHAIN_CONNECTION if geth: ETH_NODE = actions.get_provider_process() provider_uri = ETH_NODE.provider_uri(scheme='file') # # Eager Actions (No Authentication Required) # if action == 'init': """Create a brand-new persistent Alice""" if dev: raise click.BadArgumentUsage( "Cannot create a persistent development character") if not config_root: # Flag config_root = click_config.config_file # Envvar new_alice_config = AliceConfiguration.generate( password=click_config.get_password(confirm=True), config_root=config_root, checksum_address=pay_with, rest_host="localhost", domains={network} if network else None, federated_only=federated_only, download_registry=no_registry, registry_filepath=registry_filepath, provider_process=ETH_NODE, poa=poa, provider_uri=provider_uri, m=m, n=n, duration=duration, rate=rate) painting.paint_new_installation_help( new_configuration=new_alice_config, config_root=config_root, config_file=config_file) return # Exit elif action == "view": """Paint an existing configuration to the console""" configuration_file_location = config_file or AliceConfiguration.DEFAULT_CONFIG_FILE_LOCATION response = AliceConfiguration._read_configuration_file( filepath=configuration_file_location) click_config.emit(response) return # Exit # # Make Alice # if dev: alice_config = AliceConfiguration( dev_mode=True, network_middleware=click_config.middleware, domains={network}, provider_process=ETH_NODE, provider_uri=provider_uri, federated_only=True) else: try: alice_config = AliceConfiguration.from_configuration_file( filepath=config_file, domains={network} if network else None, network_middleware=click_config.middleware, rest_port=discovery_port, checksum_address=pay_with, provider_process=ETH_NODE, provider_uri=provider_uri) except FileNotFoundError: return actions.handle_missing_configuration_file( character_config_class=AliceConfiguration, config_file=config_file) ALICE = actions.make_cli_character(character_config=alice_config, click_config=click_config, dev=dev, teacher_uri=teacher_uri, min_stake=min_stake, sync=sync) # # Admin Actions # if action == "run": """Start Alice Web Controller""" ALICE.controller.emitter( message=f"Alice Verifying Key {bytes(ALICE.stamp).hex()}", color="green", bold=True) controller = ALICE.make_web_controller( crash_on_error=click_config.debug) ALICE.log.info('Starting Alice Web Controller') return controller.start(http_port=controller_port or alice_config.controller_port, dry_run=dry_run) elif action == "destroy": """Delete all configuration files from the disk""" if dev: message = "'nucypher alice destroy' cannot be used in --dev mode" raise click.BadOptionUsage(option_name='--dev', message=message) return actions.destroy_configuration(character_config=alice_config, force=force) # # Alice API # elif action == "public-keys": response = ALICE.controller.public_keys() return response elif action == "derive-policy-pubkey": # Validate if not label: raise click.BadOptionUsage( option_name='label', message= "--label is required for deriving a policy encrypting key.") # Request return ALICE.controller.derive_policy_encrypting_key(label=label) elif action == "grant": # Validate if not all((bob_verifying_key, bob_encrypting_key, label)): raise click.BadArgumentUsage( message= "--bob-verifying-key, --bob-encrypting-key, and --label are " "required options to grant (optionally --m, --n, and --expiration)." ) # Request grant_request = { 'bob_encrypting_key': bob_encrypting_key, 'bob_verifying_key': bob_verifying_key, 'label': label, 'm': m, 'n': n, 'expiration': expiration, } if not ALICE.federated_only: grant_request.update({'value': value}) return ALICE.controller.grant(request=grant_request) elif action == "revoke": # Validate if not label and bob_verifying_key: raise click.BadArgumentUsage( message= f"--label and --bob-verifying-key are required options for revoke." ) # Request revoke_request = { 'label': label, 'bob_verifying_key': bob_verifying_key } return ALICE.controller.revoke(request=revoke_request) elif action == "decrypt": # Validate if not all((label, message_kit)): input_specification, output_specification = ALICE.controller.get_specifications( interface_name=action) required_fields = ', '.join(input_specification) raise click.BadArgumentUsage( f'{required_fields} are required flags to decrypt') # Request request_data = {'label': label, 'message_kit': message_kit} response = ALICE.controller.decrypt(request=request_data) return response else: raise click.BadArgumentUsage(f"No such argument {action}")
def init( click_config, # Admin Options geth, provider_uri, federated_only, dev, pay_with, network, registry_filepath, # Other config_root, poa, m, n, rate, duration_periods): """ Create a brand new persistent Alice. """ ### Setup ### emitter = _setup_emitter(click_config) if federated_only and geth: raise click.BadOptionUsage( option_name="--geth", message="Federated only cannot be used with the --geth flag") # # Managed Ethereum Client # ETH_NODE = NO_BLOCKCHAIN_CONNECTION if geth: ETH_NODE = actions.get_provider_process() provider_uri = ETH_NODE.provider_uri(scheme='file') ############# if dev: raise click.BadArgumentUsage( "Cannot create a persistent development character") if not provider_uri and not federated_only: raise click.BadOptionUsage( option_name='--provider', message= "--provider is required to create a new decentralized alice.") if not config_root: # Flag config_root = click_config.config_file # Envvar if not pay_with and not federated_only: pay_with = select_client_account(emitter=emitter, provider_uri=provider_uri) new_alice_config = AliceConfiguration.generate( password=get_nucypher_password(confirm=True), config_root=config_root, checksum_address=pay_with, domains={network} if network else None, federated_only=federated_only, registry_filepath=registry_filepath, provider_process=ETH_NODE, poa=poa, provider_uri=provider_uri, m=m, n=n, duration_periods=duration_periods, rate=rate) painting.paint_new_installation_help(emitter, new_configuration=new_alice_config)
def alice(click_config, action, teacher_uri, min_stake, http_port, discovery_port, federated_only, network, config_root, config_file, provider_uri, no_registry, registry_filepath, dev, force, dry_run, bob_encrypting_key, bob_verifying_key, policy_encrypting_key, label, m, n): """ Start and manage an "Alice" character. """ if not click_config.json_ipc and not click_config.quiet: click.secho(ALICE_BANNER) if action == 'init': """Create a brand-new persistent Alice""" if not network: raise click.BadArgumentUsage( '--network is required to initialize a new configuration.') if dev: click_config.emitter( message="WARNING: Using temporary storage area", color='yellow') if not config_root: # Flag config_root = click_config.config_file # Envvar new_alice_config = AliceConfiguration.generate( password=click_config._get_password(confirm=True), config_root=config_root, rest_host="localhost", domains={network} if network else None, federated_only=federated_only, no_registry=no_registry, registry_filepath=registry_filepath, provider_uri=provider_uri) return painting.paint_new_installation_help( new_configuration=new_alice_config, config_root=config_root, config_file=config_file) elif action == "destroy": """Delete all configuration files from the disk""" if dev: message = "'nucypher ursula destroy' cannot be used in --dev mode" raise click.BadOptionUsage(option_name='--dev', message=message) destroyed_path = actions.destroy_system_configuration( config_class=AliceConfiguration, config_file=config_file, network=network, config_root=config_root, force=force) return nucypher_click_config.emitter( message=f"Destroyed {destroyed_path}", color='red') # # Get Alice Configuration # if dev: alice_config = AliceConfiguration( dev_mode=True, network_middleware=click_config.middleware, domains={network}, provider_uri=provider_uri, federated_only=True) else: alice_config = AliceConfiguration.from_configuration_file( filepath=config_file, domains={network or GLOBAL_DOMAIN}, network_middleware=click_config.middleware, rest_port=discovery_port, provider_uri=provider_uri) if not dev: click_config.unlock_keyring(character_configuration=alice_config) # Teacher Ursula teacher_uris = [teacher_uri] if teacher_uri else list() teacher_nodes = actions.load_seednodes( teacher_uris=teacher_uris, min_stake=min_stake, federated_only=federated_only, network_middleware=click_config.middleware) # Produce ALICE = alice_config(known_nodes=teacher_nodes, network_middleware=click_config.middleware) # Switch to character control emitter if click_config.json_ipc: ALICE.controller.emitter = IPCStdoutEmitter(quiet=click_config.quiet) if action == "run": """Start Alice Web Controller""" ALICE.controller.emitter( message=f"Alice Verifying Key {bytes(ALICE.stamp).hex()}", color="green", bold=True) controller = ALICE.make_web_controller( crash_on_error=click_config.debug) ALICE.log.info('Starting HTTP Character Web Controller') return controller.start(http_port=http_port, dry_run=dry_run) elif action == "view": """Paint an existing configuration to the console""" configuration_file_location = config_file or alice_config.config_file_location response = AliceConfiguration._read_configuration_file( filepath=configuration_file_location) return ALICE.controller.emitter( response=response) # TODO: Uses character control instead elif action == "public-keys": response = ALICE.controller.public_keys() return response elif action == "create-policy": if not all((bob_verifying_key, bob_encrypting_key, label)): raise click.BadArgumentUsage( message= "--bob-verifying-key, --bob-encrypting-key, and --label are " "required options to create a new policy.") create_policy_request = { 'bob_encrypting_key': bob_encrypting_key, 'bob_verifying_key': bob_verifying_key, 'label': label, 'm': m, 'n': n, } return ALICE.controller.create_policy(request=create_policy_request) elif action == "derive-policy-pubkey": return ALICE.controller.derive_policy_encrypting_key(label=label) elif action == "grant": grant_request = { 'bob_encrypting_key': bob_encrypting_key, 'bob_verifying_key': bob_verifying_key, 'label': label, 'm': m, 'n': n, 'expiration': (maya.now() + datetime.timedelta(days=3)).iso8601(), # TODO } return ALICE.controller.grant(request=grant_request) elif action == "revoke": return ALICE.controller.revoke( policy_encrypting_key=policy_encrypting_key) else: raise click.BadArgumentUsage(f"No such argument {action}")
def alice(click_config, action, quiet, teacher_uri, min_stake, http_port, discovery_port, federated_only, network, config_root, config_file, provider_uri, registry_filepath, dev, force, dry_run, bob_encrypting_key, bob_verifying_key, label, m, n): """ Start and manage an "Alice" character. """ if not quiet: click.secho(ALICE_BANNER) if action == 'init': """Create a brand-new persistent Alice""" if dev and not quiet: click.secho("WARNING: Using temporary storage area", fg='yellow') if not config_root: # Flag config_root = click_config.config_file # Envvar alice_config = AliceConfiguration.generate( password=click_config.get_password(confirm=True), config_root=config_root, rest_host="localhost", domains={network} if network else None, federated_only=federated_only, no_registry=True, # Yes we have no registry, registry_filepath=registry_filepath, provider_uri=provider_uri, ) if not quiet: click.secho("Generated keyring {}".format( alice_config.keyring_dir), fg='green') click.secho("Saved configuration file {}".format( alice_config.config_file_location), fg='green') # Give the use a suggestion as to what to do next... how_to_run_message = "\nTo run an Alice node from the default configuration filepath run: \n\n'{}'\n" suggested_command = 'nucypher alice run' if config_root is not None: config_file_location = os.path.join( config_root, config_file or AliceConfiguration.CONFIG_FILENAME) suggested_command += ' --config-file {}'.format( config_file_location) click.secho(how_to_run_message.format(suggested_command), fg='green') return # FIN else: click.secho("OK") elif action == "destroy": """Delete all configuration files from the disk""" if dev: message = "'nucypher ursula destroy' cannot be used in --dev mode" raise click.BadOptionUsage(option_name='--dev', message=message) destroy_system_configuration(config_class=AliceConfiguration, config_file=config_file, network=network, config_root=config_root, force=force) if not quiet: click.secho("Destroyed {}".format(config_root)) return # # Get Alice Configuration # if dev: alice_config = AliceConfiguration( dev_mode=True, domains={network}, provider_uri=provider_uri, federated_only=True, ) else: alice_config = AliceConfiguration.from_configuration_file( filepath=config_file, domains={network or GLOBAL_DOMAIN}, rest_port=discovery_port, provider_uri=provider_uri) # Teacher teacher_nodes = list() if teacher_uri: teacher_node = Ursula.from_teacher_uri( teacher_uri=teacher_uri, min_stake=min_stake, federated_only=alice_config.federated_only) teacher_nodes.append(teacher_node) if not dev: # Keyring try: click.secho("Decrypting keyring...", fg='blue') alice_config.keyring.unlock(password=click_config.get_password()) except CryptoError: raise alice_config.keyring.AuthenticationFailed finally: click_config.alice_config = alice_config # Produce ALICE = alice_config(known_nodes=teacher_nodes) if action == "run": # Alice Control alice_control = ALICE.make_wsgi_app() click.secho("Starting Alice Character Control...") click.secho(f"Alice Verifying Key {bytes(ALICE.stamp).hex()}", fg="green", bold=True) # Run if dry_run: return hx_deployer = HendrixDeploy(action="start", options={ "wsgi": alice_control, "http_port": http_port }) hx_deployer.run() # <--- Blocking Call to Reactor elif action == "view": """Paint an existing configuration to the console""" paint_configuration( config_filepath=config_file or alice_config.config_file_location) return elif action == "create-policy": if not all((bob_verifying_key, bob_encrypting_key, label)): raise click.BadArgumentUsage( message= "--bob-verifying-key, --bob-encrypting-key, and --label are " "required options to create a new policy.") request_data = { 'bob_encrypting_key': bob_encrypting_key, 'bob_signing_key': bob_verifying_key, 'label': b64encode(bytes(label, encoding='utf-8')).decode(), 'm': m, 'n': n, } response = requests.put(f'http://localhost:{http_port}/create_policy', data=json.dumps(request_data)) click.secho(response.json()) return elif action == "derive-policy": response = requests.post( f'http://localhost:{http_port}/derive_policy_pubkey/{label}') response_data = response.json() policy_encrypting_key = response_data['result'][ 'policy_encrypting_pubkey'] click.secho( f"Created new Policy with label {label} | {policy_encrypting_key}", fg='green') elif action == "grant": request_data = { 'bob_encrypting_key': bob_encrypting_key, 'bob_signing_key': bob_verifying_key, 'label': b64encode(bytes(label, encoding='utf-8')).decode(), 'm': m, 'n': n, 'expiration_time': (maya.now() + datetime.timedelta(days=3)).iso8601(), # TODO } response = requests.put(f'http://localhost:{http_port}/grant', data=json.dumps(request_data)) click.secho(response) return elif action == "revoke": raise NotImplementedError # TODO else: raise click.BadArgumentUsage(f"No such argument {action}")