From ae1e7edf438c7af013ce11a644375140703e79ce Mon Sep 17 00:00:00 2001 From: derekpierre Date: Wed, 11 Aug 2021 10:48:46 -0400 Subject: [PATCH] Add RetrievalKit field for marshalling/unmarshalling of request/response data that requires a RetrievalKit - intended to be part of Bob's retrieve schema in Porter. --- .../control/specifications/fields/retrieve.py | 31 +++++++++++++++++++ tests/unit/test_porter.py | 25 +++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 nucypher/utilities/porter/control/specifications/fields/retrieve.py diff --git a/nucypher/utilities/porter/control/specifications/fields/retrieve.py b/nucypher/utilities/porter/control/specifications/fields/retrieve.py new file mode 100644 index 000000000..317db6adc --- /dev/null +++ b/nucypher/utilities/porter/control/specifications/fields/retrieve.py @@ -0,0 +1,31 @@ +""" + 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 nucypher.control.specifications.exceptions import InvalidInputData +from nucypher.control.specifications.fields import Base64BytesRepresentation +from nucypher.crypto.kits import RetrievalKit as RetrievalKitClass + + +# TODO should this be moved to character control - would this be used by a Bob character control endpoint? +class RetrievalKit(Base64BytesRepresentation): + def _deserialize(self, value, attr, data, **kwargs): + try: + # decode base64 to bytes + retrieval_kit_bytes = super()._deserialize(value, attr, data, **kwargs) + return RetrievalKitClass.from_bytes(retrieval_kit_bytes) + except Exception as e: + raise InvalidInputData(f"Could not convert input for {self.name} to a valid checksum address: {e}") diff --git a/tests/unit/test_porter.py b/tests/unit/test_porter.py index 6fc3f77f8..c06073e4c 100644 --- a/tests/unit/test_porter.py +++ b/tests/unit/test_porter.py @@ -20,10 +20,13 @@ 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 from nucypher.utilities.porter.control.specifications.fields import ( HRAC, UrsulaChecksumAddress, ) +from nucypher.utilities.porter.control.specifications.fields.retrieve import RetrievalKit from tests.utils.policy import retrieval_request_setup @@ -131,3 +134,25 @@ def test_ursula_checksum_address_string_list_field(get_random_checksum_address): with pytest.raises(InvalidInputData): field._deserialize(value=f"{ursula_1},{ursula_2},{ursula_3},{ursula_4},0xdeadbeef", attr=None, data=None) + + +def test_retrieval_kit_field(): + encrypting_key = SecretKey.random().public_key() + capsule, _ = encrypt(encrypting_key, b'testing_retrieval_kit') + + retrieval_kit = RetrievalKitClass(capsule, set()) + + field = RetrievalKit() + serialized = field._serialize(value=retrieval_kit, attr=None, obj=None) + assert serialized == b64encode(bytes(retrieval_kit)).decode() + + deserialized = field.deserialize(value=serialized, attr=None, data=None) + assert isinstance(deserialized, RetrievalKitClass) + assert deserialized.capsule == capsule + assert len(deserialized.queried_addresses) == 0 + + with pytest.raises(InvalidInputData): + field.deserialize(value=b"non_base_64_data", attr=None, data=None) + + with pytest.raises(InvalidInputData): + field.deserialize(value=b64encode(b"invalid_retrieval_kit_bytes").decode(), attr=None, data=None)