2018-11-04 19:23:11 +00:00
|
|
|
"""
|
|
|
|
This file is part of nucypher.
|
|
|
|
|
|
|
|
nucypher is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
nucypher is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with nucypher. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
"""
|
2018-07-29 19:21:40 +00:00
|
|
|
|
|
|
|
|
2017-12-10 01:21:43 +00:00
|
|
|
import datetime
|
2018-06-04 18:00:08 +00:00
|
|
|
import maya
|
2018-11-08 11:07:12 +00:00
|
|
|
import os
|
2018-09-24 20:59:38 +00:00
|
|
|
import pytest
|
2018-07-29 19:21:40 +00:00
|
|
|
from apistar.test import TestClient
|
2018-07-20 21:48:37 +00:00
|
|
|
from umbral.fragments import KFrag
|
2018-02-11 09:06:39 +00:00
|
|
|
|
2018-11-08 11:07:52 +00:00
|
|
|
from nucypher.characters.lawful import Bob, Ursula
|
2018-11-08 11:07:12 +00:00
|
|
|
from nucypher.config.characters import AliceConfiguration
|
|
|
|
from nucypher.config.storages import LocalFileBasedNodeStorage
|
2018-05-08 19:35:34 +00:00
|
|
|
from nucypher.crypto.api import keccak_digest
|
2018-11-15 07:42:06 +00:00
|
|
|
from nucypher.crypto.kits import RevocationKit
|
2018-11-08 11:07:52 +00:00
|
|
|
from nucypher.crypto.powers import SigningPower, DelegatingPower, EncryptingPower
|
2018-11-08 11:07:12 +00:00
|
|
|
from nucypher.utilities.sandbox.constants import TEST_URSULA_INSECURE_DEVELOPMENT_PASSWORD
|
|
|
|
from nucypher.utilities.sandbox.middleware import MockRestMiddleware
|
2018-09-13 19:26:25 +00:00
|
|
|
from nucypher.utilities.sandbox.policy import MockPolicyCreation
|
2018-02-11 03:53:57 +00:00
|
|
|
|
2017-12-10 01:21:43 +00:00
|
|
|
|
2018-09-25 01:16:04 +00:00
|
|
|
@pytest.mark.skip(reason="to be implemented")
|
2018-09-24 20:59:38 +00:00
|
|
|
@pytest.mark.usefixtures('blockchain_ursulas')
|
|
|
|
def test_mocked_decentralized_grant(blockchain_alice, blockchain_bob, three_agents):
|
2018-09-25 01:16:04 +00:00
|
|
|
|
2018-09-13 19:26:25 +00:00
|
|
|
# Monkey patch Policy Creation
|
2018-09-25 01:16:04 +00:00
|
|
|
_token_agent, _miner_agent, policy_agent = three_agents
|
2018-06-17 07:49:12 +00:00
|
|
|
policy_agent.blockchain.wait_for_receipt = MockPolicyCreation.wait_for_receipt
|
|
|
|
policy_agent.contract.functions.createPolicy = MockPolicyCreation
|
|
|
|
|
2018-09-25 01:16:04 +00:00
|
|
|
# Setup the policy details
|
|
|
|
n = 3
|
|
|
|
policy_end_datetime = maya.now() + datetime.timedelta(days=5)
|
|
|
|
label = b"this_is_the_path_to_which_access_is_being_granted"
|
|
|
|
|
|
|
|
# Create the Policy, Grating access to Bob
|
2018-09-24 20:59:38 +00:00
|
|
|
policy = blockchain_alice.grant(blockchain_bob, label, m=2, n=n, expiration=policy_end_datetime)
|
2018-06-23 03:27:43 +00:00
|
|
|
|
|
|
|
# The number of accepted arrangements at least the number of Ursulas we're using (n)
|
|
|
|
assert len(policy._accepted_arrangements) >= n
|
2018-06-17 07:49:12 +00:00
|
|
|
|
2018-06-23 03:27:43 +00:00
|
|
|
# The number of actually enacted arrangements is exactly equal to n.
|
|
|
|
assert len(policy._enacted_arrangements) == n
|
2017-12-10 01:21:43 +00:00
|
|
|
|
2018-06-23 03:27:43 +00:00
|
|
|
# Let's look at the enacted arrangements.
|
|
|
|
for kfrag in policy.kfrags:
|
|
|
|
arrangement = policy._enacted_arrangements[kfrag]
|
2017-12-10 01:21:43 +00:00
|
|
|
|
2018-06-23 03:27:43 +00:00
|
|
|
# Get the Arrangement from Ursula's datastore, looking up by hrac.
|
|
|
|
# This will be changed in 180, when we use the Arrangement ID.
|
2018-09-24 20:59:38 +00:00
|
|
|
proper_hrac = keccak_digest(bytes(blockchain_alice.stamp) + bytes(blockchain_bob.stamp) + label)
|
2018-09-06 18:44:03 +00:00
|
|
|
retrieved_policy = arrangement.ursula.datastore.get_policy_arrangement(arrangement.id.hex().encode())
|
2018-10-19 01:06:34 +00:00
|
|
|
retrieved_kfrag = KFrag.from_bytes(retrieved_policy.kfrag)
|
2018-02-12 21:33:34 +00:00
|
|
|
|
2018-06-23 03:27:43 +00:00
|
|
|
assert kfrag == retrieved_kfrag
|
2018-09-25 01:16:04 +00:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.usefixtures('federated_ursulas')
|
|
|
|
def test_federated_grant(federated_alice, federated_bob):
|
|
|
|
|
|
|
|
# Setup the policy details
|
2018-11-08 11:06:35 +00:00
|
|
|
m, n = 2, 3
|
2018-09-25 01:16:04 +00:00
|
|
|
policy_end_datetime = maya.now() + datetime.timedelta(days=5)
|
|
|
|
label = b"this_is_the_path_to_which_access_is_being_granted"
|
|
|
|
|
2018-11-08 11:06:35 +00:00
|
|
|
# Create the Policy, granting access to Bob
|
|
|
|
policy = federated_alice.grant(federated_bob, label, m=m, n=n, expiration=policy_end_datetime)
|
2018-09-25 01:16:04 +00:00
|
|
|
|
|
|
|
# The number of accepted arrangements at least the number of Ursulas we're using (n)
|
|
|
|
assert len(policy._accepted_arrangements) >= n
|
|
|
|
|
|
|
|
# The number of actually enacted arrangements is exactly equal to n.
|
|
|
|
assert len(policy._enacted_arrangements) == n
|
|
|
|
|
|
|
|
# Let's look at the enacted arrangements.
|
|
|
|
for kfrag in policy.kfrags:
|
|
|
|
arrangement = policy._enacted_arrangements[kfrag]
|
|
|
|
|
|
|
|
# Get the Arrangement from Ursula's datastore, looking up by hrac.
|
|
|
|
# This will be changed in 180, when we use the Arrangement ID.
|
|
|
|
proper_hrac = keccak_digest(bytes(federated_alice.stamp) + bytes(federated_bob.stamp) + label)
|
|
|
|
retrieved_policy = arrangement.ursula.datastore.get_policy_arrangement(arrangement.id.hex().encode())
|
2018-10-19 01:06:34 +00:00
|
|
|
retrieved_kfrag = KFrag.from_bytes(retrieved_policy.kfrag)
|
2018-09-25 01:16:04 +00:00
|
|
|
|
|
|
|
assert kfrag == retrieved_kfrag
|
2018-11-08 11:07:12 +00:00
|
|
|
|
2018-07-29 19:21:40 +00:00
|
|
|
failed_revocations = alice.revoke(policy)
|
|
|
|
assert len(failed_revocations) == 0
|
|
|
|
|
2018-11-08 11:07:12 +00:00
|
|
|
|
2018-11-08 11:07:52 +00:00
|
|
|
def test_alices_powers_are_persistent(federated_ursulas, tmpdir):
|
2018-11-08 11:07:12 +00:00
|
|
|
|
|
|
|
passphrase = TEST_URSULA_INSECURE_DEVELOPMENT_PASSWORD
|
|
|
|
|
|
|
|
# Let's create an Alice from a Configuration.
|
|
|
|
# This requires creating a local storage for her first.
|
|
|
|
node_storage = LocalFileBasedNodeStorage(
|
|
|
|
federated_only=True,
|
2018-11-08 11:07:52 +00:00
|
|
|
character_class=Ursula, # Alice needs to store some info about Ursula
|
2018-11-08 11:07:12 +00:00
|
|
|
known_metadata_dir=os.path.join(tmpdir, "known_metadata"),
|
|
|
|
)
|
|
|
|
|
|
|
|
alice_config = AliceConfiguration(
|
|
|
|
config_root=os.path.join(tmpdir, "config_root"),
|
|
|
|
node_storage=node_storage,
|
|
|
|
auto_initialize=True,
|
|
|
|
auto_generate_keys=True,
|
|
|
|
passphrase=passphrase,
|
|
|
|
is_me=True,
|
|
|
|
network_middleware=MockRestMiddleware(),
|
|
|
|
known_nodes=federated_ursulas,
|
|
|
|
start_learning_now=False,
|
|
|
|
federated_only=True,
|
|
|
|
save_metadata=False,
|
|
|
|
load_metadata=False
|
|
|
|
)
|
|
|
|
alice = alice_config(passphrase=passphrase)
|
|
|
|
|
|
|
|
# We will save Alice's config to a file for later use
|
|
|
|
alice_config_file = alice_config.to_configuration_file()
|
|
|
|
|
2018-11-08 11:07:52 +00:00
|
|
|
# Let's save Alice's public keys too to check they are correctly restored later
|
|
|
|
alices_verifying_key = alice.public_keys(SigningPower)
|
|
|
|
alices_receiving_key = alice.public_keys(EncryptingPower)
|
|
|
|
|
|
|
|
# Next, let's fix a label for all the policies we will create later.
|
|
|
|
label = b"this_is_the_path_to_which_access_is_being_granted"
|
|
|
|
|
|
|
|
# Even before creating the policies, we can know what will be its public key.
|
|
|
|
# This can be used by DataSources to encrypt messages before Alice grants access to Bobs
|
|
|
|
policy_pubkey = alice.get_policy_pubkey_from_label(label)
|
|
|
|
|
|
|
|
# Now, let's create a policy for some Bob.
|
2018-11-08 11:07:12 +00:00
|
|
|
m, n = 3, 4
|
|
|
|
policy_end_datetime = maya.now() + datetime.timedelta(days=5)
|
|
|
|
|
|
|
|
bob = Bob(federated_only=True,
|
|
|
|
start_learning_now=False,
|
|
|
|
network_middleware=MockRestMiddleware(),
|
|
|
|
)
|
|
|
|
|
|
|
|
bob_policy = alice.grant(bob, label, m=m, n=n, expiration=policy_end_datetime)
|
|
|
|
|
2018-11-08 11:07:52 +00:00
|
|
|
assert policy_pubkey == bob_policy.public_key
|
|
|
|
|
2018-11-08 11:07:12 +00:00
|
|
|
# ... and Alice and her configuration disappear.
|
|
|
|
del alice
|
|
|
|
del alice_config
|
|
|
|
|
|
|
|
###################################
|
|
|
|
# Some time passes. #
|
|
|
|
# ... #
|
|
|
|
# (jmyles plays the Song of Time) #
|
|
|
|
# ... #
|
|
|
|
# Alice appears again. #
|
|
|
|
###################################
|
|
|
|
|
2018-11-08 11:07:52 +00:00
|
|
|
# A new Alice is restored from the configuration file
|
2018-11-08 11:07:12 +00:00
|
|
|
new_alice_config = AliceConfiguration.from_configuration_file(
|
|
|
|
filepath=alice_config_file,
|
|
|
|
network_middleware=MockRestMiddleware(),
|
|
|
|
known_nodes=federated_ursulas,
|
|
|
|
start_learning_now=False,
|
|
|
|
)
|
|
|
|
|
|
|
|
new_alice = new_alice_config(passphrase=passphrase)
|
|
|
|
|
2018-11-08 11:07:52 +00:00
|
|
|
# First, we check that her public keys are correctly restored
|
|
|
|
assert alices_verifying_key == new_alice.public_keys(SigningPower)
|
|
|
|
assert alices_receiving_key == new_alice.public_keys(EncryptingPower)
|
|
|
|
|
2018-11-08 11:07:12 +00:00
|
|
|
# Bob's eldest brother, Roberto, appears too
|
|
|
|
roberto = Bob(federated_only=True,
|
|
|
|
start_learning_now=False,
|
|
|
|
network_middleware=MockRestMiddleware(),
|
|
|
|
)
|
|
|
|
|
|
|
|
# Alice creates a new policy for Roberto. Note how all the parameters
|
|
|
|
# except for the label (i.e., recipient, m, n, policy_end) are different
|
|
|
|
# from previous policy
|
|
|
|
m, n = 2, 5
|
|
|
|
policy_end_datetime = maya.now() + datetime.timedelta(days=3)
|
|
|
|
roberto_policy = new_alice.grant(roberto, label, m=m, n=n, expiration=policy_end_datetime)
|
|
|
|
|
2018-11-08 11:07:52 +00:00
|
|
|
# Both policies must share the same public key (i.e., the policy public key)
|
|
|
|
assert policy_pubkey == roberto_policy.public_key
|
2018-11-08 11:07:12 +00:00
|
|
|
|