def test_bob_can_follow_treasure_map_even_if_he_only_knows_of_one_node( enacted_federated_policy, federated_ursulas, certificates_tempdir): """ Similar to above, but this time, we'll show that if Bob can connect to a single node, he can learn enough to follow the TreasureMap. Also, we'll get the TreasureMap from the hrac alone (ie, not via a side channel). """ from nucypher.characters.lawful import Bob bob = Bob(network_middleware=MockRestMiddleware(), domain=TEMPORARY_DOMAIN, start_learning_now=False, abort_on_learning_error=True, federated_only=True) # Again, let's assume that he received the TreasureMap via a side channel. hrac, treasure_map = enacted_federated_policy.hrac( ), enacted_federated_policy.treasure_map map_id = treasure_map.public_id() bob.treasure_maps[map_id] = treasure_map # Now, let's create a scenario in which Bob knows of only one node. assert len(bob.known_nodes) == 0 first_ursula = list(federated_ursulas).pop(0) bob.remember_node(first_ursula) assert len(bob.known_nodes) == 1 # This time, when he follows the TreasureMap... unknown_nodes, known_nodes = bob.peek_at_treasure_map(map_id=map_id) # Bob already knew about one node; the rest are unknown. assert len(unknown_nodes) == len(treasure_map) - 1 # He needs to actually follow the treasure map to get the rest. bob.follow_treasure_map(map_id=map_id) # The nodes in the learning loop are now his top target, but he's not learning yet. assert not bob._learning_task.running # ...so he hasn't learned anything (ie, Bob still knows of just one node). assert len(bob.known_nodes) == 1 # Now, we'll start his learning loop. bob.start_learning_loop() # ...and block until the unknown_nodes have all been found. d = threads.deferToThread(bob.block_until_specific_nodes_are_known, unknown_nodes) yield d # ...and he now has no more unknown_nodes. assert len(bob.known_nodes) == len(treasure_map) bob.disenchant()
def make_bob_control(drone_bob: Bob, teacher_node: Ursula): bob_control = Flask('bob-control') teacher_node.verify_node(drone_bob.network_middleware) drone_bob.remember_node(teacher_node) drone_bob.start_learning_loop(now=True) @bob_control.route('/join_policy', methods=['POST']) def join_policy(): """ Character control endpoint for joining a policy on the network. This is an unfinished endpoint. You're probably looking for retrieve. """ try: request_data = json.loads(request.data) label = b64decode(request_data['label']) alice_pubkey_sig = bytes.fromhex( request_data['alice_signing_pubkey']) except (KeyError, JSONDecodeError) as e: return Response(e, status=400) drone_bob.join_policy(label=label, alice_pubkey_sig=alice_pubkey_sig) return Response('Policy joined!', status=200) @bob_control.route('/retrieve', methods=['POST']) def retrieve(): """ Character control endpoint for re-encrypting and decrypting policy data. """ try: request_data = json.loads(request.data) label = b64decode(request_data['label']) policy_pubkey_enc = bytes.fromhex( request_data['policy_encrypting_pubkey']) alice_pubkey_sig = bytes.fromhex( request_data['alice_signing_pubkey']) datasource_pubkey_sig = bytes.fromhex( request_data['datasource_signing_pubkey']) message_kit = b64decode(request_data['message_kit']) except (KeyError, JSONDecodeError) as e: return Response(e, status=400) policy_pubkey_enc = UmbralPublicKey.from_bytes(policy_pubkey_enc) alice_pubkey_sig = UmbralPublicKey.from_bytes(alice_pubkey_sig) message_kit = UmbralMessageKit.from_bytes(message_kit) data_source = DataSource.from_public_keys(policy_pubkey_enc, datasource_pubkey_sig, label=label) drone_bob.join_policy(label=label, alice_pubkey_sig=alice_pubkey_sig) plaintexts = drone_bob.retrieve(message_kit=message_kit, data_source=data_source, alice_verifying_key=alice_pubkey_sig) plaintexts = [ b64encode(plaintext).decode() for plaintext in plaintexts ] response_data = { 'result': { 'plaintext': plaintexts, } } return Response(json.dumps(response_data), status=200) return bob_control