mirror of https://github.com/nucypher/nucypher.git
157 lines
5.1 KiB
Python
157 lines
5.1 KiB
Python
"""
|
|
This file is part of nucypher.
|
|
|
|
nucypher is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Affero General Public License
|
|
along with nucypher. If not, see <https://www.gnu.org/licenses/>.
|
|
"""
|
|
|
|
import datetime
|
|
import sys
|
|
import json
|
|
import os
|
|
import shutil
|
|
|
|
import maya
|
|
|
|
from nucypher.characters.lawful import Bob, Ursula
|
|
from nucypher.config.characters import AliceConfiguration
|
|
from nucypher.config.constants import TEMPORARY_DOMAIN
|
|
from nucypher.utilities.logging import GlobalLoggerSettings
|
|
|
|
|
|
######################
|
|
# Boring setup stuff #
|
|
######################
|
|
|
|
|
|
# Twisted Logger
|
|
|
|
GlobalLoggerSettings.start_console_logging()
|
|
|
|
TEMP_ALICE_DIR = os.path.join('/', 'tmp', 'heartbeat-demo-alice')
|
|
|
|
|
|
# if your ursulas are NOT running on your current host,
|
|
# run like this: python alicia.py 172.28.1.3:11500
|
|
# otherwise the default will be fine.
|
|
|
|
try:
|
|
SEEDNODE_URI = sys.argv[1]
|
|
except IndexError:
|
|
SEEDNODE_URI = "localhost:11500"
|
|
|
|
POLICY_FILENAME = "policy-metadata.json"
|
|
|
|
|
|
#######################################
|
|
# Alicia, the Authority of the Policy #
|
|
#######################################
|
|
|
|
|
|
# We get a persistent Alice.
|
|
# If we had an existing Alicia in disk, let's get it from there
|
|
|
|
passphrase = "TEST_ALICIA_INSECURE_DEVELOPMENT_PASSWORD"
|
|
# 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)
|
|
|
|
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()
|
|
|
|
# We will save Alicia's config to a file for later use
|
|
alice_config_file = alice_config.to_configuration_file()
|
|
|
|
# Let's get to learn about the NuCypher network
|
|
alicia.start_learning_loop(now=True)
|
|
|
|
# At this point, Alicia is fully operational and can create policies.
|
|
# The Policy Label is a bytestring that categorizes the data that Alicia wants to share.
|
|
# Note: we add some random chars to create different policies, only for demonstration purposes
|
|
label = "heart-data-❤️-"+os.urandom(4).hex()
|
|
label = label.encode()
|
|
|
|
# Alicia can create the public key associated to the policy label,
|
|
# even before creating any associated policy.
|
|
policy_pubkey = alicia.get_policy_encrypting_key_from_label(label)
|
|
|
|
print("The policy public key for "
|
|
"label '{}' is {}".format(label.decode("utf-8"), policy_pubkey.to_bytes().hex()))
|
|
|
|
# Data Sources can produce encrypted data for access policies
|
|
# that **don't exist yet**.
|
|
# In this example, we create a local file with encrypted data, containing
|
|
# heart rate measurements from a heart monitor
|
|
import heart_monitor
|
|
heart_monitor.generate_heart_rate_samples(policy_pubkey,
|
|
samples=50,
|
|
save_as_file=True)
|
|
|
|
|
|
# Alicia now wants to share data associated with this label.
|
|
# To do so, she needs the public key of the recipient.
|
|
# In this example, we generate it on the fly (for demonstration purposes)
|
|
from doctor_keys import get_doctor_pubkeys
|
|
doctor_pubkeys = get_doctor_pubkeys()
|
|
|
|
# We create a view of the Bob who's going to be granted access.
|
|
doctor_strange = Bob.from_public_keys(verifying_key=doctor_pubkeys['sig'],
|
|
encrypting_key=doctor_pubkeys['enc'],
|
|
federated_only=True)
|
|
|
|
# Here are our remaining Policy details, such as:
|
|
# - Policy expiration date
|
|
policy_end_datetime = maya.now() + datetime.timedelta(days=5)
|
|
# - m-out-of-n: This means Alicia splits the re-encryption key in 5 pieces and
|
|
# she requires Bob to seek collaboration of at least 3 Ursulas
|
|
m, n = 2, 3
|
|
|
|
|
|
# With this information, Alicia creates a policy granting access to Bob.
|
|
# The policy is sent to the NuCypher network.
|
|
print("Creating access policy for the Doctor...")
|
|
policy = alicia.grant(bob=doctor_strange,
|
|
label=label,
|
|
m=m,
|
|
n=n,
|
|
expiration=policy_end_datetime)
|
|
print("Done!")
|
|
|
|
# For the demo, we need a way to share with Bob some additional info
|
|
# about the policy, so we store it in a JSON file
|
|
policy_info = {
|
|
"policy_pubkey": policy.public_key.to_bytes().hex(),
|
|
"alice_sig_pubkey": bytes(alicia.stamp).hex(),
|
|
"label": label.decode("utf-8"),
|
|
}
|
|
|
|
filename = POLICY_FILENAME
|
|
with open(filename, 'w') as f:
|
|
json.dump(policy_info, f)
|