mirror of https://github.com/nucypher/nucypher.git
Define initial schema for /retrieve_cfrags Porter endpoint - (untested at the moment)
parent
2cd7698da7
commit
61c0978e52
|
@ -164,7 +164,7 @@ class BobInterface(CharacterPublicInterface):
|
||||||
policy_encrypting_key: PublicKey,
|
policy_encrypting_key: PublicKey,
|
||||||
alice_verifying_key: PublicKey,
|
alice_verifying_key: PublicKey,
|
||||||
message_kit: bytes,
|
message_kit: bytes,
|
||||||
encrypted_treasure_map: 'EncryptedTreasureMap'):
|
encrypted_treasure_map: 'EncryptedTreasureMap') -> dict:
|
||||||
"""
|
"""
|
||||||
Character control endpoint for re-encrypting and decrypting policy data.
|
Character control endpoint for re-encrypting and decrypting policy data.
|
||||||
"""
|
"""
|
||||||
|
@ -180,7 +180,7 @@ class BobInterface(CharacterPublicInterface):
|
||||||
return response_data
|
return response_data
|
||||||
|
|
||||||
@attach_schema(bob.PublicKeys)
|
@attach_schema(bob.PublicKeys)
|
||||||
def public_keys(self):
|
def public_keys(self) -> dict:
|
||||||
"""
|
"""
|
||||||
Character control endpoint for getting Bob's encrypting and signing public keys
|
Character control endpoint for getting Bob's encrypting and signing public keys
|
||||||
"""
|
"""
|
||||||
|
@ -193,7 +193,7 @@ class BobInterface(CharacterPublicInterface):
|
||||||
class EnricoInterface(CharacterPublicInterface):
|
class EnricoInterface(CharacterPublicInterface):
|
||||||
|
|
||||||
@attach_schema(enrico.EncryptMessage)
|
@attach_schema(enrico.EncryptMessage)
|
||||||
def encrypt_message(self, plaintext: Union[str, bytes]):
|
def encrypt_message(self, plaintext: Union[str, bytes]) -> dict:
|
||||||
"""
|
"""
|
||||||
Character control endpoint for encrypting data for a policy and
|
Character control endpoint for encrypting data for a policy and
|
||||||
receiving the messagekit (and signature) to give to Bob.
|
receiving the messagekit (and signature) to give to Bob.
|
||||||
|
|
|
@ -19,6 +19,8 @@ from typing import List, Optional
|
||||||
from eth_typing import ChecksumAddress
|
from eth_typing import ChecksumAddress
|
||||||
|
|
||||||
from nucypher.control.interfaces import ControlInterface, attach_schema
|
from nucypher.control.interfaces import ControlInterface, attach_schema
|
||||||
|
from nucypher.crypto.umbral_adapter import PublicKey
|
||||||
|
from nucypher.policy.kits import RetrievalKit
|
||||||
from nucypher.utilities.porter.control.specifications import porter_schema
|
from nucypher.utilities.porter.control.specifications import porter_schema
|
||||||
|
|
||||||
|
|
||||||
|
@ -40,9 +42,7 @@ class PorterInterface(ControlInterface):
|
||||||
exclude_ursulas=exclude_ursulas,
|
exclude_ursulas=exclude_ursulas,
|
||||||
include_ursulas=include_ursulas)
|
include_ursulas=include_ursulas)
|
||||||
|
|
||||||
response_data = {
|
response_data = {"ursulas": ursulas_info}
|
||||||
"ursulas": ursulas_info
|
|
||||||
}
|
|
||||||
return response_data
|
return response_data
|
||||||
|
|
||||||
@attach_schema(porter_schema.AliceRevoke)
|
@attach_schema(porter_schema.AliceRevoke)
|
||||||
|
@ -52,3 +52,24 @@ class PorterInterface(ControlInterface):
|
||||||
# 2. call self.implementer.some_function() i.e. Porter learner has an associated function to call
|
# 2. call self.implementer.some_function() i.e. Porter learner has an associated function to call
|
||||||
# 3. create response
|
# 3. create response
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@attach_schema(porter_schema.BobRetrieveCFrags)
|
||||||
|
def retrieve_cfrags(self,
|
||||||
|
treasure_map: 'TreasureMap',
|
||||||
|
retrieval_kits: List[RetrievalKit],
|
||||||
|
alice_verifying_key: PublicKey,
|
||||||
|
bob_encrypting_key: PublicKey,
|
||||||
|
bob_verifying_key: PublicKey,
|
||||||
|
policy_encrypting_key: PublicKey,
|
||||||
|
publisher_verifying_key: Optional[PublicKey] = None,
|
||||||
|
) -> dict:
|
||||||
|
retrieval_results = self.implementer.retrieve_cfrags(treasure_map=treasure_map,
|
||||||
|
retrieval_kits=retrieval_kits,
|
||||||
|
alice_verifying_key=alice_verifying_key,
|
||||||
|
bob_encrypting_key=bob_encrypting_key,
|
||||||
|
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
|
||||||
|
response_data = {'retrieve_results': results}
|
||||||
|
return response_data
|
||||||
|
|
|
@ -17,3 +17,4 @@
|
||||||
|
|
||||||
from nucypher.utilities.porter.control.specifications.fields.ursula import *
|
from nucypher.utilities.porter.control.specifications.fields.ursula import *
|
||||||
from nucypher.utilities.porter.control.specifications.fields.hrac import *
|
from nucypher.utilities.porter.control.specifications.fields.hrac import *
|
||||||
|
from nucypher.utilities.porter.control.specifications.fields.retrieve import *
|
||||||
|
|
|
@ -14,10 +14,13 @@
|
||||||
You should have received a copy of the GNU Affero General Public License
|
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 marshmallow import fields
|
||||||
|
from nucypher.control.specifications.base import BaseSchema
|
||||||
from nucypher.control.specifications.exceptions import InvalidInputData
|
from nucypher.control.specifications.exceptions import InvalidInputData
|
||||||
from nucypher.control.specifications.fields import Base64BytesRepresentation
|
from nucypher.control.specifications.fields import Base64BytesRepresentation
|
||||||
from nucypher.crypto.kits import RetrievalKit as RetrievalKitClass
|
from nucypher.crypto.kits import RetrievalKit as RetrievalKitClass
|
||||||
|
from nucypher.crypto.umbral_adapter import Capsule as CapsuleClass, CapsuleFrag as CapsuleFragClass
|
||||||
|
from nucypher.utilities.porter.control.specifications.fields import UrsulaChecksumAddress
|
||||||
|
|
||||||
|
|
||||||
# TODO should this be moved to character control - would this be used by a Bob character control endpoint?
|
# TODO should this be moved to character control - would this be used by a Bob character control endpoint?
|
||||||
|
@ -29,3 +32,27 @@ class RetrievalKit(Base64BytesRepresentation):
|
||||||
return RetrievalKitClass.from_bytes(retrieval_kit_bytes)
|
return RetrievalKitClass.from_bytes(retrieval_kit_bytes)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise InvalidInputData(f"Could not convert input for {self.name} to a valid checksum address: {e}")
|
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):
|
||||||
|
def _deserialize(self, value, attr, data, **kwargs):
|
||||||
|
try:
|
||||||
|
capsule_bytes = super()._deserialize(value, attr, data, **kwargs)
|
||||||
|
return CapsuleFragClass.from_bytes(capsule_bytes)
|
||||||
|
except Exception as e:
|
||||||
|
raise InvalidInputData(f"Could not parse {self.name}: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
class RetrievalResultSchema(BaseSchema):
|
||||||
|
"""Schema for the result of retrieve_cfrags."""
|
||||||
|
capsule = Capsule()
|
||||||
|
cfrags = fields.Dict(keys=UrsulaChecksumAddress(), values=CapsuleFrag())
|
||||||
|
|
|
@ -117,3 +117,74 @@ class AliceGetUrsulas(BaseSchema):
|
||||||
|
|
||||||
class AliceRevoke(BaseSchema):
|
class AliceRevoke(BaseSchema):
|
||||||
pass # TODO need to understand revoke process better
|
pass # TODO need to understand revoke process better
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Bob Endpoints
|
||||||
|
#
|
||||||
|
class BobRetrieveCFrags(BaseSchema):
|
||||||
|
treasure_map = character_fields.TreasureMap(
|
||||||
|
required=True,
|
||||||
|
load_only=True,
|
||||||
|
click=click.option(
|
||||||
|
'--treasure-map',
|
||||||
|
'-t',
|
||||||
|
help="Treasure Map to publish",
|
||||||
|
type=click.STRING,
|
||||||
|
required=True))
|
||||||
|
retrieval_kits = base_fields.List(
|
||||||
|
fields.RetrievalKit(),
|
||||||
|
click=click.option(
|
||||||
|
'--retrieval-kits',
|
||||||
|
'-r',
|
||||||
|
help="Retrieval kits for reencryption",
|
||||||
|
multiple=True,
|
||||||
|
type=click.STRING,
|
||||||
|
required=True,
|
||||||
|
default=[]),
|
||||||
|
required=True,
|
||||||
|
load_only=True)
|
||||||
|
alice_verifying_key = character_fields.Key(
|
||||||
|
required=True,
|
||||||
|
load_only=True,
|
||||||
|
click=click.option(
|
||||||
|
'--alice-verifying-key',
|
||||||
|
'-avk',
|
||||||
|
help="Alice's verifying key as a hexadecimal string",
|
||||||
|
type=click.STRING,
|
||||||
|
required=True))
|
||||||
|
bob_encrypting_key = character_fields.Key(
|
||||||
|
required=True,
|
||||||
|
load_only=True,
|
||||||
|
click=option_bob_encrypting_key())
|
||||||
|
bob_verifying_key = character_fields.Key(
|
||||||
|
required=True,
|
||||||
|
load_only=True,
|
||||||
|
click=click.option(
|
||||||
|
'--bob-verifying-key',
|
||||||
|
'-bvk',
|
||||||
|
help="Bob's verifying key as a hexadecimal string",
|
||||||
|
type=click.STRING,
|
||||||
|
required=True))
|
||||||
|
policy_encrypting_key = character_fields.Key(
|
||||||
|
required=True,
|
||||||
|
load_only=True,
|
||||||
|
click=click.option(
|
||||||
|
'--policy-encrypting-key',
|
||||||
|
help="Encrypting Public Key for Policy as hexadecimal string",
|
||||||
|
type=click.STRING,
|
||||||
|
required=True))
|
||||||
|
|
||||||
|
# optional
|
||||||
|
publisher_verifying_key = character_fields.Key(
|
||||||
|
required=False,
|
||||||
|
load_only=True,
|
||||||
|
click=click.option(
|
||||||
|
'--publisher-verifying-key',
|
||||||
|
'-pvk',
|
||||||
|
help="Alice's verifying key as a hexadecimal string",
|
||||||
|
type=click.STRING,
|
||||||
|
required=False))
|
||||||
|
|
||||||
|
# output
|
||||||
|
retrieval_results = marshmallow_fields.List(marshmallow_fields.Nested(fields.RetrievalResultSchema), dump_only=True)
|
||||||
|
|
|
@ -23,11 +23,14 @@ from flask import request, Response
|
||||||
from nucypher.blockchain.eth.agents import ContractAgency, StakingEscrowAgent
|
from nucypher.blockchain.eth.agents import ContractAgency, StakingEscrowAgent
|
||||||
from nucypher.blockchain.eth.interfaces import BlockchainInterfaceFactory
|
from nucypher.blockchain.eth.interfaces import BlockchainInterfaceFactory
|
||||||
from nucypher.blockchain.eth.registry import BaseContractRegistry, InMemoryContractRegistry
|
from nucypher.blockchain.eth.registry import BaseContractRegistry, InMemoryContractRegistry
|
||||||
from nucypher.characters.lawful import Ursula
|
from nucypher.characters.lawful import RetrievalClient, Ursula
|
||||||
from nucypher.control.controllers import JSONRPCController, WebController
|
from nucypher.control.controllers import JSONRPCController, WebController
|
||||||
from nucypher.crypto.powers import DecryptingPower
|
from nucypher.crypto.powers import DecryptingPower
|
||||||
from nucypher.crypto.umbral_adapter import PublicKey
|
from nucypher.crypto.umbral_adapter import PublicKey
|
||||||
from nucypher.network.nodes import Learner
|
from nucypher.network.nodes import Learner
|
||||||
|
from nucypher.policy.kits import RetrievalKit
|
||||||
|
from nucypher.policy.maps import TreasureMap
|
||||||
|
from nucypher.policy.orders import RetrievalResult
|
||||||
from nucypher.policy.reservoir import (
|
from nucypher.policy.reservoir import (
|
||||||
make_federated_staker_reservoir,
|
make_federated_staker_reservoir,
|
||||||
make_decentralized_staker_reservoir,
|
make_decentralized_staker_reservoir,
|
||||||
|
@ -148,14 +151,18 @@ the Pipe for nucypher network operations
|
||||||
ursulas_info = successes.values()
|
ursulas_info = successes.values()
|
||||||
return list(ursulas_info)
|
return list(ursulas_info)
|
||||||
|
|
||||||
def exec_work_order(self, ursula_address: ChecksumAddress, work_order_payload: bytes) -> bytes:
|
def retrieve_cfrags(self,
|
||||||
self.block_until_specific_nodes_are_known(addresses={ursula_address}, learn_on_this_thread=True)
|
treasure_map: TreasureMap,
|
||||||
ursula = self.known_nodes[ursula_address]
|
retrieval_kits: Sequence[RetrievalKit],
|
||||||
ursula_rest_response = self.network_middleware.send_work_order_payload_to_ursula(
|
alice_verifying_key: PublicKey,
|
||||||
ursula=ursula,
|
bob_encrypting_key: PublicKey,
|
||||||
work_order_payload=work_order_payload)
|
bob_verifying_key: PublicKey,
|
||||||
result = ursula_rest_response.content
|
policy_encrypting_key: PublicKey,
|
||||||
return result
|
publisher_verifying_key: Optional[PublicKey] = None) -> List[RetrievalResult]:
|
||||||
|
client = RetrievalClient(self)
|
||||||
|
return client.retrieve_cfrags(treasure_map, retrieval_kits,
|
||||||
|
alice_verifying_key, bob_encrypting_key, bob_verifying_key, policy_encrypting_key,
|
||||||
|
publisher_verifying_key)
|
||||||
|
|
||||||
def _make_staker_reservoir(self,
|
def _make_staker_reservoir(self,
|
||||||
quantity: int,
|
quantity: int,
|
||||||
|
@ -229,10 +236,10 @@ the Pipe for nucypher network operations
|
||||||
response = controller(method_name='revoke', control_request=request)
|
response = controller(method_name='revoke', control_request=request)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
@porter_flask_control.route("/exec_work_order", methods=['POST'])
|
@porter_flask_control.route("/retrieve_cfrags", methods=['POST'])
|
||||||
def exec_work_order() -> Response:
|
def retrieve_cfrags() -> Response:
|
||||||
"""Porter control endpoint for executing a PRE work order on behalf of Bob."""
|
"""Porter control endpoint for executing a PRE work order on behalf of Bob."""
|
||||||
response = controller(method_name='exec_work_order', control_request=request)
|
response = controller(method_name='retrieve_cfrags', control_request=request)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
return controller
|
return controller
|
||||||
|
|
|
@ -21,12 +21,12 @@ import pytest
|
||||||
from nucypher.control.specifications.exceptions import InvalidInputData
|
from nucypher.control.specifications.exceptions import InvalidInputData
|
||||||
from nucypher.control.specifications.fields import StringList
|
from nucypher.control.specifications.fields import StringList
|
||||||
from nucypher.crypto.kits import RetrievalKit as RetrievalKitClass
|
from nucypher.crypto.kits import RetrievalKit as RetrievalKitClass
|
||||||
from nucypher.crypto.umbral_adapter import SecretKey, encrypt
|
from nucypher.crypto.umbral_adapter import SecretKey, encrypt, Capsule as CapsuleClass
|
||||||
from nucypher.utilities.porter.control.specifications.fields import (
|
from nucypher.utilities.porter.control.specifications.fields import (
|
||||||
HRAC,
|
HRAC,
|
||||||
UrsulaChecksumAddress,
|
UrsulaChecksumAddress,
|
||||||
)
|
)
|
||||||
from nucypher.utilities.porter.control.specifications.fields.retrieve import RetrievalKit
|
from nucypher.utilities.porter.control.specifications.fields.retrieve import RetrievalKit, Capsule
|
||||||
from tests.utils.policy import retrieval_request_setup
|
from tests.utils.policy import retrieval_request_setup
|
||||||
|
|
||||||
|
|
||||||
|
@ -156,3 +156,19 @@ def test_retrieval_kit_field():
|
||||||
|
|
||||||
with pytest.raises(InvalidInputData):
|
with pytest.raises(InvalidInputData):
|
||||||
field.deserialize(value=b64encode(b"invalid_retrieval_kit_bytes").decode(), attr=None, data=None)
|
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)
|
||||||
|
|
Loading…
Reference in New Issue