Modify character classes to use runtime files and directories: certificates and metadata

pull/437/head
Kieran Prasch 2018-09-17 14:10:48 -07:00 committed by jMyles
parent 47d50a9e1a
commit 9842b5d096
6 changed files with 55 additions and 44 deletions

View File

@ -45,7 +45,7 @@ class NucypherTokenActor:
self.checksum_public_address = checksum_address self.checksum_public_address = checksum_address
if registry_filepath is not None: if registry_filepath is not None:
EthereumContractRegistry.from_config(registry_filepath=registry_filepath) EthereumContractRegistry(registry_filepath=registry_filepath)
self.token_agent = token_agent if token_agent is not None else NucypherTokenAgent() self.token_agent = token_agent if token_agent is not None else NucypherTokenAgent()
self._transaction_cache = list() # track transactions transmitted self._transaction_cache = list() # track transactions transmitted

View File

@ -304,8 +304,9 @@ class Character(Teacher):
def __init__(self, def __init__(self,
is_me: bool = True, is_me: bool = True,
config_root=DEFAULT_CONFIG_ROOT,
network_middleware: RestMiddleware = None, network_middleware: RestMiddleware = None,
known_certificates_dir: str = None,
known_metadata_dir: str = None,
crypto_power: CryptoPower = None, crypto_power: CryptoPower = None,
crypto_power_ups: List[CryptoPowerUp] = None, crypto_power_ups: List[CryptoPowerUp] = None,
federated_only: bool = False, federated_only: bool = False,
@ -337,8 +338,9 @@ class Character(Teacher):
""" """
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.config_root = config_root
self.federated_only = federated_only # type: bool self.federated_only = federated_only # type: bool
self.known_certificates_dir = known_certificates_dir
self.known_metadata_dir = known_metadata_dir
# #
# Power-ups and Powers # Power-ups and Powers
@ -487,9 +489,12 @@ class Character(Teacher):
unresponsive_nodes = set() unresponsive_nodes = set()
try: try:
# FIXME
response = self.network_middleware.get_nodes_via_rest(rest_url, response = self.network_middleware.get_nodes_via_rest(rest_url,
nodes_i_need=self._node_ids_to_learn_about_immediately, nodes_i_need=self._node_ids_to_learn_about_immediately,
announce_nodes=announce_nodes) announce_nodes=announce_nodes,
certificate_path=current_teacher.certificate_filepath)
except requests.exceptions.ConnectionError: except requests.exceptions.ConnectionError:
unresponsive_nodes.add(current_teacher) unresponsive_nodes.add(current_teacher)
teacher_rest_info = current_teacher.rest_information()[0] teacher_rest_info = current_teacher.rest_information()[0]

View File

@ -405,7 +405,7 @@ class Ursula(Character, VerifiableNode, Miner):
rest_host, rest_host,
rest_port, rest_port,
certificate=None, certificate=None,
certificate_dir=None, certificate_filepath: str = None,
db_name=None, db_name=None,
is_me=True, is_me=True,
interface_signature=None, interface_signature=None,
@ -413,6 +413,7 @@ class Ursula(Character, VerifiableNode, Miner):
# Blockchain # Blockchain
miner_agent=None, miner_agent=None,
checksum_address: str = None, checksum_address: str = None,
registry_filepath: str = None,
# Character # Character
abort_on_learning_error: bool = False, abort_on_learning_error: bool = False,
@ -443,7 +444,8 @@ class Ursula(Character, VerifiableNode, Miner):
Miner.__init__(self, Miner.__init__(self,
is_me=is_me, is_me=is_me,
miner_agent=miner_agent, miner_agent=miner_agent,
checksum_address=checksum_address) checksum_address=checksum_address,
registry_filepath=registry_filepath)
blockchain_power = BlockchainPower(blockchain=self.blockchain, account=self.checksum_public_address) blockchain_power = BlockchainPower(blockchain=self.blockchain, account=self.checksum_public_address)
self._crypto_power.consume_power_up(blockchain_power) self._crypto_power.consume_power_up(blockchain_power)
@ -489,26 +491,34 @@ class Ursula(Character, VerifiableNode, Miner):
curve=tls_curve, curve=tls_curve,
host=rest_host, host=rest_host,
certificate=certificate, certificate=certificate,
certificate_dir=certificate_dir) certificate_dir=self.known_certificates_dir)
tls_hosting_power = TLSHostingPower(rest_server=rest_server, tls_hosting_power = TLSHostingPower(rest_server=rest_server,
keypair=tls_hosting_keypair) keypair=tls_hosting_keypair)
else: else:
# Unless the caller passed a crypto power, we'll make our own TLSHostingPower for this stranger. # Unless the caller passed a crypto power, we'll make our own TLSHostingPower for this stranger.
rest_server = ProxyRESTServer( rest_server = ProxyRESTServer(
rest_host=rest_host, rest_host=rest_host,
rest_port=rest_port, rest_port=rest_port,
) )
if certificate: if certificate or certificate_filepath:
tls_hosting_power = TLSHostingPower(rest_server=rest_server, certificate=certificate) tls_hosting_power = TLSHostingPower(rest_server=rest_server,
certificate_filepath=certificate_filepath,
certificate=certificate)
else: else:
tls_hosting_keypair = HostingKeypair( tls_hosting_keypair = HostingKeypair(
common_name=self.checksum_public_address, common_name=self.checksum_public_address,
curve=tls_curve, curve=tls_curve,
host=rest_host, host=rest_host,
certificate_dir=certificate_dir) certificate_filepath=certificate_filepath,
certificate_dir=self.known_certificates_dir)
tls_hosting_power = TLSHostingPower(rest_server=rest_server, tls_hosting_power = TLSHostingPower(rest_server=rest_server,
keypair=tls_hosting_keypair) keypair=tls_hosting_keypair)
self._crypto_power.consume_power_up(tls_hosting_power) # Make this work for not me for certificate to work self._crypto_power.consume_power_up(tls_hosting_power) # Make this work for not me for certificate to work
else: else:
self.log.info("Not adhering rest_server; we'll use the one on crypto_power..") self.log.info("Not adhering rest_server; we'll use the one on crypto_power..")

View File

@ -117,17 +117,13 @@ def ecdsa_verify(
def _save_tls_certificate(certificate: Certificate, def _save_tls_certificate(certificate: Certificate,
directory: str, directory: str,
common_name: str = None, common_name: str = None,
is_me: bool = False,
force: bool = True, force: bool = True,
) -> str: ) -> str:
if is_me is False and not common_name: certificate_filepath = os.path.join(directory, '{}.pem'.format(common_name[2:8]))
raise NucypherConfigurationError('A common name must be passed to save another node\'s certificate.')
certificate_filepath = os.path.join(directory, '{}.pem'.format(common_name[:6]))
if force is False and os.path.isfile(certificate_filepath): if force is False and os.path.isfile(certificate_filepath):
raise NucypherConfigurationError('A TLS certificate already exists at {}.'.format(certificate_filepath)) raise FileExistsError('A TLS certificate already exists at {}.'.format(certificate_filepath))
with open(certificate_filepath, 'wb') as certificate_file: with open(certificate_filepath, 'wb') as certificate_file:
public_pem_bytes = certificate.public_bytes(Encoding.PEM) public_pem_bytes = certificate.public_bytes(Encoding.PEM)
@ -146,9 +142,10 @@ def load_tls_certificate(filepath):
def generate_self_signed_certificate(common_name, def generate_self_signed_certificate(common_name,
curve, curve,
host, host,
certificate_dir,
private_key=None, private_key=None,
days_valid=365, days_valid=365,
certificate_dir=None): ):
if not private_key: if not private_key:
private_key = ec.generate_private_key(curve, default_backend()) private_key = ec.generate_private_key(curve, default_backend())
@ -169,10 +166,10 @@ def generate_self_signed_certificate(common_name,
cert = cert.add_extension(x509.SubjectAlternativeName([x509.DNSName(host)]), critical=False) cert = cert.add_extension(x509.SubjectAlternativeName([x509.DNSName(host)]), critical=False)
cert = cert.sign(private_key, hashes.SHA512(), default_backend()) cert = cert.sign(private_key, hashes.SHA512(), default_backend())
if certificate_dir: # if certificate_dir:
tls_certificate_filepath = _save_tls_certificate(cert, directory=certificate_dir, common_name=common_name) tls_certificate_filepath = _save_tls_certificate(cert, directory=certificate_dir, common_name=common_name)
else: # else:
tls_certificate_filepath = constants.CERTIFICATE_NOT_SAVED # tls_certificate_filepath = constants.CERTIFICATE_NOT_SAVED
return cert, private_key, tls_certificate_filepath return cert, private_key, tls_certificate_filepath

View File

@ -13,7 +13,7 @@ from umbral.keys import UmbralPrivateKey, UmbralPublicKey
from umbral.signing import Signature, Signer from umbral.signing import Signature, Signer
from nucypher.crypto import api as API from nucypher.crypto import api as API
from nucypher.crypto.api import generate_self_signed_certificate, _save_tls_certificate from nucypher.crypto.api import generate_self_signed_certificate, _save_tls_certificate, load_tls_certificate
from nucypher.crypto.kits import MessageKit from nucypher.crypto.kits import MessageKit
from nucypher.crypto.signing import SignatureStamp, StrangerStamp from nucypher.crypto.signing import SignatureStamp, StrangerStamp
@ -132,46 +132,47 @@ class HostingKeypair(Keypair):
common_name=None, common_name=None,
host=None, host=None,
private_key: Union[UmbralPrivateKey, UmbralPublicKey] = None, private_key: Union[UmbralPrivateKey, UmbralPublicKey] = None,
certificate=None,
curve=None, curve=None,
generate_keys_if_needed=True, certificate=None,
certificate_filepath: str = None,
certificate_dir=None, certificate_dir=None,
) -> None: ) -> None:
self.curve = curve or self._DEFAULT_CURVE self.curve = curve or self._DEFAULT_CURVE
self.certificate_filepath = None
if private_key: if private_key:
super().__init__(private_key=private_key) super().__init__(private_key=private_key)
elif certificate: elif certificate:
self.certificate = certificate
super().__init__(public_key=certificate.public_key()) super().__init__(public_key=certificate.public_key())
elif generate_keys_if_needed: elif certificate_filepath:
certificate = load_tls_certificate(filepath=certificate_filepath)
elif generate_certificate:
if not all((common_name, host)): if not all((common_name, host)):
message = "If you don't supply the certificate, one will be generated for you." \ message = "If you don't supply the certificate, one will be generated for you." \
"But for that, you need to pass both host and common_name.." "But for that, you need to pass both host and common_name.."
raise TypeError(message) raise TypeError(message)
self.certificate, private_key, self.certificate_filepath = generate_self_signed_certificate(common_name=common_name,
private_key=private_key, certificate, private_key, certificate_filepath = generate_self_signed_certificate(common_name=common_name,
curve=self.curve, private_key=private_key,
host=host, curve=self.curve,
) host=host,
certificate_dir=certificate_dir)
super().__init__(private_key=private_key) super().__init__(private_key=private_key)
else: else:
raise TypeError("You didn't provide a cert, but also told us not to generate keys. Not sure what to do.") raise TypeError("You didn't provide a cert, but also told us not to generate keys. Not sure what to do.")
if certificate_dir: self.certificate = certificate
self.certificate_filepath = _save_tls_certificate(self.certificate, self.certificate_filepath = certificate_filepath
directory=certificate_dir, self.certificate_dir = certificate_dir
common_name=common_name,
is_me=False,
force=False,
)
def generate_self_signed_cert(self, common_name): def generate_self_signed_cert(self, common_name):
cryptography_key = self._privkey.to_cryptography_privkey() cryptography_key = self._privkey.to_cryptography_privkey()
return generate_self_signed_certificate(common_name, default_curve(), cryptography_key) return generate_self_signed_certificate(common_name, default_curve(),
cryptography_key, certificate_dir=self.certificate_dir)
def get_deployer(self, rest_app, port): def get_deployer(self, rest_app, port):
return HendrixDeployTLS("start", return HendrixDeployTLS("start",

View File

@ -9,20 +9,18 @@ from umbral.fragments import CapsuleFrag
class RestMiddleware: class RestMiddleware:
def consider_arrangement(self, arrangement, certificate_path): def consider_arrangement(self, arrangement, certificate_path):
certificate = load_tls_certificate(filepath=certificate_path)
node = arrangement.ursula node = arrangement.ursula
port = node.rest_interface.port port = node.rest_interface.port
address = node.rest_interface.host address = node.rest_interface.host
response = requests.post("https://{}:{}/consider_arrangement".format(address, port), bytes(arrangement), verify=certificate) response = requests.post("https://{}:{}/consider_arrangement".format(address, port), bytes(arrangement), verify=certificate_path)
if not response.status_code == 200: if not response.status_code == 200:
raise RuntimeError("Bad response: {}".format(response.content)) raise RuntimeError("Bad response: {}".format(response.content))
return response return response
def enact_policy(self, ursula, id, payload, certificate_path): def enact_policy(self, ursula, id, payload, certificate_path):
certificate = load_tls_certificate(filepath=certificate_path)
port = ursula.rest_interface.port port = ursula.rest_interface.port
address = ursula.rest_interface.host address = ursula.rest_interface.host
response = requests.post('https://{}:{}/kFrag/{}'.format(address, port, id.hex()), payload, verify=certificate) response = requests.post('https://{}:{}/kFrag/{}'.format(address, port, id.hex()), payload, verify=certificate_path)
if not response.status_code == 200: if not response.status_code == 200:
raise RuntimeError("Bad response: {}".format(response.content)) raise RuntimeError("Bad response: {}".format(response.content))
return True, ursula.stamp.as_umbral_pubkey() return True, ursula.stamp.as_umbral_pubkey()