Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve keyring creation prompts and warnings #2662

Merged
merged 3 commits into from May 7, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions newsfragments/2662.misc.rst
@@ -0,0 +1 @@
Improves password collection hints while running `init` commands.
cygnusv marked this conversation as resolved.
Show resolved Hide resolved
10 changes: 6 additions & 4 deletions nucypher/cli/actions/auth.py
Expand Up @@ -21,18 +21,19 @@
from constant_sorrow.constants import NO_PASSWORD
from nacl.exceptions import CryptoError

from nucypher.blockchain.eth.signers.software import ClefSigner
from nucypher.blockchain.eth.decorators import validate_checksum_address
from nucypher.blockchain.eth.signers.software import ClefSigner
from nucypher.characters.control.emitters import StdoutEmitter
from nucypher.cli.literature import (
COLLECT_ETH_PASSWORD,
COLLECT_NUCYPHER_PASSWORD,
DECRYPTING_CHARACTER_KEYRING,
GENERIC_PASSWORD_PROMPT
GENERIC_PASSWORD_PROMPT,
PASSWORD_COLLECTION_NOTICE
)
from nucypher.config.base import CharacterConfiguration
from nucypher.config.constants import NUCYPHER_ENVVAR_KEYRING_PASSWORD
from nucypher.config.keyring import NucypherKeyring
from nucypher.config.base import CharacterConfiguration


def get_password_from_prompt(prompt: str = GENERIC_PASSWORD_PROMPT, envvar: str = None, confirm: bool = False) -> str:
Expand Down Expand Up @@ -77,11 +78,12 @@ 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(PASSWORD_COLLECTION_NOTICE)
prompt += f" ({NucypherKeyring.MINIMUM_PASSWORD_LENGTH} character minimum)"
keyring_password = get_password_from_prompt(prompt=prompt, confirm=confirm, envvar=envvar)
return keyring_password
Expand Down
2 changes: 1 addition & 1 deletion nucypher/cli/commands/alice.py
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion nucypher/cli/commands/bob.py
Expand Up @@ -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,
Expand Down
8 changes: 4 additions & 4 deletions nucypher/cli/commands/felix.py
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Expand Down
4 changes: 3 additions & 1 deletion nucypher/cli/commands/ursula.py
Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Expand Down
6 changes: 6 additions & 0 deletions nucypher/cli/literature.py
Expand Up @@ -210,6 +210,7 @@
#
# Snapshots
#

SNAPSHOTS_DISABLING_AGREEMENT = """
By disabling snapshots, staker {staking_address} will be excluded from all future DAO validations
until snapshots are enabled.
Expand Down Expand Up @@ -380,6 +381,11 @@
# Authentication
#

PASSWORD_COLLECTION_NOTICE = f"""
Please provide a password to lock Worker keys.
Do not forget this password, and ideally store it using a password manager.
"""

COLLECT_ETH_PASSWORD = "Enter ethereum account password ({checksum_address})"

COLLECT_NUCYPHER_PASSWORD = 'Enter nucypher keyring password'
Expand Down
13 changes: 12 additions & 1 deletion nucypher/cli/painting/help.py
Expand Up @@ -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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: wil -> will

cygnusv marked this conversation as resolved.
Show resolved Hide resolved
- Remember your password! Without the password, it's impossible to decrypt the key!

""")

default_config_filepath = True
if new_configuration.default_filepath() != filepath:
Expand Down
2 changes: 1 addition & 1 deletion nucypher/cli/utils.py
Expand Up @@ -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:
Expand Down
3 changes: 2 additions & 1 deletion tests/integration/cli/actions/test_auth_actions.py
Expand Up @@ -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,
Expand Down Expand Up @@ -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()
Expand Down