mirror of https://github.com/nucypher/nucypher.git
initial specifications refactor commit
parent
072bf76e1b
commit
52551da5da
1
Pipfile
1
Pipfile
|
@ -18,6 +18,7 @@ cryptography = ">=2.3"
|
|||
pysha3="*"
|
||||
requests = "*"
|
||||
sqlalchemy = "*"
|
||||
marshmallow = "*"
|
||||
maya = "*"
|
||||
flask = "*"
|
||||
flask_sqlalchemy = "*"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "2a36b4160cdf1d70dbdb8ae0113c35e7e2f4cf97bff4088c9ca0133c45f592b1"
|
||||
"sha256": "da7b7364c172c115fa1d88b6e6e35128dfde996366b51b08e2c3b1eacff52387"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
|
@ -483,6 +483,14 @@
|
|||
],
|
||||
"version": "==1.1.1"
|
||||
},
|
||||
"marshmallow": {
|
||||
"hashes": [
|
||||
"sha256:0ba81b6da4ae69eb229b74b3c741ff13fe04fb899824377b1aff5aaa1a9fd46e",
|
||||
"sha256:3e53dd9e9358977a3929e45cdbe4a671f9eff53a7d6a23f33ed3eab8c1890d8f"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.3.0"
|
||||
},
|
||||
"maya": {
|
||||
"hashes": [
|
||||
"sha256:7f53e06d5a123613dce7c270cbc647643a6942590dba7a19ec36194d0338c3f4",
|
||||
|
|
|
@ -1,59 +0,0 @@
|
|||
-i https://pypi.python.org/simple
|
||||
aafigure==0.6
|
||||
alabaster==0.7.12
|
||||
ansible==2.9.2
|
||||
apipkg==1.5
|
||||
attrs==19.3.0
|
||||
babel==2.7.0
|
||||
bumpversion==0.5.3
|
||||
certifi==2019.11.28
|
||||
cffi==1.13.2
|
||||
chardet==3.0.4
|
||||
commonmark==0.9.1
|
||||
coverage==5.0.1
|
||||
cryptography==2.8
|
||||
decorator==4.4.1
|
||||
docutils==0.16rc1
|
||||
execnet==1.7.1
|
||||
git+https://github.com/nucypher/py-solc.git@391b8da1a6bac5816877197bda25527c6b0b8c15#egg=py-solc
|
||||
greenlet==0.4.15
|
||||
idna==2.8
|
||||
imagesize==1.1.0
|
||||
importlib-metadata==1.3.0 ; python_version < '3.8'
|
||||
jinja2==2.10.3
|
||||
markupsafe==1.1.1
|
||||
more-itertools==8.0.2
|
||||
mypy-extensions==0.4.3
|
||||
mypy==0.761
|
||||
packaging==19.2
|
||||
pluggy==0.13.1
|
||||
py==1.8.0
|
||||
pycparser==2.19
|
||||
pygments==2.5.2
|
||||
pyparsing==2.4.5
|
||||
pytest-cov==2.8.1
|
||||
pytest-forked==1.1.3
|
||||
pytest-mock==1.13.0
|
||||
pytest-mypy==0.4.2
|
||||
pytest-twisted==1.12
|
||||
pytest-xdist==1.31.0
|
||||
pytest==5.3.2
|
||||
pytz==2019.3
|
||||
pyyaml==5.3b1
|
||||
recommonmark==0.6.0
|
||||
requests==2.22.0
|
||||
six==1.13.0
|
||||
snowballstemmer==2.0.0
|
||||
sphinx-rtd-theme==0.4.3
|
||||
sphinx==2.3.1
|
||||
sphinxcontrib-applehelp==1.0.1
|
||||
sphinxcontrib-devhelp==1.0.1
|
||||
sphinxcontrib-htmlhelp==1.0.2
|
||||
sphinxcontrib-jsmath==1.0.1
|
||||
sphinxcontrib-qthelp==1.0.2
|
||||
sphinxcontrib-serializinghtml==1.1.3
|
||||
typed-ast==1.4.0
|
||||
typing-extensions==3.7.4.1
|
||||
urllib3==1.25.7
|
||||
wcwidth==0.1.7
|
||||
zipp==0.6.0
|
|
@ -1,3 +1,8 @@
|
|||
|
||||
from .bob import specifications as bob
|
||||
from .alice import specifications as alice
|
||||
from .enrico import specifications as enrico
|
||||
|
||||
from abc import ABC
|
||||
from collections import namedtuple
|
||||
|
||||
|
@ -33,6 +38,32 @@ class CharacterSpecification(ABC):
|
|||
k: spec.get(k, ())
|
||||
for k in ['input', 'optional', 'output']})
|
||||
|
||||
@classmethod
|
||||
def get_spec(cls, interface_name: str) -> tuple:
|
||||
if cls._specifications is NotImplemented:
|
||||
raise NotImplementedError("Missing specifications for character")
|
||||
try:
|
||||
spec = cls.specifications()[interface_name]
|
||||
except KeyError:
|
||||
raise cls.SpecificationError(f"{cls.__class__.__name__} has no such control interface: '{interface_name}'")
|
||||
|
||||
return spec
|
||||
|
||||
@classmethod
|
||||
def get_specifications(cls, interface_name: str) -> tuple:
|
||||
spec = cls.get_spec(interface_name)
|
||||
|
||||
if isinstance(spec, dict):
|
||||
return SpecificationTuple(**{
|
||||
k: spec.get(k, ())
|
||||
for k in ['input', 'optional', 'output']})
|
||||
|
||||
return SpecificationTuple(
|
||||
[k for k, f in spec.load_fields.items() if f.required],
|
||||
[k for k, f in spec.load_fields.items() if not f.required],
|
||||
list(spec.dump_fields.keys())
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def specifications(cls):
|
||||
if cls._specifications is NotImplemented:
|
||||
|
@ -65,56 +96,14 @@ class CharacterSpecification(ABC):
|
|||
_, _, output_specification = self.get_specifications(interface_name=interface_name)
|
||||
return self.__validate(specification=output_specification, data=response, error_class=self.InvalidInputField)
|
||||
|
||||
|
||||
class AliceSpecification(CharacterSpecification):
|
||||
|
||||
__create_policy = {'input': ('bob_encrypting_key', 'bob_verifying_key', 'm', 'n', 'label', 'expiration'),
|
||||
'optional': ('value', 'rate'),
|
||||
'output': ('label', 'policy_encrypting_key')}
|
||||
|
||||
__derive_policy_encrypting_key = {'input': ('label', ),
|
||||
'output': ('policy_encrypting_key', 'label')}
|
||||
|
||||
__grant = {'input': ('bob_encrypting_key', 'bob_verifying_key', 'm', 'n', 'label', 'expiration'),
|
||||
'optional': ('value', 'rate'),
|
||||
'output': ('treasure_map', 'policy_encrypting_key', 'alice_verifying_key')}
|
||||
|
||||
__revoke = {'input': ('label', 'bob_verifying_key', ),
|
||||
'output': ('failed_revocations',)}
|
||||
|
||||
__decrypt = {'input': ('label', 'message_kit'),
|
||||
'output': ('cleartexts', )}
|
||||
|
||||
__public_keys = {'input': (),
|
||||
'output': ('alice_verifying_key',)}
|
||||
|
||||
_specifications = {'create_policy': __create_policy, # type: Tuple[Tuple[str]]
|
||||
'derive_policy_encrypting_key': __derive_policy_encrypting_key,
|
||||
'grant': __grant,
|
||||
'revoke': __revoke,
|
||||
'public_keys': __public_keys,
|
||||
'decrypt': __decrypt, }
|
||||
|
||||
_specifications = alice
|
||||
|
||||
class BobSpecification(CharacterSpecification):
|
||||
|
||||
__join_policy = {'input': ('label', 'alice_verifying_key'),
|
||||
'output': ('policy_encrypting_key', )}
|
||||
|
||||
__retrieve = {'input': ('label', 'policy_encrypting_key', 'alice_verifying_key', 'message_kit'),
|
||||
'output': ('cleartexts', )}
|
||||
|
||||
__public_keys = {'input': (),
|
||||
'output': ('bob_encrypting_key', 'bob_verifying_key')}
|
||||
|
||||
_specifications = {'join_policy': __join_policy,
|
||||
'retrieve': __retrieve,
|
||||
'public_keys': __public_keys}
|
||||
|
||||
_specifications = bob
|
||||
|
||||
class EnricoSpecification(CharacterSpecification):
|
||||
|
||||
__encrypt_message = {'input': ('message', ),
|
||||
'output': ('message_kit', 'signature')}
|
||||
|
||||
_specifications = {'encrypt_message': __encrypt_message}
|
||||
_specifications = enrico
|
|
@ -0,0 +1,68 @@
|
|||
from marshmallow import Schema
|
||||
from .fields import fields
|
||||
|
||||
|
||||
class PolicyBaseSchema(Schema):
|
||||
|
||||
#required input fields
|
||||
bob_encrypting_key = fields.Key(required=True, load_only=True)
|
||||
bob_verifying_key = fields.Key(required=True, load_only=True)
|
||||
m = fields.Integer(required=True, load_only=True)
|
||||
n = fields.Integer(required=True, load_only=True)
|
||||
expiration = fields.Date(required=True, load_only=True)
|
||||
|
||||
# optional input
|
||||
value = fields.Integer(load_only=True)
|
||||
first_period_reward = fields.Integer(load_only=True)
|
||||
rate = fields.Integer(load_only=True)
|
||||
|
||||
#output
|
||||
policy_encrypting_key = fields.Key(dump_only=True)
|
||||
|
||||
|
||||
class CreatePolicy(PolicyBaseSchema):
|
||||
|
||||
label = fields.Str(required=True)
|
||||
|
||||
|
||||
class GrantPolicy(PolicyBaseSchema):
|
||||
|
||||
treasure_map = fields.TreasureMap(dump_only=True)
|
||||
alice_verifying_key = fields.Key(dump_only=True)
|
||||
label = fields.Str(load_only=True, required=True)
|
||||
|
||||
|
||||
class DerivePolicyEncryptionKey(Schema):
|
||||
|
||||
label = fields.Str(required=True)
|
||||
policy_encrypting_key = fields.Key(dump_only=True)
|
||||
|
||||
|
||||
class Revoke(Schema):
|
||||
|
||||
label = fields.Str(required=True, load_only=True)
|
||||
bob_verifying_key = fields.Key(required=True, load_only=True)
|
||||
|
||||
failed_revocations = fields.List(fields.Str(), dump_only=True)
|
||||
|
||||
|
||||
class Decrypt(Schema):
|
||||
label = fields.Str(required=True, load_only=True)
|
||||
message_kit = fields.MessageKit(load_only=True)
|
||||
|
||||
cleartexts = fields.List(fields.Str(), dump_only=True)
|
||||
|
||||
|
||||
class PublicKeys(Schema):
|
||||
|
||||
alice_verifying_key = fields.Key(dump_only=True)
|
||||
|
||||
|
||||
specifications = {
|
||||
'create_policy': CreatePolicy(),
|
||||
'derive_policy_encrypting_key': DerivePolicyEncryptionKey(),
|
||||
'grant': GrantPolicy(),
|
||||
'revoke': Revoke(),
|
||||
'public_keys': PublicKeys(),
|
||||
'decrypt': Decrypt(),
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
__join_policy = {'input': ('label', 'alice_verifying_key'),
|
||||
'output': ('policy_encrypting_key', )}
|
||||
|
||||
__retrieve = {'input': ('label', 'policy_encrypting_key', 'alice_verifying_key', 'message_kit'),
|
||||
'output': ('cleartexts', )}
|
||||
|
||||
__public_keys = {'input': (),
|
||||
'output': ('bob_encrypting_key', 'bob_verifying_key')}
|
||||
|
||||
specifications = {'join_policy': __join_policy,
|
||||
'retrieve': __retrieve,
|
||||
'public_keys': __public_keys}
|
|
@ -0,0 +1,5 @@
|
|||
|
||||
__encrypt_message = {'input': ('message', ),
|
||||
'output': ('message_kit', 'signature')}
|
||||
|
||||
specifications = {'encrypt_message': __encrypt_message}
|
|
@ -0,0 +1,7 @@
|
|||
from marshmallow import fields
|
||||
from .key import *
|
||||
from .treasuremap import *
|
||||
from .messagekit import *
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
from marshmallow import fields
|
||||
|
||||
class KeyField(fields.Field):
|
||||
|
||||
def _serialize(self, value, attr, obj, **kwargs):
|
||||
|
||||
return value
|
||||
|
||||
def _deserialize(self, value, attr, data, **kwargs):
|
||||
return value
|
||||
|
||||
fields.Key = KeyField
|
|
@ -0,0 +1,12 @@
|
|||
from marshmallow import fields
|
||||
|
||||
class MessageKitField(fields.Field):
|
||||
|
||||
def _serialize(self, value, attr, obj, **kwargs):
|
||||
|
||||
return value
|
||||
|
||||
def _deserialize(self, value, attr, data, **kwargs):
|
||||
return value
|
||||
|
||||
fields.MessageKit = MessageKitField
|
|
@ -0,0 +1,12 @@
|
|||
from marshmallow import fields
|
||||
|
||||
class TreasureMapField(fields.Field):
|
||||
|
||||
def _serialize(self, value, attr, obj, **kwargs):
|
||||
|
||||
return value
|
||||
|
||||
def _deserialize(self, value, attr, data, **kwargs):
|
||||
return value
|
||||
|
||||
fields.TreasureMap = TreasureMapField
|
102
requirements.txt
102
requirements.txt
|
@ -1,102 +0,0 @@
|
|||
-i https://pypi.python.org/simple
|
||||
appdirs==1.4.3
|
||||
argh==0.26.2
|
||||
asn1crypto==1.2.0
|
||||
attrdict==2.0.1
|
||||
attrs==19.3.0
|
||||
autobahn==19.11.1
|
||||
automat==0.8.0
|
||||
base58==1.0.3
|
||||
blake2b-py==0.1.3
|
||||
bytestring-splitter==1.3.0
|
||||
cached-property==1.5.1
|
||||
certifi==2019.11.28
|
||||
cffi==1.13.2
|
||||
chardet==3.0.4
|
||||
click==7.0
|
||||
coincurve==13.0.0
|
||||
colorama==0.4.3
|
||||
constant-sorrow==0.1.0a8
|
||||
constantly==15.1.0
|
||||
cryptography==2.8
|
||||
cytoolz==0.10.1 ; implementation_name == 'cpython'
|
||||
dateparser==0.7.2
|
||||
eth-abi==2.1.0
|
||||
eth-account==0.4.0
|
||||
eth-bloom==1.0.3
|
||||
eth-hash[pycryptodome]==0.2.0
|
||||
eth-keyfile==0.5.1
|
||||
eth-keys==0.2.4
|
||||
eth-rlp==0.1.2
|
||||
eth-tester==0.4.0b1
|
||||
eth-typing==2.2.1
|
||||
eth-utils==1.8.4
|
||||
flask-limiter==1.1.0
|
||||
flask-sqlalchemy==2.4.1
|
||||
flask==1.1.1
|
||||
hendrix==3.2.5
|
||||
hexbytes==0.2.0
|
||||
humanize==0.5.1
|
||||
hyperlink==19.0.0
|
||||
idna==2.8
|
||||
importlib-metadata==1.3.0 ; python_version < '3.8'
|
||||
incremental==17.5.0
|
||||
ipfshttpclient==0.4.12
|
||||
itsdangerous==1.1.0
|
||||
jinja2==2.10.3
|
||||
jsonschema==3.2.0
|
||||
limits==1.4.1
|
||||
lru-dict==1.1.6
|
||||
markupsafe==1.1.1
|
||||
maya==0.6.1
|
||||
more-itertools==8.0.2
|
||||
msgpack-python==0.5.6
|
||||
multiaddr==0.0.9
|
||||
mypy-extensions==0.4.3
|
||||
netaddr==0.7.19
|
||||
parsimonious==0.8.1
|
||||
pathtools==0.1.2
|
||||
pendulum==2.0.5
|
||||
protobuf==3.11.2
|
||||
py-ecc==1.7.1
|
||||
py-evm==0.3.0a12
|
||||
py-geth==2.2.0
|
||||
pyasn1-modules==0.2.7
|
||||
pyasn1==0.4.8
|
||||
pychalk==2.0.1
|
||||
pycparser==2.19
|
||||
pycryptodome==3.9.4
|
||||
pyethash==0.1.27
|
||||
pyhamcrest==1.9.0
|
||||
pynacl==1.3.0
|
||||
pyopenssl==19.1.0
|
||||
pyrsistent==0.15.6
|
||||
pysha3==1.0.2
|
||||
python-dateutil==2.8.1
|
||||
pytz==2019.3
|
||||
pytzdata==2019.3
|
||||
pyyaml==5.3b1
|
||||
regex==2019.12.20
|
||||
requests==2.22.0
|
||||
rlp==1.2.0
|
||||
semantic-version==2.8.4
|
||||
sentry-sdk==0.9.0
|
||||
service-identity==18.1.0
|
||||
six==1.13.0
|
||||
snaptime==0.2.4
|
||||
sqlalchemy==1.3.12
|
||||
toolz==0.10.0
|
||||
trie==1.4.0
|
||||
twisted==19.10.0
|
||||
txaio==18.8.1
|
||||
typing-extensions==3.7.4.1
|
||||
tzlocal==2.0.0
|
||||
umbral==0.1.3a2
|
||||
urllib3==1.25.7
|
||||
varint==1.0.2
|
||||
watchdog==0.9.0
|
||||
web3==5.4.0
|
||||
websockets==8.1
|
||||
werkzeug==0.16.0
|
||||
zipp==0.6.0
|
||||
zope.interface==4.7.1
|
|
@ -0,0 +1,13 @@
|
|||
import pytest
|
||||
from marshmallow.exceptions import ValidationError
|
||||
from nucypher.characters.control.specifications import AliceSpecification
|
||||
|
||||
|
||||
def test_alice_spec_validate(federated_alice, federated_bob):
|
||||
|
||||
createPolicy = AliceSpecification.get_spec('create_policy')
|
||||
specs = AliceSpecification.get_specifications('create_policy')
|
||||
|
||||
with pytest.raises(ValidationError) as e:
|
||||
result = createPolicy.load({})
|
||||
|
Loading…
Reference in New Issue