diff --git a/examples/heartbeat_demo/alicia.py b/examples/heartbeat_demo/alicia.py index 72c6438f2..e6b77b666 100644 --- a/examples/heartbeat_demo/alicia.py +++ b/examples/heartbeat_demo/alicia.py @@ -57,7 +57,6 @@ ursula = Ursula.from_seed_and_stake_info(seed_uri=SEEDNODE_URI, alice_config = AliceConfiguration( config_root=os.path.join(TEMP_ALICE_DIR), - is_me=True, domains={TEMPORARY_DOMAIN}, known_nodes={ursula}, start_learning_now=False, diff --git a/examples/heartbeat_demo/doctor.py b/examples/heartbeat_demo/doctor.py index 04792cb34..6e0b2b24b 100644 --- a/examples/heartbeat_demo/doctor.py +++ b/examples/heartbeat_demo/doctor.py @@ -56,7 +56,6 @@ power_ups = [enc_power, sig_power] print("Creating the Doctor ...") doctor = Bob( - is_me=True, domains={TEMPORARY_DOMAIN}, federated_only=True, crypto_power_ups=power_ups, diff --git a/nucypher/cli/actions.py b/nucypher/cli/actions.py index a784b1fbc..768fd18c7 100644 --- a/nucypher/cli/actions.py +++ b/nucypher/cli/actions.py @@ -242,6 +242,7 @@ def make_cli_character(character_config, # Handle Keyring if not dev: + character_config.attach_keyring() click_config.unlock_keyring(character_configuration=character_config, password=click_config.get_password(confirm=False)) diff --git a/nucypher/cli/characters/alice.py b/nucypher/cli/characters/alice.py index 30ffa7ea3..190eb5b0d 100644 --- a/nucypher/cli/characters/alice.py +++ b/nucypher/cli/characters/alice.py @@ -137,7 +137,7 @@ def alice(click_config, elif action == "view": """Paint an existing configuration to the console""" - configuration_file_location = config_file or AliceConfiguration.generate_filepath() + configuration_file_location = config_file or AliceConfiguration.default_filepath() response = AliceConfiguration._read_configuration_file(filepath=configuration_file_location) click_config.emit(response) return # Exit diff --git a/nucypher/cli/config.py b/nucypher/cli/config.py index fbb992268..9ea563cbc 100644 --- a/nucypher/cli/config.py +++ b/nucypher/cli/config.py @@ -105,6 +105,7 @@ class NucypherClickConfig: # NuCypher try: + character_configuration.attach_keyring() character_configuration.keyring.unlock(password=password) # Takes ~3 seconds, ~1GB Ram except CryptoError: raise character_configuration.keyring.AuthenticationFailed diff --git a/nucypher/config/characters.py b/nucypher/config/characters.py index f085ce568..9d17e06f9 100644 --- a/nucypher/config/characters.py +++ b/nucypher/config/characters.py @@ -138,13 +138,12 @@ class AliceConfiguration(CharacterConfiguration): first_period_rate: float = None, duration: int = None, *args, **kwargs): - - super().__init__(*args, **kwargs) self.m = m or self.DEFAULT_M self.n = n or self.DEFAULT_N self.rate = rate or self.DEFAULT_RATE self.first_period_rate = first_period_rate or self.DEFAULT_FIRST_PERIOD_RATE self.duration = duration or self.DEFAULT_DURATION + super().__init__(*args, **kwargs) def static_payload(self) -> dict: payload = dict(m=self.m, @@ -198,6 +197,7 @@ class FelixConfiguration(CharacterConfiguration): certificate: Certificate = None, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) if not rest_port: rest_port = self.DEFAULT_REST_PORT self.rest_port = rest_port or self.DEFAULT_REST_PORT @@ -205,7 +205,6 @@ class FelixConfiguration(CharacterConfiguration): self.tls_curve = tls_curve or self.__DEFAULT_TLS_CURVE self.certificate = certificate self.db_filepath = db_filepath or os.path.join(self.config_root, self.DEFAULT_DB_NAME) - super().__init__(*args, **kwargs) def static_payload(self) -> dict: payload = dict( diff --git a/nucypher/config/keyring.py b/nucypher/config/keyring.py index 4d77a5d8b..58b1c7f5b 100644 --- a/nucypher/config/keyring.py +++ b/nucypher/config/keyring.py @@ -386,15 +386,6 @@ class NucypherKeyring: def checksum_address(self) -> str: return to_checksum_address(self.__account) - @property - def federated_address(self) -> str: - signature_pubkey = self.signing_public_key - uncompressed_bytes = signature_pubkey.to_bytes(is_compressed=False) - without_prefix = uncompressed_bytes[1:] - verifying_key_as_eth_key = EthKeyAPI.PublicKey(without_prefix) - address = verifying_key_as_eth_key.to_checksum_address() - return to_checksum_address(address) - @property def signing_public_key(self): signature_pubkey_bytes = _read_keyfile(keypath=self.__signing_pub_keypath, deserializer=None) @@ -558,6 +549,10 @@ class NucypherKeyring: keyring_args = dict() + if checksum_address: + # Addresses read from some node keyrings (clients) are *not* returned in checksum format. + checksum_address = to_checksum_address(checksum_address) + if encrypting is True: signing_private_key, signing_public_key = _generate_signing_keys() @@ -575,9 +570,6 @@ class NucypherKeyring: if not checksum_address: raise ValueError("Checksum address must bas provided for non-federated keyring generation") - # Addresses read from some node keyrings (clients) are *not* returned in checksum format. - checksum_address = to_checksum_address(checksum_address) - __key_filepaths = cls._generate_key_filepaths(account=checksum_address, private_key_dir=_private_key_dir, public_key_dir=_public_key_dir) diff --git a/nucypher/config/node.py b/nucypher/config/node.py index 717339474..dea467761 100644 --- a/nucypher/config/node.py +++ b/nucypher/config/node.py @@ -222,6 +222,7 @@ class CharacterConfiguration(BaseConfiguration): def destroy(self) -> None: """Parse a node configuration and remove all associated files from the filesystem""" + self.attach_keyring() self.keyring.destroy() os.remove(self.config_file_location) @@ -354,12 +355,12 @@ class CharacterConfiguration(BaseConfiguration): def attach_keyring(self, checksum_address: str = None, *args, **kwargs) -> None: account = checksum_address or self.checksum_address + if not account: + raise self.ConfigurationError("No account specified to unlock keyring") if self.keyring is not NO_KEYRING_ATTACHED: if self.keyring.checksum_address != account: raise self.ConfigurationError("There is already a keyring attached to this configuration.") return - if not account: - raise self.ConfigurationError("No account specified to unlock keyring") self.keyring = NucypherKeyring(keyring_root=self.keyring_root, account=account, *args, **kwargs) def derive_node_power_ups(self) -> List[CryptoPowerUp]: @@ -383,17 +384,20 @@ class CharacterConfiguration(BaseConfiguration): def initialize(self, password: str) -> str: """Initialize a new configuration and write installation files to disk.""" - if password is DEVELOPMENT_CONFIGURATION: - self.abort_on_learning_error = True - self.save_metadata = False - self.reload_metadata = False - alphabet = string.ascii_letters + string.digits - password = ''.join(secrets.choice(alphabet) for _ in range(32)) - - # Configuration Root - if self.__dev_mode: + # Development + if self.dev_mode: + if password is DEVELOPMENT_CONFIGURATION: + self.abort_on_learning_error = True + self.save_metadata = False + self.reload_metadata = False + alphabet = string.ascii_letters + string.digits + password = ''.join(secrets.choice(alphabet) for _ in range(32)) + else: + raise self.ConfigurationError("Password cannot be specified for development configurations.") self.__temp_dir = TemporaryDirectory(prefix=self.TEMP_CONFIGURATION_DIR_PREFIX) self.config_root = self.__temp_dir.name + + # Persistent else: self.write_config_root() self.write_keyring(password=password) diff --git a/tests/characters/test_alice_can_grant_and_revoke.py b/tests/characters/test_alice_can_grant_and_revoke.py index bcc1628f1..9c329d101 100644 --- a/tests/characters/test_alice_can_grant_and_revoke.py +++ b/tests/characters/test_alice_can_grant_and_revoke.py @@ -248,6 +248,7 @@ def test_alices_powers_are_persistent(federated_ursulas, tmpdir): ) # Alice unlocks her restored keyring from disk + new_alice_config.attach_keyring() new_alice_config.keyring.unlock(password=INSECURE_DEVELOPMENT_PASSWORD) new_alice = new_alice_config() diff --git a/tests/cli/test_alice.py b/tests/cli/test_alice.py index 5d84fcff6..bc00ed151 100644 --- a/tests/cli/test_alice.py +++ b/tests/cli/test_alice.py @@ -27,7 +27,7 @@ def test_initialize_alice_defaults(click_runner, mocker): assert 'Repeat for confirmation:' in result.output, 'User was not prompted to confirm password' -def test_alice_control_starts_mocked(click_runner, mocker): +def test_alice_control_starts_with_mocked_keyring(click_runner, mocker): class MockKeyring: is_unlocked = False @@ -37,8 +37,8 @@ def test_alice_control_starts_mocked(click_runner, mocker): assert password == INSECURE_DEVELOPMENT_PASSWORD cls.is_unlocked = True + mocker.patch.object(AliceConfiguration, "attach_keyring", return_value=None) good_enough_config = AliceConfiguration(dev_mode=True, federated_only=True, keyring=MockKeyring) - mocker.patch.object(AliceConfiguration, "from_configuration_file", return_value=good_enough_config) init_args = ('alice', 'run', '-x') diff --git a/tests/cli/test_felix.py b/tests/cli/test_felix.py index 988da9112..ce51af3a4 100644 --- a/tests/cli/test_felix.py +++ b/tests/cli/test_felix.py @@ -48,7 +48,8 @@ def test_run_felix(click_runner, assert result.exit_code == 0 # Felix creates a system configuration - init_args = ('felix', 'init', + init_args = ('--debug', + 'felix', 'init', '--checksum-address', testerchain.interface.w3.eth.accounts[0], '--config-root', MOCK_CUSTOM_INSTALLATION_PATH_2, '--network', TEMPORARY_DOMAIN, @@ -61,7 +62,8 @@ def test_run_felix(click_runner, configuration_file_location = os.path.join(MOCK_CUSTOM_INSTALLATION_PATH_2, FelixConfiguration.generate_filename()) # Felix Creates a Database - db_args = ('felix', 'createdb', + db_args = ('--debug', + 'felix', 'createdb', '--config-file', configuration_file_location, '--provider-uri', TEST_PROVIDER_URI) @@ -86,6 +88,8 @@ def test_run_felix(click_runner, # Init an equal Felix to the already running one. felix_config = FelixConfiguration.from_configuration_file(filepath=configuration_file_location) + + felix_config.attach_keyring() felix_config.keyring.unlock(password=INSECURE_DEVELOPMENT_PASSWORD) felix = felix_config.produce() diff --git a/tests/config/test_keyring.py b/tests/config/test_keyring.py index 801740a5e..c22e28cdc 100644 --- a/tests/config/test_keyring.py +++ b/tests/config/test_keyring.py @@ -7,18 +7,6 @@ from nucypher.config.keyring import NucypherKeyring from nucypher.crypto.powers import DelegatingPower, DecryptingPower -@pytest.mark.skip("Redacted and refactored for sensitive info leakage") -def test_validate_password(): - # Password too short - password = 'x' * 5 - with pytest.raises(ValueError): - _keyring = NucypherKeyring.generate(password=password) - - # Empty password is provided - with pytest.raises(ValueError): - _keyring = NucypherKeyring.generate(password="") - - def test_generate_alice_keyring(tmpdir): password = 'x' * 16