2017-10-04 04:13:46 +00:00
|
|
|
import pytest
|
2018-09-12 12:04:02 +00:00
|
|
|
from hendrix.experience import crosstown_traffic
|
|
|
|
from hendrix.utils.test_utils import crosstownTaskListDecoratorFactory
|
2017-11-07 04:42:21 +00:00
|
|
|
from kademlia.utils import digest
|
2018-04-12 03:17:39 +00:00
|
|
|
|
2018-09-23 04:05:11 +00:00
|
|
|
from nucypher.characters.lawful import Ursula
|
2018-09-12 12:04:02 +00:00
|
|
|
from nucypher.characters.unlawful import Vladimir
|
2018-05-08 19:35:34 +00:00
|
|
|
from nucypher.crypto.api import keccak_digest
|
2018-09-12 12:04:02 +00:00
|
|
|
from nucypher.crypto.powers import SigningPower
|
2018-09-13 19:32:38 +00:00
|
|
|
from nucypher.utilities.sandbox.middleware import MockRestMiddleware
|
2017-12-15 05:21:27 +00:00
|
|
|
|
|
|
|
|
2018-09-13 19:35:44 +00:00
|
|
|
def test_all_blockchain_ursulas_know_about_all_other_ursulas(blockchain_ursulas, three_agents):
|
2017-11-09 21:48:40 +00:00
|
|
|
"""
|
|
|
|
Once launched, all Ursulas know about - and can help locate - all other Ursulas in the network.
|
|
|
|
"""
|
2018-06-23 20:48:06 +00:00
|
|
|
token_agent, miner_agent, policy_agent = three_agents
|
2018-09-13 19:35:44 +00:00
|
|
|
for address in miner_agent.swarm():
|
|
|
|
for propagating_ursula in blockchain_ursulas:
|
2018-09-13 22:20:20 +00:00
|
|
|
assert address in propagating_ursula.known_nodes, "{} did not know about {}".format(propagating_ursula, address)
|
2017-11-06 21:35:54 +00:00
|
|
|
|
|
|
|
|
2018-06-30 03:25:36 +00:00
|
|
|
@pytest.mark.skip("What do we want this test to do now?")
|
2018-09-13 19:35:44 +00:00
|
|
|
def test_blockchain_alice_finds_ursula_via_rest(blockchain_alice, blockchain_ursulas):
|
2018-04-17 08:46:13 +00:00
|
|
|
# Imagine alice knows of nobody.
|
2018-09-13 22:20:20 +00:00
|
|
|
blockchain_alice.known_nodes = {}
|
2018-04-17 08:46:13 +00:00
|
|
|
|
2018-09-13 19:35:44 +00:00
|
|
|
some_ursula_interface = blockchain_ursulas.pop().rest_interface
|
2018-06-23 20:48:06 +00:00
|
|
|
|
2018-09-13 19:35:44 +00:00
|
|
|
new_nodes = blockchain_alice.learn_from_teacher_node()
|
2018-06-30 03:25:36 +00:00
|
|
|
|
2018-09-13 19:35:44 +00:00
|
|
|
assert len(new_nodes) == len(blockchain_ursulas)
|
2018-04-14 16:05:11 +00:00
|
|
|
|
2018-09-13 19:35:44 +00:00
|
|
|
for ursula in blockchain_ursulas:
|
2018-04-14 16:05:11 +00:00
|
|
|
assert ursula.stamp.as_umbral_pubkey() in new_nodes
|
|
|
|
|
|
|
|
|
2018-07-02 12:18:31 +00:00
|
|
|
def test_alice_creates_policy_with_correct_hrac(idle_federated_policy):
|
2017-11-09 22:28:11 +00:00
|
|
|
"""
|
2018-07-02 12:18:31 +00:00
|
|
|
Alice creates a Policy. It has the proper HRAC, unique per her, Bob, and the uri (resource_id).
|
2017-11-09 22:28:11 +00:00
|
|
|
"""
|
2018-06-30 03:25:36 +00:00
|
|
|
alice = idle_federated_policy.alice
|
|
|
|
bob = idle_federated_policy.bob
|
2017-11-09 22:28:11 +00:00
|
|
|
|
2018-06-30 03:25:36 +00:00
|
|
|
assert idle_federated_policy.hrac() == keccak_digest(
|
2018-07-02 12:18:31 +00:00
|
|
|
bytes(alice.stamp) + bytes(bob.stamp) + idle_federated_policy.label)
|
2017-11-21 03:24:03 +00:00
|
|
|
|
2017-11-21 03:50:38 +00:00
|
|
|
|
2018-09-13 19:35:44 +00:00
|
|
|
def test_alice_sets_treasure_map(enacted_federated_policy, federated_ursulas):
|
2017-10-04 04:13:46 +00:00
|
|
|
"""
|
2018-09-14 13:50:27 +00:00
|
|
|
Having enacted all the policies of a PolicyGroup, Alice creates a TreasureMap and ...... TODO
|
2017-10-04 04:13:46 +00:00
|
|
|
"""
|
2017-10-03 15:43:12 +00:00
|
|
|
|
2018-09-21 17:16:38 +00:00
|
|
|
enacted_federated_policy.publish_treasure_map(network_middleware=MockRestMiddleware())
|
2018-09-13 19:35:44 +00:00
|
|
|
|
|
|
|
treasure_map_as_set_on_network = list(federated_ursulas)[0].treasure_maps[
|
2018-07-02 12:18:31 +00:00
|
|
|
digest(enacted_federated_policy.treasure_map.public_id())]
|
|
|
|
assert treasure_map_as_set_on_network == enacted_federated_policy.treasure_map
|
2017-10-24 00:28:10 +00:00
|
|
|
|
|
|
|
|
2018-09-13 19:35:44 +00:00
|
|
|
def test_treasure_map_stored_by_ursula_is_the_correct_one_for_bob(alice, bob, federated_ursulas, enacted_federated_policy):
|
2017-11-09 22:28:11 +00:00
|
|
|
"""
|
|
|
|
The TreasureMap given by Alice to Ursula is the correct one for Bob; he can decrypt and read it.
|
|
|
|
"""
|
2018-09-13 19:35:44 +00:00
|
|
|
treasure_map_as_set_on_network = list(federated_ursulas)[0].treasure_maps[
|
2018-07-02 12:18:31 +00:00
|
|
|
digest(enacted_federated_policy.treasure_map.public_id())]
|
2018-02-14 08:19:26 +00:00
|
|
|
|
2018-07-02 12:18:31 +00:00
|
|
|
hrac_by_bob = bob.construct_policy_hrac(alice.stamp, enacted_federated_policy.label)
|
|
|
|
assert enacted_federated_policy.hrac() == hrac_by_bob
|
2017-11-22 06:03:31 +00:00
|
|
|
|
2018-07-13 19:12:28 +00:00
|
|
|
hrac, map_id_by_bob = bob.construct_hrac_and_map_id(alice.stamp, enacted_federated_policy.label)
|
2018-07-02 12:18:31 +00:00
|
|
|
assert map_id_by_bob == treasure_map_as_set_on_network.public_id()
|
2017-10-03 15:43:12 +00:00
|
|
|
|
|
|
|
|
2018-09-16 21:37:11 +00:00
|
|
|
def test_bob_can_retreive_the_treasure_map_and_decrypt_it(enacted_federated_policy, federated_ursulas):
|
2017-10-24 00:28:10 +00:00
|
|
|
"""
|
2017-11-09 22:28:11 +00:00
|
|
|
Above, we showed that the TreasureMap saved on the network is the correct one for Bob. Here, we show
|
|
|
|
that Bob can retrieve it with only the information about which he is privy pursuant to the PolicyGroup.
|
2017-10-24 00:28:10 +00:00
|
|
|
"""
|
2018-06-30 03:25:36 +00:00
|
|
|
bob = enacted_federated_policy.bob
|
2017-10-28 02:26:23 +00:00
|
|
|
|
2017-11-10 10:04:01 +00:00
|
|
|
# Of course, in the real world, Bob has sufficient information to reconstitute a PolicyGroup, gleaned, we presume,
|
|
|
|
# through a side-channel with Alice.
|
2018-02-25 23:37:14 +00:00
|
|
|
|
|
|
|
# If Bob doesn't know about any Ursulas, he can't find the TreasureMap via the REST swarm:
|
2018-09-23 04:05:11 +00:00
|
|
|
with pytest.raises(Ursula.NotEnoughUrsulas):
|
2018-07-02 12:18:31 +00:00
|
|
|
treasure_map_from_wire = bob.get_treasure_map(enacted_federated_policy.alice.stamp,
|
|
|
|
enacted_federated_policy.label)
|
2018-02-25 23:37:14 +00:00
|
|
|
|
2018-09-16 21:37:11 +00:00
|
|
|
# Bob finds out about one Ursula (in the real world, a seed node)
|
|
|
|
bob.remember_node(list(federated_ursulas)[0])
|
2018-02-25 23:37:14 +00:00
|
|
|
|
2018-09-16 21:37:11 +00:00
|
|
|
# ...and then learns about the rest of the network.
|
|
|
|
bob.learn_from_teacher_node(eager=True)
|
|
|
|
|
|
|
|
# Now he'll have better success finding that map.
|
2018-07-02 12:18:31 +00:00
|
|
|
treasure_map_from_wire = bob.get_treasure_map(enacted_federated_policy.alice.stamp,
|
|
|
|
enacted_federated_policy.label)
|
2017-10-27 02:46:34 +00:00
|
|
|
|
2018-06-30 03:25:36 +00:00
|
|
|
assert enacted_federated_policy.treasure_map == treasure_map_from_wire
|
2017-10-24 00:28:10 +00:00
|
|
|
|
|
|
|
|
2018-09-23 04:05:11 +00:00
|
|
|
def test_treasure_map_is_legit(enacted_federated_policy):
|
2017-11-09 22:28:11 +00:00
|
|
|
"""
|
|
|
|
Sure, the TreasureMap can get to Bob, but we also need to know that each Ursula in the TreasureMap is on the network.
|
|
|
|
"""
|
2018-07-12 06:13:44 +00:00
|
|
|
for ursula_address, _node_id in enacted_federated_policy.treasure_map:
|
2018-09-13 22:20:20 +00:00
|
|
|
assert ursula_address in enacted_federated_policy.bob.known_nodes
|
2018-07-10 01:12:49 +00:00
|
|
|
|
|
|
|
|
2018-09-13 19:35:44 +00:00
|
|
|
def test_vladimir_illegal_interface_key_does_not_propagate(blockchain_ursulas):
|
2018-09-12 12:04:33 +00:00
|
|
|
"""
|
2018-09-16 21:37:11 +00:00
|
|
|
Although Ursulas propagate each other's interface information, as demonstrated above,
|
|
|
|
they do not propagate interface information for Vladimir.
|
|
|
|
|
|
|
|
Specifically, if Vladimir tries to perform the most obvious imitation attack -
|
|
|
|
propagating his own wallet address along with Ursula's information - the validity
|
|
|
|
check will catch it and Ursula will refuse to propagate it and also record Vladimir's
|
|
|
|
details.
|
2018-09-12 12:04:33 +00:00
|
|
|
"""
|
2018-09-13 19:35:44 +00:00
|
|
|
ursulas = list(blockchain_ursulas)
|
2018-09-12 12:04:33 +00:00
|
|
|
ursula_whom_vladimir_will_imitate, other_ursula = ursulas[0], ursulas[1]
|
|
|
|
|
|
|
|
# This Ursula is totally legit...
|
|
|
|
ursula_whom_vladimir_will_imitate.verify_node(MockRestMiddleware(),
|
|
|
|
accept_federated_only=True)
|
|
|
|
|
|
|
|
# ...until Vladimir sees her on the network and tries to use her public information.
|
|
|
|
vladimir = Vladimir.from_target_ursula(ursula_whom_vladimir_will_imitate)
|
|
|
|
|
|
|
|
learning_callers = []
|
|
|
|
crosstown_traffic.decorator = crosstownTaskListDecoratorFactory(learning_callers)
|
|
|
|
|
|
|
|
vladimir.network_middleware.propagate_shitty_interface_id(other_ursula, bytes(vladimir))
|
|
|
|
|
|
|
|
# So far, Ursula hasn't noticed any Vladimirs.
|
|
|
|
assert other_ursula.suspicious_activities_witnessed['vladimirs'] == []
|
|
|
|
|
|
|
|
# ...but now, Ursula will now try to learn about Vladimir on a different thread.
|
|
|
|
# We only passed one node (Vladimir)...
|
|
|
|
learn_about_vladimir = learning_callers.pop()
|
|
|
|
# ...so there was only one learning caller in the queue (now none since we popped it just now).
|
|
|
|
assert len(learning_callers) == 0
|
|
|
|
|
|
|
|
# OK, so cool, let's see what happens when Ursula tries to learn about Vlad.
|
|
|
|
learn_about_vladimir()
|
|
|
|
|
|
|
|
# And indeed, Ursula noticed the situation.
|
|
|
|
# She didn't record Vladimir's address.
|
2018-09-13 22:20:20 +00:00
|
|
|
assert vladimir.checksum_public_address not in other_ursula.known_nodes
|
2018-09-12 12:04:33 +00:00
|
|
|
|
|
|
|
# But she *did* record the actual Ursula's address.
|
2018-09-13 22:20:20 +00:00
|
|
|
assert ursula_whom_vladimir_will_imitate.checksum_public_address in other_ursula.known_nodes
|
2018-09-12 12:04:33 +00:00
|
|
|
|
|
|
|
# Furthermore, she properly marked Vladimir as suspicious.
|
2018-09-13 22:20:20 +00:00
|
|
|
assert vladimir in other_ursula.suspicious_activities_witnessed['vladimirs']
|
2018-09-12 12:04:33 +00:00
|
|
|
|
|
|
|
|
2018-09-13 19:35:44 +00:00
|
|
|
def test_alice_refuses_to_make_arrangement_unless_ursula_is_valid(blockchain_alice,
|
|
|
|
idle_blockchain_policy,
|
|
|
|
blockchain_ursulas):
|
|
|
|
target = list(blockchain_ursulas)[2]
|
2018-07-10 01:12:49 +00:00
|
|
|
# First, let's imagine that Alice has sampled a Vladimir while making this policy.
|
2018-09-12 12:04:33 +00:00
|
|
|
vladimir = Vladimir.from_target_ursula(target)
|
2018-09-13 19:35:44 +00:00
|
|
|
|
2018-07-10 01:12:49 +00:00
|
|
|
message = vladimir._signable_interface_info_message()
|
|
|
|
signature = vladimir._crypto_power.power_ups(SigningPower).sign(message)
|
2018-09-13 19:35:44 +00:00
|
|
|
|
2018-07-10 01:12:49 +00:00
|
|
|
vladimir.substantiate_stamp()
|
|
|
|
vladimir._interface_signature_object = signature
|
|
|
|
|
|
|
|
class FakeArrangement:
|
|
|
|
federated = False
|
|
|
|
|
|
|
|
with pytest.raises(vladimir.InvalidNode):
|
|
|
|
idle_blockchain_policy.consider_arrangement(network_middleware=blockchain_alice.network_middleware,
|
|
|
|
arrangement=FakeArrangement(),
|
2018-09-13 19:35:44 +00:00
|
|
|
ursula=vladimir)
|