Smoothing over auto-ip detection

pull/1040/head
Kieran R. Prasch 2019-05-15 19:04:29 -06:00 committed by Kieran Prasch
parent 64742d2bc6
commit af812be748
No known key found for this signature in database
GPG Key ID: 199AB839D4125A62
5 changed files with 91 additions and 92 deletions

View File

@ -84,6 +84,7 @@ class EthereumContractRegistry:
raise cls.RegistryError(f"Failed to fetch registry from {github_endpoint} with status code {response.status_code} ")
filepath = filepath or cls._default_registry_filepath
# TODO : Use envvar for config root and registry path
try:
with open(filepath, 'wb') as registry_file: # TODO: Skip re-write if already up to date
registry_file.write(response.content)

View File

@ -27,6 +27,7 @@ from typing import List
from nucypher.characters.lawful import Ursula
from nucypher.cli.config import NucypherClickConfig
from nucypher.cli.types import IPV4_ADDRESS
from nucypher.config.constants import DEFAULT_CONFIG_ROOT, USER_LOG_DIR
from nucypher.network.middleware import RestMiddleware
from nucypher.network.teachers import TEACHER_NODES
@ -55,6 +56,10 @@ LOG = Logger('cli.actions')
console_emitter = NucypherClickConfig.emit
class UnknownIPAddress(RuntimeError):
pass
def load_seednodes(min_stake: int,
federated_only: bool,
network_domain: str,
@ -105,31 +110,48 @@ def destroy_configuration_root(config_root=None, force=False, logs: bool = False
return config_root
def get_external_ip():
def get_external_ip_from_centralized_source():
ip_request = requests.get('https://ifconfig.me/')
if ip_request.status_code == 200:
return ip_request.text
return None
raise UnknownIPAddress(f"There was an error determining the IP address automatically. (status code {ip_request.status_code})")
def determine_external_ip_address(force: bool = False) -> str:
try:
rest_host = get_external_ip_from_centralized_source()
except UnknownIPAddress:
if force:
raise
else:
# Interactive
if not force:
if not click.confirm(f"Is this the public-facing IPv4 address ({rest_host}) you want to use for Ursula?"):
rest_host = click.prompt("Please enter Ursula's public-facing IPv4 address here:", type=IPV4_ADDRESS)
else:
console_emitter(message=f"WARNING: --force is set, using auto-detected IP '{rest_host}'", color='yellow')
return rest_host
def destroy_configuration(character_config, force: bool = False) -> None:
if not force:
click.confirm(CHARACTER_DESTRUCTION.format(name=character_config._NAME,
root=character_config.config_root), abort=True)
if not force:
click.confirm(CHARACTER_DESTRUCTION.format(name=character_config._NAME,
root=character_config.config_root), abort=True)
try:
character_config.destroy()
try:
character_config.destroy()
except FileNotFoundError:
message = 'Failed: No nucypher files found at {}'.format(character_config.config_root)
console_emitter(message=message, color='red')
character_config.log.debug(message)
raise click.Abort()
else:
message = "Deleted configuration files at {}".format(character_config.config_root)
console_emitter(message=message, color='green')
character_config.log.debug(message)
except FileNotFoundError:
message = 'Failed: No nucypher files found at {}'.format(character_config.config_root)
console_emitter(message=message, color='red')
character_config.log.debug(message)
raise click.Abort()
else:
message = "Deleted configuration files at {}".format(character_config.config_root)
console_emitter(message=message, color='green')
character_config.log.debug(message)
def forget(configuration):

View File

@ -27,6 +27,7 @@ from nucypher.blockchain.eth.clients import NuCypherGethDevnetProcess
from nucypher.blockchain.eth.token import NU
from nucypher.characters.banners import URSULA_BANNER
from nucypher.cli import actions, painting
from nucypher.cli.actions import UnknownIPAddress
from nucypher.cli.config import nucypher_click_config
from nucypher.cli.processes import UrsulaCommandProtocol
from nucypher.cli.types import (
@ -35,8 +36,8 @@ from nucypher.cli.types import (
EXISTING_READABLE_FILE,
STAKE_DURATION,
STAKE_EXTENSION,
STAKE_VALUE
)
STAKE_VALUE,
IPV4_ADDRESS)
from nucypher.config.characters import UrsulaConfiguration
from nucypher.utilities.sandbox.constants import (
TEMPORARY_DOMAIN,
@ -170,25 +171,7 @@ def ursula(click_config,
# Attempts to automatically get the external IP from ifconfig.me
# If the request fails, it falls back to the standard process.
if not rest_host:
rest_host = actions.get_external_ip()
if rest_host is None and force:
raise RuntimeError(f"There was an error determining the IP address automatically.")
else:
is_valid_address = False
if rest_host is not None and not force:
is_valid_address = click.confirm(f"Is this the public-facing IPv4 address ({rest_host}) you want to use for Ursula?")
if not is_valid_address:
rest_host = click.prompt("Please enter Ursula's public-facing IPv4 address here:")
# Validate the IPv4 address
try:
socket.inet_aton(rest_host)
if force:
click_config.emit(message=f"WARNING: --force is set, using IP {rest_host}", color='yellow')
except OSError:
raise ValueError("The IP address {rest_host} is not a valid IPv4 address.")
rest_host = actions.determine_external_ip_address(force=force)
new_password = click_config.get_password(confirm=True)

View File

@ -640,13 +640,15 @@ class NodeConfiguration(ABC):
*args, **kwargs)
def write_keyring(self, password: str, **generation_kwargs) -> NucypherKeyring:
#
# Decentralized
#
# Note: It is assumed the blockchain is not yet available.
if not self.federated_only and not self.checksum_public_address:
#
# Integrated Provider Process
#
# "Casual Geth"
if self.provider_process:
if not os.path.exists(self.provider_process.data_dir):

View File

@ -23,6 +23,7 @@ from twisted.internet import threads
from nucypher.characters.base import Learner
from nucypher.cli import actions
from nucypher.cli.actions import UnknownIPAddress
from nucypher.cli.main import nucypher_cli
from nucypher.config.node import NodeConfiguration
from nucypher.utilities.sandbox.constants import (
@ -119,63 +120,53 @@ def test_ursula_cannot_init_with_dev_flag(click_runner):
def test_ursula_rest_host_determination(click_runner):
# Patch the get_external_ip call
original_call = actions.get_external_ip
actions.get_external_ip = lambda: '192.0.2.0'
original_call = actions.get_external_ip_from_centralized_source
try:
actions.get_external_ip_from_centralized_source = lambda: '192.0.2.0'
args = ('ursula', 'init',
'--federated-only',
'--network', TEMPORARY_DOMAIN
)
args = ('ursula', 'init',
'--federated-only',
'--network', TEMPORARY_DOMAIN
)
user_input = f'Y\n{INSECURE_DEVELOPMENT_PASSWORD}\n{INSECURE_DEVELOPMENT_PASSWORD}'
user_input = f'Y\n{INSECURE_DEVELOPMENT_PASSWORD}\n{INSECURE_DEVELOPMENT_PASSWORD}'
result = click_runner.invoke(nucypher_cli, args, catch_exceptions=False,
input=user_input)
assert result.exit_code == 0
assert '(192.0.2.0)' in result.output
args = ('ursula', 'init',
'--federated-only',
'--network', TEMPORARY_DOMAIN,
'--force'
)
user_input = f'{INSECURE_DEVELOPMENT_PASSWORD}\n{INSECURE_DEVELOPMENT_PASSWORD}\n'
result = click_runner.invoke(nucypher_cli, args, catch_exceptions=False,
input=user_input)
assert result.exit_code == 0
assert 'IP 192.0.2.0' in result.output
# Patch get_external_ip call to error output
actions.get_external_ip = lambda: None
args = ('ursula', 'init',
'--federated-only',
'--network', TEMPORARY_DOMAIN,
'--force'
)
user_input = f'{INSECURE_DEVELOPMENT_PASSWORD}\n{INSECURE_DEVELOPMENT_PASSWORD}\n'
with pytest.raises(RuntimeError):
result = click_runner.invoke(nucypher_cli, args, catch_exceptions=True,
result = click_runner.invoke(nucypher_cli, args, catch_exceptions=False,
input=user_input)
# Patch get_external_ip call to return bad IP
actions.get_external_ip = lambda: '382.328.382.328'
assert result.exit_code == 0
assert '(192.0.2.0)' in result.output
args = ('ursula', 'init',
'--federated-only',
'--network', TEMPORARY_DOMAIN,
'--force'
)
args = ('ursula', 'init',
'--federated-only',
'--network', TEMPORARY_DOMAIN,
'--force'
)
user_input = f'{INSECURE_DEVELOPMENT_PASSWORD}\n{INSECURE_DEVELOPMENT_PASSWORD}\n'
with pytest.raises(OSError):
result = click_runner.invoke(nucypher_cli, args, catch_exceptions=True,
user_input = f'{INSECURE_DEVELOPMENT_PASSWORD}\n{INSECURE_DEVELOPMENT_PASSWORD}\n'
result = click_runner.invoke(nucypher_cli, args, catch_exceptions=False,
input=user_input)
# Unpatch call
actions.get_external_ip = original_call
assert result.exit_code == 0
assert '192.0.2.0' in result.output
# Patch get_external_ip call to error output
def amazing_ip_oracle():
raise UnknownIPAddress
actions.get_external_ip_from_centralized_source = amazing_ip_oracle()
args = ('ursula', 'init',
'--federated-only',
'--network', TEMPORARY_DOMAIN,
'--force'
)
user_input = f'{INSECURE_DEVELOPMENT_PASSWORD}\n{INSECURE_DEVELOPMENT_PASSWORD}\n'
with pytest.raises(UnknownIPAddress):
_result = click_runner.invoke(nucypher_cli, args, catch_exceptions=True, input=user_input)
finally:
# Unpatch call
actions.get_external_ip_from_centralized_source = original_call