mirror of https://github.com/nucypher/nucypher.git
Code cleanup after rebase over retrieval protocol work in #2730.
parent
57bfba6d4e
commit
dfa65a2976
|
@ -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. |
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
from bytestring_splitter import BytestringSplittingError
|
||||
from cryptography.exceptions import InternalError
|
||||
|
||||
# TODO: catch cryptography.exceptions.InternalError in PyUmbral
|
||||
InvalidNativeDataTypes = (ValueError, TypeError, BytestringSplittingError, InternalError)
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -15,40 +15,30 @@
|
|||
along with nucypher. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
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
|
||||
raise InvalidInputData(f"Could not convert input for {self.name} to a TreasureMap: {e}") from e
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
You should have received a copy of the GNU Affero General Public License
|
||||
along with nucypher. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
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)
|
||||
|
|
|
@ -16,23 +16,22 @@ along with nucypher. If not, see <https://www.gnu.org/licenses/>.
|
|||
"""
|
||||
|
||||
|
||||
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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}")
|
||||
|
|
|
@ -15,11 +15,12 @@
|
|||
along with nucypher. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
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:
|
||||
|
|
|
@ -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():
|
||||
|
|
|
@ -14,8 +14,6 @@
|
|||
You should have received a copy of the GNU Affero General Public License
|
||||
along with nucypher. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
|
||||
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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -73,4 +73,4 @@ def test_retrieve_cfrags(federated_porter,
|
|||
|
||||
result = federated_porter.retrieve_cfrags(**retrieval_args)
|
||||
|
||||
assert result, "valid result returned"
|
||||
assert result, "valid result returned"
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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']),
|
||||
|
|
Loading…
Reference in New Issue