def test_deserialize_ursulas_version_1(): """ DON'T 'FIX' THIS TEST IF FAILING, UNLESS YOU KNOW WHAT YOU'RE DOING. The goal of this test is to show incompatibility of current Discovery Loop version wrt to version 1. See issue #1869 "Test with a hard-coded, versioned node metadata bytestring" https://github.com/nucypher/nucypher/issues/1869 """ expected_version = 1 ursulas_matrix = versioned_ursulas[expected_version] for fossilized_ursula in ursulas_matrix: fossilized_ursula = bytes.fromhex(fossilized_ursula) version, _ = Ursula.version_splitter(fossilized_ursula, return_remainder=True) assert version == expected_version assert version != Ursula.LEARNER_VERSION with pytest.raises(Teacher.AreYouFromThePast, match=f"purported to be of version 1, " f"but we're version {Ursula.LEARNER_VERSION}"): _resurrected_ursula = Ursula.from_bytes(fossilized_ursula, fail_fast=True) assert UNKNOWN_VERSION == Ursula.from_bytes(fossilized_ursula, fail_fast=False)
def from_target_ursula(cls, target_ursula: Ursula, claim_signing_key: bool = False, attach_transacting_key: bool = True ) -> 'Vladimir': """ Sometimes Vladimir seeks to attack or imitate a *specific* target Ursula. TODO: This is probably a more instructive method if it takes a bytes representation instead of the entire Ursula. """ crypto_power = CryptoPower(power_ups=target_ursula._default_crypto_powerups) if claim_signing_key: crypto_power.consume_power_up(SigningPower(pubkey=target_ursula.stamp.as_umbral_pubkey())) if attach_transacting_key: cls.attach_transacting_key(blockchain=target_ursula.blockchain) vladimir = cls(is_me=True, crypto_power=crypto_power, db_filepath=cls.db_filepath, rest_host=target_ursula.rest_information()[0].host, rest_port=target_ursula.rest_information()[0].port, certificate=target_ursula.rest_server_certificate(), network_middleware=cls.network_middleware, checksum_address = cls.fraud_address, ######### Asshole. timestamp=target_ursula._timestamp, interface_signature=target_ursula._interface_signature, ######### ) cls.attach_transacting_key(blockchain=target_ursula.blockchain) return vladimir
def test_refund(click_runner, testerchain, agency_local_registry, token_economics): bidder = testerchain.client.accounts[2] worker_address = testerchain.unassigned_accounts[-1] # # WorkLock Staker-Worker # worklock_agent = ContractAgency.get_agent(WorkLockAgent, registry=agency_local_registry) # Bidder is now STAKER. Bond a worker. staker = Staker(is_me=True, checksum_address=bidder, registry=agency_local_registry) receipt = staker.bond_worker(worker_address=worker_address) assert receipt['status'] == 1 worker = Ursula(is_me=True, registry=agency_local_registry, checksum_address=bidder, worker_address=worker_address, rest_host=MOCK_IP_ADDRESS, rest_port=select_test_port(), db_filepath=tempfile.mkdtemp()) # Ensure there is work to do remaining_work = worklock_agent.get_remaining_work(checksum_address=bidder) assert remaining_work > 0 # Unlock transacting_power = worker._crypto_power.power_ups(TransactingPower) transacting_power.activate(password=INSECURE_DEVELOPMENT_PASSWORD) # Do some work for i in range(3): txhash = worker.commit_to_next_period() testerchain.wait_for_receipt(txhash) assert receipt['status'] == 1 testerchain.time_travel(periods=1) command = ('refund', '--participant-address', bidder, '--registry-filepath', agency_local_registry.filepath, '--provider', TEST_PROVIDER_URI, '--network', TEMPORARY_DOMAIN, '--force') user_input = f'{INSECURE_DEVELOPMENT_PASSWORD}\n' + 'Y\n' result = click_runner.invoke(worklock, command, input=user_input, catch_exceptions=False) assert result.exit_code == 0 # Less work to do... new_remaining_work = worklock_agent.get_remaining_work( checksum_address=bidder) assert new_remaining_work < remaining_work
def test_refund(click_runner, testerchain, agency_local_registry, token_economics): bidder = testerchain.unassigned_accounts[1] worker_address = testerchain.unassigned_accounts[-1] # # WorkLock Staker-Worker # worklock_agent = ContractAgency.get_agent(WorkLockAgent, registry=agency_local_registry) # Bidder is now STAKER. Bond a worker. staker = Staker(is_me=True, checksum_address=bidder, registry=agency_local_registry) receipt = staker.set_worker(worker_address=worker_address) assert receipt['status'] == 1 worker = Ursula(is_me=True, registry=agency_local_registry, checksum_address=bidder, worker_address=worker_address, rest_host=MOCK_IP_ADDRESS, rest_port=select_test_port()) # Ensure there is work to do remaining_work = worklock_agent.get_remaining_work(checksum_address=bidder) assert remaining_work > 0 # Do some work for i in range(3): receipt = worker.confirm_activity() assert receipt['status'] == 1 testerchain.time_travel(periods=1) command = ('refund', '--bidder-address', bidder, '--registry-filepath', agency_local_registry.filepath, '--provider', TEST_PROVIDER_URI, '--poa', '--force') user_input = f'{INSECURE_DEVELOPMENT_PASSWORD}\n' + 'Y\n' result = click_runner.invoke(worklock, command, input=user_input, catch_exceptions=False) assert result.exit_code == 0 # Less work to do... new_remaining_work = worklock_agent.get_remaining_work( checksum_address=bidder) assert new_remaining_work < remaining_work
def get_external_ip_from_default_teacher( network: str, federated_only: bool = False, registry: Optional[BaseContractRegistry] = None, log: Logger = IP_DETECTION_LOGGER) -> Union[str, None]: # Prevents circular imports from nucypher.characters.lawful import Ursula from nucypher.network.nodes import TEACHER_NODES if federated_only and registry: raise ValueError( 'Federated mode must not be true if registry is provided.') base_error = 'Cannot determine IP using default teacher' if network not in TEACHER_NODES: log.debug(f'{base_error}: Unknown network "{network}".') return #### # TODO: Clean this mess #1481 (Federated Mode) node_storage = LocalFileBasedNodeStorage(federated_only=federated_only) Ursula.set_cert_storage_function(node_storage.store_node_certificate) Ursula.set_federated_mode(federated_only) ##### external_ip = None for teacher_uri in TEACHER_NODES[network]: try: teacher = Ursula.from_teacher_uri( teacher_uri=teacher_uri, federated_only=federated_only, 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) external_ip = _request_from_node(teacher=teacher) # Found a reachable teacher, return from loop if external_ip: break except NodeSeemsToBeDown: # Teacher is unreachable, try next one continue if not external_ip: log.debug( f'{base_error}: No teacher available for network "{network}".') return return external_ip
def initialize_bob(bob_privkeys): ursula = Ursula.from_seed_and_stake_info(seed_uri=SEEDNODE_URI, federated_only=True, minimum_stake=0) TEMP_DOCTOR_DIR = "{}/listener-files".format( os.path.dirname(os.path.abspath(__file__))) # Remove previous demo files and create new ones shutil.rmtree(TEMP_DOCTOR_DIR, ignore_errors=True) bob_enc_keypair = DecryptingKeypair(private_key=bob_privkeys["enc"]) bob_sig_keypair = SigningKeypair(private_key=bob_privkeys["sig"]) enc_power = DecryptingPower(keypair=bob_enc_keypair) sig_power = SigningPower(keypair=bob_sig_keypair) power_ups = [enc_power, sig_power] print("Creating the Listener ...") listener = Bob( domains={TEMPORARY_DOMAIN}, federated_only=True, crypto_power_ups=power_ups, start_learning_now=True, abort_on_learning_error=True, known_nodes=[ursula], save_metadata=False, network_middleware=RestMiddleware(), ) print("Listener = ", listener) return listener
def connect(self, nucypher_network, ipfs_api_gateway): """ client = ncipfs.Connect( nucypher_network="localhost:11500", ipfs_api_gateway="localhost:5001" ) """ self.nucypher_network = nucypher_network self.ipfs_api_gateway = ipfs_api_gateway try: self.ipfs_gateway_api = ipfsapi.connect('127.0.0.1', 5001) except Exception as e: # should be more specific ConnectionRefusedError, NewConnectionError, MaxRetryError not sure print("Automatic Mode A Public Gateway will be used as a fallback") self.ipfs_gateway_api = ipfsapi.connect('https://ipfs.infura.io', 5001) # SEEDNODE_URL = self.nucypher_network POLICY_FILENAME = "policy-metadata.json" # # FOR LOCAL RUNNING NET # self.ursula = Ursula.from_seed_and_stake_info( # seed_uri=SEEDNODE_URL, # federated_only=True, # minimum_stake=0 # ) self.ursula =urs = Ursula.from_teacher_uri( teacher_uri=self.nucypher_network, federated_only=True, min_stake=0 ) return True
def _read_and_write_metadata(self, ursula, node_storage): # Write Node node_storage.store_node_metadata(node=ursula) # Read Node node_from_storage = node_storage.get(checksum_address=ursula.checksum_address, federated_only=True) assert ursula == node_from_storage, "Node storage {} failed".format(node_storage) # Save more nodes all_known_nodes = set() for port in range(MOCK_URSULA_STARTING_PORT, MOCK_URSULA_STARTING_PORT+100): node = Ursula(rest_host='127.0.0.1', db_filepath=MOCK_URSULA_DB_FILEPATH, rest_port=port, federated_only=True) node_storage.store_node_metadata(node=node) all_known_nodes.add(node) # Read all nodes from storage all_stored_nodes = node_storage.all(federated_only=True) all_known_nodes.add(ursula) assert len(all_known_nodes) == len(all_stored_nodes) assert all_stored_nodes == all_known_nodes # Read random nodes for i in range(3): random_node = all_known_nodes.pop() random_node_from_storage = node_storage.get(checksum_address=random_node.checksum_address, federated_only=True) assert random_node.checksum_address == random_node_from_storage.checksum_address return True
def check_availability(): """Asks this node: Can you access my public information endpoint?""" try: requesting_ursula = Ursula.from_metadata_bytes(request.data) requesting_ursula.mature() except ValueError: return Response({'error': 'Invalid Ursula'}, status=HTTPStatus.BAD_REQUEST) else: initiator_address, initiator_port = tuple(requesting_ursula.rest_interface) # Compare requester and posted Ursula information request_address = request.remote_addr if request_address != initiator_address: message = f'Origin address mismatch: Request origin is {request_address} but metadata claims {initiator_address}.' return Response({'error': message}, status=HTTPStatus.BAD_REQUEST) # Make a Sandwich try: requesting_ursula_metadata = this_node.network_middleware.client.node_information( host=initiator_address, port=initiator_port, ) except NodeSeemsToBeDown: return Response({'error': 'Unreachable node'}, status=HTTPStatus.BAD_REQUEST) # ... toasted # Compare the results of the outer POST with the inner GET... yum if requesting_ursula_metadata == request.data: return Response(status=HTTPStatus.OK) else: return Response({'error': 'Suspicious node'}, status=HTTPStatus.BAD_REQUEST)
def test_alice_does_not_update_with_old_ursula_info(federated_alice, federated_ursulas): ursula = list(federated_ursulas)[0] old_metadata = bytes(ursula) # Alice has remembered Ursula. assert federated_alice.known_nodes[ ursula.checksum_public_address] == ursula # But now, Ursula wants to sign and date her interface info again. This causes a new timestamp. ursula._sign_and_date_interface_info() # Indeed, her metadata is not the same now. assert bytes(ursula) != old_metadata old_ursula = Ursula.from_bytes(old_metadata, federated_only=True) # Once Alice learns about Ursula's updated info... federated_alice.remember_node(ursula) # ...she can't learn about old ursula anymore. federated_alice.remember_node(old_ursula) new_metadata = bytes( federated_alice.known_nodes[ursula.checksum_public_address]) assert new_metadata != old_metadata
def _read_and_write_to_storage(self, ursula, node_storage): # Write Node node_storage.save(node=ursula) # Read Node node_from_storage = node_storage.get(checksum_address=ursula.checksum_public_address, federated_only=True) assert ursula == node_from_storage, "Node storage {} failed".format(node_storage) # Save more nodes all_known_nodes = set() for port in range(10152, 10251): node = Ursula(rest_host='127.0.0.1', rest_port=port, federated_only=True) node_storage.save(node=node) all_known_nodes.add(node) # Read all nodes from storage all_stored_nodes = node_storage.all(federated_only=True) all_known_nodes.add(ursula) assert len(all_known_nodes) == len(all_stored_nodes) assert all_stored_nodes == all_known_nodes # Read random nodes for i in range(3): random_node = all_known_nodes.pop() random_node_from_storage = node_storage.get(checksum_address=random_node.checksum_public_address, federated_only=True) assert random_node.checksum_public_address == random_node_from_storage.checksum_public_address return True
def initialize_alice(): ursula = Ursula.from_seed_and_stake_info(seed_uri=SEEDNODE_URI, federated_only=True, minimum_stake=0) # If anything fails, let's create Alicia from scratch # Remove previous demo files and create new ones shutil.rmtree(TEMP_ALICE_DIR, ignore_errors=True) alice_config = AliceConfiguration( config_root=os.path.join(TEMP_ALICE_DIR), domains={TEMPORARY_DOMAIN}, known_nodes={ursula}, start_learning_now=False, federated_only=True, learn_on_same_thread=True, ) alice_config.initialize(password=passphrase) alice_config.keyring.unlock(password=passphrase) # We will save Alicia's config to a file for later use alice_config_file = alice_config.to_configuration_file() with open(os.path.join(TEMP_ALICE_DIR, 'alice.config.json'), 'w') as f: f.write(open(alice_config_file).read()) alicia = alice_config.produce() # Let's get to learn about the NuCypher network alicia.start_learning_loop(now=True) return alicia, alice_config_file
def light_ursula(temp_dir_path): node = Ursula(rest_host=LOOPBACK_ADDRESS, rest_port=MOCK_URSULA_STARTING_PORT, db_filepath=MOCK_URSULA_DB_FILEPATH, federated_only=True, domain=TEMPORARY_DOMAIN) yield node
def createGenericAlicia(passphrase): print('createGenericAlicia') TEMP_ALICE_DIR = os.path.join('/', 'tmp', 'zkDonationFlaskApp') shutil.rmtree(TEMP_ALICE_DIR, ignore_errors=True) ursula = Ursula.from_seed_and_stake_info(seed_uri=SEEDNODE_URI, federated_only=True, minimum_stake=0) alice_config = AliceConfiguration( config_root=os.path.join(TEMP_ALICE_DIR), domains={TEMPORARY_DOMAIN}, known_nodes={ursula}, start_learning_now=False, federated_only=True, learn_on_same_thread=True, ) alice_config.initialize(password=passphrase) alice_config.keyring.unlock(password=passphrase) alicia = alice_config.produce() alice_config.to_configuration_file() alicia.start_learning_loop(now=True) return alicia
def load_seednodes(min_stake: int, federated_only: bool, network_domains: set, network_middleware: RestMiddleware = None, teacher_uris: list = None ) -> List[Ursula]: # Set domains if network_domains is None: from nucypher.config.node import CharacterConfiguration network_domains = {CharacterConfiguration.DEFAULT_DOMAIN, } teacher_nodes = list() # Ursula if teacher_uris is None: teacher_uris = list() for domain in network_domains: try: teacher_uris = TEACHER_NODES[domain] except KeyError: # TODO: If this is a unknown domain, require the caller to pass a teacher URI explicitly? if not teacher_uris: console_emitter(message=f"No default teacher nodes exist for the specified network: {domain}") for uri in teacher_uris: teacher_node = Ursula.from_teacher_uri(teacher_uri=uri, min_stake=min_stake, federated_only=federated_only, network_middleware=network_middleware) teacher_nodes.append(teacher_node) if not teacher_nodes: console_emitter(message=f'WARNING - No Bootnodes Available') return teacher_nodes
def aggregate_nodes() -> Tuple[Set[Ursula], Set[Ursula]]: """generates ursulas from URIs used in grant metrics collection""" seednodes = set() if DEFAULT_SEEDNODE_URIS: for uri in DEFAULT_SEEDNODE_URIS: ursula = Ursula.from_seed_and_stake_info(seed_uri=uri, federated_only=False) seednodes.add(ursula) handpicked_ursulas = set() if HANDPICKED_URSULA_URIS: for uri in HANDPICKED_URSULA_URIS: ursula = Ursula.from_seed_and_stake_info(seed_uri=uri, federated_only=False) handpicked_ursulas.add(ursula) return seednodes, handpicked_ursulas
def crawl( general_config, teacher_uri, registry_filepath, min_stake, network, learn_on_launch, provider_uri, influx_host, influx_port, http_port, dry_run, eager, poa, ): """ Gather NuCypher network information. """ # Banner emitter = general_config.emitter emitter.clear() emitter.banner(MONITOR_BANNER.format(CRAWLER)) # Setup BlockchainInterfaceFactory.initialize_interface(provider_uri=provider_uri, poa=poa) registry = _get_registry(registry_filepath, network) middleware = RestMiddleware() # Teacher Ursula sage_node = None if teacher_uri: sage_node = Ursula.from_teacher_uri( teacher_uri=teacher_uri, min_stake=0, # TODO: Where to get this? federated_only=False, # always False network_middleware=middleware, registry=registry) crawler = Crawler(domain=network if network else None, network_middleware=middleware, known_nodes=[sage_node] if teacher_uri else None, registry=registry, start_learning_now=eager, learn_on_same_thread=learn_on_launch, influx_host=influx_host, influx_port=influx_port) emitter.message(f"Network: {network.capitalize()}", color='blue') emitter.message(f"InfluxDB: {influx_host}:{influx_port}", color='blue') emitter.message(f"Provider: {provider_uri}", color='blue') emitter.message(f"Refresh Rate: {crawler._refresh_rate}s", color='blue') message = f"Running Nucypher Crawler JSON endpoint at http://localhost:{http_port}/stats" emitter.message(message, color='green', bold=True) if not dry_run: crawler.start(eager=eager) reactor.run()
def ping(): """ GET: Asks this node: "What is my IP address?" POST: Asks this node: "Can you access my public information endpoint?" """ if request.method == 'GET': requester_ip_address = request.remote_addr return Response(requester_ip_address, status=200) elif request.method == 'POST': try: requesting_ursula = Ursula.from_bytes(request.data) requesting_ursula.mature() except ValueError: return Response({'error': 'Invalid Ursula'}, status=400) else: initiator_address, initiator_port = tuple( requesting_ursula.rest_interface) # Compare requester and posted Ursula information request_address = request.remote_addr if request_address != initiator_address: message = f'Origin address mismatch: Request origin is {request_address} but metadata claims {initiator_address}.' return Response({'error': message}, status=400) # # Make a Sandwich # try: # Fetch and store initiator's teacher certificate. certificate = this_node.network_middleware.get_certificate( host=initiator_address, port=initiator_port) certificate_filepath = this_node.node_storage.store_node_certificate( certificate=certificate) requesting_ursula_bytes = this_node.network_middleware.client.node_information( host=initiator_address, port=initiator_port, certificate_filepath=certificate_filepath) except NodeSeemsToBeDown: return Response({'error': 'Unreachable node'}, status=400) # ... toasted except InvalidNodeCertificate: return Response( { 'error': 'Invalid TLS certificate - missing checksum address' }, status=400) # ... invalid # Compare the results of the outer POST with the inner GET... yum if requesting_ursula_bytes == request.data: return Response(status=200) else: return Response({'error': 'Suspicious node'}, status=400)
def substitute_bob(*args, **kwargs): log.info("Substituting the Policy's Bob in CLI runtime.") this_fuckin_guy = enacted_federated_policy.bob somebody_else = Ursula.from_teacher_uri(teacher_uri=kwargs['teacher_uri'], min_stake=0, federated_only=True, network_middleware=this_fuckin_guy.network_middleware) this_fuckin_guy.remember_node(somebody_else) this_fuckin_guy.controller.emitter = JSONRPCStdoutEmitter() return this_fuckin_guy
def __read_metadata(self, filepath: str, federated_only: bool): from nucypher.characters.lawful import Ursula try: with open(filepath, "rb") as seed_file: seed_file.seek(0) node_bytes = self.deserializer(seed_file.read()) node = Ursula.from_bytes(node_bytes, federated_only=federated_only) except FileNotFoundError: raise self.UnknownNode return node
def load_seednodes(self, read_storages: bool = True, retry_attempts: int = 3): # TODO: why are these unused? """ Engage known nodes from storages and pre-fetch hardcoded seednode certificates for node learning. """ if self.done_seeding: sendMessage( encodeMessage( "log:Level:Debug, Date:{}, Message:Already done seeding; won't try again." .format(get_sysdate()))) #self.log.debug("Already done seeding; won't try again.") return from nucypher.characters.lawful import Ursula for seednode_metadata in self._seed_nodes: sendMessage( encodeMessage( "log:Level:Debug, Date:{}, Message:Seeding from: {}|{}:{}". format(get_sysdate(), seednode_metadata.checksum_address, seednode_metadata.rest_host, seednode_metadata.rest_port))) #self.log.debug( # "Seeding from: {}|{}:{}".format(seednode_metadata.checksum_public_address, # seednode_metadata.rest_host, # seednode_metadata.rest_port)) seed_node = Ursula.from_seednode_metadata( seednode_metadata=seednode_metadata, network_middleware=self.network_middleware, federated_only=self.federated_only) # TODO: 466 if seed_node is False: self.unresponsive_seed_nodes.add(seednode_metadata) else: self.unresponsive_seed_nodes.discard(seednode_metadata) self.remember_node(seed_node) if not self.unresponsive_seed_nodes: sendMessage( encodeMessage( "log:Level:Info, Date:{}, Message: Finished learning about all seednodes." .format(get_sysdate()))) #self.log.info("Finished learning about all seednodes.") self.done_seeding = True if read_storages is True: self.read_nodes_from_storage() if not self.known_nodes: sendMessage( encodeMessage( "log:Level:Warn, Date:{}, Message: No seednodes were available after {} attempts" .format(get_sysdate(), retry_attempts)))
def light_ursula(temp_dir_path): db_name = 'ursula-{}.db'.format(10151) node = Ursula(rest_host='127.0.0.1', rest_port=10151, db_filepath=db_name, # TODO: Needs cleanup db_name=db_name, federated_only=True) yield node with contextlib.suppress(Exception): os.remove(db_name)
def load_seednodes( emitter, min_stake: int, federated_only: bool, network_domains: set, network_middleware: RestMiddleware = None, teacher_uris: list = None, registry: BaseContractRegistry = None, ) -> List: """ Aggregates seednodes URI sources into a list or teacher URIs ordered by connection priority in the following order: 1. --teacher CLI flag 2. static-nodes.json 3. Hardcoded teachers """ # Heads up emitter.message("Connecting to preferred teacher nodes...", color='yellow') from nucypher.characters.lawful import Ursula # Aggregate URIs (Ordered by Priority) teacher_nodes = list() # type: List[Ursula] teacher_uris = aggregate_seednode_uris(domains=network_domains, highest_priority=teacher_uris) if not teacher_uris: emitter.message( f"No teacher nodes available for domains: {','.join(network_domains)}" ) return teacher_nodes # Construct Ursulas for uri in teacher_uris: try: teacher_node = Ursula.from_teacher_uri( teacher_uri=uri, min_stake=min_stake, federated_only=federated_only, network_middleware=network_middleware, registry=registry) except NodeSeemsToBeDown: LOG.info(f"Failed to connect to teacher: {uri}") continue except Teacher.NotStaking: LOG.info(f"Teacher: {uri} is not actively staking, skipping") continue teacher_nodes.append(teacher_node) if not teacher_nodes: emitter.message( f"WARNING - No Peers Available for domains: {','.join(network_domains)}" ) return teacher_nodes
def test_tls_hosting_certificate_remains_the_same(tmpdir, mocker): keyring = NucypherKeyring.generate(checksum_address=FEDERATED_ADDRESS, password=INSECURE_DEVELOPMENT_PASSWORD, encrypting=True, rest=True, host=LOOPBACK_ADDRESS, keyring_root=tmpdir) keyring.unlock(password=INSECURE_DEVELOPMENT_PASSWORD) rest_port = 12345 db_filepath = tempfile.mkdtemp() ursula = Ursula(federated_only=True, start_learning_now=False, keyring=keyring, rest_host=LOOPBACK_ADDRESS, rest_port=rest_port, db_filepath=db_filepath, domain=TEMPORARY_DOMAIN) assert ursula.keyring is keyring assert ursula.certificate == ursula._crypto_power.power_ups( TLSHostingPower).keypair.certificate original_certificate_bytes = ursula.certificate.public_bytes( encoding=Encoding.PEM) ursula.disenchant() del ursula spy_rest_server_init = mocker.spy(ProxyRESTServer, '__init__') recreated_ursula = Ursula(federated_only=True, start_learning_now=False, keyring=keyring, rest_host=LOOPBACK_ADDRESS, rest_port=rest_port, db_filepath=db_filepath, domain=TEMPORARY_DOMAIN) assert recreated_ursula.keyring is keyring assert recreated_ursula.certificate.public_bytes( encoding=Encoding.PEM) == 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_deserialize_ursulas_version_2(): """ DON'T 'FIX' THIS TEST IF FAILING, UNLESS YOU KNOW WHAT YOU'RE DOING. The goal of this test is to show compatibility of a hard-coded version 2 bytestring. See issue #1869 "Test with a hard-coded, versioned node metadata bytestring" https://github.com/nucypher/nucypher/issues/1869 """ expected_version = 2 ursulas_matrix = versioned_ursulas[expected_version] for fossilized_ursula in ursulas_matrix: fossilized_ursula = bytes.fromhex(fossilized_ursula) version, _ = Ursula.version_splitter(fossilized_ursula, return_remainder=True) assert version == expected_version assert version == Ursula.LEARNER_VERSION resurrected_ursula = Ursula.from_bytes(fossilized_ursula, fail_fast=True) assert TEMPORARY_DOMAIN.encode('utf-8') == resurrected_ursula.domain
def load_seednodes( emitter, min_stake: int, federated_only: bool, network_domains: set, network_middleware: RestMiddleware = None, teacher_uris: list = None, registry: BaseContractRegistry = None, ) -> List: """ Aggregates seednodes URI sources into a list or teacher URIs ordered by connection priority in the following order: 1. --teacher CLI flag 2. static-nodes.json 3. Hardcoded teachers """ # Heads up emitter.message(START_LOADING_SEEDNODES, color='yellow') from nucypher.characters.lawful import Ursula # Aggregate URIs (Ordered by Priority) teacher_nodes = list() # type: List[Ursula] teacher_uris = aggregate_seednode_uris(domains=network_domains, highest_priority=teacher_uris) if not teacher_uris: emitter.message( NO_DOMAIN_PEERS.format(domains=','.join(network_domains))) return teacher_nodes # Construct Ursulas for uri in teacher_uris: try: teacher_node = Ursula.from_teacher_uri( teacher_uri=uri, min_stake=min_stake, federated_only=federated_only, network_middleware=network_middleware, registry=registry) except NodeSeemsToBeDown: emitter.message(UNREADABLE_SEEDNODE_ADVISORY.format(uri=uri)) continue except Teacher.NotStaking: emitter.message(SEEDNODE_NOT_STAKING_WARNING.format(uri=uri)) continue teacher_nodes.append(teacher_node) if not teacher_nodes: emitter.message( NO_DOMAIN_PEERS.format(domains=','.join(network_domains))) return teacher_nodes
def ping(): """ Asks this node: "Can you access my public information endpoint"? """ try: requesting_ursula = Ursula.from_bytes(request.data, registry=this_node.registry) requesting_ursula.mature() except ValueError: # (ValueError) return Response({'error': 'Invalid Ursula'}, status=400) else: initiator_address, initiator_port = tuple( requesting_ursula.rest_interface) # Compare requester and posted Ursula information request_address = request.environ['REMOTE_ADDR'] if request_address != initiator_address: return Response({'error': 'Suspicious origin address'}, status=400) # # Make a Sandwich # try: # Fetch and store initiator's teacher certificate. certificate = this_node.network_middleware.get_certificate( host=initiator_address, port=initiator_port) certificate_filepath = this_node.node_storage.store_node_certificate( certificate=certificate) requesting_ursula_bytes = this_node.network_middleware.client.node_information( host=initiator_address, port=initiator_port, certificate_filepath=certificate_filepath) except NodeSeemsToBeDown: return Response({'error': 'Unreachable node'}, status=400) # ... toasted except InvalidNodeCertificate: return Response( { 'error': 'Invalid TLS certificate - missing checksum address' }, status=400) # ... invalid # Compare the results of the outer POST with the inner GET... yum if requesting_ursula_bytes == request.data: return Response(status=200) else: return Response({'error': 'Suspicious node'}, status=400)
def load_known_nodes(self, known_metadata_dir=None) -> None: if known_metadata_dir is None: known_metadata_dir = self.known_metadata_dir glob_pattern = os.path.join(known_metadata_dir, '*.node') metadata_paths = sorted(glob(glob_pattern), key=os.path.getctime) for metadata_path in metadata_paths: from nucypher.characters.lawful import Ursula node = Ursula.from_metadata_file( filepath=abspath(metadata_path), federated_only=self.federated_only) self.known_nodes.add(node)
def start_pytest_ursula_services(ursula: Ursula) -> Certificate: """ Takes an ursula and starts its learning services when running tests with pytest twisted. """ node_deployer = ursula.get_deployer() node_deployer.addServices() node_deployer.catalogServers(node_deployer.hendrix) node_deployer.start() certificate_as_deployed = node_deployer.cert.to_cryptography() return certificate_as_deployed
def test_characters_use_keyring(tmpdir): keyring = NucypherKeyring.generate(checksum_address=FEDERATED_ADDRESS, password=INSECURE_DEVELOPMENT_PASSWORD, encrypting=True, rest=False, keyring_root=tmpdir) keyring.unlock(password=INSECURE_DEVELOPMENT_PASSWORD) Alice(federated_only=True, start_learning_now=False, keyring=keyring) Bob(federated_only=True, start_learning_now=False, keyring=keyring) Ursula(federated_only=True, start_learning_now=False, keyring=keyring, rest_host='127.0.0.1', rest_port=12345)