diff --git a/docs/source/application_development/porter.rst b/docs/source/application_development/porter.rst
index ac5a06a00..5ed2ee81a 100644
--- a/docs/source/application_development/porter.rst
+++ b/docs/source/application_development/porter.rst
@@ -475,8 +475,8 @@ Parameters
+-------------------------------------------+---------------+----------------------------------------+
| **Parameter** | **Type** | **Description** |
+===========================================+===============+========================================+
-| ``treasure_map`` | String | | Decrypted treasure map bytes encoded |
-| | | | as base64. |
+| ``treasure_map`` | String | | Unencrypted treasure map bytes |
+| | | | encoded as base64. |
+-------------------------------------------+---------------+----------------------------------------+
| ``retrieval_kits`` | List[String] | | List of retrieval kits bytes encoded |
| | | | as base64. |
diff --git a/nucypher/characters/control/specifications/bob.py b/nucypher/characters/control/specifications/bob.py
index 5e7e62c2e..535762f85 100644
--- a/nucypher/characters/control/specifications/bob.py
+++ b/nucypher/characters/control/specifications/bob.py
@@ -20,8 +20,8 @@ import click
import nucypher.control.specifications.fields as base_fields
from nucypher.characters.control.specifications import fields as character_fields
from nucypher.characters.control.specifications.fields.treasuremap import EncryptedTreasureMap
-from nucypher.control.specifications.base import BaseSchema
from nucypher.cli import options
+from nucypher.control.specifications.base import BaseSchema
class RetrieveAndDecrypt(BaseSchema):
@@ -46,17 +46,6 @@ class RetrieveAndDecrypt(BaseSchema):
load_only=True,
click=options.option_message_kit(required=True)
)
- # optional
- treasure_map = character_fields.TreasureMap(
- required=False,
- load_only=True,
- click=click.option(
- '--treasure-map',
- '-t',
- help="Treasure Map for retrieve",
- type=click.STRING,
- required=False))
-
encrypted_treasure_map = EncryptedTreasureMap(required=True,
load_only=True,
click=options.option_treasure_map)
diff --git a/nucypher/characters/control/specifications/exceptions.py b/nucypher/characters/control/specifications/exceptions.py
deleted file mode 100644
index ec74c47bc..000000000
--- a/nucypher/characters/control/specifications/exceptions.py
+++ /dev/null
@@ -1,22 +0,0 @@
-"""
- 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 .
-"""
-
-from bytestring_splitter import BytestringSplittingError
-from cryptography.exceptions import InternalError
-
-# TODO: catch cryptography.exceptions.InternalError in PyUmbral
-InvalidNativeDataTypes = (ValueError, TypeError, BytestringSplittingError, InternalError)
diff --git a/nucypher/characters/control/specifications/fields/key.py b/nucypher/characters/control/specifications/fields/key.py
index e33020d78..c55b701d0 100644
--- a/nucypher/characters/control/specifications/fields/key.py
+++ b/nucypher/characters/control/specifications/fields/key.py
@@ -17,8 +17,7 @@
from marshmallow import fields
-from nucypher.characters.control.specifications.exceptions import InvalidNativeDataTypes
-from nucypher.control.specifications.exceptions import InvalidInputData
+from nucypher.control.specifications.exceptions import InvalidInputData, InvalidNativeDataTypes
from nucypher.control.specifications.fields.base import BaseField
from nucypher.crypto.umbral_adapter import PublicKey
diff --git a/nucypher/characters/control/specifications/fields/messagekit.py b/nucypher/characters/control/specifications/fields/messagekit.py
index e7b96412e..fd9211a31 100644
--- a/nucypher/characters/control/specifications/fields/messagekit.py
+++ b/nucypher/characters/control/specifications/fields/messagekit.py
@@ -19,8 +19,7 @@ from base64 import b64decode, b64encode
from marshmallow import fields
-from nucypher.characters.control.specifications.exceptions import InvalidNativeDataTypes
-from nucypher.control.specifications.exceptions import InvalidInputData
+from nucypher.control.specifications.exceptions import InvalidInputData, InvalidNativeDataTypes
from nucypher.control.specifications.fields.base import BaseField
from nucypher.policy.kits import MessageKit as MessageKitClass
diff --git a/nucypher/characters/control/specifications/fields/signature.py b/nucypher/characters/control/specifications/fields/signature.py
index 420b62009..cda78a710 100644
--- a/nucypher/characters/control/specifications/fields/signature.py
+++ b/nucypher/characters/control/specifications/fields/signature.py
@@ -19,8 +19,7 @@ from base64 import b64decode, b64encode
from marshmallow import fields
-from nucypher.characters.control.specifications.exceptions import InvalidNativeDataTypes
-from nucypher.control.specifications.exceptions import InvalidInputData
+from nucypher.control.specifications.exceptions import InvalidInputData, InvalidNativeDataTypes
from nucypher.control.specifications.fields.base import BaseField
from nucypher.crypto.umbral_adapter import Signature
diff --git a/nucypher/characters/control/specifications/fields/treasuremap.py b/nucypher/characters/control/specifications/fields/treasuremap.py
index 8196bd951..af8559789 100644
--- a/nucypher/characters/control/specifications/fields/treasuremap.py
+++ b/nucypher/characters/control/specifications/fields/treasuremap.py
@@ -15,40 +15,30 @@
along with nucypher. If not, see .
"""
-from base64 import b64decode, b64encode
-
-from marshmallow import fields
-
from nucypher.control.specifications.exceptions import InvalidInputData
-from nucypher.control.specifications.fields.base import BaseField
-from nucypher.policy.maps import EncryptedTreasureMap as EncryptedTreasureMapClass, TreasureMap as TreaureMapClass
+from nucypher.control.specifications.fields.base import Base64BytesRepresentation
+from nucypher.policy.maps import EncryptedTreasureMap as EncryptedTreasureMapClass, TreasureMap as TreasureMapClass
-class EncryptedTreasureMap(BaseField, fields.Field):
+class EncryptedTreasureMap(Base64BytesRepresentation):
"""
JSON Parameter representation of EncryptedTreasureMap.
"""
- def _serialize(self, value, attr, obj, **kwargs):
- return b64encode(bytes(value)).decode()
-
def _deserialize(self, value, attr, data, **kwargs):
try:
- treasure_map_bytes = b64decode(value)
- return EncryptedTreasureMapClass.from_bytes(treasure_map_bytes)
+ encrypted_treasure_map_bytes = super()._deserialize(value, attr, data, **kwargs)
+ return EncryptedTreasureMapClass.from_bytes(encrypted_treasure_map_bytes)
except Exception as e:
raise InvalidInputData(f"Could not convert input for {self.name} to an EncryptedTreasureMap: {e}") from e
-class TreasureMap(BaseField, fields.Field):
+class TreasureMap(Base64BytesRepresentation):
"""
- JSON Parameter representation of (decrypted) TreasureMap.
+ JSON Parameter representation of (unencrypted) TreasureMap.
"""
- def _serialize(self, value, attr, obj, **kwargs):
- return b64encode(bytes(value)).decode()
-
def _deserialize(self, value, attr, data, **kwargs):
try:
- treasure_map_bytes = b64decode(value)
- return TreaureMapClass.from_bytes(treasure_map_bytes)
+ treasure_map_bytes = super()._deserialize(value, attr, data, **kwargs)
+ return TreasureMapClass.from_bytes(treasure_map_bytes)
except Exception as e:
- raise InvalidInputData(f"Could not convert input for {self.name} to a TreaureMap: {e}") from e
\ No newline at end of file
+ raise InvalidInputData(f"Could not convert input for {self.name} to a TreasureMap: {e}") from e
diff --git a/nucypher/control/specifications/exceptions.py b/nucypher/control/specifications/exceptions.py
index c7efb288a..51ff7825c 100644
--- a/nucypher/control/specifications/exceptions.py
+++ b/nucypher/control/specifications/exceptions.py
@@ -14,6 +14,8 @@
You should have received a copy of the GNU Affero General Public License
along with nucypher. If not, see .
"""
+from bytestring_splitter import BytestringSplittingError
+from cryptography.exceptions import InternalError
class SpecificationError(ValueError):
@@ -34,3 +36,6 @@ class InvalidOutputData(SpecificationError):
class InvalidArgumentCombo(SpecificationError):
"""Arguments specified are incompatible"""
+
+
+InvalidNativeDataTypes = (ValueError, TypeError, BytestringSplittingError, InternalError)
diff --git a/nucypher/policy/maps.py b/nucypher/policy/maps.py
index 948633cda..e4c038320 100644
--- a/nucypher/policy/maps.py
+++ b/nucypher/policy/maps.py
@@ -16,23 +16,22 @@ along with nucypher. If not, see .
"""
-from typing import Optional, Callable, Union, Sequence, Dict
+from typing import Optional, Callable, Sequence, Dict
from bytestring_splitter import (
BytestringSplitter,
VariableLengthBytestring,
BytestringSplittingError,
)
-from constant_sorrow.constants import NO_DECRYPTION_PERFORMED, NOT_SIGNED
-from eth_utils.address import to_checksum_address, to_canonical_address
from eth_typing.evm import ChecksumAddress
+from eth_utils.address import to_checksum_address, to_canonical_address
from nucypher.blockchain.eth.constants import ETH_ADDRESS_BYTE_LENGTH
from nucypher.crypto.constants import EIP712_MESSAGE_SIGNATURE_SIZE
-from nucypher.crypto.powers import DecryptingPower, SigningPower
+from nucypher.crypto.powers import DecryptingPower
from nucypher.crypto.signing import SignatureStamp, InvalidSignature
from nucypher.crypto.splitters import signature_splitter, kfrag_splitter
-from nucypher.crypto.umbral_adapter import KeyFrag, VerifiedKeyFrag, PublicKey, Signature
+from nucypher.crypto.umbral_adapter import KeyFrag, VerifiedKeyFrag, Signature
from nucypher.crypto.utils import keccak_digest, verify_eip_191
from nucypher.network.middleware import RestMiddleware
from nucypher.policy.hrac import HRAC, hrac_splitter
@@ -131,6 +130,9 @@ class TreasureMap:
destinations = {u: k for u, k in ursula_and_kfrags}
return cls(threshold, hrac, destinations)
+ def __eq__(self, other):
+ return bytes(self) == bytes(other)
+
def __iter__(self):
return iter(self.destinations.items())
@@ -313,3 +315,6 @@ class EncryptedTreasureMap:
result = cls(hrac, public_signature, message_kit, blockchain_signature=blockchain_signature)
result._public_verify()
return result
+
+ def __eq__(self, other):
+ return bytes(self) == bytes(other)
diff --git a/nucypher/utilities/porter/control/interfaces.py b/nucypher/utilities/porter/control/interfaces.py
index cb0cfeb6c..d4a50deca 100644
--- a/nucypher/utilities/porter/control/interfaces.py
+++ b/nucypher/utilities/porter/control/interfaces.py
@@ -21,6 +21,7 @@ from eth_typing import ChecksumAddress
from nucypher.control.interfaces import ControlInterface, attach_schema
from nucypher.crypto.umbral_adapter import PublicKey
from nucypher.policy.kits import RetrievalKit
+from nucypher.policy.maps import TreasureMap
from nucypher.utilities.porter.control.specifications import porter_schema
@@ -55,7 +56,7 @@ class PorterInterface(ControlInterface):
@attach_schema(porter_schema.BobRetrieveCFrags)
def retrieve_cfrags(self,
- treasure_map: 'TreasureMap',
+ treasure_map: TreasureMap,
retrieval_kits: List[RetrievalKit],
alice_verifying_key: PublicKey,
bob_encrypting_key: PublicKey,
@@ -70,6 +71,6 @@ class PorterInterface(ControlInterface):
bob_verifying_key=bob_verifying_key,
policy_encrypting_key=policy_encrypting_key,
publisher_verifying_key=publisher_verifying_key)
- results = retrieval_results.results # list of RetrievalResult objects
+ results = retrieval_results # list of RetrievalResult objects
response_data = {'retrieval_results': results}
return response_data
diff --git a/nucypher/utilities/porter/control/specifications/fields/hrac.py b/nucypher/utilities/porter/control/specifications/fields/hrac.py
index ddecfda61..24b60d19f 100644
--- a/nucypher/utilities/porter/control/specifications/fields/hrac.py
+++ b/nucypher/utilities/porter/control/specifications/fields/hrac.py
@@ -17,8 +17,7 @@
from marshmallow import fields
-from nucypher.characters.control.specifications.exceptions import InvalidNativeDataTypes
-from nucypher.control.specifications.exceptions import InvalidInputData
+from nucypher.control.specifications.exceptions import InvalidInputData, InvalidNativeDataTypes
from nucypher.control.specifications.fields.base import BaseField
from nucypher.policy.hrac import HRAC as HRACClass
@@ -30,12 +29,7 @@ class HRAC(BaseField, fields.String):
def _deserialize(self, value, attr, data, **kwargs):
try:
- return bytes.fromhex(value)
- except InvalidNativeDataTypes as e:
- raise InvalidInputData(f"Could not convert input for {self.name} to a valid HRAC serialization: {e}")
-
- def _validate(self, value):
- try:
- HRACClass.from_bytes(value)
+ hrac_bytes = bytes.fromhex(value)
+ return HRACClass.from_bytes(hrac_bytes)
except InvalidNativeDataTypes as e:
raise InvalidInputData(f"Could not convert input for {self.name} to a valid HRAC: {e}")
diff --git a/nucypher/utilities/porter/control/specifications/fields/retrieve.py b/nucypher/utilities/porter/control/specifications/fields/retrieve.py
index a03fc179e..a91f26a20 100644
--- a/nucypher/utilities/porter/control/specifications/fields/retrieve.py
+++ b/nucypher/utilities/porter/control/specifications/fields/retrieve.py
@@ -15,11 +15,12 @@
along with nucypher. If not, see .
"""
from marshmallow import fields
+
from nucypher.control.specifications.base import BaseSchema
from nucypher.control.specifications.exceptions import InvalidInputData
from nucypher.control.specifications.fields import Base64BytesRepresentation
-from nucypher.crypto.kits import RetrievalKit as RetrievalKitClass
-from nucypher.crypto.umbral_adapter import Capsule as CapsuleClass, CapsuleFrag as CapsuleFragClass
+from nucypher.crypto.umbral_adapter import CapsuleFrag as CapsuleFragClass
+from nucypher.policy.kits import RetrievalKit as RetrievalKitClass
from nucypher.utilities.porter.control.specifications.fields import UrsulaChecksumAddress
@@ -34,16 +35,7 @@ class RetrievalKit(Base64BytesRepresentation):
raise InvalidInputData(f"Could not convert input for {self.name} to a valid checksum address: {e}")
-class Capsule(Base64BytesRepresentation):
- def _deserialize(self, value, attr, data, **kwargs):
- try:
- capsule_bytes = super()._deserialize(value, attr, data, **kwargs)
- return CapsuleClass.from_bytes(capsule_bytes)
- except Exception as e:
- raise InvalidInputData(f"Could not parse {self.name}: {e}")
-
-
-class CapsuleFrag(Base64BytesRepresentation):
+class VerifiedCapsuleFrag(Base64BytesRepresentation):
def _deserialize(self, value, attr, data, **kwargs):
try:
capsule_frag_bytes = super()._deserialize(value, attr, data, **kwargs)
@@ -54,8 +46,7 @@ class CapsuleFrag(Base64BytesRepresentation):
class RetrievalResultSchema(BaseSchema):
"""Schema for the result of retrieve_cfrags."""
- capsule = Capsule()
- cfrags = fields.Dict(keys=UrsulaChecksumAddress(), values=CapsuleFrag())
+ cfrags = fields.Dict(keys=UrsulaChecksumAddress(), values=VerifiedCapsuleFrag())
# maintain field declaration ordering
class Meta:
diff --git a/nucypher/utilities/porter/control/specifications/porter_schema.py b/nucypher/utilities/porter/control/specifications/porter_schema.py
index 69c7dd3b6..d580aced9 100644
--- a/nucypher/utilities/porter/control/specifications/porter_schema.py
+++ b/nucypher/utilities/porter/control/specifications/porter_schema.py
@@ -17,15 +17,15 @@
import click
-from marshmallow import validates_schema
from marshmallow import fields as marshmallow_fields
+from marshmallow import validates_schema
-from nucypher.control.specifications.base import BaseSchema
-from nucypher.control.specifications import fields as base_fields
-from nucypher.control.specifications.exceptions import InvalidArgumentCombo
-from nucypher.utilities.porter.control.specifications import fields
from nucypher.characters.control.specifications import fields as character_fields
from nucypher.cli import types
+from nucypher.control.specifications import fields as base_fields
+from nucypher.control.specifications.base import BaseSchema
+from nucypher.control.specifications.exceptions import InvalidArgumentCombo
+from nucypher.utilities.porter.control.specifications import fields
def option_ursula():
diff --git a/tests/acceptance/characters/control/test_rpc_control_blockchain.py b/tests/acceptance/characters/control/test_rpc_control_blockchain.py
index 86675ba1d..7f430c0d2 100644
--- a/tests/acceptance/characters/control/test_rpc_control_blockchain.py
+++ b/tests/acceptance/characters/control/test_rpc_control_blockchain.py
@@ -14,8 +14,6 @@
You should have received a copy of the GNU Affero General Public License
along with nucypher. If not, see .
"""
-
-
from base64 import b64encode
import pytest
@@ -34,10 +32,10 @@ def test_enrico_rpc_character_control_encrypt_message(enrico_rpc_controller_test
interface=EnricoInterface)
-def test_bob_rpc_character_control_retrieve_with_tmap(
- enacted_blockchain_policy, blockchain_bob, blockchain_alice,
- bob_rpc_controller, retrieve_control_request):
-
+def test_bob_rpc_character_control_retrieve_with_tmap(enacted_blockchain_policy,
+ blockchain_bob,
+ bob_rpc_controller,
+ retrieve_control_request):
# So that this test can run even independently.
if not blockchain_bob.done_seeding:
blockchain_bob.learn_from_teacher_node()
diff --git a/tests/acceptance/porter/control/test_porter_rpc_control_blockchain.py b/tests/acceptance/porter/control/test_porter_rpc_control_blockchain.py
index de6f798a3..5157c75d8 100644
--- a/tests/acceptance/porter/control/test_porter_rpc_control_blockchain.py
+++ b/tests/acceptance/porter/control/test_porter_rpc_control_blockchain.py
@@ -21,7 +21,6 @@ import pytest
from nucypher.control.specifications.exceptions import InvalidInputData
from nucypher.network.nodes import Learner
-from nucypher.utilities.porter.control.specifications.fields import Capsule
from tests.utils.middleware import MockRestMiddleware
from tests.utils.policy import retrieval_request_setup, retrieval_params_decode_from_rest
@@ -100,15 +99,10 @@ def test_retrieve_cfrags(blockchain_porter,
retrieval_results = response.data['result']['retrieval_results']
assert retrieval_results
- # expected results - can only compare capsules, ursulas are randomized to obtain cfrags
+ # expected results - can only compare length of results, ursulas are randomized to obtain cfrags
retrieve_args = retrieval_params_decode_from_rest(retrieve_cfrags_params)
- expected_results = blockchain_porter.retrieve_cfrags(**retrieve_args).results
- capsule_field = Capsule()
+ expected_results = blockchain_porter.retrieve_cfrags(**retrieve_args)
assert len(retrieval_results) == len(expected_results)
- for i, result in enumerate(retrieval_results):
- # compare capsule
- capsule = capsule_field._deserialize(value=result['capsule'], attr=None, data=None)
- assert capsule == expected_results[i].capsule
# Failure - use encrypted treasure map
failure_retrieve_cfrags_params = dict(retrieve_cfrags_params)
diff --git a/tests/acceptance/porter/control/test_porter_web_control_blockchain.py b/tests/acceptance/porter/control/test_porter_web_control_blockchain.py
index 2b57e86d8..c8f08e3a0 100644
--- a/tests/acceptance/porter/control/test_porter_web_control_blockchain.py
+++ b/tests/acceptance/porter/control/test_porter_web_control_blockchain.py
@@ -18,8 +18,8 @@
import json
import os
from base64 import b64encode
+from urllib.parse import urlencode
-from nucypher.utilities.porter.control.specifications.fields import Capsule
from tests.utils.middleware import MockRestMiddleware
from tests.utils.policy import retrieval_request_setup, retrieval_params_decode_from_rest
@@ -110,15 +110,10 @@ def test_retrieve_cfrags(blockchain_porter,
retrieval_results = response_data['result']['retrieval_results']
assert retrieval_results
- # expected results - can only compare capsules, ursulas are randomized to obtain cfrags
+ # expected results - can only compare length of results, ursulas are randomized to obtain cfrags
retrieve_args = retrieval_params_decode_from_rest(retrieve_cfrags_params)
- expected_results = blockchain_porter.retrieve_cfrags(**retrieve_args).results
- capsule_field = Capsule()
+ expected_results = blockchain_porter.retrieve_cfrags(**retrieve_args)
assert len(retrieval_results) == len(expected_results)
- for i, result in enumerate(retrieval_results):
- # compare capsule
- capsule = capsule_field._deserialize(value=result['capsule'], attr=None, data=None)
- assert capsule == expected_results[i].capsule
# try same retrieval using query parameters
url_retrieve_params = dict(retrieve_cfrags_params)
diff --git a/tests/integration/characters/test_specifications.py b/tests/integration/characters/test_specifications.py
index 543d26a16..9dab95e6f 100644
--- a/tests/integration/characters/test_specifications.py
+++ b/tests/integration/characters/test_specifications.py
@@ -22,14 +22,14 @@ from base64 import b64encode
import maya
import pytest
-from nucypher.policy.maps import TreasureMap as TreasureMapClass
from nucypher.characters.control.specifications import fields
from nucypher.characters.control.specifications.alice import GrantPolicy
-from nucypher.characters.control.specifications.fields.treasuremap import EncryptedTreasureMap
+from nucypher.characters.control.specifications.fields.treasuremap import EncryptedTreasureMap, TreasureMap
from nucypher.control.specifications.base import BaseSchema
from nucypher.control.specifications.exceptions import SpecificationError, InvalidInputData, InvalidArgumentCombo
from nucypher.crypto.powers import DecryptingPower
from nucypher.crypto.umbral_adapter import PublicKey
+from nucypher.policy.maps import EncryptedTreasureMap as EncryptedTreasureMapClass, TreasureMap as TreasureMapClass
def test_various_field_validations_by_way_of_alice_grant(federated_bob):
@@ -52,7 +52,7 @@ def test_various_field_validations_by_way_of_alice_grant(federated_bob):
}
# validate data with both rate and value fails validation
- with pytest.raises(InvalidArgumentCombo) as e:
+ with pytest.raises(InvalidArgumentCombo):
GrantPolicy().load(data)
# remove value and now it works
@@ -62,24 +62,27 @@ def test_various_field_validations_by_way_of_alice_grant(federated_bob):
# validate that negative "m" value fails
data['threshold'] = -5
- with pytest.raises(SpecificationError) as e:
+ with pytest.raises(SpecificationError):
GrantPolicy().load(data)
# validate that m > n fails validation
data['threshold'] = data['shares'] + 19
- with pytest.raises(SpecificationError) as e:
+ with pytest.raises(SpecificationError):
GrantPolicy().load(data)
-def test_treasuremap_validation(enacted_federated_policy):
+def test_treasure_map_validation(enacted_federated_policy,
+ federated_bob):
"""Tell people exactly what's wrong with their treasuremaps"""
-
- class TreasureMapsOnly(BaseSchema):
+ #
+ # encrypted treasure map
+ #
+ class EncryptedTreasureMapsOnly(BaseSchema):
tmap = EncryptedTreasureMap()
# this will raise a base64 error
with pytest.raises(SpecificationError) as e:
- TreasureMapsOnly().load({'tmap': "your face looks like a treasure map"})
+ EncryptedTreasureMapsOnly().load({'tmap': "your face looks like a treasure map"})
# assert that field name is in the error message
assert "Could not parse tmap" in str(e)
@@ -87,7 +90,7 @@ def test_treasuremap_validation(enacted_federated_policy):
# valid base64 but invalid treasuremap
with pytest.raises(InvalidInputData) as e:
- TreasureMapsOnly().load({'tmap': "VGhpcyBpcyB0b3RhbGx5IG5vdCBhIHRyZWFzdXJlbWFwLg=="})
+ EncryptedTreasureMapsOnly().load({'tmap': "VGhpcyBpcyB0b3RhbGx5IG5vdCBhIHRyZWFzdXJlbWFwLg=="})
assert "Could not convert input for tmap to an EncryptedTreasureMap" in str(e)
assert "Invalid encrypted treasure map contents." in str(e)
@@ -95,7 +98,36 @@ def test_treasuremap_validation(enacted_federated_policy):
# a valid treasuremap for once...
tmap_bytes = bytes(enacted_federated_policy.treasure_map)
tmap_b64 = b64encode(tmap_bytes)
- result = TreasureMapsOnly().load({'tmap': tmap_b64.decode()})
+ result = EncryptedTreasureMapsOnly().load({'tmap': tmap_b64.decode()})
+ assert isinstance(result['tmap'], EncryptedTreasureMapClass)
+
+ #
+ # unencrypted treasure map
+ #
+ class UnenncryptedTreasureMapsOnly(BaseSchema):
+ tmap = TreasureMap()
+
+ # this will raise a base64 error
+ with pytest.raises(SpecificationError) as e:
+ UnenncryptedTreasureMapsOnly().load({'tmap': "your face looks like a treasure map"})
+
+ # assert that field name is in the error message
+ assert "Could not parse tmap" in str(e)
+ assert "Invalid base64-encoded string" in str(e)
+
+ # valid base64 but invalid treasuremap
+ with pytest.raises(InvalidInputData) as e:
+ UnenncryptedTreasureMapsOnly().load({'tmap': "VGhpcyBpcyB0b3RhbGx5IG5vdCBhIHRyZWFzdXJlbWFwLg=="})
+
+ assert "Could not convert input for tmap to a TreasureMap" in str(e)
+ assert "Invalid treasure map contents." in str(e)
+
+ # a valid treasuremap
+ decrypted_treasure_map = federated_bob._decrypt_treasure_map(enacted_federated_policy.treasure_map,
+ enacted_federated_policy.publisher_verifying_key)
+ tmap_bytes = bytes(decrypted_treasure_map)
+ tmap_b64 = b64encode(tmap_bytes).decode()
+ result = UnenncryptedTreasureMapsOnly().load({'tmap': tmap_b64})
assert isinstance(result['tmap'], TreasureMapClass)
diff --git a/tests/integration/porter/control/test_porter_rpc_control_federated.py b/tests/integration/porter/control/test_porter_rpc_control_federated.py
index 8ba174a92..eb2a8b572 100644
--- a/tests/integration/porter/control/test_porter_rpc_control_federated.py
+++ b/tests/integration/porter/control/test_porter_rpc_control_federated.py
@@ -21,7 +21,6 @@ import pytest
from nucypher.control.specifications.exceptions import InvalidInputData
from nucypher.network.nodes import Learner
-from nucypher.utilities.porter.control.specifications.fields import Capsule
from tests.utils.policy import retrieval_request_setup, retrieval_params_decode_from_rest
@@ -95,19 +94,14 @@ def test_retrieve_cfrags(federated_porter,
retrieval_results = response.data['result']['retrieval_results']
assert retrieval_results
- # expected results - can only compare capsules, ursulas are randomized to obtain cfrags
+ # expected results - can only compare length of results, ursulas are randomized to obtain cfrags
retrieve_args = retrieval_params_decode_from_rest(retrieve_cfrags_params)
- expected_results = federated_porter.retrieve_cfrags(**retrieve_args).results
- capsule_field = Capsule()
+ expected_results = federated_porter.retrieve_cfrags(**retrieve_args)
assert len(retrieval_results) == len(expected_results)
- for i, result in enumerate(retrieval_results):
- # compare capsule
- capsule = capsule_field._deserialize(value=result['capsule'], attr=None, data=None)
- assert capsule == expected_results[i].capsule
# Failure - use encrypted treasure map
failure_retrieve_cfrags_params = dict(retrieve_cfrags_params)
- _, _, random_treasure_map = random_federated_treasure_map_data
+ _, random_treasure_map = random_federated_treasure_map_data
failure_retrieve_cfrags_params['treasure_map'] = b64encode(bytes(random_treasure_map)).decode()
request_data = {'method': method, 'params': failure_retrieve_cfrags_params}
with pytest.raises(InvalidInputData):
diff --git a/tests/integration/porter/control/test_porter_web_control_federated.py b/tests/integration/porter/control/test_porter_web_control_federated.py
index a9f939803..6e79f6f29 100644
--- a/tests/integration/porter/control/test_porter_web_control_federated.py
+++ b/tests/integration/porter/control/test_porter_web_control_federated.py
@@ -18,8 +18,8 @@
import json
from base64 import b64encode
+from urllib.parse import urlencode
-from nucypher.utilities.porter.control.specifications.fields import Capsule
from tests.utils.policy import retrieval_request_setup, retrieval_params_decode_from_rest
@@ -106,15 +106,10 @@ def test_retrieve_cfrags(federated_porter,
retrieval_results = response_data['result']['retrieval_results']
assert retrieval_results
- # expected results - can only compare capsules, ursulas are randomized to obtain cfrags
+ # expected results - can only compare length of results, ursulas are randomized to obtain cfrags
retrieve_args = retrieval_params_decode_from_rest(retrieve_cfrags_params)
- expected_results = federated_porter.retrieve_cfrags(**retrieve_args).results
- capsule_field = Capsule()
+ expected_results = federated_porter.retrieve_cfrags(**retrieve_args)
assert len(retrieval_results) == len(expected_results)
- for i, result in enumerate(retrieval_results):
- # compare capsule
- capsule = capsule_field._deserialize(value=result['capsule'], attr=None, data=None)
- assert capsule == expected_results[i].capsule
# try same retrieval using query parameters
url_retrieve_params = dict(retrieve_cfrags_params)
@@ -127,7 +122,7 @@ def test_retrieve_cfrags(federated_porter,
failure_retrieve_cfrags_params = dict(retrieve_cfrags_params)
# use encrypted treasure map
- _, _, random_treasure_map = random_federated_treasure_map_data
+ _, random_treasure_map = random_federated_treasure_map_data
failure_retrieve_cfrags_params['treasure_map'] = b64encode(bytes(random_treasure_map)).decode()
response = federated_porter_web_controller.post('/retrieve_cfrags', data=json.dumps(failure_retrieve_cfrags_params))
assert response.status_code == 400 # invalid treasure map provided
diff --git a/tests/integration/porter/test_federated_porter.py b/tests/integration/porter/test_federated_porter.py
index 8622b9046..7a57f28d8 100644
--- a/tests/integration/porter/test_federated_porter.py
+++ b/tests/integration/porter/test_federated_porter.py
@@ -73,4 +73,4 @@ def test_retrieve_cfrags(federated_porter,
result = federated_porter.retrieve_cfrags(**retrieval_args)
- assert result, "valid result returned"
\ No newline at end of file
+ assert result, "valid result returned"
diff --git a/tests/integration/porter/test_porter_specifications.py b/tests/integration/porter/test_porter_specifications.py
index 23ba2c071..c8b717dbf 100644
--- a/tests/integration/porter/test_porter_specifications.py
+++ b/tests/integration/porter/test_porter_specifications.py
@@ -205,9 +205,9 @@ def test_bob_retrieve_cfrags(federated_porter,
retrieval_results = federated_porter.retrieve_cfrags(**non_encoded_retrieval_args)
expected_retrieval_results_json = []
retrieval_result_schema = RetrievalResultSchema()
- for result in retrieval_results.results:
+ for result in retrieval_results:
data = retrieval_result_schema.dump(result)
expected_retrieval_results_json.append(data)
- output = bob_retrieve_cfrags_schema.dump(obj={'retrieval_results': retrieval_results.results})
+ output = bob_retrieve_cfrags_schema.dump(obj={'retrieval_results': retrieval_results})
assert output == {"retrieval_results": expected_retrieval_results_json}
diff --git a/tests/unit/test_porter.py b/tests/unit/test_porter.py
index a75e85fd2..3d9a5420c 100644
--- a/tests/unit/test_porter.py
+++ b/tests/unit/test_porter.py
@@ -20,13 +20,10 @@ import pytest
from nucypher.control.specifications.exceptions import InvalidInputData
from nucypher.control.specifications.fields import StringList
-from nucypher.crypto.kits import RetrievalKit as RetrievalKitClass
-from nucypher.crypto.umbral_adapter import SecretKey, encrypt, Capsule as CapsuleClass
-from nucypher.utilities.porter.control.specifications.fields import (
- HRAC,
- UrsulaChecksumAddress,
-)
-from nucypher.utilities.porter.control.specifications.fields.retrieve import RetrievalKit, Capsule
+from nucypher.crypto.umbral_adapter import SecretKey, encrypt
+from nucypher.policy.kits import RetrievalKit as RetrievalKitClass
+from nucypher.utilities.porter.control.specifications.fields import HRAC, UrsulaChecksumAddress
+from nucypher.utilities.porter.control.specifications.fields.retrieve import RetrievalKit
def test_hrac_field(enacted_federated_policy):
@@ -37,11 +34,10 @@ def test_hrac_field(enacted_federated_policy):
assert serialized == bytes(hrac).hex()
deserialized = field._deserialize(value=serialized, attr=None, data=None)
- assert deserialized == bytes(hrac)
+ assert deserialized == hrac
- field._validate(value=bytes(hrac))
with pytest.raises(InvalidInputData):
- field._validate(value=b'not hrac')
+ field._deserialize(value=b'not hrac', attr=None, data=None)
def test_ursula_checksum_address_field(get_random_checksum_address):
@@ -124,19 +120,3 @@ def test_retrieval_kit_field():
with pytest.raises(InvalidInputData):
field.deserialize(value=b64encode(b"invalid_retrieval_kit_bytes").decode(), attr=None, data=None)
-
-
-def test_capsule_field():
- encrypting_key = SecretKey.random().public_key()
- capsule, _ = encrypt(encrypting_key, b'testing_retrieval_kit')
-
- field = Capsule()
- serialized = field._serialize(value=capsule, attr=None, obj=None)
- assert serialized == b64encode(bytes(capsule)).decode()
-
- deserialized = field._deserialize(value=serialized, attr=None, data=None)
- assert isinstance(deserialized, CapsuleClass)
- assert deserialized == capsule
-
- with pytest.raises(InvalidInputData):
- field._deserialize(value=b64encode(b"faux_capsule").decode(), attr=None, data=None)
diff --git a/tests/utils/policy.py b/tests/utils/policy.py
index 020d0390a..bdf62e194 100644
--- a/tests/utils/policy.py
+++ b/tests/utils/policy.py
@@ -20,7 +20,7 @@ import random
import string
from typing import Dict
-from nucypher.characters.control.specifications.fields import Key, DecryptedTreasureMap
+from nucypher.characters.control.specifications.fields import Key, TreasureMap
from nucypher.characters.lawful import Enrico
from nucypher.crypto.powers import DecryptingPower
from nucypher.utilities.porter.control.specifications.fields import RetrievalKit
@@ -47,7 +47,8 @@ def retrieval_request_setup(enacted_policy, bob, alice, encode_for_rest=False) -
bob.start_learning_loop()
bob.follow_treasure_map(treasure_map=treasure_map, block=True, timeout=1)
- decrypted_map = treasure_map.as_decrypted_map()
+ decrypted_treasure_map = bob._decrypt_treasure_map(enacted_policy.treasure_map,
+ enacted_policy.publisher_verifying_key)
# We'll test against just a single Ursula - here, we make a WorkOrder for just one.
# We can pass any number of capsules as args; here we pass just one.
@@ -57,7 +58,7 @@ def retrieval_request_setup(enacted_policy, bob, alice, encode_for_rest=False) -
encode_bytes = (lambda field, obj: field()._serialize(value=obj, attr=None, obj=None)) if encode_for_rest else (lambda field, obj: obj)
- return dict(treasure_map=encode_bytes(DecryptedTreasureMap, decrypted_map),
+ return dict(treasure_map=encode_bytes(TreasureMap, decrypted_treasure_map),
retrieval_kits=[encode_bytes(RetrievalKit, message_kit.as_retrieval_kit())],
alice_verifying_key=encode_bytes(Key, alice.stamp.as_umbral_pubkey()),
bob_encrypting_key=encode_bytes(Key, bob.public_keys(DecryptingPower)),
@@ -67,7 +68,7 @@ def retrieval_request_setup(enacted_policy, bob, alice, encode_for_rest=False) -
def retrieval_params_decode_from_rest(retrieval_params: Dict) -> Dict:
decode_bytes = (lambda field, data: field()._deserialize(value=data, attr=None, data=None))
- return dict(treasure_map=decode_bytes(DecryptedTreasureMap, retrieval_params['treasure_map']),
+ return dict(treasure_map=decode_bytes(TreasureMap, retrieval_params['treasure_map']),
retrieval_kits=[decode_bytes(RetrievalKit, kit) for kit in retrieval_params['retrieval_kits']],
alice_verifying_key=decode_bytes(Key, retrieval_params['alice_verifying_key']),
bob_encrypting_key=decode_bytes(Key, retrieval_params['bob_encrypting_key']),