diff --git a/nucypher/cli/actions/auth.py b/nucypher/cli/actions/auth.py index dffac5e346a..7dc7f5e7e8c 100644 --- a/nucypher/cli/actions/auth.py +++ b/nucypher/cli/actions/auth.py @@ -77,13 +77,14 @@ def unlock_signer_account(config: CharacterConfiguration, json_ipc: bool) -> Non config.signer.unlock_account(account=config.checksum_address, password=__password) -def get_nucypher_password(confirm: bool = False, envvar=NUCYPHER_ENVVAR_KEYRING_PASSWORD) -> str: +def get_nucypher_password(emitter, confirm: bool = False, envvar=NUCYPHER_ENVVAR_KEYRING_PASSWORD) -> str: """Interactively collect a nucypher password""" prompt = COLLECT_NUCYPHER_PASSWORD if confirm: from nucypher.config.keyring import NucypherKeyring + emitter.message(f"Ursula keys are locked with a password. Please provide a password. Do not forget this password.") prompt += f" ({NucypherKeyring.MINIMUM_PASSWORD_LENGTH} character minimum)" - keyring_password = get_password_from_prompt(prompt=prompt, confirm=confirm, envvar=envvar) + keyring_password = get_password_from_prompt(prompt=prompt, confirm=confirm, envvar=envvar) return keyring_password diff --git a/nucypher/cli/commands/alice.py b/nucypher/cli/commands/alice.py index b781b6e93dd..dbf03bfdcc3 100644 --- a/nucypher/cli/commands/alice.py +++ b/nucypher/cli/commands/alice.py @@ -206,7 +206,7 @@ def generate_config(self, emitter: StdoutEmitter, config_root: str) -> AliceConf network=opts.domain) return AliceConfiguration.generate( - password=get_nucypher_password(confirm=True), + password=get_nucypher_password(emitter=emitter, confirm=True), config_root=config_root, checksum_address=pay_with, domain=opts.domain, diff --git a/nucypher/cli/commands/bob.py b/nucypher/cli/commands/bob.py index f313dce9771..c1908df8d33 100644 --- a/nucypher/cli/commands/bob.py +++ b/nucypher/cli/commands/bob.py @@ -141,7 +141,7 @@ def generate_config(self, emitter: StdoutEmitter, config_root: str) -> BobConfig provider_uri=self.provider_uri) # TODO: See #1888 return BobConfiguration.generate( - password=get_nucypher_password(confirm=True), + password=get_nucypher_password(emitter=emitter, confirm=True), config_root=config_root, checksum_address=checksum_address, domain=self.domain, diff --git a/nucypher/cli/commands/felix.py b/nucypher/cli/commands/felix.py index be37fe5280b..26ea1c836e3 100644 --- a/nucypher/cli/commands/felix.py +++ b/nucypher/cli/commands/felix.py @@ -16,10 +16,10 @@ """ -import os - import click +import os +from nucypher.characters.control.emitters import StdoutEmitter from nucypher.cli.actions.auth import ( get_client_password, get_nucypher_password, @@ -116,7 +116,7 @@ def create_config(self, emitter, config_file): def generate_config(self, config_root, discovery_port): return FelixConfiguration.generate( - password=get_nucypher_password(confirm=True), + password=get_nucypher_password(emitter=StdoutEmitter(), confirm=True), config_root=config_root, rest_host=self.host, rest_port=discovery_port, @@ -163,7 +163,7 @@ def create_character(self, emitter, config_file, debug): # Authenticate unlock_nucypher_keyring(emitter, character_configuration=felix_config, - password=get_nucypher_password(confirm=False)) + password=get_nucypher_password(emitter=emitter, confirm=False)) client_password = get_client_password(checksum_address=felix_config.checksum_address, envvar=NUCYPHER_ENVVAR_WORKER_ETH_PASSWORD) diff --git a/nucypher/cli/commands/ursula.py b/nucypher/cli/commands/ursula.py index 2bc6d27fb6b..7b36d3c76b4 100644 --- a/nucypher/cli/commands/ursula.py +++ b/nucypher/cli/commands/ursula.py @@ -179,7 +179,7 @@ def generate_config(self, emitter, config_root, force): if not self.rest_host: self.rest_host = collect_worker_ip_address(emitter, network=self.domain, force=force) - return UrsulaConfiguration.generate(password=get_nucypher_password(confirm=True), + return UrsulaConfiguration.generate(password=get_nucypher_password(emitter=emitter, confirm=True), config_root=config_root, rest_host=self.rest_host, rest_port=self.rest_port, @@ -301,6 +301,8 @@ def init(general_config, config_options, force, config_root): _pre_launch_warnings(emitter, dev=None, force=force) if not config_root: config_root = general_config.config_root + if not config_options.federated_only and not config_options.provider_uri: + raise click.BadOptionUsage('--provider', message="--provider is required to initialize a new ursula.") if not config_options.federated_only and not config_options.domain: config_options.domain = select_network(emitter) ursula_config = config_options.generate_config(emitter, config_root, force) diff --git a/nucypher/cli/painting/help.py b/nucypher/cli/painting/help.py index 5075aac1b83..f27b73a4b16 100644 --- a/nucypher/cli/painting/help.py +++ b/nucypher/cli/painting/help.py @@ -55,7 +55,18 @@ def paint_new_installation_help(emitter, new_configuration, filepath): character_config_class = new_configuration.__class__ character_name = character_config_class.NAME.lower() - emitter.message(f"Generated keyring {new_configuration.keyring_root}", color='green') + emitter.message(f"Generated keyring", color='green') + emitter.message(f""" + +Public key (stamp): {bytes(new_configuration.keyring.signing_public_key).hex()} +Path to keyring: {new_configuration.keyring_root} + +- You can share your public key with anyone. Others need it to interact with you. +- Never share secret keys with anyone! Character keys are required to interact with the network! +- Backup your keyring! Without the keyring you wil not be able to use existing network policies. +- Remember your password! Without the password, it's impossible to decrypt the key! + +""") default_config_filepath = True if new_configuration.default_filepath() != filepath: diff --git a/nucypher/cli/utils.py b/nucypher/cli/utils.py index ec0338a63d8..f8c4e68bc8f 100644 --- a/nucypher/cli/utils.py +++ b/nucypher/cli/utils.py @@ -84,7 +84,7 @@ def make_cli_character(character_config, if unlock_keyring: unlock_nucypher_keyring(emitter, character_configuration=character_config, - password=get_nucypher_password(confirm=False)) + password=get_nucypher_password(emitter=emitter, confirm=False)) # Handle Signer/Wallet if unlock_signer: diff --git a/tests/integration/cli/actions/test_auth_actions.py b/tests/integration/cli/actions/test_auth_actions.py index 5ac65ce0713..d25a7352490 100644 --- a/tests/integration/cli/actions/test_auth_actions.py +++ b/tests/integration/cli/actions/test_auth_actions.py @@ -21,6 +21,7 @@ from nacl.exceptions import CryptoError from nucypher.blockchain.eth.decorators import InvalidChecksumAddress +from nucypher.characters.control.emitters import StdoutEmitter from nucypher.cli.actions.auth import ( get_client_password, get_nucypher_password, @@ -90,7 +91,7 @@ def test_get_client_password(mock_stdin, mock_account, confirm, capsys): @pytest.mark.parametrize('confirm', (True, False)) def test_get_nucypher_password(mock_stdin, mock_account, confirm, capsys): mock_stdin.password(INSECURE_DEVELOPMENT_PASSWORD, confirm=confirm) - result = get_nucypher_password(confirm=confirm) + result = get_nucypher_password(emitter=StdoutEmitter(), confirm=confirm) assert result == INSECURE_DEVELOPMENT_PASSWORD assert mock_stdin.empty() captured = capsys.readouterr()