mirror of https://github.com/nucypher/nucypher.git
Use a unified method of MessageKit bytes serialization; remove '__bytes__'.
parent
8c12304944
commit
6c29fd05c9
|
@ -15,6 +15,7 @@ You should have received a copy of the GNU Affero General Public License
|
||||||
along with nucypher. If not, see <https://www.gnu.org/licenses/>.
|
along with nucypher. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
from typing import Optional, Dict
|
from typing import Optional, Dict
|
||||||
|
|
||||||
from bytestring_splitter import BytestringKwargifier, VariableLengthBytestring
|
from bytestring_splitter import BytestringKwargifier, VariableLengthBytestring
|
||||||
|
@ -128,9 +129,6 @@ class MessageKit(CryptoKit):
|
||||||
def signature(self):
|
def signature(self):
|
||||||
return self._signature
|
return self._signature
|
||||||
|
|
||||||
def __bytes__(self):
|
|
||||||
return bytes(self.capsule) + VariableLengthBytestring(self.ciphertext)
|
|
||||||
|
|
||||||
|
|
||||||
class PolicyMessageKit(MessageKit):
|
class PolicyMessageKit(MessageKit):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -227,10 +227,9 @@ class RestMiddleware:
|
||||||
|
|
||||||
def send_work_order_payload_to_ursula(self, work_order):
|
def send_work_order_payload_to_ursula(self, work_order):
|
||||||
payload = work_order.payload()
|
payload = work_order.payload()
|
||||||
id_as_hex = work_order.arrangement_id.hex()
|
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
node_or_sprout=work_order.ursula,
|
node_or_sprout=work_order.ursula,
|
||||||
path=f"reencrypt/{id_as_hex}",
|
path=f"reencrypt",
|
||||||
data=payload,
|
data=payload,
|
||||||
timeout=2
|
timeout=2
|
||||||
)
|
)
|
||||||
|
|
|
@ -16,18 +16,22 @@ along with nucypher. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
|
import time
|
||||||
from collections import defaultdict, deque
|
from collections import defaultdict, deque
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
from queue import Queue
|
from queue import Queue
|
||||||
from typing import Iterable, List, Set, Tuple, Union, Callable
|
from typing import Callable
|
||||||
|
from typing import Iterable, List
|
||||||
|
from typing import Set, Tuple, Union
|
||||||
|
|
||||||
import maya
|
import maya
|
||||||
import requests
|
import requests
|
||||||
import time
|
|
||||||
from bytestring_splitter import (
|
from bytestring_splitter import (
|
||||||
BytestringSplitter,
|
BytestringSplitter,
|
||||||
PartiallyKwargifiedBytes,
|
PartiallyKwargifiedBytes,
|
||||||
VariableLengthBytestring,
|
VariableLengthBytestring
|
||||||
|
)
|
||||||
|
from bytestring_splitter import (
|
||||||
BytestringSplittingError
|
BytestringSplittingError
|
||||||
)
|
)
|
||||||
from constant_sorrow import constant_or_bytes
|
from constant_sorrow import constant_or_bytes
|
||||||
|
@ -58,13 +62,13 @@ from nucypher.config.storages import ForgetfulNodeStorage
|
||||||
from nucypher.crypto.kits import UmbralMessageKit
|
from nucypher.crypto.kits import UmbralMessageKit
|
||||||
from nucypher.crypto.powers import DecryptingPower, NoSigningPower, SigningPower
|
from nucypher.crypto.powers import DecryptingPower, NoSigningPower, SigningPower
|
||||||
from nucypher.crypto.splitters import signature_splitter
|
from nucypher.crypto.splitters import signature_splitter
|
||||||
|
from nucypher.crypto.umbral_adapter import Signature
|
||||||
from nucypher.crypto.utils import recover_address_eip_191, verify_eip_191
|
from nucypher.crypto.utils import recover_address_eip_191, verify_eip_191
|
||||||
from nucypher.network import LEARNING_LOOP_VERSION
|
from nucypher.network import LEARNING_LOOP_VERSION
|
||||||
from nucypher.network.exceptions import NodeSeemsToBeDown
|
from nucypher.network.exceptions import NodeSeemsToBeDown
|
||||||
from nucypher.network.middleware import RestMiddleware
|
from nucypher.network.middleware import RestMiddleware
|
||||||
from nucypher.network.protocols import SuspiciousActivity
|
from nucypher.network.protocols import SuspiciousActivity
|
||||||
from nucypher.utilities.logging import Logger
|
from nucypher.utilities.logging import Logger
|
||||||
from nucypher.crypto.umbral_adapter import Signature
|
|
||||||
|
|
||||||
TEACHER_NODES = {
|
TEACHER_NODES = {
|
||||||
NetworksInventory.MAINNET: (
|
NetworksInventory.MAINNET: (
|
||||||
|
@ -191,7 +195,7 @@ class Learner:
|
||||||
__DEFAULT_MIDDLEWARE_CLASS = RestMiddleware
|
__DEFAULT_MIDDLEWARE_CLASS = RestMiddleware
|
||||||
|
|
||||||
LEARNER_VERSION = LEARNING_LOOP_VERSION
|
LEARNER_VERSION = LEARNING_LOOP_VERSION
|
||||||
LOWEST_COMPATIBLE_VERSION = 2 # Disallow versions lower than this
|
LOWEST_COMPATIBLE_VERSION = 2 # Disallow versions lower than this
|
||||||
|
|
||||||
node_splitter = BytestringSplitter(VariableLengthBytestring)
|
node_splitter = BytestringSplitter(VariableLengthBytestring)
|
||||||
version_splitter = BytestringSplitter((int, 2, {"byteorder": "big"}))
|
version_splitter = BytestringSplitter((int, 2, {"byteorder": "big"}))
|
||||||
|
@ -270,7 +274,8 @@ class Learner:
|
||||||
|
|
||||||
from nucypher.characters.lawful import Ursula
|
from nucypher.characters.lawful import Ursula
|
||||||
self.node_class = node_class or Ursula
|
self.node_class = node_class or Ursula
|
||||||
self.node_class.set_cert_storage_function(node_storage.store_node_certificate) # TODO: Fix this temporary workaround for on-disk cert storage. #1481
|
self.node_class.set_cert_storage_function(
|
||||||
|
node_storage.store_node_certificate) # TODO: Fix this temporary workaround for on-disk cert storage. #1481
|
||||||
|
|
||||||
known_nodes = known_nodes or tuple()
|
known_nodes = known_nodes or tuple()
|
||||||
self.unresponsive_startup_nodes = list() # TODO: Buckets - Attempt to use these again later #567
|
self.unresponsive_startup_nodes = list() # TODO: Buckets - Attempt to use these again later #567
|
||||||
|
@ -416,7 +421,7 @@ class Learner:
|
||||||
# This node is already known. We can safely return.
|
# This node is already known. We can safely return.
|
||||||
return False
|
return False
|
||||||
|
|
||||||
self.known_nodes.record_node(node) # FIXME - dont always remember nodes, bucket them.
|
self.known_nodes.record_node(node) # FIXME - dont always remember nodes, bucket them.
|
||||||
|
|
||||||
if self.save_metadata:
|
if self.save_metadata:
|
||||||
self.node_storage.store_node_metadata(node=node)
|
self.node_storage.store_node_metadata(node=node)
|
||||||
|
@ -808,7 +813,8 @@ class Learner:
|
||||||
# These except clauses apply to the current_teacher itself, not the learned-about nodes.
|
# These except clauses apply to the current_teacher itself, not the learned-about nodes.
|
||||||
except NodeSeemsToBeDown as e:
|
except NodeSeemsToBeDown as e:
|
||||||
unresponsive_nodes.add(current_teacher)
|
unresponsive_nodes.add(current_teacher)
|
||||||
self.log.info(f"Teacher {str(current_teacher)} is perhaps down:{e}.") # FIXME: This was printing the node bytestring. Is this really necessary? #1712
|
self.log.info(
|
||||||
|
f"Teacher {str(current_teacher)} is perhaps down:{e}.") # FIXME: This was printing the node bytestring. Is this really necessary? #1712
|
||||||
return
|
return
|
||||||
except current_teacher.InvalidNode as e:
|
except current_teacher.InvalidNode as e:
|
||||||
# Ugh. The teacher is invalid. Rough.
|
# Ugh. The teacher is invalid. Rough.
|
||||||
|
@ -824,10 +830,12 @@ class Learner:
|
||||||
# TODO: Sort this out.
|
# TODO: Sort this out.
|
||||||
return RELAX
|
return RELAX
|
||||||
else:
|
else:
|
||||||
self.log.warn(f"Unhandled error while learning from {str(current_teacher)}: {bytes(current_teacher)}:{e}.")
|
self.log.warn(
|
||||||
|
f"Unhandled error while learning from {str(current_teacher)}: {bytes(current_teacher)}:{e}.")
|
||||||
raise
|
raise
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log.warn(f"Unhandled error while learning from {str(current_teacher)}: {bytes(current_teacher)}:{e}.") # To track down 2345 / 1698
|
self.log.warn(
|
||||||
|
f"Unhandled error while learning from {str(current_teacher)}: {bytes(current_teacher)}:{e}.") # To track down 2345 / 1698
|
||||||
raise
|
raise
|
||||||
finally:
|
finally:
|
||||||
# Is cycling happening in the right order?
|
# Is cycling happening in the right order?
|
||||||
|
|
|
@ -16,7 +16,6 @@ along with nucypher. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
import binascii
|
|
||||||
import os
|
import os
|
||||||
import uuid
|
import uuid
|
||||||
import weakref
|
import weakref
|
||||||
|
@ -29,12 +28,14 @@ from flask import Flask, Response, jsonify, request
|
||||||
from mako import exceptions as mako_exceptions
|
from mako import exceptions as mako_exceptions
|
||||||
from mako.template import Template
|
from mako.template import Template
|
||||||
from maya import MayaDT
|
from maya import MayaDT
|
||||||
|
from umbral.key_frag import KeyFrag
|
||||||
|
|
||||||
|
from nucypher.blockchain.eth.constants import NULL_ADDRESS
|
||||||
from nucypher.config.constants import MAX_UPLOAD_CONTENT_LENGTH
|
from nucypher.config.constants import MAX_UPLOAD_CONTENT_LENGTH
|
||||||
from nucypher.crypto.keypairs import HostingKeypair
|
from nucypher.crypto.keypairs import HostingKeypair
|
||||||
|
from nucypher.crypto.kits import PolicyMessageKit
|
||||||
from nucypher.crypto.powers import KeyPairBasedPower, PowerUpError
|
from nucypher.crypto.powers import KeyPairBasedPower, PowerUpError
|
||||||
from nucypher.crypto.signing import InvalidSignature
|
from nucypher.crypto.signing import InvalidSignature
|
||||||
from nucypher.crypto.utils import canonical_address_from_umbral_key
|
|
||||||
from nucypher.datastore.datastore import Datastore, RecordNotFound, DatastoreTransactionError
|
from nucypher.datastore.datastore import Datastore, RecordNotFound, DatastoreTransactionError
|
||||||
from nucypher.datastore.models import PolicyArrangement, TreasureMap, Workorder
|
from nucypher.datastore.models import PolicyArrangement, TreasureMap, Workorder
|
||||||
from nucypher.network import LEARNING_LOOP_VERSION
|
from nucypher.network import LEARNING_LOOP_VERSION
|
||||||
|
@ -237,51 +238,42 @@ def _make_rest_app(datastore: Datastore, this_node, domain: str, log: Logger) ->
|
||||||
log.info("KeyFrag successfully removed.")
|
log.info("KeyFrag successfully removed.")
|
||||||
return Response(response='KeyFrag deleted!', status=200)
|
return Response(response='KeyFrag deleted!', status=200)
|
||||||
|
|
||||||
@rest_app.route('/reencrypt/<id_as_hex>/', methods=["POST"])
|
@rest_app.route('/reencrypt', methods=["POST"])
|
||||||
def reencrypt(id_as_hex):
|
def reencrypt():
|
||||||
|
|
||||||
# Get Policy Arrangement
|
|
||||||
try:
|
|
||||||
arrangement_id = binascii.unhexlify(id_as_hex)
|
|
||||||
except (binascii.Error, TypeError):
|
|
||||||
return Response(response=b'Invalid arrangement ID', status=405)
|
|
||||||
|
|
||||||
# TODO: Verify payment
|
|
||||||
try:
|
|
||||||
# Get KeyFrag
|
|
||||||
# TODO: Yeah, well, what if this arrangement hasn't been enacted? 1702
|
|
||||||
with datastore.describe(PolicyArrangement, id_as_hex) as policy_arrangement:
|
|
||||||
alice_verifying_key = policy_arrangement.alice_verifying_key
|
|
||||||
except RecordNotFound:
|
|
||||||
return Response(response=arrangement_id, status=404)
|
|
||||||
|
|
||||||
# Get Work Order
|
# Get Work Order
|
||||||
from nucypher.policy.collections import WorkOrder # Avoid circular import
|
from nucypher.policy.collections import WorkOrder # Avoid circular import
|
||||||
alice_address = canonical_address_from_umbral_key(alice_verifying_key)
|
|
||||||
work_order_payload = request.data
|
work_order_payload = request.data
|
||||||
work_order = WorkOrder.from_rest_payload(arrangement_id=arrangement_id,
|
work_order = WorkOrder.from_rest_payload(rest_payload=work_order_payload, ursula=this_node)
|
||||||
rest_payload=work_order_payload,
|
|
||||||
ursula=this_node,
|
|
||||||
alice_address=alice_address)
|
|
||||||
log.info(f"Work Order from {work_order.bob}, signed {work_order.receipt_signature}")
|
log.info(f"Work Order from {work_order.bob}, signed {work_order.receipt_signature}")
|
||||||
|
|
||||||
# Get KFrag
|
# Deserialize Entities
|
||||||
encrypted_kfrag = work_order.kfrag
|
authorizer = Alice.from_public_keys(verifying_key=work_order.authorizer_verifying_key)
|
||||||
kfrag = this_node.verify_from(alice_verifying_key, encrypted_kfrag, decrypt=True)
|
authorizer_verifying_key = authorizer.stamp.as_umbral_pubkey()
|
||||||
if not kfrag.verify(signing_pubkey=alice_verifying_key): # TODO: Maybe this check is redundant?
|
kfrag_kit = PolicyMessageKit.from_bytes(work_order.encrypted_kfrag)
|
||||||
return Response(response="{} is invalid".format(kfrag), status=422) # TODO: Maybe good, ol' 400 is OK.
|
|
||||||
|
# Verify & Decrypt KFrag
|
||||||
|
# TODO: Cache the result of kfrag verification for optimization
|
||||||
|
kfrag_plaintext = this_node.verify_from(stranger=authorizer, message_kit=kfrag_kit, decrypt=True)
|
||||||
|
kfrag = KeyFrag.from_bytes(kfrag_plaintext)
|
||||||
|
if not kfrag.verify(signing_pubkey=authorizer_verifying_key):
|
||||||
|
log.info(f"Invalid KFrag detected - sender {authorizer_verifying_key.to_bytes().hex()}")
|
||||||
|
return Response(response="{} is invalid".format(kfrag), status=401)
|
||||||
|
|
||||||
|
# TODO: Verify policy payment
|
||||||
|
# TODO: Cache the result of payment verification for optimization
|
||||||
|
|
||||||
# Re-encrypt
|
# Re-encrypt
|
||||||
response = this_node._reencrypt(kfrag=kfrag,
|
response = this_node._reencrypt(kfrag=kfrag,
|
||||||
work_order=work_order,
|
work_order=work_order,
|
||||||
alice_verifying_key=alice_verifying_key)
|
alice_verifying_key=authorizer_verifying_key)
|
||||||
|
|
||||||
# Now, Ursula saves this workorder to her database...
|
# Now, Ursula saves this workorder to her database...
|
||||||
# Note: we give the work order a random ID to store it under.
|
# Note: we give the work order a random ID to store it under.
|
||||||
with datastore.describe(Workorder, str(uuid.uuid4()), writeable=True) as new_workorder:
|
work_order_id = str(uuid.uuid4())
|
||||||
new_workorder.arrangement_id = work_order.arrangement_id
|
with datastore.describe(Workorder, work_order_id, writeable=True) as new_workorder:
|
||||||
new_workorder.bob_verifying_key = work_order.bob.stamp.as_umbral_pubkey()
|
new_workorder.bob_verifying_key = work_order.bob.stamp.as_umbral_pubkey()
|
||||||
new_workorder.bob_signature = work_order.receipt_signature
|
new_workorder.bob_signature = work_order.receipt_signature # Handle for challenge protocol
|
||||||
|
|
||||||
headers = {'Content-Type': 'application/octet-stream'}
|
headers = {'Content-Type': 'application/octet-stream'}
|
||||||
return Response(headers=headers, response=response)
|
return Response(headers=headers, response=response)
|
||||||
|
|
Loading…
Reference in New Issue