Skip to content

Commit 31f8c66

Browse files
authored
Add type definitions and annotations (#4)
I'm not sure if this is the best way to define the types (should they inherit from the types in nacl.signing?) but the main objective is to define stable names which can be referenced in applications.
1 parent cafafc0 commit 31f8c66

5 files changed

Lines changed: 106 additions & 17 deletions

File tree

setup.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ def exec_file(path_segments, name):
4848
"canonicaljson>=1.0.0",
4949
"unpaddedbase64>=1.0.1",
5050
"pynacl>=0.3.0",
51+
"typing_extensions>=3.5",
52+
'typing>=3.5;python_version<"3.5"',
5153
],
5254
long_description=read_file(("README.rst",)),
5355
keywords="json",

signedjson/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
__version__ = "1.0.0"
15+
__version__ = "1.1-dev1"

signedjson/key.py

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,36 @@
1-
from unpaddedbase64 import encode_base64, decode_base64
1+
# -*- coding: utf-8 -*-
2+
3+
# Copyright 2014 OpenMarket Ltd
4+
# Copyright 2020 The Matrix.org Foundation C.I.C
5+
#
6+
# Licensed under the Apache License, Version 2.0 (the "License");
7+
# you may not use this file except in compliance with the License.
8+
# You may obtain a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing, software
13+
# distributed under the License is distributed on an "AS IS" BASIS,
14+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
# See the License for the specific language governing permissions and
16+
# limitations under the License.
17+
18+
from typing import Iterable, List, TextIO
19+
220
import nacl.signing
21+
from unpaddedbase64 import decode_base64, encode_base64
22+
23+
from signedjson.types import SigningKey, VerifyKey
324

425
NACL_ED25519 = "ed25519"
526
SUPPORTED_ALGORITHMS = [NACL_ED25519]
627

728

829
def generate_signing_key(version):
30+
# type: (str) -> SigningKey
931
"""Generate a new signing key
1032
Args:
11-
version (str): Identifies this key out the keys for this entity.
33+
version: Identifies this key out the keys for this entity.
1234
Returns:
1335
A SigningKey object.
1436
"""
@@ -19,6 +41,7 @@ def generate_signing_key(version):
1941

2042

2143
def get_verify_key(signing_key):
44+
# type: (SigningKey) -> VerifyKey
2245
"""Get a verify key from a signing key"""
2346
verify_key = signing_key.verify_key
2447
verify_key.version = signing_key.version
@@ -27,11 +50,12 @@ def get_verify_key(signing_key):
2750

2851

2952
def decode_signing_key_base64(algorithm, version, key_base64):
53+
# type: (str, str, bytes) -> SigningKey
3054
"""Decode a base64 encoded signing key
3155
Args:
32-
algorithm (str): The algorithm the key is for (currently "ed25519").
33-
version (str): Identifies this key out of the keys for this entity.
34-
key_base64 (str): Base64 encoded bytes of the key.
56+
algorithm: The algorithm the key is for (currently "ed25519").
57+
version: Identifies this key out of the keys for this entity.
58+
key_base64: Base64 encoded bytes of the key.
3559
Returns:
3660
A SigningKey object.
3761
"""
@@ -46,26 +70,29 @@ def decode_signing_key_base64(algorithm, version, key_base64):
4670

4771

4872
def encode_signing_key_base64(key):
73+
# type: (SigningKey) -> str
4974
"""Encode a signing key as base64
5075
Args:
51-
key (SigningKey): A signing key to encode.
76+
key: A signing key to encode.
5277
Returns:
5378
base64 encoded string.
5479
"""
5580
return encode_base64(key.encode())
5681

5782

5883
def encode_verify_key_base64(key):
84+
# type: (VerifyKey) -> str
5985
"""Encode a verify key as base64
6086
Args:
61-
key (VerifyKey): A signing key to encode.
87+
key: A signing key to encode.
6288
Returns:
6389
base64 encoded string.
6490
"""
6591
return encode_base64(key.encode())
6692

6793

6894
def is_signing_algorithm_supported(key_id):
95+
# type: (str) -> bool
6996
"""Is the signing algorithm for this key_id supported"""
7097
if key_id.startswith(NACL_ED25519 + ":"):
7198
return True
@@ -74,10 +101,11 @@ def is_signing_algorithm_supported(key_id):
74101

75102

76103
def decode_verify_key_bytes(key_id, key_bytes):
104+
# type: (str, bytes) -> VerifyKey
77105
"""Decode a raw verify key
78106
Args:
79-
key_id (str): Identifies this key out of the keys for this entity.
80-
key_bytes (str): Raw bytes of the key.
107+
key_id: Identifies this key out of the keys for this entity.
108+
key_bytes: Raw bytes of the key.
81109
Returns:
82110
A VerifyKey object.
83111
"""
@@ -92,6 +120,7 @@ def decode_verify_key_bytes(key_id, key_bytes):
92120

93121

94122
def read_signing_keys(stream):
123+
# type: (Iterable[str]) -> List[SigningKey]
95124
"""Reads a list of keys from a stream
96125
Args:
97126
stream : A stream to iterate for keys.
@@ -107,6 +136,7 @@ def read_signing_keys(stream):
107136

108137

109138
def read_old_signing_keys(stream):
139+
# type: (Iterable[str]) -> List[VerifyKey]
110140
"""Reads a list of old keys from a stream
111141
Args:
112142
stream : A stream to iterate for keys.
@@ -124,6 +154,7 @@ def read_old_signing_keys(stream):
124154

125155

126156
def write_signing_keys(stream, keys):
157+
# type: (TextIO, Iterable[SigningKey]) -> None
127158
"""Writes a list of keys to a stream.
128159
Args:
129160
stream: Stream to write keys to.

signedjson/sign.py

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# -*- coding: utf-8 -*-
22

33
# Copyright 2014 OpenMarket Ltd
4+
# Copyright 2020 The Matrix.org Foundation C.I.C
45
#
56
# Licensed under the Apache License, Version 2.0 (the "License");
67
# you may not use this file except in compliance with the License.
@@ -14,16 +15,23 @@
1415
# See the License for the specific language governing permissions and
1516
# limitations under the License.
1617

17-
from canonicaljson import encode_canonical_json
18-
from unpaddedbase64 import encode_base64, decode_base64
19-
from signedjson.key import SUPPORTED_ALGORITHMS
2018

2119
import logging
20+
from typing import Any, Dict, Iterable, List
21+
22+
from canonicaljson import encode_canonical_json
23+
from unpaddedbase64 import decode_base64, encode_base64
24+
25+
from signedjson.key import SUPPORTED_ALGORITHMS
26+
from signedjson.types import SigningKey, VerifyKey
2227

2328
logger = logging.getLogger(__name__)
2429

30+
JsonDict = Dict[str, Any]
31+
2532

2633
def sign_json(json_object, signature_name, signing_key):
34+
# type: (JsonDict, str, SigningKey) -> JsonDict
2735
"""Sign the JSON object. Stores the signature in json_object["signatures"].
2836
2937
Args:
@@ -55,6 +63,7 @@ def sign_json(json_object, signature_name, signing_key):
5563

5664
def signature_ids(json_object, signature_name,
5765
supported_algorithms=SUPPORTED_ALGORITHMS):
66+
# type: (JsonDict, str, Iterable[str]) -> List[str]
5867
"""Does the JSON object have a signature for the given name?
5968
Args:
6069
json_object (dict): The JSON object to check.
@@ -77,15 +86,16 @@ class SignatureVerifyException(Exception):
7786

7887

7988
def verify_signed_json(json_object, signature_name, verify_key):
89+
# type: (JsonDict, str, VerifyKey) -> None
8090
"""Check a signature on a signed JSON object.
8191
8292
Args:
83-
json_object (dict): The signed JSON object to check.
84-
signature_name (str): The name of the signature to check.
85-
verify_key (syutil.crypto.VerifyKey): The key to verify the signature.
93+
json_object: The signed JSON object to check.
94+
signature_name: The name of the signature to check.
95+
verify_key: The key to verify the signature.
8696
8797
Raises:
88-
InvalidSignature: If the signature isn't valid
98+
SignatureVerifyException: If the signature isn't valid
8999
"""
90100

91101
try:

signedjson/types.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# -*- coding: utf-8 -*-
2+
# Copyright 2020 The Matrix.org Foundation C.I.C.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
import nacl.signing
17+
from typing_extensions import Protocol
18+
19+
20+
class BaseKey(Protocol):
21+
"""Common base type for VerifyKey and SigningKey"""
22+
version = "" # type: str
23+
alg = "" # type: str
24+
25+
def encode(self):
26+
# type: () -> bytes
27+
pass # pragma: nocover
28+
29+
30+
class VerifyKey(BaseKey):
31+
"""The public part of a key pair, for use with verify_signed_json"""
32+
def verify(self, message, signature):
33+
# type: (bytes, bytes) -> bytes
34+
pass # pragma: nocover
35+
36+
37+
class SigningKey(BaseKey):
38+
"""The private part of a key pair, for use with sign_json"""
39+
def sign(self, message):
40+
# type: (bytes) -> nacl.signing.SignedMessage
41+
pass # pragma: nocover
42+
43+
@property
44+
def verify_key(self):
45+
# type: () -> nacl.signing.VerifyKey
46+
pass # pragma: nocover

0 commit comments

Comments
 (0)