Exemplo n.º 1
0
def test_restore_keystore_from_mnemonic(tmpdir, mocker):

    # Setup
    spy = mocker.spy(Mnemonic, 'generate')

    # Decrypt post-generation
    keystore = Keystore.generate(INSECURE_DEVELOPMENT_PASSWORD, keystore_dir=tmpdir)
    keystore.unlock(password=INSECURE_DEVELOPMENT_PASSWORD)
    mnemonic = Mnemonic(_MNEMONIC_LANGUAGE)
    words = spy.spy_return
    secret = bytes(mnemonic.to_entropy(words))
    keystore_path = keystore.keystore_path

    # remove local and disk references, simulating a
    # lost keystore or forgotten password.
    del keystore
    os.unlink(keystore_path)

    # prove the keystore is lost or missing
    assert not keystore_path.exists()
    with pytest.raises(Keystore.NotFound):
        _keystore = Keystore(keystore_path=keystore_path)

    # Restore with user-supplied words and a new password
    keystore = Keystore.restore(words=words, password='******')
    keystore.unlock(password='******')
    assert keystore._Keystore__secret == secret
Exemplo n.º 2
0
def test_invalid_keystore_file_type(tmp_path, tmp_path_factory):

    # Not a file
    invalid_path = Path()
    with pytest.raises(ValueError, match="Keystore path must be a file."):
        _keystore = Keystore(invalid_path)
    invalid_path = Path(tmp_path)
    with pytest.raises(ValueError, match="Keystore path must be a file."):
        _keystore = Keystore(invalid_path)

    # Not an existing file
    invalid_path = Path('does-not-exist')
    with pytest.raises(Keystore.NotFound, match=f"Keystore '{invalid_path.absolute()}' does not exist."):
        _keystore = Keystore(invalid_path)
Exemplo n.º 3
0
def test_default_character_configuration_preservation(
        configuration_class, testerchain, test_registry_source_manager,
        tmpdir):

    configuration_class.DEFAULT_CONFIG_ROOT = Path('/tmp')
    fake_address = '0xdeadbeef'
    network = TEMPORARY_DOMAIN

    expected_filename = f'{configuration_class.NAME}.{configuration_class._CONFIG_FILE_EXTENSION}'
    generated_filename = configuration_class.generate_filename()
    assert generated_filename == expected_filename
    expected_filepath = Path('/', 'tmp', generated_filename)

    if expected_filepath.exists():
        expected_filepath.unlink()
    assert not expected_filepath.exists()

    if configuration_class == StakeHolderConfiguration:
        # special case for defaults
        character_config = StakeHolderConfiguration(
            provider_uri=testerchain.provider_uri, domain=network)

    elif configuration_class == UrsulaConfiguration:
        # special case for rest_host & dev mode
        # use keystore
        keystore = Keystore.generate(password=INSECURE_DEVELOPMENT_PASSWORD,
                                     keystore_dir=tmpdir)
        keystore.signing_public_key = SecretKey.random().public_key()
        character_config = configuration_class(checksum_address=fake_address,
                                               domain=network,
                                               rest_host=MOCK_IP_ADDRESS,
                                               keystore=keystore)

    else:
        character_config = configuration_class(checksum_address=fake_address,
                                               domain=network)

    generated_filepath = character_config.generate_filepath()
    assert generated_filepath == expected_filepath

    written_filepath = character_config.to_configuration_file()
    assert written_filepath == expected_filepath
    assert written_filepath.exists()

    try:
        # Read
        with open(character_config.filepath, 'r') as f:
            contents = f.read()

        # Restore from JSON file
        restored_configuration = configuration_class.from_configuration_file()
        assert character_config.serialize(
        ) == restored_configuration.serialize()

        # File still exists after reading
        assert written_filepath.exists()

    finally:
        if expected_filepath.exists():
            expected_filepath.unlink()
Exemplo n.º 4
0
def test_unlock_nucypher_keystore_dev_mode(mocker, test_emitter, capsys,
                                           alice_blockchain_test_config,
                                           tmpdir):

    # Setup
    unlock_spy = mocker.spy(Keystore, 'unlock')
    mocker.patch.object(CharacterConfiguration,
                        'dev_mode',
                        return_value=True,
                        new_callable=mocker.PropertyMock)
    keystore = Keystore.generate(password=INSECURE_DEVELOPMENT_PASSWORD,
                                 keystore_dir=tmpdir)
    alice_blockchain_test_config.attach_keystore(keystore)

    result = unlock_nucypher_keystore(
        emitter=test_emitter,
        password=INSECURE_DEVELOPMENT_PASSWORD,
        character_configuration=alice_blockchain_test_config)

    assert result
    output = capsys.readouterr().out
    message = DECRYPTING_CHARACTER_KEYSTORE.format(
        name=alice_blockchain_test_config.NAME.capitalize())
    assert message in output

    unlock_spy.assert_not_called()
Exemplo n.º 5
0
def test_unlock_nucypher_keystore_invalid_password(
        mocker, test_emitter, alice_blockchain_test_config, capsys, tmpdir,
        test_registry_source_manager):

    # Setup
    mocker.patch.object(passwords,
                        'secret_box_decrypt',
                        side_effect=SecretBoxAuthenticationError)
    mocker.patch.object(CharacterConfiguration,
                        'dev_mode',
                        return_value=False,
                        new_callable=mocker.PropertyMock)
    keystore = Keystore.generate(password=INSECURE_DEVELOPMENT_PASSWORD,
                                 keystore_dir=tmpdir)
    alice_blockchain_test_config.attach_keystore(keystore)

    # Test
    with pytest.raises(Keystore.AuthenticationFailed):
        unlock_nucypher_keystore(
            emitter=test_emitter,
            password=INSECURE_DEVELOPMENT_PASSWORD + 'typo',
            character_configuration=alice_blockchain_test_config)

    captured = capsys.readouterr()
    assert DECRYPTING_CHARACTER_KEYSTORE.format(
        name=alice_blockchain_test_config.NAME.capitalize()) in captured.out
Exemplo n.º 6
0
def test_unlock_nucypher_keystore(mocker, test_emitter, capsys,
                                  alice_blockchain_test_config, patch_keystore,
                                  tmpdir):

    # Setup
    # Do not test "real" unlocking here, just the plumbing
    unlock_spy = mocker.patch.object(Keystore, 'unlock', return_value=True)
    mocker.patch.object(CharacterConfiguration,
                        'dev_mode',
                        return_value=False,
                        new_callable=mocker.PropertyMock)
    mocker.patch.object(Mnemonic, 'detect_language', return_value='english')
    keystore = Keystore.generate(password=INSECURE_DEVELOPMENT_PASSWORD,
                                 keystore_dir=tmpdir)
    alice_blockchain_test_config.attach_keystore(keystore)

    result = unlock_nucypher_keystore(
        emitter=test_emitter,
        password=INSECURE_DEVELOPMENT_PASSWORD,
        character_configuration=alice_blockchain_test_config)

    assert result
    captured = capsys.readouterr()
    message = DECRYPTING_CHARACTER_KEYSTORE.format(
        name=alice_blockchain_test_config.NAME.capitalize())
    assert message in captured.out

    unlock_spy.assert_called_once_with(password=INSECURE_DEVELOPMENT_PASSWORD)
Exemplo n.º 7
0
def test_generate_alice_keystore(temp_dir_path):

    keystore = Keystore.generate(password=INSECURE_DEVELOPMENT_PASSWORD,
                                 keystore_dir=temp_dir_path)

    with pytest.raises(Keystore.Locked):
        _dec_keypair = keystore.derive_crypto_power(DecryptingPower).keypair

    keystore.unlock(password=INSECURE_DEVELOPMENT_PASSWORD)
    assert keystore.derive_crypto_power(DecryptingPower).keypair

    label = b'test'

    delegating_power = keystore.derive_crypto_power(DelegatingPower)
    delegating_pubkey = delegating_power.get_pubkey_from_label(label)

    bob_pubkey = SecretKey.random().public_key()
    signer = Signer(SecretKey.random())
    delegating_pubkey_again, _kfrags = delegating_power.generate_kfrags(
        bob_pubkey, signer, label, threshold=2, shares=3)

    assert delegating_pubkey == delegating_pubkey_again

    another_delegating_power = keystore.derive_crypto_power(DelegatingPower)
    another_delegating_pubkey = another_delegating_power.get_pubkey_from_label(
        label)

    assert delegating_pubkey == another_delegating_pubkey
Exemplo n.º 8
0
def test_keystore_persistence(tmpdir):
    """Regression test for keystore file persistence"""
    keystore = Keystore.generate(INSECURE_DEVELOPMENT_PASSWORD, keystore_dir=tmpdir)
    keystore.unlock(password=INSECURE_DEVELOPMENT_PASSWORD)
    path = keystore.keystore_path
    del keystore
    assert path.exists()
Exemplo n.º 9
0
def test_keystore_lock_unlock(tmpdir):
    keystore = Keystore.generate(INSECURE_DEVELOPMENT_PASSWORD, keystore_dir=tmpdir)

    # locked by default
    assert not keystore.is_unlocked
    assert keystore._Keystore__secret is KEYSTORE_LOCKED

    # incorrect password
    with pytest.raises(Keystore.AuthenticationFailed):
        keystore.unlock('opensaysme')

    # unlock
    keystore.unlock(INSECURE_DEVELOPMENT_PASSWORD)
    assert keystore.is_unlocked
    assert keystore._Keystore__secret != KEYSTORE_LOCKED
    assert isinstance(keystore._Keystore__secret, bytes)

    # unlock when already unlocked
    keystore.unlock(INSECURE_DEVELOPMENT_PASSWORD)
    assert keystore.is_unlocked

    # incorrect password when already unlocked
    with pytest.raises(Keystore.AuthenticationFailed):
        keystore.unlock('opensaysme')

    # lock
    keystore.lock()
    assert not keystore.is_unlocked

    # lock when already locked
    keystore.lock()
    assert not keystore.is_unlocked
Exemplo n.º 10
0
def test_initialize_ursula_defaults(click_runner, mocker, tmpdir):

    # Mock out filesystem writes
    mocker.patch.object(UrsulaConfiguration, 'initialize', autospec=True)
    mocker.patch.object(UrsulaConfiguration,
                        'to_configuration_file',
                        autospec=True)

    # Mock Keystore init
    keystore = Keystore.generate(keystore_dir=tmpdir,
                                 password=INSECURE_DEVELOPMENT_PASSWORD)
    mocker.patch.object(CharacterConfiguration,
                        'keystore',
                        return_value=keystore,
                        new_callable=PropertyMock)

    # Use default ursula init args
    init_args = ('ursula', 'init', '--network', TEMPORARY_DOMAIN,
                 '--federated-only')

    user_input = YES_ENTER + FAKE_PASSWORD_CONFIRMED
    result = click_runner.invoke(nucypher_cli,
                                 init_args,
                                 input=user_input,
                                 catch_exceptions=False)
    assert result.exit_code == 0

    # REST Host
    assert "Is this the public-facing address of Ursula? " in result.output

    # Auth
    assert COLLECT_NUCYPHER_PASSWORD in result.output, 'WARNING: User was not prompted for password'
    assert 'Repeat for confirmation:' in result.output, 'User was not prompted to confirm password'
Exemplo n.º 11
0
def test_derive_hosting_power(tmpdir):
    keystore = Keystore.generate(INSECURE_DEVELOPMENT_PASSWORD, keystore_dir=tmpdir)
    keystore.unlock(password=INSECURE_DEVELOPMENT_PASSWORD)
    hosting_power = keystore.derive_crypto_power(power_class=TLSHostingPower, host=LOOPBACK_ADDRESS)
    assert hosting_power.public_key().public_numbers()
    assert hosting_power.keypair.certificate.public_bytes(encoding=Encoding.PEM)
    rederived_hosting_power = keystore.derive_crypto_power(power_class=TLSHostingPower, host=LOOPBACK_ADDRESS)
    assert hosting_power.public_key().public_numbers() == rederived_hosting_power.public_key().public_numbers()
Exemplo n.º 12
0
def test_derive_delegating_power(tmpdir):
    keystore = Keystore.generate(INSECURE_DEVELOPMENT_PASSWORD, keystore_dir=tmpdir)
    keystore.unlock(password=INSECURE_DEVELOPMENT_PASSWORD)
    delegating_power = keystore.derive_crypto_power(power_class=DelegatingPower)
    parent_skf = SecretKeyFactory.from_secure_randomness(keystore._Keystore__secret)
    child_skf = parent_skf.make_factory(_DELEGATING_INFO)
    assert delegating_power._DelegatingPower__secret_key_factory.to_secret_bytes() == child_skf.to_secret_bytes()
    assert delegating_power._get_privkey_from_label(label=b'some-label')
Exemplo n.º 13
0
def test_import_custom_keystore(tmpdir):

    # Too short - 32 bytes is required
    custom_secret = b'tooshort'
    with pytest.raises(ValueError, match=f'Entropy bytes bust be exactly {SecretKey.serialized_size()}.'):
        _keystore = Keystore.import_secure(key_material=custom_secret,
                                           password=INSECURE_DEVELOPMENT_PASSWORD,
                                           keystore_dir=tmpdir)

    # Too short - 32 bytes is required
    custom_secret = b'thisisabunchofbytesthatisabittoolong'
    with pytest.raises(ValueError, match=f'Entropy bytes bust be exactly {SecretKey.serialized_size()}.'):
        _keystore = Keystore.import_secure(key_material=custom_secret,
                                           password=INSECURE_DEVELOPMENT_PASSWORD,
                                           keystore_dir=tmpdir)

    # Import private key
    custom_secret = os.urandom(SecretKey.serialized_size())  # insecure but works
    keystore = Keystore.import_secure(key_material=custom_secret,
                                      password=INSECURE_DEVELOPMENT_PASSWORD,
                                      keystore_dir=tmpdir)
    keystore.unlock(password=INSECURE_DEVELOPMENT_PASSWORD)
    assert keystore._Keystore__secret == custom_secret
    keystore.lock()

    path = keystore.keystore_path
    del keystore

    # Restore custom secret from encrypted keystore file
    keystore = Keystore(keystore_path=path)
    keystore.unlock(password=INSECURE_DEVELOPMENT_PASSWORD)
    assert keystore._Keystore__secret == custom_secret
Exemplo n.º 14
0
def test_keystore_generation_defaults(tmp_path_factory):

    # Setup
    parent = Path(tmp_path_factory.mktemp('test-keystore-'))
    parent.touch(exist_ok=True)

    # Test
    keystore = Keystore.generate(INSECURE_DEVELOPMENT_PASSWORD, keystore_dir=parent)
    assert not keystore.is_unlocked        # defaults to locked
    assert keystore._Keystore__secret is KEYSTORE_LOCKED
    assert parent in keystore.keystore_path.parents  # created in the correct directory
Exemplo n.º 15
0
def test_decrypt_keystore(tmpdir, mocker):

    # Setup
    spy = mocker.spy(Mnemonic, 'generate')

    # Decrypt post-generation
    keystore = Keystore.generate(INSECURE_DEVELOPMENT_PASSWORD, keystore_dir=tmpdir)
    keystore.unlock(password=INSECURE_DEVELOPMENT_PASSWORD)
    mnemonic = Mnemonic(_MNEMONIC_LANGUAGE)
    words = spy.spy_return
    secret = bytes(mnemonic.to_entropy(words))
    assert keystore._Keystore__secret == secret

    # Decrypt from keystore file
    keystore_path = keystore.keystore_path
    del words
    del keystore
    keystore = Keystore(keystore_path=keystore_path)
    keystore.unlock(INSECURE_DEVELOPMENT_PASSWORD)
    assert keystore._Keystore__secret == secret
Exemplo n.º 16
0
def recover_keystore(emitter) -> None:
    emitter.message('This procedure will recover your nucypher keystore from mnemonic seed words. '
                    'You will need to provide the entire mnemonic (space seperated) in the correct '
                    'order and choose a new password.', color='cyan')
    click.confirm('Do you want to continue', abort=True)
    __words = click.prompt("Enter nucypher keystore seed words")
    word_count = len(__words.split())
    if word_count != _WORD_COUNT:
        emitter.message(f'Invalid mnemonic - Number of words must be {str(_WORD_COUNT)}, but only got {word_count}')
    __password = get_nucypher_password(emitter=emitter, confirm=True)
    keystore = Keystore.restore(words=__words, password=__password)
    emitter.message(f'Recovered nucypher keystore {keystore.id} to \n {keystore.keystore_path}', color='green')
Exemplo n.º 17
0
    def write_keystore(self,
                       password: str,
                       key_material: Optional[bytes] = None,
                       interactive: bool = True) -> Keystore:
        if key_material:
            self.__keystore = Keystore.import_secure(
                key_material=key_material,
                password=password,
                keystore_dir=self.keystore_dir)
        else:
            if interactive:
                self.__keystore = Keystore.generate(
                    password=password,
                    keystore_dir=self.keystore_dir,
                    interactive=interactive)
            else:
                self.__keystore, _ = Keystore.generate(
                    password=password,
                    keystore_dir=self.keystore_dir,
                    interactive=interactive)

        return self.keystore
Exemplo n.º 18
0
def test_keystore_instantiation_defaults(tmp_path_factory):

    # Setup
    parent = Path(tmp_path_factory.mktemp('test-keystore-'))
    parent.touch(exist_ok=True)
    keystore_id = ''.join(random.choice(string.hexdigits.lower()) for _ in range(Keystore._ID_SIZE))
    path = parent / f'123-{keystore_id}.priv'
    path.touch()

    # Test
    keystore = Keystore(path)
    assert keystore.keystore_path == path  # retains the correct keystore path
    assert keystore.id == keystore_id      # accurately parses filename for ID
    assert not keystore.is_unlocked        # defaults to locked
    assert keystore._Keystore__secret is KEYSTORE_LOCKED
    assert parent in keystore.keystore_path.parents  # created in the correct directory
Exemplo n.º 19
0
def test_tls_hosting_certificate_remains_the_same(temp_dir_path, mocker):
    keystore = Keystore.generate(password=INSECURE_DEVELOPMENT_PASSWORD,
                                 keystore_dir=temp_dir_path)
    keystore.unlock(password=INSECURE_DEVELOPMENT_PASSWORD)

    rest_port = 12345
    db_filepath = tempfile.mkdtemp()

    ursula = Ursula(federated_only=True,
                    start_learning_now=False,
                    keystore=keystore,
                    rest_host=LOOPBACK_ADDRESS,
                    rest_port=rest_port,
                    db_filepath=db_filepath,
                    domain=TEMPORARY_DOMAIN)

    assert ursula.keystore is keystore
    assert ursula.certificate == ursula._crypto_power.power_ups(
        TLSHostingPower).keypair.certificate

    original_certificate_bytes = ursula.certificate.public_bytes(
        encoding=Encoding.DER)
    ursula.disenchant()
    del ursula

    spy_rest_server_init = mocker.spy(ProxyRESTServer, '__init__')
    recreated_ursula = Ursula(federated_only=True,
                              start_learning_now=False,
                              keystore=keystore,
                              rest_host=LOOPBACK_ADDRESS,
                              rest_port=rest_port,
                              db_filepath=db_filepath,
                              domain=TEMPORARY_DOMAIN)

    assert recreated_ursula.keystore is keystore
    assert recreated_ursula.certificate.public_bytes(
        encoding=Encoding.DER) == original_certificate_bytes
    tls_hosting_power = recreated_ursula._crypto_power.power_ups(
        TLSHostingPower)
    spy_rest_server_init.assert_called_once_with(
        ANY,  # self
        rest_host=LOOPBACK_ADDRESS,
        rest_port=rest_port,
        rest_app=IsType(Flask),
        datastore=IsType(Datastore),
        hosting_power=tls_hosting_power)
    recreated_ursula.disenchant()
def test_characters_use_keystore(temp_dir_path):
    keystore = Keystore.generate(password=INSECURE_DEVELOPMENT_PASSWORD,
                                 keystore_dir=temp_dir_path)
    keystore.unlock(password=INSECURE_DEVELOPMENT_PASSWORD)
    alice = Alice(federated_only=True,
                  start_learning_now=False,
                  keystore=keystore)
    Bob(federated_only=True, start_learning_now=False, keystore=keystore)
    Ursula(federated_only=True,
           start_learning_now=False,
           keystore=keystore,
           rest_host=LOOPBACK_ADDRESS,
           rest_port=12345,
           db_filepath=tempfile.mkdtemp(),
           domain=TEMPORARY_DOMAIN)
    alice.disenchant(
    )  # To stop Alice's publication threadpool.  TODO: Maybe only start it at first enactment?
Exemplo n.º 21
0
def test_initialize_alice_defaults(click_runner, mocker, custom_filepath,
                                   monkeypatch, blockchain_ursulas, tmpdir):
    monkeypatch.delenv(NUCYPHER_ENVVAR_KEYSTORE_PASSWORD, raising=False)

    # Mock out filesystem writes
    mocker.patch.object(AliceConfiguration, 'initialize', autospec=True)
    mocker.patch.object(AliceConfiguration,
                        'to_configuration_file',
                        autospec=True)
    mocker.patch.object(LocalFileBasedNodeStorage,
                        'all',
                        return_value=blockchain_ursulas)

    # Mock Keystore init
    keystore = Keystore.generate(keystore_dir=tmpdir,
                                 password=INSECURE_DEVELOPMENT_PASSWORD)
    mocker.patch.object(CharacterConfiguration,
                        'keystore',
                        return_value=keystore,
                        new_callable=PropertyMock)

    # Use default alice init args
    init_args = ('alice', 'init', '--network',
                 TEMPORARY_DOMAIN, '--config-root',
                 str(custom_filepath.absolute()), '--federated-only')
    result = click_runner.invoke(nucypher_cli,
                                 init_args,
                                 input=FAKE_PASSWORD_CONFIRMED,
                                 catch_exceptions=False)
    assert result.exit_code == 0

    # REST Host
    assert "nucypher alice run" in result.output

    # Auth
    assert COLLECT_NUCYPHER_PASSWORD in result.output, 'WARNING: User was not prompted for password'
    assert 'Repeat for confirmation:' in result.output, 'User was not prompted to confirm password'
Exemplo n.º 22
0
def test_keystore_generate_report_interactive_false(tmpdir):
    _keystore, words = Keystore.generate(
        INSECURE_DEVELOPMENT_PASSWORD,
        keystore_dir=tmpdir,
        interactive=False)
    assert len(words.split(" ")) == 24
Exemplo n.º 23
0
    def __init__(
            self,

            # Base
            emitter=None,
            config_root: Optional[Path] = None,
            filepath: Optional[Path] = None,

            # Mode
            dev_mode: bool = False,
            federated_only: bool = False,

            # Identity
            checksum_address: str = None,
            crypto_power: CryptoPower = None,

            # Keystore
            keystore: Keystore = None,
            keystore_path: Optional[Path] = None,

            # Learner
            learn_on_same_thread: bool = False,
            abort_on_learning_error: bool = False,
            start_learning_now: bool = True,

            # Network
            controller_port: int = None,
            domain: str = DEFAULT_DOMAIN,
            network_middleware: RestMiddleware = None,
            lonely: bool = False,

            # Node Storage
            known_nodes: set = None,
            node_storage: NodeStorage = None,
            reload_metadata: bool = True,
            save_metadata: bool = True,

            # Blockchain
            poa: bool = None,
            light: bool = False,
            provider_uri: str = None,
            gas_strategy: Union[Callable, str] = DEFAULT_GAS_STRATEGY,
            max_gas_price: Optional[int] = None,
            signer_uri: str = None,

            # Registry
            registry: BaseContractRegistry = None,
            registry_filepath: Optional[Path] = None,

            # Deployed Workers
            worker_data: dict = None):

        self.log = Logger(self.__class__.__name__)

        # This constant is used to signal that a path can be generated if one is not provided.
        UNINITIALIZED_CONFIGURATION.bool_value(False)

        # Identity
        # NOTE: NodeConfigurations can only be used with Self-Characters
        self.is_me = True
        self.checksum_address = checksum_address

        # Keystore
        self.crypto_power = crypto_power
        if keystore_path and not keystore:
            keystore = Keystore(keystore_path=keystore_path)
        self.__keystore = self.__keystore = keystore or NO_KEYSTORE_ATTACHED.bool_value(
            False)
        self.keystore_dir = Path(
            keystore.keystore_path
        ).parent if keystore else UNINITIALIZED_CONFIGURATION

        # Contract Registry
        if registry and registry_filepath:
            if registry.filepath != registry_filepath:
                error = f"Inconsistent registry filepaths for '{registry.filepath.absolute()}'" \
                        f" and '{registry_filepath.absolute()}'."
                raise ValueError(error)
            else:
                self.log.warn(
                    f"Registry and registry filepath were both passed.")
        self.registry = registry or NO_BLOCKCHAIN_CONNECTION.bool_value(False)
        self.registry_filepath = registry_filepath or UNINITIALIZED_CONFIGURATION

        # Blockchain
        self.poa = poa
        self.is_light = light
        self.provider_uri = provider_uri or NO_BLOCKCHAIN_CONNECTION
        self.signer_uri = signer_uri or None

        # Learner
        self.federated_only = federated_only
        self.domain = domain
        self.learn_on_same_thread = learn_on_same_thread
        self.abort_on_learning_error = abort_on_learning_error
        self.start_learning_now = start_learning_now
        self.save_metadata = save_metadata
        self.reload_metadata = reload_metadata
        self.known_nodes = known_nodes or set()  # handpicked
        self.lonely = lonely

        # Configuration
        self.__dev_mode = dev_mode
        self.config_file_location = filepath or UNINITIALIZED_CONFIGURATION
        self.config_root = UNINITIALIZED_CONFIGURATION

        # Deployed Workers
        self.worker_data = worker_data

        #
        # Federated vs. Blockchain arguments consistency
        #

        #
        # Federated
        #

        if self.federated_only:
            # Check for incompatible values
            blockchain_args = {
                'filepath': registry_filepath,
                'poa': poa,
                'provider_uri': provider_uri,
                'gas_strategy': gas_strategy,
                'max_gas_price': max_gas_price
            }
            if any(blockchain_args.values()):
                bad_args = ", ".join(f"{arg}={val}"
                                     for arg, val in blockchain_args.items()
                                     if val)
                self.log.warn(
                    f"Arguments {bad_args} are incompatible with federated_only. "
                    f"Overridden with a sane default.")

                # Clear decentralized attributes to ensure consistency with a
                # federated configuration.
                self.poa = False
                self.is_light = False
                self.provider_uri = None
                self.registry_filepath = None
                self.gas_strategy = None
                self.max_gas_price = None

        #
        # Decentralized
        #

        else:
            self.gas_strategy = gas_strategy
            self.max_gas_price = max_gas_price  # gwei
            is_initialized = BlockchainInterfaceFactory.is_interface_initialized(
                provider_uri=self.provider_uri)
            if not is_initialized and provider_uri:
                BlockchainInterfaceFactory.initialize_interface(
                    provider_uri=self.provider_uri,
                    poa=self.poa,
                    light=self.is_light,
                    emitter=emitter,
                    gas_strategy=self.gas_strategy,
                    max_gas_price=self.max_gas_price)
            else:
                self.log.warn(
                    f"Using existing blockchain interface connection ({self.provider_uri})."
                )

            if not self.registry:
                # TODO: These two code blocks are untested.
                if not self.registry_filepath:  # TODO: Registry URI  (goerli://speedynet.json) :-)
                    self.log.info(f"Fetching latest registry from source.")
                    self.registry = InMemoryContractRegistry.from_latest_publication(
                        network=self.domain)
                else:
                    self.registry = LocalContractRegistry(
                        filepath=self.registry_filepath)
                    self.log.info(f"Using local registry ({self.registry}).")

            self.testnet = self.domain != NetworksInventory.MAINNET
            self.signer = Signer.from_signer_uri(self.signer_uri,
                                                 testnet=self.testnet)

        if dev_mode:
            self.__temp_dir = UNINITIALIZED_CONFIGURATION
            self._setup_node_storage()
            self.initialize(password=DEVELOPMENT_CONFIGURATION)
        else:
            self.__temp_dir = LIVE_CONFIGURATION
            self.config_root = config_root or self.DEFAULT_CONFIG_ROOT
            self._cache_runtime_filepaths()
            self._setup_node_storage(node_storage=node_storage)

        # Network
        self.controller_port = controller_port or self.DEFAULT_CONTROLLER_PORT
        self.network_middleware = network_middleware or self.DEFAULT_NETWORK_MIDDLEWARE(
            registry=self.registry)

        super().__init__(filepath=self.config_file_location,
                         config_root=self.config_root)
Exemplo n.º 24
0
def test_keystore_invalid_password(tmpdir):
    with pytest.raises(InvalidPassword):
        _keystore = Keystore.generate('short', keystore_dir=tmpdir)
Exemplo n.º 25
0
def test_derive_decrypting_power(tmpdir):
    keystore = Keystore.generate(INSECURE_DEVELOPMENT_PASSWORD, keystore_dir=tmpdir)
    keystore.unlock(password=INSECURE_DEVELOPMENT_PASSWORD)
    decrypting_power = keystore.derive_crypto_power(power_class=DecryptingPower)
    assert bytes(decrypting_power.public_key()).hex()
    assert decrypting_power.keypair.fingerprint()
Exemplo n.º 26
0
def test_keystore_derive_crypto_power_without_unlock(tmpdir):
    keystore = Keystore.generate(INSECURE_DEVELOPMENT_PASSWORD, keystore_dir=tmpdir)
    with pytest.raises(Keystore.Locked):
        keystore.derive_crypto_power(power_class=DecryptingPower)
Exemplo n.º 27
0
    def __init__(self,
                 domain: str = None,
                 known_node_class: object = None,
                 is_me: bool = True,
                 federated_only: bool = False,
                 checksum_address: str = None,
                 network_middleware: RestMiddleware = None,
                 keystore: Keystore = None,
                 crypto_power: CryptoPower = None,
                 crypto_power_ups: List[CryptoPowerUp] = None,
                 eth_provider_uri: str = None,
                 signer: Signer = None,
                 registry: BaseContractRegistry = None,
                 include_self_in_the_state: bool = False,
                 *args,
                 **kwargs) -> None:
        """

        A participant in the cryptological drama (a screenplay, if you like) of NuCypher.

        Characters can represent users, nodes, wallets, offline devices, or other objects of varying levels of abstraction.

        The Named Characters use this class as a Base, and achieve their individuality from additional methods and PowerUps.


        PowerUps
        ========
        :param crypto_power: A CryptoPower object; if provided, this will be the character's CryptoPower.
        :param crypto_power_ups: If crypto_power is not provided, a new one will be made to consume all CryptoPowerUps.

        If neither crypto_power nor crypto_power_ups are provided, we give this
        Character all CryptoPowerUps listed in their _default_crypto_powerups
        attribute.

        :param is_me: Set this to True when you want this Character to represent
            the owner of the configuration under which the program is being run.
            A Character who is_me can do things that other Characters can't,
            like run servers, sign messages, and decrypt messages which are
            encrypted for them.  Typically this will be True for exactly one
            Character, but there are scenarios in which its imaginable to be
            represented by zero Characters or by more than one Character.

        """

        #
        # Prologue of the federation
        #

        # FIXME: excuse me... can I speak to the manager?
        if is_me:
            # If this is a federated-is_me-character, assume everyone else is too.
            self._set_known_node_class(known_node_class, federated_only)
        else:
            # What an awful hack.  The last convulsions of #466.  # TODO: Anything else.
            with suppress(AttributeError):
                federated_only = known_node_class._federated_only_instances

        if federated_only:
            if registry or eth_provider_uri:
                raise ValueError(
                    f"Cannot init federated-only character with {registry or eth_provider_uri}."
                )
        self.federated_only: bool = federated_only

        ##########################################

        #
        # Keys & Powers
        #

        if keystore:
            crypto_power_ups = list()
            for power_up in self._default_crypto_powerups:
                power = keystore.derive_crypto_power(power_class=power_up)
                crypto_power_ups.append(power)
        self.keystore = keystore

        if crypto_power and crypto_power_ups:
            raise ValueError(
                "Pass crypto_power or crypto_power_ups (or neither), but not both."
            )
        crypto_power_ups = crypto_power_ups or list()  # type: list

        if crypto_power:
            self._crypto_power = crypto_power  # type: CryptoPower
        elif crypto_power_ups:
            self._crypto_power = CryptoPower(power_ups=crypto_power_ups)
        else:
            self._crypto_power = CryptoPower(
                power_ups=self._default_crypto_powerups)

        #
        # Self
        #

        if is_me:

            # Signing Power
            self.signer = signer
            try:
                signing_power = self._crypto_power.power_ups(
                    SigningPower)  # type: SigningPower
                self._stamp = signing_power.get_signature_stamp(
                )  # type: SignatureStamp
            except NoSigningPower:
                self._stamp = NO_SIGNING_POWER

            # Blockchainy
            if not self.federated_only:
                self.eth_provider_uri = eth_provider_uri
                self.registry = registry or InMemoryContractRegistry.from_latest_publication(
                    network=domain)  # See #1580
            else:
                self.registry = NO_BLOCKCHAIN_CONNECTION.bool_value(False)

            # REST
            self.network_middleware = network_middleware or RestMiddleware(
                registry=self.registry, eth_provider_uri=eth_provider_uri)

            # Learner
            Learner.__init__(
                self,
                domain=domain,
                network_middleware=self.network_middleware,
                node_class=known_node_class,
                include_self_in_the_state=include_self_in_the_state,
                *args,
                **kwargs)

            if self.federated_only:
                try:
                    derived_federated_address = self.derive_federated_address()
                except NoSigningPower:
                    # TODO: Why allow such a character (without signing power) to be created at all?
                    derived_federated_address = NO_SIGNING_POWER.bool_value(
                        False)

                if checksum_address and (checksum_address !=
                                         derived_federated_address):
                    raise ValueError(
                        f"Provided checksum address {checksum_address} "
                        f"does not match federated character's verifying key {derived_federated_address}"
                    )
                checksum_address = derived_federated_address

            self.checksum_address = checksum_address

        #
        # Stranger
        #

        else:
            if network_middleware is not None:
                raise TypeError(
                    "Network middleware cannot be attached to a Stranger-Character."
                )

            if registry is not None:
                raise TypeError(
                    "Registry cannot be attached to stranger-Characters.")

            verifying_key = self.public_keys(SigningPower)
            self._stamp = StrangerStamp(verifying_key)
            self.keystore_dir = STRANGER
            self.network_middleware = STRANGER
            self.checksum_address = checksum_address

        self.__setup_nickname(is_me=is_me)

        # Character Control
        # TODO: have argument about meaning of 'lawful' and whether maybe only Lawful characters have an interface
        if hasattr(self, '_interface_class'):
            # Controller Interface
            self.interface = self._interface_class(character=self)
        self.controller = NO_CONTROL_PROTOCOL