Enrico is now a lawful Character. Fixes #241.

pull/760/head
jMyles 2019-02-13 13:14:25 -07:00
parent 55dec8ff25
commit 188c0773b4
11 changed files with 83 additions and 102 deletions

View File

@ -119,7 +119,7 @@
"source": [
"Next, we'll import some Classes these bestow specific powers to each 'character' involved in the data sharing narrative. \n",
"\n",
"A common misconception made about the characters present in the NuCypher codebase is that they precisely embody the end-users of a digital application a patient, a doctor, etc. Instead, the NuCypher characters are in fact the *tools*, or *devices*, utilized by end-users to achieve their goals not the end-users themselves. This distinction will become clearer as we introduce each character (*Alice*, *Bob*, *Ursula* & *DataSource*) in detail."
"A common misconception made about the characters present in the NuCypher codebase is that they precisely embody the end-users of a digital application a patient, a doctor, etc. Instead, the NuCypher characters are in fact the *tools*, or *devices*, utilized by end-users to achieve their goals not the end-users themselves. This distinction will become clearer as we introduce each character (*Alice*, *Bob*, *Ursula* & *Enrico*) in detail."
]
},
{
@ -129,7 +129,7 @@
"outputs": [],
"source": [
"from nucypher.characters.lawful import Alice, Bob, Ursula\n",
"from nucypher.data_sources import DataSource"
"from nucypher.characters.lawful import Enrico"
]
},
{
@ -158,7 +158,7 @@
"\n",
"The NuCypher network, once launched, will comprise thousands of proxies scattered around the world, collectively performing the re-encryptions necessary to power the data sharing narratives within applications/protocols leveraging NuCypher. Every time a permission needs updating, or a data recipient has their access to granted or revoked, multiple Ursulas are marshalled to make this happen. Ursulas provide this service in exchange for fees, paid by developers like yourself. Ursulas are referred to as nodes, network participants, network nodes, miners, re-encryptors, proxies and service-providers in other contexts. Similar to the other characters, 'Ursula' represents the device utilized by a human node operator to provide a re-encryption service.\n",
"\n",
"We won't be touching Ursula directly over the course of this narrative. Instead, we'll be focusing on the characters most pertinent to an end-user facing application: Alice, Bob & DataSource. Nonetheless, it's critical to have a grasp of Ursula's role, at least on a conceptual level as there is a great deal of behind-the-scenes interaction with Ursulas occurring in virtually all NuCypher data sharing narratives. "
"We won't be touching Ursula directly over the course of this narrative. Instead, we'll be focusing on the characters most pertinent to an end-user facing application: Alice, Bob & Enrico. Nonetheless, it's critical to have a grasp of Ursula's role, at least on a conceptual level as there is a great deal of behind-the-scenes interaction with Ursulas occurring in virtually all NuCypher data sharing narratives. "
]
},
{
@ -315,7 +315,7 @@
"\n",
"##### Relevance to example real-world application\n",
"\n",
"In our hypothetical real-world application, the granting of a policy is likely to be the first instance where the medical patient proactively does something: namely, decides to add a specific doctor to an approved list of those that can see her health records. Note that Alice does not need to encrypt or send the actual data at this moment. In fact, the data doesn't even need to exist yet for example, not-yet-available results from a medical exam could be shared automatically under this policy (to all the doctors added to it), once they are ready. More on this scenario below, when we introduce *DataSource*.\n",
"In our hypothetical real-world application, the granting of a policy is likely to be the first instance where the medical patient proactively does something: namely, decides to add a specific doctor to an approved list of those that can see her health records. Note that Alice does not need to encrypt or send the actual data at this moment. In fact, the data doesn't even need to exist yet for example, not-yet-available results from a medical exam could be shared automatically under this policy (to all the doctors added to it), once they are ready. More on this scenario below, when we introduce *Enrico*.\n",
"\n",
"A few more words on the *label* architecture. Besides the security benefits mentioned above, they are a flexible way to choose per-category sharing parameters for specific data. For example, a patient might have various categories of health data, each with its own unique set of permissions their oncology results might be shared with a small group of specialists for a limited period, while the cardio data from a wearable device is shared with all their doctors, indefinitely. Labels enable the application developer to stratify the data in this way, without having to store all the data with the same parameters in the same location or file path. \n",
"\n",
@ -456,26 +456,26 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"### Encrypting and sharing on Alice's behalf with *DataSource*\n",
"### Encrypting and sharing on Alice's behalf with *Enrico*\n",
"\n",
"We're nearly there! We have a sharing policy, a confirmed recipient, and some underlying/bulk data we want to share. However, the bulk data is currently in plaintext format. To securely transport it to the recipient, we need to encrypt it in such a way that it can remain encrypted until it reaches Bob, and that he alone can decrypt it.\n",
"\n",
"To achieve this, we're going to introduce the final character in our narrative: *'DataSource'*. An important reason DataSource exists is so that Alice (& the data controller) are not needed at this stage in the narrative to perform the encryption themselves. However, this may be doing DataSource a disservice, as the character can be harnessed for more including 'producing' data on the data controller's behalf. \n",
"To achieve this, we're going to introduce the final character in our narrative: *'Enrico'*. An important reason Enrico exists is so that Alice (& the data controller) are not needed at this stage in the narrative to perform the encryption themselves. However, this may be doing Enrico a disservice, as the character can be harnessed for more including 'producing' data on the data controller's behalf. \n",
"\n",
"##### Relevance to example real-world application\n",
"\n",
"In general, DataSource affords great flexibility to applications leveraging NuCypher, because it widens the range of possible entities that can encrypt for Bob. \n",
"In general, Enrico affords great flexibility to applications leveraging NuCypher, because it widens the range of possible entities that can encrypt for Bob. \n",
"\n",
"Imagine a medical scenario where the patient is expecting a regular stream of test results, from a third-party blood-testing lab, at some point in the future, and wants those results to be immediately shared with the doctors on an existing sharing policy. It would be undesirable to stay online and continually grant access to each test-result as it arrived. \n",
"\n",
"To avoid this, the application can assign a special role to the blood-testing lab, such that the lab gains the encryption powers of DataSource. Similar to the way 'Alice' represents the patient's device, DataSource can do the same for primary producers of data in this case, the blood-testing lab. Hence, the lab can write the new data onto the sharing policy, under the specified label. Then, the designated doctors can access it. Thus, DataSource is 'producing' data on the patient's behalf. \n",
"To avoid this, the application can assign a special role to the blood-testing lab, such that the lab gains the encryption powers of Enrico. Similar to the way 'Alice' represents the patient's device, Enrico can do the same for primary producers of data in this case, the blood-testing lab. Hence, the lab can write the new data onto the sharing policy, under the specified label. Then, the designated doctors can access it. Thus, Enrico is 'producing' data on the patient's behalf. \n",
"\n",
"Note: this does not mean that DataSource, or the lab, can access other data on the sharing policy - including their own test results, once they've been saved. Accessing the data would require a *read* permission, which has only been granted to Bob through the existence of a sharing policy, and re-encryption key, in his name. Rather, DataSource(s) have been solely granted a *write* permission to the policy. \n",
"Note: this does not mean that Enrico, or the lab, can access other data on the sharing policy - including their own test results, once they've been saved. Accessing the data would require a *read* permission, which has only been granted to Bob through the existence of a sharing policy, and re-encryption key, in his name. Rather, Enrico(s) have been solely granted a *write* permission to the policy. \n",
"\n",
"In general, these write permissions can be recorded directly onto a distributed ledger, such that the application can reliably confirm the correct actor is producing/encrypting data for a given sharing policy. As we will encounter below, this data also comes with a signature, which helps the recipient further verify its authenticity. \n",
"\n",
"\n",
"Let's first create a DataSource specifically for our sharing policy. "
"Let's first create a Enrico specifically for our sharing policy. "
]
},
{
@ -484,16 +484,16 @@
"metadata": {},
"outputs": [],
"source": [
"data_source = DataSource(policy_pubkey_enc=policy.public_key)"
"data_source = Enrico(policy_pubkey_enc=policy.public_key)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We're going to use DataSource to encrypt the data we wish to share the passages from Finnegans Wake. We're also going to generate an artifact known as a 'MessageKit' this contains a ciphertext (the encrypted version of the passages), plus two unique identifiers: the policy's public key, and the recipient's public key. \n",
"We're going to use Enrico to encrypt the data we wish to share the passages from Finnegans Wake. We're also going to generate an artifact known as a 'MessageKit' this contains a ciphertext (the encrypted version of the passages), plus two unique identifiers: the policy's public key, and the recipient's public key. \n",
"\n",
"We'll also take this opportunity to generate a signature. The signature is unique to that message, and, when verified, can confirm that the data has not been corrupted or manipulated while in transit, and that the data did indeed come from the expected, correct DataSource. This further mitigates the risk of incorrect data being added to a label from a malignant source that has gotten hold of the relevant public keys. The signature can be sent to Bob via a side-channel, or published publicly as a evidence of the manner in which the data was shared.\n",
"We'll also take this opportunity to generate a signature. The signature is unique to that message, and, when verified, can confirm that the data has not been corrupted or manipulated while in transit, and that the data did indeed come from the expected, correct Enrico. This further mitigates the risk of incorrect data being added to a label from a malignant source that has gotten hold of the relevant public keys. The signature can be sent to Bob via a side-channel, or published publicly as a evidence of the manner in which the data was shared.\n",
"\n",
"Let's go ahead and create a tuple for these: "
]
@ -511,7 +511,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"We want Bob to be able to verify that MessageKit and signature he will soon access came from the right DataSource, so we'll save its public key, in the same way we did Alice's public key earlier: "
"We want Bob to be able to verify that MessageKit and signature he will soon access came from the right Enrico, so we'll save its public key, in the same way we did Alice's public key earlier: "
]
},
{
@ -528,7 +528,7 @@
"metadata": {},
"source": [
"### Retrieiving the data with *Bob*\n",
"To give the designated recipient even greater independence with regard to when and how they access the data, we're going to include a snippet which reconstructs the DataSource from Bob's perspective. This may not be necessary, if the DataSource remains online and available, but this means there's no obligation to keep DataSource around."
"To give the designated recipient even greater independence with regard to when and how they access the data, we're going to include a snippet which reconstructs the Enrico from Bob's perspective. This may not be necessary, if the Enrico remains online and available, but this means there's no obligation to keep Enrico around."
]
},
{
@ -537,9 +537,9 @@
"metadata": {},
"outputs": [],
"source": [
"datasource_as_understood_by_bob = DataSource.from_public_keys(\n",
"enrico_as_understood_by_bob = Enrico.from_public_keys(\n",
" policy_public_key=policy.public_key,\n",
" datasource_public_key=data_source_public_key,\n",
" enrico_public_key=data_source_public_key,\n",
" label=label\n",
" )"
]
@ -552,13 +552,13 @@
"\n",
"1) The MessageKit the actual data. \n",
"\n",
"2) DataSource where we got the data from.\n",
"2) Enrico where we got the data from.\n",
"\n",
"3) Alice's public key an identifier for the original delegator of the data. \n",
"\n",
"##### Relevance to example real-world application\n",
"\n",
"In our hypothetical medical application, this is the stage where the doctor accesses the patient's health records. How the doctor does this is flexible the application could automatically retrieve the data as soon as it is suitably encrypted by DataSource, or the doctor could be required to proactively decide when they want their access to begin the latter may be useful if it's desirable to notify the patient that the doctor has now begun their analysis/diagnosis, and/or how much time the doctor spends looking at the data, for example. \n",
"In our hypothetical medical application, this is the stage where the doctor accesses the patient's health records. How the doctor does this is flexible the application could automatically retrieve the data as soon as it is suitably encrypted by Enrico, or the doctor could be required to proactively decide when they want their access to begin the latter may be useful if it's desirable to notify the patient that the doctor has now begun their analysis/diagnosis, and/or how much time the doctor spends looking at the data, for example. \n",
"\n",
"##### Relevant work/optionality abstracted by the .retrieve() method\n",
"\n",
@ -583,7 +583,7 @@
"outputs": [],
"source": [
" delivered_cleartext = BOB.retrieve(message_kit=message_kit,\n",
" data_source=datasource_as_understood_by_bob,\n",
" data_source=enrico_as_understood_by_bob,\n",
" alice_pubkey_sig=alices_pubkey_saved_for_posterity)"
]
},

View File

@ -7,10 +7,10 @@ participants in public consensus networks, without revealing data keys to interm
1. Alice sets a Policy on the NuCypher network (2/3) and grants access to Bob
2. Label and Alice's key public key provided to Bob
4. Bob joins the policy by Label and Alice's public key
5. DataSource created for the policy
6. Each plaintext message gets encapsulated through the DataSource to messageKit
5. Bob receives and reconstructs the DataSource from Policy public key and DataSource public key
6. Bob retrieves the original message form DataSource and MessageKit
5. Enrico created for the policy
6. Each plaintext message gets encapsulated through the Enrico to messageKit
5. Bob receives and reconstructs the Enrico from Policy public key and Enrico public key
6. Bob retrieves the original message form Enrico and MessageKit
### Install Nucypher
```

View File

@ -7,7 +7,7 @@ from twisted.logger import globalLogPublisher
from umbral.keys import UmbralPublicKey
from nucypher.characters.lawful import Alice, Bob, Ursula
from nucypher.data_sources import DataSource as Enrico
from nucypher.characters.lawful import Enrico as Enrico
from nucypher.network.middleware import RestMiddleware
from nucypher.utilities.logging import SimpleObserver
@ -122,7 +122,7 @@ for counter, plaintext in enumerate(finnegans_wake):
enrico_as_understood_by_bob = Enrico.from_public_keys(
policy_public_key=policy_pubkey,
datasource_public_key=data_source_public_key,
enrico_public_key=data_source_public_key,
label=label
)

View File

@ -2,13 +2,13 @@ import random
import time
import msgpack
from nucypher.data_sources import DataSource
from nucypher.characters.lawful import Enrico
HEART_DATA_FILENAME = 'heart_data.msgpack'
# Alicia defined a label to categorize all her heart-related data ❤️
# All DataSources that produce this type of data will use this label.
# All Enricos that produce this type of data will use this label.
DEFAULT_LABEL = b"Alicia's heart data"
@ -16,7 +16,7 @@ def generate_heart_rate_samples(policy_pubkey,
label: bytes = DEFAULT_LABEL,
samples: int = 500,
save_as_file: bool = False):
data_source = DataSource(policy_pubkey_enc=policy_pubkey,
data_source = Enrico(policy_pubkey_enc=policy_pubkey,
label=label)
data_source_public_key = bytes(data_source.stamp)

View File

@ -16,31 +16,30 @@ along with nucypher. If not, see <https://www.gnu.org/licenses/>.
"""
import json
import random
import socket
from collections import OrderedDict
from flask import Flask, request, Response
from functools import partial
from typing import Dict
from typing import Iterable
from typing import List
from typing import Set
from json.decoder import JSONDecodeError
from base64 import b64encode, b64decode
from collections import OrderedDict
from json.decoder import JSONDecodeError
import maya
import requests
import socket
import time
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurve
from cryptography.hazmat.primitives.serialization import Encoding
from cryptography.x509 import load_pem_x509_certificate, Certificate, NameOID
from eth_utils import to_checksum_address
from flask import Flask, request, Response
from functools import partial
from twisted.internet import threads
from twisted.logger import Logger
from typing import Dict
from typing import Iterable
from typing import List
from typing import Set
from umbral.keys import UmbralPublicKey
from umbral.signing import Signature
from typing import Tuple
from bytestring_splitter import BytestringKwargifier, BytestringSplittingError
from bytestring_splitter import BytestringSplitter, VariableLengthBytestring
@ -51,8 +50,9 @@ from nucypher.blockchain.eth.agents import MinerAgent
from nucypher.characters.base import Character, Learner
from nucypher.config.constants import GLOBAL_DOMAIN
from nucypher.config.storages import NodeStorage, ForgetfulNodeStorage
from nucypher.crypto.api import keccak_digest
from nucypher.crypto.api import keccak_digest, encrypt_and_sign
from nucypher.crypto.constants import PUBLIC_KEY_LENGTH, PUBLIC_ADDRESS_LENGTH
from nucypher.crypto.kits import UmbralMessageKit
from nucypher.crypto.powers import SigningPower, DecryptingPower, DelegatingPower, BlockchainPower, PowerUpError
from nucypher.keystore.keypairs import HostingKeypair
from nucypher.network.middleware import RestMiddleware, UnexpectedResponse, NotFound
@ -995,3 +995,24 @@ class Ursula(Teacher, Character, Miner):
if work_order.bob == bob:
work_orders_from_bob.append(work_order)
return work_orders_from_bob
class Enrico(Character):
_default_crypto_powerups = [SigningPower]
def __init__(self, policy_encrypting_key, label, *args, **kwargs):
self.policy_pubkey = policy_encrypting_key
self.label = label
# Encrico never uses the blockchain, hence federated_only)
super().__init__(federated_only=True, *args, **kwargs)
def encrypt_message(self,
message: bytes
) -> Tuple[UmbralMessageKit, Signature]:
message_kit, signature = encrypt_and_sign(self.policy_pubkey,
plaintext=message,
signer=self.stamp)
message_kit.policy_pubkey = self.policy_pubkey # TODO: We can probably do better here.
return message_kit, signature

View File

@ -23,34 +23,3 @@ from nucypher.crypto.kits import UmbralMessageKit
from nucypher.crypto.signing import Signature
from nucypher.crypto.powers import SigningPower
from nucypher.keystore.keypairs import SigningKeypair
class DataSource:
def __init__(self, policy_pubkey_enc, signing_keypair=NO_SIGNING_POWER, label=None) -> None:
self.policy_pubkey = policy_pubkey_enc
if signing_keypair is NO_SIGNING_POWER:
signing_keypair = SigningKeypair() # TODO: Generate signing key properly. #241
signing_power = SigningPower(keypair=signing_keypair)
self.stamp = signing_power.get_signature_stamp()
self.label = label
def encrypt_message(self,
message: bytes
) -> Tuple[UmbralMessageKit, Signature]:
message_kit, signature = encrypt_and_sign(self.policy_pubkey,
plaintext=message,
signer=self.stamp)
message_kit.policy_pubkey = self.policy_pubkey # TODO: We can probably do better here.
return message_kit, signature
@classmethod
def from_public_keys(cls,
policy_public_key: UmbralPublicKey,
datasource_public_key: bytes,
label: bytes):
umbral_public_key = UmbralPublicKey.from_bytes(datasource_public_key)
return cls(policy_public_key,
signing_keypair=SigningKeypair(public_key=umbral_public_key),
label=label,
)

View File

@ -4,10 +4,10 @@ from base64 import b64encode, b64decode
from flask import Flask, request, Response
from json.decoder import JSONDecodeError
from nucypher.data_sources import DataSource
from nucypher.characters.lawful import Enrico
def make_enrico_control(drone_enrico: DataSource):
def make_enrico_control(drone_enrico: Enrico):
enrico_control = Flask("enrico-control")
@enrico_control.route('/encrypt_message', methods=['POST'])

View File

@ -299,6 +299,6 @@ def test_federated_bob_retrieves(federated_bob,
data_source=the_data_source,
alice_verifying_key=alices_verifying_key)
# We show that indeed this is the passage originally encrypted by the DataSource.
# We show that indeed this is the passage originally encrypted by the Enrico.
assert b"Welcome to the flippering." == delivered_cleartexts[0]

View File

@ -6,7 +6,7 @@ import pytest
from constant_sorrow.constants import NO_DECRYPTION_PERFORMED
from nucypher.characters.lawful import Bob, Ursula
from nucypher.data_sources import DataSource
from nucypher.characters.lawful import Enrico
from nucypher.keystore.keypairs import SigningKeypair
from nucypher.policy.models import TreasureMap
from nucypher.utilities.sandbox.constants import NUMBER_OF_URSULAS_IN_DEVELOPMENT_NETWORK, MOCK_POLICY_DEFAULT_M
@ -38,7 +38,7 @@ def test_federated_bob_retrieves(federated_ursulas,
data_source=the_data_source,
alice_verifying_key=alices_verifying_key)
# We show that indeed this is the passage originally encrypted by the DataSource.
# We show that indeed this is the passage originally encrypted by the Enrico.
assert b"Welcome to the flippering." == delivered_cleartexts[0]
@ -86,20 +86,19 @@ def test_bob_joins_policy_and_retrieves(federated_alice,
# In the end, Bob should know all the Ursulas
assert len(bob.known_nodes) == len(federated_ursulas)
# DataSource becomes
data_source = DataSource(policy_pubkey_enc=policy.public_key,
signing_keypair=SigningKeypair(),
# Enrico becomes
enrico = Enrico(policy_encrypting_key=policy.public_key,
label=label
)
plaintext = b"What's your approach? Mississippis or what?"
message_kit, _signature = data_source.encrypt_message(plaintext)
message_kit, _signature = enrico.encrypt_message(plaintext)
alices_verifying_key = federated_alice.stamp.as_umbral_pubkey()
# Bob takes the message_kit and retrieves the message within
delivered_cleartexts = bob.retrieve(message_kit=message_kit,
data_source=data_source,
data_source=enrico,
alice_verifying_key=alices_verifying_key)
assert plaintext == delivered_cleartexts[0]
@ -110,7 +109,7 @@ def test_bob_joins_policy_and_retrieves(federated_alice,
with pytest.raises(Ursula.NotEnoughUrsulas):
_cleartexts = bob.retrieve(message_kit=message_kit,
data_source=data_source,
data_source=enrico,
alice_verifying_key=alices_verifying_key)

View File

@ -16,13 +16,13 @@ along with nucypher. If not, see <https://www.gnu.org/licenses/>.
"""
import eth_utils
import pytest
from constant_sorrow import constants
from constant_sorrow import constants
from nucypher.characters.lawful import Alice, Character, Bob
from nucypher.characters.lawful import Enrico
from nucypher.crypto import api
from nucypher.crypto.powers import CryptoPower, SigningPower, NoSigningPower, \
BlockchainPower, PowerUpError
from nucypher.data_sources import DataSource
"""
Chapter 1: SIGNING
@ -239,20 +239,18 @@ def test_encrypt_but_do_not_sign(federated_alice, federated_bob):
def test_alice_can_decrypt(federated_alice):
label = b"boring test label"
policy_pubkey = federated_alice.get_policy_pubkey_from_label(label)
data_source = DataSource(policy_pubkey_enc=policy_pubkey,
label=label)
enrico = Enrico(policy_encrypting_key=policy_pubkey,
label=label)
message = b"boring test message"
message_kit, signature = data_source.encrypt_message(message=message)
message_kit, signature = enrico.encrypt_message(message=message)
cleartext = federated_alice.verify_from(stranger=data_source,
cleartext = federated_alice.verify_from(stranger=enrico,
message_kit=message_kit,
signature=signature,
decrypt=True)
assert cleartext == message

View File

@ -29,16 +29,11 @@ from nucypher.blockchain.eth.deployers import PolicyManagerDeployer, NucypherTok
from nucypher.blockchain.eth.interfaces import BlockchainDeployerInterface
from nucypher.blockchain.eth.registry import InMemoryEthereumContractRegistry
from nucypher.blockchain.eth.sol.compile import SolidityCompiler
from nucypher.characters.lawful import Bob
from nucypher.config.characters import UrsulaConfiguration, AliceConfiguration, BobConfiguration
from nucypher.config.constants import BASE_DIR
from nucypher.config.node import NodeConfiguration
from nucypher.data_sources import DataSource
from nucypher.keystore import keystore
from nucypher.keystore.db import Base
from nucypher.keystore.keypairs import SigningKeypair
from nucypher.network.character_control import bob
from nucypher.network.character_control import enrico
from nucypher.utilities.sandbox.blockchain import TesterBlockchain, token_airdrop
from nucypher.utilities.sandbox.constants import (NUMBER_OF_URSULAS_IN_DEVELOPMENT_NETWORK,
DEVELOPMENT_TOKEN_AIRDROP_AMOUNT, MOCK_URSULA_STARTING_PORT,
@ -262,10 +257,9 @@ def enacted_blockchain_policy(idle_blockchain_policy, blockchain_ursulas):
@pytest.fixture(scope="module")
def capsule_side_channel(enacted_federated_policy):
data_source = DataSource(policy_pubkey_enc=enacted_federated_policy.public_key,
signing_keypair=SigningKeypair(),
label=enacted_federated_policy.label
)
data_source = Enrico(policy_encrypting_key=enacted_federated_policy.public_key,
label=enacted_federated_policy.label
)
message_kit, _signature = data_source.encrypt_message(b"Welcome to the flippering.")
return message_kit, data_source
@ -337,7 +331,7 @@ def alice_control(federated_alice, federated_ursulas):
@pytest.fixture(scope='module')
def bob_control(federated_bob, federated_ursulas):
teacher_node = list(federated_ursulas)[0]
bob_control = bob.make_bob_control(federated_bob, teacher_node)
bob_control = make_bob_control(federated_bob, teacher_node)
bob_control.config['DEBUG'] = True
bob_control.config['TESTING'] = True
yield bob_control.test_client()
@ -346,7 +340,7 @@ def bob_control(federated_bob, federated_ursulas):
@pytest.fixture(scope='module')
def enrico_control(capsule_side_channel):
_, data_source = capsule_side_channel
enrico_control = enrico.make_enrico_control(data_source)
enrico_control = make_enrico_control(data_source)
enrico_control.config['DEBUG'] = True
enrico_control.config['TESTING'] = True
yield enrico_control.test_client()