From 28567b756106dd94f37bb5843d6494f339df1bf8 Mon Sep 17 00:00:00 2001 From: "Kieran R. Prasch" Date: Tue, 16 Jun 2020 20:18:08 -0700 Subject: [PATCH] Use a signature field for enrico and represent as base64 --- nucypher/characters/control/controllers.py | 3 +- .../control/specifications/enrico.py | 3 +- .../control/specifications/fields/__init__.py | 1 + .../specifications/fields/signature.py | 44 +++++++++++++++++++ nucypher/characters/lawful.py | 8 ++-- nucypher/cli/commands/bob.py | 1 + nucypher/cli/commands/enrico.py | 3 ++ 7 files changed, 56 insertions(+), 7 deletions(-) create mode 100644 nucypher/characters/control/specifications/fields/signature.py diff --git a/nucypher/characters/control/controllers.py b/nucypher/characters/control/controllers.py index a602dcff4..76abfa40b 100644 --- a/nucypher/characters/control/controllers.py +++ b/nucypher/characters/control/controllers.py @@ -141,7 +141,8 @@ class CLIController(CharacterControlServer): def handle_request(self, method_name, request): start = maya.now() response = self._perform_action(action=method_name, request=request) - return self.emitter.ipc(response=response, request_id=start.epoch, duration=maya.now() - start) + self.emitter.ipc(response=response, request_id=start.epoch, duration=maya.now() - start) + return response class JSONRPCController(CharacterControlServer): diff --git a/nucypher/characters/control/specifications/enrico.py b/nucypher/characters/control/specifications/enrico.py index 0e47ae5de..ef0410874 100644 --- a/nucypher/characters/control/specifications/enrico.py +++ b/nucypher/characters/control/specifications/enrico.py @@ -62,7 +62,6 @@ class EncryptMessage(BaseSchema): return {"plaintext": data} - # output message_kit = fields.UmbralMessageKit(dump_only=True) - signature = fields.String(dump_only=True) # maybe we need a signature field? + signature = fields.UmbralSignature(dump_only=True) # maybe we need a signature field? diff --git a/nucypher/characters/control/specifications/fields/__init__.py b/nucypher/characters/control/specifications/fields/__init__.py index ae5e73bab..17912d924 100644 --- a/nucypher/characters/control/specifications/fields/__init__.py +++ b/nucypher/characters/control/specifications/fields/__init__.py @@ -23,3 +23,4 @@ from nucypher.characters.control.specifications.fields.label import * from nucypher.characters.control.specifications.fields.cleartext import * from nucypher.characters.control.specifications.fields.misc import * from nucypher.characters.control.specifications.fields.file import * +from nucypher.characters.control.specifications.fields.signature import * diff --git a/nucypher/characters/control/specifications/fields/signature.py b/nucypher/characters/control/specifications/fields/signature.py new file mode 100644 index 000000000..68d5cf50c --- /dev/null +++ b/nucypher/characters/control/specifications/fields/signature.py @@ -0,0 +1,44 @@ +""" + 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 base64 import b64decode, b64encode + +from marshmallow import fields +from umbral.signing import Signature + +from nucypher.characters.control.specifications.exceptions import InvalidInputData, InvalidNativeDataTypes +from nucypher.characters.control.specifications.fields.base import BaseField + + +class UmbralSignature(BaseField, fields.Field): + + def _serialize(self, value: Signature, attr, obj, **kwargs): + return b64encode(bytes(value)).decode() + + def _deserialize(self, value, attr, data, **kwargs): + if isinstance(value, bytes): + return value + try: + return b64decode(value) + except InvalidNativeDataTypes as e: + raise InvalidInputData(f"Could not parse {self.name}: {e}") + + def _validate(self, value): + try: + Signature.from_bytes(value) + except InvalidNativeDataTypes as e: + raise InvalidInputData(f"Could not parse {self.name}: {e}") diff --git a/nucypher/characters/lawful.py b/nucypher/characters/lawful.py index dc82a23a2..83b9a7e56 100644 --- a/nucypher/characters/lawful.py +++ b/nucypher/characters/lawful.py @@ -792,15 +792,15 @@ class Bob(Character): self.get_reencrypted_cfrags(work_order, retain_cfrags=retain_cfrags) except NodeSeemsToBeDown as e: # TODO: What to do here? Ursula isn't supposed to be down. NRN - self.log.info( - f"Ursula ({work_order.ursula}) seems to be down while trying to complete WorkOrder: {work_order}") + self.log.info(f"Ursula ({work_order.ursula}) seems to be down while trying to complete WorkOrder: {work_order}") continue except self.network_middleware.NotFound: # This Ursula claims not to have a matching KFrag. Maybe this has been revoked? # TODO: What's the thing to do here? Do we want to track these Ursulas in some way in case they're lying? 567 - self.log.warn( - f"Ursula ({work_order.ursula}) claims not to have the KFrag to complete WorkOrder: {work_order}. Has accessed been revoked?") + self.log.warn(f"Ursula ({work_order.ursula}) claims not to have the KFrag to complete WorkOrder: {work_order}. Has accessed been revoked?") continue + except self.network_middleware.UnexpectedResponse: + raise # TODO: Handle this for capsule, pre_task in work_order.tasks.items(): try: diff --git a/nucypher/cli/commands/bob.py b/nucypher/cli/commands/bob.py index 0d1d87ec1..e5755b525 100644 --- a/nucypher/cli/commands/bob.py +++ b/nucypher/cli/commands/bob.py @@ -14,6 +14,7 @@ You should have received a copy of the GNU Affero General Public License along with nucypher. If not, see . """ +import base64 import click diff --git a/nucypher/cli/commands/enrico.py b/nucypher/cli/commands/enrico.py index 921b1acb0..c5a0da58b 100644 --- a/nucypher/cli/commands/enrico.py +++ b/nucypher/cli/commands/enrico.py @@ -61,12 +61,15 @@ def run(general_config, policy_encrypting_key, dry_run, http_port): @group_general_config def encrypt(general_config, policy_encrypting_key, message, file): """Encrypt a message under a given policy public key.""" + + # Setup emitter = setup_emitter(general_config=general_config, banner=policy_encrypting_key) ENRICO = _create_enrico(emitter, policy_encrypting_key) if not (bool(message) ^ bool(file)): emitter.error(f'Pass either --message or --file. Got {message}, {file}.') raise click.Abort + # Encryption Request encryption_request = {'policy_encrypting_key': policy_encrypting_key, 'message': message, 'filepath': file} response = ENRICO.controller.encrypt_message(request=encryption_request) return response