def test_alice_can_grant_even_when_the_first_nodes_she_tries_are_down( federated_alice, federated_bob, federated_ursulas): m, n = 2, 3 policy_end_datetime = maya.now() + datetime.timedelta(days=5) label = b"this_is_the_path_to_which_access_is_being_granted" federated_alice.known_nodes.current_state._nodes = {} federated_alice.network_middleware = NodeIsDownMiddleware() # OK, her first and only node is down. down_node = list(federated_ursulas)[0] federated_alice.remember_node(down_node) federated_alice.network_middleware.node_is_down(down_node) # Here's the command we want to run. alice_grant_action = partial(federated_alice.grant, federated_bob, label, m=m, n=n, expiration=policy_end_datetime, timeout=.1) # Go! federated_alice.start_learning_loop() # Now we'll have a situation where Alice knows about all 10, # though only one is up. # She'll try to learn about more, but there aren't any. # Because she has successfully completed learning, but the nodes about which she learned are down, # she'll get a different error. more_nodes = list(federated_ursulas)[1:10] for node in more_nodes: federated_alice.network_middleware.node_is_down(node) for node in more_nodes: federated_alice.remember_node(node) with pytest.raises(Policy.NotEnoughUrsulas): alice_grant_action() # Now let's let a few of them come up. for node in more_nodes[0:4]: federated_alice.network_middleware.node_is_up(node) # Now the same exact action works. # TODO: This action only succeeds here because we are forcing # grant to accept the ursulas that just came back online (handpicked_ursulas). # Since there are now enough Ursulas online, this action *can* succeed without forcing sample. policy = alice_grant_action(handpicked_ursulas=more_nodes[:3]) # TODO: This is how it's actually done. How can we measure such random results? # The below line will fail with ? probability, if more then 2 of the nodes selected # are among those still down. # policy = alice_grant_action() # The number of actually enacted arrangements is exactly equal to n. assert len(policy.treasure_map.destinations) == n
def test_node_has_changed_cert(federated_alice, federated_ursulas): federated_alice.known_nodes.current_state._nodes = {} federated_alice.network_middleware = NodeIsDownMiddleware() federated_alice.network_middleware.client.certs_are_broken = True firstula = list(federated_ursulas)[0] federated_alice.remember_node(firstula) federated_alice.start_learning_loop(now=True) federated_alice.learn_from_teacher_node()
def test_federated_bob_cannot_resume_retrieval_without_caching(federated_bob, federated_alice, capsule_side_channel, enacted_federated_policy, federated_ursulas ): capsule_side_channel.reset() the_message_kit = capsule_side_channel() alices_verifying_key = federated_alice.stamp.as_umbral_pubkey() # Out of 10 Ursulas, eight are down. ursula1 = list(federated_ursulas)[0] ursula2 = list(federated_ursulas)[1] ursula3 = list(federated_ursulas)[2] ursula4 = list(federated_ursulas)[3] ursula5 = list(federated_ursulas)[4] ursula6 = list(federated_ursulas)[5] ursula7 = list(federated_ursulas)[6] ursula8 = list(federated_ursulas)[7] federated_bob.remember_node(ursula1) federated_bob.network_middleware = NodeIsDownMiddleware() federated_bob.network_middleware.node_is_down(ursula1) federated_bob.network_middleware.node_is_down(ursula2) federated_bob.network_middleware.node_is_down(ursula3) federated_bob.network_middleware.node_is_down(ursula4) federated_bob.network_middleware.node_is_down(ursula5) federated_bob.network_middleware.node_is_down(ursula6) federated_bob.network_middleware.node_is_down(ursula7) federated_bob.network_middleware.node_is_down(ursula8) # Since 8 Ursulas are down, Bob can only get 2 CFrags; not enough to complete retrieval. with pytest.raises(ursula1.NotEnoughUrsulas): federated_bob.retrieve(the_message_kit, enrico=capsule_side_channel.enrico, alice_verifying_key=alices_verifying_key, label=enacted_federated_policy.label) # Since we weren't caching, there are no attached Cfrags. assert len(the_message_kit.capsule) == 0 # Now the remaining two Ursulas go down. ursula9 = list(federated_ursulas)[8] ursula10 = list(federated_ursulas)[9] federated_bob.network_middleware.node_is_down(ursula9) federated_bob.network_middleware.node_is_down(ursula10) # ...but one other comes up. federated_bob.network_middleware.node_is_up(ursula4) with pytest.raises(ursula1.NotEnoughUrsulas): federated_bob.retrieve(the_message_kit, enrico=capsule_side_channel.enrico, alice_verifying_key=alices_verifying_key, label=enacted_federated_policy.label)
def test_use_external_cache(enacted_federated_policy, federated_bob, federated_ursulas): federated_bob.start_learning_loop() messages, message_kits = _make_message_kits( enacted_federated_policy.public_key) ursulas = list(federated_ursulas) # All Ursulas are down except for two federated_bob.network_middleware = NodeIsDownMiddleware() for ursula in ursulas[2:]: federated_bob.network_middleware.node_is_down(ursula) # Fetch what we can without decrypting loaded_message_kits = federated_bob.retrieve( message_kits=message_kits, **_policy_info_kwargs(enacted_federated_policy), ) # Not enough cfrags yet assert not any(mk.is_decryptable_by_receiver() for mk in loaded_message_kits) # Now the remaining two Ursulas go down. for ursula in ursulas[:2]: federated_bob.network_middleware.node_is_down(ursula) # ...but one other comes up. federated_bob.network_middleware.node_is_up(ursulas[2]) # Try again, building on top of the existing cache loaded_message_kits = federated_bob.retrieve( message_kits=loaded_message_kits, **_policy_info_kwargs(enacted_federated_policy), ) assert all(mk.is_decryptable_by_receiver() for mk in loaded_message_kits) # Should be enough cfrags now. Disconnect all Ursulas # to be sure Bob doesn't cheat and contact them again. for ursula in ursulas: federated_bob.network_middleware.node_is_down(ursula) cleartexts = federated_bob.retrieve_and_decrypt( message_kits=loaded_message_kits, **_policy_info_kwargs(enacted_federated_policy), ) assert cleartexts == messages
def test_blockchain_ursulas_reencrypt(blockchain_ursulas, blockchain_alice, blockchain_bob, policy_value): label = b'bbo' # TODO: Make sample selection buffer configurable - #1061 m = n = 10 expiration = maya.now() + datetime.timedelta(days=5) _policy = blockchain_alice.grant(bob=blockchain_bob, label=label, m=m, n=n, expiration=expiration, value=policy_value) enrico = Enrico.from_alice(blockchain_alice, label) message = b"Oh, this isn't even BO. This is beyond BO. It's BBO." message_kit, signature = enrico.encrypt_message(message) blockchain_bob.start_learning_loop(now=True) blockchain_bob.join_policy(label, bytes(blockchain_alice.stamp)) plaintext = blockchain_bob.retrieve( message_kit, alice_verifying_key=blockchain_alice.stamp, label=label, enrico=enrico) assert plaintext[0] == message # Let's consider also that a node may be down when granting blockchain_alice.network_middleware = NodeIsDownMiddleware() blockchain_alice.network_middleware.node_is_down(blockchain_ursulas[0]) with pytest.raises(BlockchainPolicy.NotEnoughBlockchainUrsulas): _policy = blockchain_alice.grant(bob=blockchain_bob, label=b'another-label', m=m, n=n, expiration=expiration, value=policy_value)
def test_blockchain_ursulas_reencrypt(blockchain_ursulas, blockchain_alice, blockchain_bob, policy_value): label = b'bbo' # TODO: Make sample selection buffer configurable - #1061 threshold = shares = 10 expiration = maya.now() + datetime.timedelta(days=35) _policy = blockchain_alice.grant(bob=blockchain_bob, label=label, threshold=threshold, shares=shares, expiration=expiration, value=policy_value) enrico = Enrico.from_alice(blockchain_alice, label) message = b"Oh, this isn't even BO. This is beyond BO. It's BBO." message_kit = enrico.encrypt_message(message) blockchain_bob.start_learning_loop(now=True) plaintexts = blockchain_bob.retrieve_and_decrypt( [message_kit], encrypted_treasure_map=_policy.treasure_map, alice_verifying_key=blockchain_alice.stamp.as_umbral_pubkey()) assert plaintexts == [message] # Let's consider also that a node may be down when granting blockchain_alice.network_middleware = NodeIsDownMiddleware() blockchain_alice.network_middleware.node_is_down(blockchain_ursulas[0]) with pytest.raises(BlockchainPolicy.NotEnoughUrsulas): _policy = blockchain_alice.grant(bob=blockchain_bob, label=b'another-label', threshold=threshold, shares=shares, expiration=expiration, value=policy_value)
def test_bob_does_not_let_a_connection_error_stop_him(enacted_federated_policy, federated_ursulas, federated_bob, federated_alice): assert len(federated_bob.known_nodes) == 0 ursula1 = list(federated_ursulas)[0] ursula2 = list(federated_ursulas)[1] federated_bob.remember_node(ursula1) federated_bob.network_middleware = NodeIsDownMiddleware() federated_bob.network_middleware.node_is_down(ursula1) with pytest.raises(TreasureMap.NowhereToBeFound): federated_bob.get_treasure_map(federated_alice.stamp, enacted_federated_policy.label) federated_bob.remember_node(ursula2) map = federated_bob.get_treasure_map(federated_alice.stamp, enacted_federated_policy.label) assert sorted(list(map.destinations.keys())) == sorted( list(u.checksum_address for u in list(federated_ursulas)))
def test_federated_retrieves_partially_then_finishes(federated_bob, federated_alice, capsule_side_channel, enacted_federated_policy, federated_ursulas): # Same setup as last time. capsule_side_channel.reset() the_message_kit = capsule_side_channel() alices_verifying_key = federated_alice.stamp.as_umbral_pubkey() ursula1 = list(federated_ursulas)[0] ursula2 = list(federated_ursulas)[1] ursula3 = list(federated_ursulas)[2] ursula4 = list(federated_ursulas)[3] ursula5 = list(federated_ursulas)[4] ursula6 = list(federated_ursulas)[5] ursula7 = list(federated_ursulas)[6] ursula8 = list(federated_ursulas)[7] federated_bob.remember_node(ursula1) federated_bob.network_middleware = NodeIsDownMiddleware() federated_bob.network_middleware.node_is_down(ursula1) federated_bob.network_middleware.node_is_down(ursula2) federated_bob.network_middleware.node_is_down(ursula3) federated_bob.network_middleware.node_is_down(ursula4) federated_bob.network_middleware.node_is_down(ursula5) federated_bob.network_middleware.node_is_down(ursula6) federated_bob.network_middleware.node_is_down(ursula7) federated_bob.network_middleware.node_is_down(ursula8) # Bob can't retrieve; there aren't enough Ursulas up. with pytest.raises(ursula1.NotEnoughUrsulas): federated_bob.retrieve(the_message_kit, enrico=capsule_side_channel.enrico, alice_verifying_key=alices_verifying_key, label=enacted_federated_policy.label, retain_cfrags=True) # Since we were caching, there are now 2 attached cfrags. assert len(the_message_kit.capsule) == 2 # Now the remaining two Ursulas go down. ursula9 = list(federated_ursulas)[8] ursula10 = list(federated_ursulas)[9] federated_bob.network_middleware.node_is_down(ursula9) federated_bob.network_middleware.node_is_down(ursula10) # ...but one other comes up. federated_bob.network_middleware.node_is_up(ursula4) # We're not allowed to try again with a Capsule with cached CFrags if we set cache to False. with pytest.raises(TypeError): federated_bob.retrieve(the_message_kit, enrico=capsule_side_channel.enrico, alice_verifying_key=alices_verifying_key, label=enacted_federated_policy.label, retain_cfrags=False) # But now, with just one Ursula up, we can use the cached CFrags to get the message. delivered_cleartexts = federated_bob.retrieve( the_message_kit, enrico=capsule_side_channel.enrico, alice_verifying_key=alices_verifying_key, label=enacted_federated_policy.label, retain_cfrags=True, use_attached_cfrags=True, ) assert b"Welcome to flippering number 1." == delivered_cleartexts[0] # In fact, if Bob is totally offline, he can get the message: for ursula in federated_ursulas: federated_bob.network_middleware.node_is_down(ursula) delivered_cleartexts = federated_bob.retrieve( the_message_kit, enrico=capsule_side_channel.enrico, alice_verifying_key=alices_verifying_key, label=enacted_federated_policy.label, retain_cfrags=True, use_attached_cfrags=True) assert b"Welcome to flippering number 1." == delivered_cleartexts[0] # Heck, even if we delete the attached CFrags, as might happen if we were loading the Capsule again from disk... the_message_kit.capsule.clear_cfrags() # ...we can still get the message with the network being down because Bob has the properly completed WorkOrders cached in state. delivered_cleartexts = federated_bob.retrieve( the_message_kit, enrico=capsule_side_channel.enrico, alice_verifying_key=alices_verifying_key, label=enacted_federated_policy.label, use_precedent_work_orders=True) assert b"Welcome to flippering number 1." == delivered_cleartexts[0] federated_bob.network_middleware.all_nodes_up()