mirror of https://github.com/nucypher/nucypher.git
Prevent reserved or invalid IP addresses from being used to run Ursula.
parent
3e76547af1
commit
424e373a21
|
@ -104,6 +104,8 @@ class Character(Learner):
|
||||||
|
|
||||||
#
|
#
|
||||||
# Operating Mode
|
# Operating Mode
|
||||||
|
#
|
||||||
|
|
||||||
if hasattr(self, '_interface_class'): # TODO: have argument about meaning of 'lawful'
|
if hasattr(self, '_interface_class'): # TODO: have argument about meaning of 'lawful'
|
||||||
# and whether maybe only Lawful characters have an interface
|
# and whether maybe only Lawful characters have an interface
|
||||||
self.interface = self._interface_class(character=self)
|
self.interface = self._interface_class(character=self)
|
||||||
|
|
|
@ -17,7 +17,7 @@ along with nucypher. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
import json
|
import json
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict, defaultdict
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import maya
|
import maya
|
||||||
|
@ -39,7 +39,6 @@ from constant_sorrow.constants import (
|
||||||
READY,
|
READY,
|
||||||
INVALIDATED
|
INVALIDATED
|
||||||
)
|
)
|
||||||
from collections import OrderedDict, defaultdict
|
|
||||||
from cryptography.hazmat.backends import default_backend
|
from cryptography.hazmat.backends import default_backend
|
||||||
from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurve
|
from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurve
|
||||||
from cryptography.hazmat.primitives.serialization import Encoding
|
from cryptography.hazmat.primitives.serialization import Encoding
|
||||||
|
@ -59,7 +58,6 @@ from typing import Dict, Iterable, List, Tuple, Union, Optional, Sequence, Set
|
||||||
from umbral import pre
|
from umbral import pre
|
||||||
from umbral.keys import UmbralPublicKey
|
from umbral.keys import UmbralPublicKey
|
||||||
from umbral.kfrags import KFrag
|
from umbral.kfrags import KFrag
|
||||||
from umbral.pre import UmbralCorrectnessError
|
|
||||||
from umbral.signing import Signature
|
from umbral.signing import Signature
|
||||||
|
|
||||||
import nucypher
|
import nucypher
|
||||||
|
@ -101,6 +99,7 @@ from nucypher.network.protocols import InterfaceInfo, parse_node_uri
|
||||||
from nucypher.network.server import ProxyRESTServer, TLSHostingPower, make_rest_app
|
from nucypher.network.server import ProxyRESTServer, TLSHostingPower, make_rest_app
|
||||||
from nucypher.network.trackers import AvailabilityTracker
|
from nucypher.network.trackers import AvailabilityTracker
|
||||||
from nucypher.utilities.logging import Logger
|
from nucypher.utilities.logging import Logger
|
||||||
|
from nucypher.utilities.networking import validate_worker_ip
|
||||||
|
|
||||||
|
|
||||||
class Alice(Character, BlockchainPolicyAuthor):
|
class Alice(Character, BlockchainPolicyAuthor):
|
||||||
|
@ -1258,9 +1257,13 @@ class Ursula(Teacher, Character, Worker):
|
||||||
if result > 0:
|
if result > 0:
|
||||||
self.log.debug(f"Pruned {result} treasure maps.")
|
self.log.debug(f"Pruned {result} treasure maps.")
|
||||||
|
|
||||||
|
def __preflight(self) -> None:
|
||||||
|
"""Called immediately before running services"""
|
||||||
|
validate_worker_ip(worker_ip=self.rest_interface.host)
|
||||||
|
|
||||||
def run(self,
|
def run(self,
|
||||||
emitter: StdoutEmitter = None,
|
emitter: StdoutEmitter = None,
|
||||||
discovery: bool = True,
|
discovery: bool = True, # TODO: see below
|
||||||
availability: bool = True,
|
availability: bool = True,
|
||||||
worker: bool = True,
|
worker: bool = True,
|
||||||
pruning: bool = True,
|
pruning: bool = True,
|
||||||
|
@ -1272,6 +1275,8 @@ class Ursula(Teacher, Character, Worker):
|
||||||
|
|
||||||
"""Schedule and start select ursula services, then optionally start the reactor."""
|
"""Schedule and start select ursula services, then optionally start the reactor."""
|
||||||
|
|
||||||
|
self.__preflight()
|
||||||
|
|
||||||
#
|
#
|
||||||
# Async loops ordered by schedule priority
|
# Async loops ordered by schedule priority
|
||||||
#
|
#
|
||||||
|
|
|
@ -37,10 +37,11 @@ from nucypher.cli.literature import (
|
||||||
COLLECT_URSULA_IPV4_ADDRESS,
|
COLLECT_URSULA_IPV4_ADDRESS,
|
||||||
CONFIRM_URSULA_IPV4_ADDRESS
|
CONFIRM_URSULA_IPV4_ADDRESS
|
||||||
)
|
)
|
||||||
from nucypher.cli.types import IPV4_ADDRESS
|
from nucypher.cli.types import IPV4_ADDRESS, WORKER_IP
|
||||||
from nucypher.config.characters import StakeHolderConfiguration
|
from nucypher.config.characters import StakeHolderConfiguration
|
||||||
from nucypher.config.constants import NUCYPHER_ENVVAR_WORKER_IP_ADDRESS
|
from nucypher.config.constants import NUCYPHER_ENVVAR_WORKER_IP_ADDRESS
|
||||||
from nucypher.config.node import CharacterConfiguration
|
from nucypher.config.node import CharacterConfiguration
|
||||||
|
from nucypher.utilities.networking import InvalidWorkerIP, validate_worker_ip
|
||||||
from nucypher.utilities.networking import determine_external_ip_address, UnknownIPAddress
|
from nucypher.utilities.networking import determine_external_ip_address, UnknownIPAddress
|
||||||
|
|
||||||
|
|
||||||
|
@ -119,12 +120,12 @@ def handle_invalid_configuration_file(emitter: StdoutEmitter,
|
||||||
raise # crash :-(
|
raise # crash :-(
|
||||||
|
|
||||||
|
|
||||||
def collect_external_ip_address(emitter: StdoutEmitter, network: str, force: bool = False) -> str:
|
def collect_worker_ip_address(emitter: StdoutEmitter, network: str, force: bool = False) -> str:
|
||||||
|
|
||||||
# From environment variable # TODO: remove this environment variable?
|
# From environment variable # TODO: remove this environment variable?
|
||||||
ip = os.environ.get(NUCYPHER_ENVVAR_WORKER_IP_ADDRESS)
|
ip = os.environ.get(NUCYPHER_ENVVAR_WORKER_IP_ADDRESS)
|
||||||
if ip:
|
if ip:
|
||||||
message = f'Using IP address from {NUCYPHER_ENVVAR_WORKER_IP_ADDRESS} environment variable'
|
message = f'Using IP address ({ip}) from {NUCYPHER_ENVVAR_WORKER_IP_ADDRESS} environment variable'
|
||||||
emitter.message(message, verbosity=2)
|
emitter.message(message, verbosity=2)
|
||||||
return ip
|
return ip
|
||||||
|
|
||||||
|
@ -141,8 +142,9 @@ def collect_external_ip_address(emitter: StdoutEmitter, network: str, force: boo
|
||||||
# Confirmation
|
# Confirmation
|
||||||
if not force:
|
if not force:
|
||||||
if not click.confirm(CONFIRM_URSULA_IPV4_ADDRESS.format(rest_host=ip)):
|
if not click.confirm(CONFIRM_URSULA_IPV4_ADDRESS.format(rest_host=ip)):
|
||||||
ip = click.prompt(COLLECT_URSULA_IPV4_ADDRESS, type=IPV4_ADDRESS)
|
ip = click.prompt(COLLECT_URSULA_IPV4_ADDRESS, type=WORKER_IP)
|
||||||
|
|
||||||
|
validate_worker_ip(worker_ip=ip)
|
||||||
return ip
|
return ip
|
||||||
|
|
||||||
|
|
||||||
|
@ -157,7 +159,17 @@ def perform_ip_checkup(emitter: StdoutEmitter, ursula: Ursula, force: bool = Fal
|
||||||
message = 'Cannot automatically determine external IP address'
|
message = 'Cannot automatically determine external IP address'
|
||||||
emitter.message(message)
|
emitter.message(message)
|
||||||
return # TODO: crash, or not to crash... that is the question
|
return # TODO: crash, or not to crash... that is the question
|
||||||
ip_mismatch = external_ip != ursula.rest_interface.host
|
rest_host = ursula.rest_interface.host
|
||||||
|
try:
|
||||||
|
validate_worker_ip(worker_ip=rest_host)
|
||||||
|
except InvalidWorkerIP:
|
||||||
|
message = f'{rest_host} is not a valid or permitted worker IP address. Set the correct external IP then try again\n' \
|
||||||
|
f'automatic configuration -> nucypher ursula config ip-address\n' \
|
||||||
|
f'manual configuration -> nucypher ursula config --rest-host <IP ADDRESS>'
|
||||||
|
emitter.message(message)
|
||||||
|
return
|
||||||
|
|
||||||
|
ip_mismatch = external_ip != rest_host
|
||||||
if ip_mismatch and not force:
|
if ip_mismatch and not force:
|
||||||
error = f'\nX External IP address ({external_ip}) does not match configuration ({ursula.rest_interface.host}).\n'
|
error = f'\nX External IP address ({external_ip}) does not match configuration ({ursula.rest_interface.host}).\n'
|
||||||
hint = f"Run 'nucypher ursula config ip-address' to reconfigure the IP address then try " \
|
hint = f"Run 'nucypher ursula config ip-address' to reconfigure the IP address then try " \
|
||||||
|
|
|
@ -18,12 +18,14 @@
|
||||||
|
|
||||||
import click
|
import click
|
||||||
|
|
||||||
|
from nucypher.blockchain.eth.networks import NetworksInventory
|
||||||
from nucypher.blockchain.eth.signers.software import ClefSigner
|
from nucypher.blockchain.eth.signers.software import ClefSigner
|
||||||
from nucypher.cli.actions.auth import get_client_password, get_nucypher_password
|
from nucypher.cli.actions.auth import get_client_password, get_nucypher_password
|
||||||
from nucypher.cli.actions.configure import (
|
from nucypher.cli.actions.configure import (
|
||||||
destroy_configuration,
|
destroy_configuration,
|
||||||
handle_missing_configuration_file,
|
handle_missing_configuration_file,
|
||||||
get_or_update_configuration, collect_external_ip_address
|
get_or_update_configuration,
|
||||||
|
collect_worker_ip_address
|
||||||
)
|
)
|
||||||
from nucypher.cli.actions.configure import forget as forget_nodes, perform_ip_checkup
|
from nucypher.cli.actions.configure import forget as forget_nodes, perform_ip_checkup
|
||||||
from nucypher.cli.actions.select import (
|
from nucypher.cli.actions.select import (
|
||||||
|
@ -59,7 +61,7 @@ from nucypher.cli.options import (
|
||||||
option_max_gas_price
|
option_max_gas_price
|
||||||
)
|
)
|
||||||
from nucypher.cli.painting.help import paint_new_installation_help
|
from nucypher.cli.painting.help import paint_new_installation_help
|
||||||
from nucypher.cli.types import EIP55_CHECKSUM_ADDRESS, NETWORK_PORT
|
from nucypher.cli.types import EIP55_CHECKSUM_ADDRESS, NETWORK_PORT, WORKER_IP
|
||||||
from nucypher.cli.utils import make_cli_character, setup_emitter
|
from nucypher.cli.utils import make_cli_character, setup_emitter
|
||||||
from nucypher.config.characters import UrsulaConfiguration
|
from nucypher.config.characters import UrsulaConfiguration
|
||||||
from nucypher.config.constants import (
|
from nucypher.config.constants import (
|
||||||
|
@ -176,7 +178,7 @@ class UrsulaConfigOptions:
|
||||||
|
|
||||||
# Resolve rest host
|
# Resolve rest host
|
||||||
if not self.rest_host:
|
if not self.rest_host:
|
||||||
self.rest_host = collect_external_ip_address(emitter, network=self.domain, force=force)
|
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(confirm=True),
|
||||||
config_root=config_root,
|
config_root=config_root,
|
||||||
|
@ -223,10 +225,10 @@ group_config_options = group_options(
|
||||||
max_gas_price=option_max_gas_price,
|
max_gas_price=option_max_gas_price,
|
||||||
worker_address=click.option('--worker-address', help="Run the worker-ursula with a specified address", type=EIP55_CHECKSUM_ADDRESS),
|
worker_address=click.option('--worker-address', help="Run the worker-ursula with a specified address", type=EIP55_CHECKSUM_ADDRESS),
|
||||||
federated_only=option_federated_only,
|
federated_only=option_federated_only,
|
||||||
rest_host=click.option('--rest-host', help="The host IP address to run Ursula network services on", type=click.STRING),
|
rest_host=click.option('--rest-host', help="The host IP address to run Ursula network services on", type=WORKER_IP),
|
||||||
rest_port=click.option('--rest-port', help="The host port to run Ursula network services on", type=NETWORK_PORT),
|
rest_port=click.option('--rest-port', help="The host port to run Ursula network services on", type=NETWORK_PORT),
|
||||||
db_filepath=option_db_filepath,
|
db_filepath=option_db_filepath,
|
||||||
network=option_network(),
|
network=option_network(default=NetworksInventory.DEFAULT),
|
||||||
registry_filepath=option_registry_filepath,
|
registry_filepath=option_registry_filepath,
|
||||||
poa=option_poa,
|
poa=option_poa,
|
||||||
light=option_light,
|
light=option_light,
|
||||||
|
@ -422,7 +424,7 @@ def config(general_config, config_options, config_file, force, action):
|
||||||
checksum_address=config_options.worker_address,
|
checksum_address=config_options.worker_address,
|
||||||
config_class=UrsulaConfiguration)
|
config_class=UrsulaConfiguration)
|
||||||
if action == 'ip-address':
|
if action == 'ip-address':
|
||||||
rest_host = collect_external_ip_address(emitter=emitter, network=config_options.domain, force=force)
|
rest_host = collect_worker_ip_address(emitter=emitter, network=config_options.domain, force=force)
|
||||||
config_options.rest_host = rest_host
|
config_options.rest_host = rest_host
|
||||||
updates = config_options.get_updates()
|
updates = config_options.get_updates()
|
||||||
get_or_update_configuration(emitter=emitter,
|
get_or_update_configuration(emitter=emitter,
|
||||||
|
|
|
@ -377,7 +377,7 @@ DECRYPTING_CHARACTER_KEYRING = 'Authenticating {name}'
|
||||||
|
|
||||||
CONFIRM_URSULA_IPV4_ADDRESS = "Detected IPv4 address ({rest_host}) - Is this the public-facing address of Ursula?"
|
CONFIRM_URSULA_IPV4_ADDRESS = "Detected IPv4 address ({rest_host}) - Is this the public-facing address of Ursula?"
|
||||||
|
|
||||||
COLLECT_URSULA_IPV4_ADDRESS = "Enter Ursula's public-facing IPv4 address:"
|
COLLECT_URSULA_IPV4_ADDRESS = "Enter Ursula's public-facing IPv4 address"
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -26,6 +26,7 @@ from nucypher.blockchain.economics import StandardTokenEconomics
|
||||||
from nucypher.blockchain.eth.interfaces import BlockchainInterface
|
from nucypher.blockchain.eth.interfaces import BlockchainInterface
|
||||||
from nucypher.blockchain.eth.networks import NetworksInventory
|
from nucypher.blockchain.eth.networks import NetworksInventory
|
||||||
from nucypher.blockchain.eth.token import NU
|
from nucypher.blockchain.eth.token import NU
|
||||||
|
from nucypher.utilities.networking import validate_worker_ip, InvalidWorkerIP
|
||||||
|
|
||||||
|
|
||||||
class ChecksumAddress(click.ParamType):
|
class ChecksumAddress(click.ParamType):
|
||||||
|
@ -46,12 +47,24 @@ class IPv4Address(click.ParamType):
|
||||||
def convert(self, value, param, ctx):
|
def convert(self, value, param, ctx):
|
||||||
try:
|
try:
|
||||||
_address = ip_address(value)
|
_address = ip_address(value)
|
||||||
except ValueError as e:
|
except ValueError:
|
||||||
self.fail("Invalid IP Address")
|
self.fail("Invalid IP Address")
|
||||||
else:
|
else:
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
class WorkerIPAddress(IPv4Address):
|
||||||
|
name = 'worker_ip'
|
||||||
|
|
||||||
|
def convert(self, value, param, ctx):
|
||||||
|
_ip = super().convert(value, param, ctx)
|
||||||
|
try:
|
||||||
|
validate_worker_ip(worker_ip=_ip)
|
||||||
|
except InvalidWorkerIP as e:
|
||||||
|
self.fail(str(e))
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
class DecimalType(click.ParamType):
|
class DecimalType(click.ParamType):
|
||||||
name = 'decimal'
|
name = 'decimal'
|
||||||
|
|
||||||
|
@ -136,6 +149,7 @@ EXISTING_READABLE_FILE = click.Path(exists=True, dir_okay=False, file_okay=True,
|
||||||
# Network
|
# Network
|
||||||
NETWORK_PORT = click.IntRange(min=0, max=65535, clamp=False)
|
NETWORK_PORT = click.IntRange(min=0, max=65535, clamp=False)
|
||||||
IPV4_ADDRESS = IPv4Address()
|
IPV4_ADDRESS = IPv4Address()
|
||||||
|
WORKER_IP = WorkerIPAddress()
|
||||||
|
|
||||||
GAS_STRATEGY_CHOICES = click.Choice(list(BlockchainInterface.GAS_STRATEGIES.keys()))
|
GAS_STRATEGY_CHOICES = click.Choice(list(BlockchainInterface.GAS_STRATEGIES.keys()))
|
||||||
UMBRAL_PUBLIC_KEY_HEX = UmbralPublicKeyHex()
|
UMBRAL_PUBLIC_KEY_HEX = UmbralPublicKeyHex()
|
||||||
|
|
|
@ -39,7 +39,6 @@ class UrsulaConfiguration(CharacterConfiguration):
|
||||||
CHARACTER_CLASS = Ursula
|
CHARACTER_CLASS = Ursula
|
||||||
NAME = CHARACTER_CLASS.__name__.lower()
|
NAME = CHARACTER_CLASS.__name__.lower()
|
||||||
|
|
||||||
DEFAULT_REST_HOST = '127.0.0.1'
|
|
||||||
DEFAULT_REST_PORT = 9151
|
DEFAULT_REST_PORT = 9151
|
||||||
DEFAULT_DEVELOPMENT_REST_PORT = 10151
|
DEFAULT_DEVELOPMENT_REST_PORT = 10151
|
||||||
__DEFAULT_TLS_CURVE = ec.SECP384R1
|
__DEFAULT_TLS_CURVE = ec.SECP384R1
|
||||||
|
@ -48,10 +47,10 @@ class UrsulaConfiguration(CharacterConfiguration):
|
||||||
LOCAL_SIGNERS_ALLOWED = True
|
LOCAL_SIGNERS_ALLOWED = True
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
|
rest_host: str,
|
||||||
worker_address: str = None,
|
worker_address: str = None,
|
||||||
dev_mode: bool = False,
|
dev_mode: bool = False,
|
||||||
db_filepath: str = None,
|
db_filepath: str = None,
|
||||||
rest_host: str = None,
|
|
||||||
rest_port: int = None,
|
rest_port: int = None,
|
||||||
tls_curve: EllipticCurve = None,
|
tls_curve: EllipticCurve = None,
|
||||||
certificate: Certificate = None,
|
certificate: Certificate = None,
|
||||||
|
@ -64,7 +63,7 @@ class UrsulaConfiguration(CharacterConfiguration):
|
||||||
else:
|
else:
|
||||||
rest_port = self.DEFAULT_REST_PORT
|
rest_port = self.DEFAULT_REST_PORT
|
||||||
self.rest_port = rest_port
|
self.rest_port = rest_port
|
||||||
self.rest_host = rest_host or self.DEFAULT_REST_HOST
|
self.rest_host = rest_host
|
||||||
self.tls_curve = tls_curve or self.__DEFAULT_TLS_CURVE
|
self.tls_curve = tls_curve or self.__DEFAULT_TLS_CURVE
|
||||||
self.certificate = certificate
|
self.certificate = certificate
|
||||||
self.db_filepath = db_filepath or UNINITIALIZED_CONFIGURATION
|
self.db_filepath = db_filepath or UNINITIALIZED_CONFIGURATION
|
||||||
|
|
|
@ -245,8 +245,7 @@ class Learner:
|
||||||
|
|
||||||
from nucypher.characters.lawful import Ursula
|
from nucypher.characters.lawful import Ursula
|
||||||
self.node_class = node_class or Ursula
|
self.node_class = node_class or Ursula
|
||||||
self.node_class.set_cert_storage_function(
|
self.node_class.set_cert_storage_function(node_storage.store_node_certificate) # TODO: Fix this temporary workaround for on-disk cert storage. #1481
|
||||||
node_storage.store_node_certificate) # TODO: Fix this temporary workaround for on-disk cert storage. #1481
|
|
||||||
|
|
||||||
known_nodes = known_nodes or tuple()
|
known_nodes = known_nodes or tuple()
|
||||||
self.unresponsive_startup_nodes = list() # TODO: Buckets - Attempt to use these again later #567
|
self.unresponsive_startup_nodes = list() # TODO: Buckets - Attempt to use these again later #567
|
||||||
|
|
|
@ -16,16 +16,15 @@
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
from ipaddress import ip_address
|
|
||||||
|
|
||||||
import random
|
import random
|
||||||
import requests
|
import requests
|
||||||
|
from ipaddress import ip_address
|
||||||
from requests.exceptions import RequestException, HTTPError
|
from requests.exceptions import RequestException, HTTPError
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
from nucypher.blockchain.eth.registry import BaseContractRegistry, InMemoryContractRegistry
|
from nucypher.config.storages import LocalFileBasedNodeStorage
|
||||||
from nucypher.acumen.perception import FleetSensor
|
from nucypher.acumen.perception import FleetSensor
|
||||||
from nucypher.characters.lawful import Ursula
|
from nucypher.blockchain.eth.registry import BaseContractRegistry, InMemoryContractRegistry
|
||||||
from nucypher.network.middleware import RestMiddleware, NucypherMiddlewareClient
|
from nucypher.network.middleware import RestMiddleware, NucypherMiddlewareClient
|
||||||
from nucypher.utilities.logging import Logger
|
from nucypher.utilities.logging import Logger
|
||||||
|
|
||||||
|
@ -34,6 +33,10 @@ class UnknownIPAddress(RuntimeError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidWorkerIP(RuntimeError):
|
||||||
|
"""Raised when an Ursula is using an invalid IP address for it's server."""
|
||||||
|
|
||||||
|
|
||||||
RequestErrors = (
|
RequestErrors = (
|
||||||
# https://requests.readthedocs.io/en/latest/user/quickstart/#errors-and-exceptions
|
# https://requests.readthedocs.io/en/latest/user/quickstart/#errors-and-exceptions
|
||||||
ConnectionError,
|
ConnectionError,
|
||||||
|
@ -42,9 +45,22 @@ RequestErrors = (
|
||||||
HTTPError
|
HTTPError
|
||||||
)
|
)
|
||||||
|
|
||||||
|
RESERVED_IP_ADDRESSES = (
|
||||||
|
'0.0.0.0',
|
||||||
|
'127.0.0.1',
|
||||||
|
'1.2.3.4'
|
||||||
|
)
|
||||||
|
|
||||||
IP_DETECTION_LOGGER = Logger('external-ip-detection')
|
IP_DETECTION_LOGGER = Logger('external-ip-detection')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def validate_worker_ip(worker_ip: str) -> None:
|
||||||
|
if worker_ip in RESERVED_IP_ADDRESSES:
|
||||||
|
raise InvalidWorkerIP(f'{worker_ip} is not a valid or permitted worker IP address. '
|
||||||
|
f'Verify the rest_host is set to the external IPV4 address')
|
||||||
|
|
||||||
|
|
||||||
def __request(url: str, certificate=None) -> Union[str, None]:
|
def __request(url: str, certificate=None) -> Union[str, None]:
|
||||||
"""
|
"""
|
||||||
Utility function to send a GET request to a URL returning it's
|
Utility function to send a GET request to a URL returning it's
|
||||||
|
@ -65,6 +81,8 @@ def get_external_ip_from_default_teacher(network: str,
|
||||||
log: Logger = IP_DETECTION_LOGGER,
|
log: Logger = IP_DETECTION_LOGGER,
|
||||||
registry: BaseContractRegistry = None
|
registry: BaseContractRegistry = None
|
||||||
) -> Union[str, None]:
|
) -> Union[str, None]:
|
||||||
|
from nucypher.characters.lawful import Ursula
|
||||||
|
|
||||||
if federated_only and registry:
|
if federated_only and registry:
|
||||||
raise ValueError('Federated mode must not be true if registry is provided.')
|
raise ValueError('Federated mode must not be true if registry is provided.')
|
||||||
base_error = 'Cannot determine IP using default teacher'
|
base_error = 'Cannot determine IP using default teacher'
|
||||||
|
@ -76,13 +94,19 @@ def get_external_ip_from_default_teacher(network: str,
|
||||||
except KeyError:
|
except KeyError:
|
||||||
log.debug(f'{base_error}: Unknown network "{network}".')
|
log.debug(f'{base_error}: Unknown network "{network}".')
|
||||||
return
|
return
|
||||||
if not registry:
|
|
||||||
# Registry is needed to perform on-chain staking verification.
|
####
|
||||||
registry = InMemoryContractRegistry.from_latest_publication(network=network)
|
# TODO: Clean this mess #1481
|
||||||
|
node_storage = LocalFileBasedNodeStorage(federated_only=federated_only)
|
||||||
|
Ursula.set_cert_storage_function(node_storage.store_node_certificate)
|
||||||
|
Ursula.set_federated_mode(federated_only)
|
||||||
|
#####
|
||||||
|
|
||||||
teacher = Ursula.from_teacher_uri(teacher_uri=top_teacher_url,
|
teacher = Ursula.from_teacher_uri(teacher_uri=top_teacher_url,
|
||||||
registry=registry,
|
|
||||||
federated_only=federated_only,
|
federated_only=federated_only,
|
||||||
min_stake=0) # TODO: Handle customized min stake here.
|
min_stake=0) # TODO: Handle customized min stake here.
|
||||||
|
|
||||||
|
# TODO: Pass registry here to verify stake (not essential here since it's a hardcoded node)
|
||||||
client = NucypherMiddlewareClient()
|
client = NucypherMiddlewareClient()
|
||||||
try:
|
try:
|
||||||
response = client.get(node_or_sprout=teacher, path=f"ping", timeout=2) # TLS certificate logic within
|
response = client.get(node_or_sprout=teacher, path=f"ping", timeout=2) # TLS certificate logic within
|
||||||
|
@ -97,6 +121,8 @@ def get_external_ip_from_default_teacher(network: str,
|
||||||
raise UnknownIPAddress(error)
|
raise UnknownIPAddress(error)
|
||||||
log.info(f'Fetched external IP address from default teacher ({top_teacher_url} reported {ip}).')
|
log.info(f'Fetched external IP address from default teacher ({top_teacher_url} reported {ip}).')
|
||||||
return ip
|
return ip
|
||||||
|
else:
|
||||||
|
log.debug(f'Failed to get external IP from teacher node ({response.status_code})')
|
||||||
|
|
||||||
|
|
||||||
def get_external_ip_from_known_nodes(known_nodes: FleetSensor,
|
def get_external_ip_from_known_nodes(known_nodes: FleetSensor,
|
||||||
|
|
Loading…
Reference in New Issue