koi-net 1.1.0b5__py3-none-any.whl → 1.1.0b7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of koi-net might be problematic. Click here for more details.
- koi_net/network/error_handler.py +6 -6
- koi_net/network/graph.py +1 -1
- koi_net/network/request_handler.py +1 -1
- koi_net/protocol/api_models.py +13 -4
- koi_net/protocol/edge.py +4 -1
- koi_net/protocol/envelope.py +10 -6
- koi_net/protocol/errors.py +6 -6
- koi_net/protocol/event.py +0 -3
- koi_net/protocol/secure.py +70 -16
- koi_net/server.py +2 -1
- {koi_net-1.1.0b5.dist-info → koi_net-1.1.0b7.dist-info}/METADATA +1 -1
- {koi_net-1.1.0b5.dist-info → koi_net-1.1.0b7.dist-info}/RECORD +14 -14
- {koi_net-1.1.0b5.dist-info → koi_net-1.1.0b7.dist-info}/WHEEL +0 -0
- {koi_net-1.1.0b5.dist-info → koi_net-1.1.0b7.dist-info}/licenses/LICENSE +0 -0
koi_net/network/error_handler.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from logging import getLogger
|
|
2
|
-
from koi_net.protocol.errors import
|
|
2
|
+
from koi_net.protocol.errors import ErrorType
|
|
3
3
|
from koi_net.protocol.event import EventType
|
|
4
4
|
from rid_lib.types import KoiNetNode
|
|
5
5
|
from ..processor.interface import ProcessorInterface
|
|
@@ -36,15 +36,15 @@ class ErrorHandler:
|
|
|
36
36
|
|
|
37
37
|
def handle_protocol_error(
|
|
38
38
|
self,
|
|
39
|
-
error_type:
|
|
39
|
+
error_type: ErrorType,
|
|
40
40
|
node: KoiNetNode
|
|
41
41
|
):
|
|
42
42
|
logger.info(f"Handling protocol error {error_type} for node {node!r}")
|
|
43
43
|
match error_type:
|
|
44
|
-
case
|
|
44
|
+
case ErrorType.UnknownNode:
|
|
45
45
|
logger.info("Peer doesn't know me, attempting handshake...")
|
|
46
46
|
self.actor.handshake_with(node)
|
|
47
47
|
|
|
48
|
-
case
|
|
49
|
-
case
|
|
50
|
-
case
|
|
48
|
+
case ErrorType.InvalidKey: ...
|
|
49
|
+
case ErrorType.InvalidSignature: ...
|
|
50
|
+
case ErrorType.InvalidTarget: ...
|
koi_net/network/graph.py
CHANGED
|
@@ -41,7 +41,7 @@ class NetworkGraph:
|
|
|
41
41
|
logger.debug(f"Added edge {rid!r} ({edge_profile.source} -> {edge_profile.target})")
|
|
42
42
|
logger.debug("Done")
|
|
43
43
|
|
|
44
|
-
def get_edge(self, source: KoiNetNode, target: KoiNetNode,) ->
|
|
44
|
+
def get_edge(self, source: KoiNetNode, target: KoiNetNode,) -> KoiNetEdge | None:
|
|
45
45
|
"""Returns edge RID given the RIDs of a source and target node."""
|
|
46
46
|
if (source, target) in self.dg.edges:
|
|
47
47
|
edge_data = self.dg.get_edge_data(source, target)
|
|
@@ -119,7 +119,7 @@ class RequestHandler:
|
|
|
119
119
|
)
|
|
120
120
|
|
|
121
121
|
try:
|
|
122
|
-
result = httpx.post(url, data=signed_envelope.model_dump_json())
|
|
122
|
+
result = httpx.post(url, data=signed_envelope.model_dump_json(exclude_none=True))
|
|
123
123
|
except httpx.ConnectError as err:
|
|
124
124
|
logger.debug("Failed to connect")
|
|
125
125
|
self.error_handler.handle_connection_error(node)
|
koi_net/protocol/api_models.py
CHANGED
|
@@ -1,51 +1,60 @@
|
|
|
1
1
|
"""Pydantic models for request and response/payload objects in the KOI-net API."""
|
|
2
2
|
|
|
3
|
-
from
|
|
3
|
+
from typing import Literal
|
|
4
|
+
from pydantic import BaseModel, Field
|
|
4
5
|
from rid_lib import RID, RIDType
|
|
5
6
|
from rid_lib.ext import Bundle, Manifest
|
|
6
7
|
from .event import Event
|
|
7
|
-
from .errors import
|
|
8
|
+
from .errors import ErrorType
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
# REQUEST MODELS
|
|
11
12
|
|
|
12
13
|
class PollEvents(BaseModel):
|
|
13
|
-
|
|
14
|
+
type: Literal["poll_events"] = Field("poll_events")
|
|
14
15
|
limit: int = 0
|
|
15
16
|
|
|
16
17
|
class FetchRids(BaseModel):
|
|
18
|
+
type: Literal["fetch_rids"] = Field("fetch_rids")
|
|
17
19
|
rid_types: list[RIDType] = []
|
|
18
20
|
|
|
19
21
|
class FetchManifests(BaseModel):
|
|
22
|
+
type: Literal["fetch_manifests"] = Field("fetch_manifests")
|
|
20
23
|
rid_types: list[RIDType] = []
|
|
21
24
|
rids: list[RID] = []
|
|
22
25
|
|
|
23
26
|
class FetchBundles(BaseModel):
|
|
27
|
+
type: Literal["fetch_bundles"] = Field("fetch_bundles")
|
|
24
28
|
rids: list[RID]
|
|
25
29
|
|
|
26
30
|
|
|
27
31
|
# RESPONSE/PAYLOAD MODELS
|
|
28
32
|
|
|
29
33
|
class RidsPayload(BaseModel):
|
|
34
|
+
type: Literal["rids_payload"] = Field("rids_payload")
|
|
30
35
|
rids: list[RID]
|
|
31
36
|
|
|
32
37
|
class ManifestsPayload(BaseModel):
|
|
38
|
+
type: Literal["manifests_payload"] = Field("manifests_payload")
|
|
33
39
|
manifests: list[Manifest]
|
|
34
40
|
not_found: list[RID] = []
|
|
35
41
|
|
|
36
42
|
class BundlesPayload(BaseModel):
|
|
43
|
+
type: Literal["bundles_payload"] = Field("bundles_payload")
|
|
37
44
|
bundles: list[Bundle]
|
|
38
45
|
not_found: list[RID] = []
|
|
39
46
|
deferred: list[RID] = []
|
|
40
47
|
|
|
41
48
|
class EventsPayload(BaseModel):
|
|
49
|
+
type: Literal["events_payload"] = Field("events_payload")
|
|
42
50
|
events: list[Event]
|
|
43
51
|
|
|
44
52
|
|
|
45
53
|
# ERROR MODELS
|
|
46
54
|
|
|
47
55
|
class ErrorResponse(BaseModel):
|
|
48
|
-
|
|
56
|
+
type: Literal["error_response"] = Field("error_response")
|
|
57
|
+
error: ErrorType
|
|
49
58
|
|
|
50
59
|
# TYPES
|
|
51
60
|
|
koi_net/protocol/edge.py
CHANGED
|
@@ -2,6 +2,7 @@ from enum import StrEnum
|
|
|
2
2
|
from pydantic import BaseModel
|
|
3
3
|
from rid_lib import RIDType
|
|
4
4
|
from rid_lib.ext.bundle import Bundle
|
|
5
|
+
from rid_lib.ext.utils import sha256_hash
|
|
5
6
|
from rid_lib.types import KoiNetEdge, KoiNetNode
|
|
6
7
|
|
|
7
8
|
|
|
@@ -27,7 +28,9 @@ def generate_edge_bundle(
|
|
|
27
28
|
rid_types: list[RIDType],
|
|
28
29
|
edge_type: EdgeType
|
|
29
30
|
) -> Bundle:
|
|
30
|
-
edge_rid = KoiNetEdge
|
|
31
|
+
edge_rid = KoiNetEdge(sha256_hash(
|
|
32
|
+
str(source) + str(target)
|
|
33
|
+
))
|
|
31
34
|
edge_profile = EdgeProfile(
|
|
32
35
|
source=source,
|
|
33
36
|
target=target,
|
koi_net/protocol/envelope.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
from typing import Generic, TypeVar
|
|
3
|
-
from pydantic import BaseModel
|
|
3
|
+
from pydantic import BaseModel, ConfigDict
|
|
4
4
|
from rid_lib.types import KoiNetNode
|
|
5
5
|
|
|
6
6
|
from .secure import PrivateKey, PublicKey
|
|
@@ -13,6 +13,8 @@ logger = logging.getLogger(__name__)
|
|
|
13
13
|
T = TypeVar("T", bound=RequestModels | ResponseModels)
|
|
14
14
|
|
|
15
15
|
class SignedEnvelope(BaseModel, Generic[T]):
|
|
16
|
+
model_config = ConfigDict(exclude_none=True)
|
|
17
|
+
|
|
16
18
|
payload: T
|
|
17
19
|
source_node: KoiNetNode
|
|
18
20
|
target_node: KoiNetNode
|
|
@@ -26,24 +28,26 @@ class SignedEnvelope(BaseModel, Generic[T]):
|
|
|
26
28
|
target_node=self.target_node
|
|
27
29
|
)
|
|
28
30
|
|
|
29
|
-
logger.debug(f"Verifying envelope: {unsigned_envelope.model_dump_json()}")
|
|
30
|
-
|
|
31
|
+
logger.debug(f"Verifying envelope: {unsigned_envelope.model_dump_json(exclude_none=True)}")
|
|
32
|
+
|
|
31
33
|
pub_key.verify(
|
|
32
34
|
self.signature,
|
|
33
|
-
unsigned_envelope.model_dump_json().encode()
|
|
35
|
+
unsigned_envelope.model_dump_json(exclude_none=True).encode()
|
|
34
36
|
)
|
|
35
37
|
|
|
36
38
|
class UnsignedEnvelope(BaseModel, Generic[T]):
|
|
39
|
+
model_config = ConfigDict(exclude_none=True)
|
|
40
|
+
|
|
37
41
|
payload: T
|
|
38
42
|
source_node: KoiNetNode
|
|
39
43
|
target_node: KoiNetNode
|
|
40
44
|
|
|
41
45
|
def sign_with(self, priv_key: PrivateKey) -> SignedEnvelope[T]:
|
|
42
|
-
logger.debug(f"Signing envelope: {self.model_dump_json()}")
|
|
46
|
+
logger.debug(f"Signing envelope: {self.model_dump_json(exclude_none=True)}")
|
|
43
47
|
logger.debug(f"Type: [{type(self.payload)}]")
|
|
44
48
|
|
|
45
49
|
signature = priv_key.sign(
|
|
46
|
-
self.model_dump_json().encode()
|
|
50
|
+
self.model_dump_json(exclude_none=True).encode()
|
|
47
51
|
)
|
|
48
52
|
|
|
49
53
|
return SignedEnvelope(
|
koi_net/protocol/errors.py
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
from enum import StrEnum
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
class
|
|
4
|
+
class ErrorType(StrEnum):
|
|
5
5
|
UnknownNode = "unknown_node"
|
|
6
6
|
InvalidKey = "invalid_key"
|
|
7
7
|
InvalidSignature = "invalid_signature"
|
|
8
8
|
InvalidTarget = "invalid_target"
|
|
9
9
|
|
|
10
10
|
class ProtocolError(Exception):
|
|
11
|
-
error_type:
|
|
11
|
+
error_type: ErrorType
|
|
12
12
|
|
|
13
13
|
class UnknownNodeError(ProtocolError):
|
|
14
|
-
error_type =
|
|
14
|
+
error_type = ErrorType.UnknownNode
|
|
15
15
|
|
|
16
16
|
class InvalidKeyError(ProtocolError):
|
|
17
|
-
error_type =
|
|
17
|
+
error_type = ErrorType.InvalidKey
|
|
18
18
|
|
|
19
19
|
class InvalidSignatureError(ProtocolError):
|
|
20
|
-
error_type =
|
|
20
|
+
error_type = ErrorType.InvalidSignature
|
|
21
21
|
|
|
22
22
|
class InvalidTargetError(ProtocolError):
|
|
23
|
-
error_type =
|
|
23
|
+
error_type = ErrorType.InvalidTarget
|
koi_net/protocol/event.py
CHANGED
koi_net/protocol/secure.py
CHANGED
|
@@ -1,22 +1,64 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
from base64 import
|
|
2
|
+
from base64 import b64decode, b64encode
|
|
3
3
|
from cryptography.hazmat.primitives import hashes
|
|
4
4
|
from cryptography.hazmat.primitives.asymmetric import ec
|
|
5
5
|
from cryptography.hazmat.primitives import serialization
|
|
6
6
|
from rid_lib.ext.utils import sha256_hash
|
|
7
|
+
from cryptography.hazmat.primitives.asymmetric.utils import (
|
|
8
|
+
decode_dss_signature,
|
|
9
|
+
encode_dss_signature
|
|
10
|
+
)
|
|
7
11
|
|
|
8
12
|
logger = logging.getLogger(__name__)
|
|
9
13
|
|
|
10
14
|
|
|
15
|
+
def der_to_raw_signature(der_signature: bytes, curve=ec.SECP256R1()) -> bytes:
|
|
16
|
+
"""Convert a DER-encoded signature to raw r||s format."""
|
|
17
|
+
|
|
18
|
+
# Decode the DER signature to get r and s
|
|
19
|
+
r, s = decode_dss_signature(der_signature)
|
|
20
|
+
|
|
21
|
+
# Determine byte length based on curve bit size
|
|
22
|
+
byte_length = (curve.key_size + 7) // 8
|
|
23
|
+
|
|
24
|
+
# Convert r and s to big-endian byte arrays of fixed length
|
|
25
|
+
r_bytes = r.to_bytes(byte_length, byteorder='big')
|
|
26
|
+
s_bytes = s.to_bytes(byte_length, byteorder='big')
|
|
27
|
+
|
|
28
|
+
# Concatenate r and s
|
|
29
|
+
return r_bytes + s_bytes
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def raw_to_der_signature(raw_signature: bytes, curve=ec.SECP256R1()) -> bytes:
|
|
33
|
+
"""Convert a raw r||s signature to DER format."""
|
|
34
|
+
|
|
35
|
+
# Determine byte length based on curve bit size
|
|
36
|
+
byte_length = (curve.key_size + 7) // 8
|
|
37
|
+
|
|
38
|
+
# Split the raw signature into r and s components
|
|
39
|
+
if len(raw_signature) != 2 * byte_length:
|
|
40
|
+
raise ValueError(f"Raw signature must be {2 * byte_length} bytes for {curve.name}")
|
|
41
|
+
|
|
42
|
+
r_bytes = raw_signature[:byte_length]
|
|
43
|
+
s_bytes = raw_signature[byte_length:]
|
|
44
|
+
|
|
45
|
+
# Convert bytes to integers
|
|
46
|
+
r = int.from_bytes(r_bytes, byteorder='big')
|
|
47
|
+
s = int.from_bytes(s_bytes, byteorder='big')
|
|
48
|
+
|
|
49
|
+
# Encode as DER
|
|
50
|
+
return encode_dss_signature(r, s)
|
|
51
|
+
|
|
52
|
+
|
|
11
53
|
class PrivateKey:
|
|
12
54
|
priv_key: ec.EllipticCurvePrivateKey
|
|
13
55
|
|
|
14
56
|
def __init__(self, priv_key):
|
|
15
57
|
self.priv_key = priv_key
|
|
16
|
-
|
|
58
|
+
|
|
17
59
|
@classmethod
|
|
18
60
|
def generate(cls):
|
|
19
|
-
return cls(priv_key=ec.generate_private_key(ec.
|
|
61
|
+
return cls(priv_key=ec.generate_private_key(ec.SECP256R1()))
|
|
20
62
|
|
|
21
63
|
def public_key(self) -> "PublicKey":
|
|
22
64
|
return PublicKey(self.priv_key.public_key())
|
|
@@ -40,12 +82,14 @@ class PrivateKey:
|
|
|
40
82
|
def sign(self, message: bytes) -> str:
|
|
41
83
|
hashed_message = sha256_hash(message.decode())
|
|
42
84
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
85
|
+
der_signature_bytes = self.priv_key.sign(
|
|
86
|
+
data=message,
|
|
87
|
+
signature_algorithm=ec.ECDSA(hashes.SHA256())
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
raw_signature_bytes = der_to_raw_signature(der_signature_bytes)
|
|
91
|
+
|
|
92
|
+
signature = b64encode(raw_signature_bytes).decode()
|
|
49
93
|
|
|
50
94
|
logger.debug(f"Signing message with [{self.public_key().to_der()}]")
|
|
51
95
|
logger.debug(f"hash: {hashed_message}")
|
|
@@ -78,29 +122,39 @@ class PublicKey:
|
|
|
78
122
|
def from_der(cls, pub_key_der: str):
|
|
79
123
|
return cls(
|
|
80
124
|
pub_key=serialization.load_der_public_key(
|
|
81
|
-
data=
|
|
125
|
+
data=b64decode(pub_key_der)
|
|
82
126
|
)
|
|
83
127
|
)
|
|
84
128
|
|
|
85
129
|
def to_der(self) -> str:
|
|
86
|
-
return
|
|
130
|
+
return b64encode(
|
|
87
131
|
self.pub_key.public_bytes(
|
|
88
132
|
encoding=serialization.Encoding.DER,
|
|
89
133
|
format=serialization.PublicFormat.SubjectPublicKeyInfo
|
|
90
134
|
)
|
|
91
135
|
).decode()
|
|
92
136
|
|
|
137
|
+
|
|
93
138
|
def verify(self, signature: str, message: bytes) -> bool:
|
|
94
|
-
hashed_message = sha256_hash(message.decode())
|
|
139
|
+
# hashed_message = sha256_hash(message.decode())
|
|
140
|
+
|
|
141
|
+
# print(message.hex())
|
|
142
|
+
# print()
|
|
143
|
+
# print(hashed_message)
|
|
144
|
+
# print()
|
|
145
|
+
# print(message.decode())
|
|
95
146
|
|
|
96
|
-
logger.debug(f"Verifying message with [{self.to_der()}]")
|
|
97
|
-
logger.debug(f"hash: {hashed_message}")
|
|
98
|
-
logger.debug(f"signature: {signature}")
|
|
147
|
+
# logger.debug(f"Verifying message with [{self.to_der()}]")
|
|
148
|
+
# logger.debug(f"hash: {hashed_message}")
|
|
149
|
+
# logger.debug(f"signature: {signature}")
|
|
150
|
+
|
|
151
|
+
raw_signature_bytes = b64decode(signature)
|
|
152
|
+
der_signature_bytes = raw_to_der_signature(raw_signature_bytes)
|
|
99
153
|
|
|
100
154
|
# NOTE: throws cryptography.exceptions.InvalidSignature on failure
|
|
101
155
|
|
|
102
156
|
self.pub_key.verify(
|
|
103
|
-
signature=
|
|
157
|
+
signature=der_signature_bytes,
|
|
104
158
|
data=message,
|
|
105
159
|
signature_algorithm=ec.ECDSA(hashes.SHA256())
|
|
106
160
|
)
|
koi_net/server.py
CHANGED
|
@@ -8,13 +8,13 @@ koi_net/identity.py,sha256=FvIWksGTqwM7HCevIwmo_6l-t-2tnYkaaR4CanZatL4,569
|
|
|
8
8
|
koi_net/lifecycle.py,sha256=GL2zltmh-aeBuNVg_rbIgsXMch672w7xkWAXCTjxst4,3550
|
|
9
9
|
koi_net/poller.py,sha256=bIrlqdac5vLQYAid35xiQJLDMR85GnOSPCXSTQ07-Mc,1173
|
|
10
10
|
koi_net/secure.py,sha256=cGNF2assqCaYq0i0fhQBm7aREoAdpY-XVypDsE1ALaU,3970
|
|
11
|
-
koi_net/server.py,sha256=
|
|
11
|
+
koi_net/server.py,sha256=PrR_cXQV5YMKa6FXwiJXwMZJ52VQVzLPYYPVl-Miuw8,4315
|
|
12
12
|
koi_net/network/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
13
|
koi_net/network/behavior.py,sha256=NZLvWlrxR0uWriE3ZzCXmocUVccQthy7Xx8E_8KBwsg,1208
|
|
14
|
-
koi_net/network/error_handler.py,sha256=
|
|
14
|
+
koi_net/network/error_handler.py,sha256=_dAl2ovpUZEVhPc8_dcLA7I-FoMNqQNwFy0QLa4uTSY,1617
|
|
15
15
|
koi_net/network/event_queue.py,sha256=DWs26C235iYkP4koKcdbhmIOHGZRJ48d072BoNWyiHo,7325
|
|
16
|
-
koi_net/network/graph.py,sha256=
|
|
17
|
-
koi_net/network/request_handler.py,sha256=
|
|
16
|
+
koi_net/network/graph.py,sha256=60SLiR3aNXIOGe-URzMGgx8abmMEJtz37EJs6jeImEM,4143
|
|
17
|
+
koi_net/network/request_handler.py,sha256=_SM5MuYkS636wGJeFkesapQsW5x_kt_1o9KTXB0wksU,6869
|
|
18
18
|
koi_net/network/resolver.py,sha256=coIp4M6k0-8sUfAy4h2NMx_7zCNroWlCHKOj3AXZVhc,5412
|
|
19
19
|
koi_net/network/response_handler.py,sha256=__R_EvEpjaMz3PCDvkNgWF_EAHe2nePGk-zK_cT4C4g,2077
|
|
20
20
|
koi_net/processor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -24,15 +24,15 @@ koi_net/processor/interface.py,sha256=ebDwqggznFRfp2PT8-UJPUAvCwX8nZaaQ68FUeWQvm
|
|
|
24
24
|
koi_net/processor/knowledge_object.py,sha256=avQnsaeqqiJxy40P1VGljuQMtAGmJB-TBa4pmBXTaIs,3863
|
|
25
25
|
koi_net/processor/knowledge_pipeline.py,sha256=i7FpCFl0UIOwCI5zhP1i8M4PX4A48VN28iV9jruvN5k,9486
|
|
26
26
|
koi_net/protocol/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
27
|
-
koi_net/protocol/api_models.py,sha256=
|
|
27
|
+
koi_net/protocol/api_models.py,sha256=jzRZWW_ZB5YsBAiwCom882-WIbr0rPyelJxExRgHZGc,1755
|
|
28
28
|
koi_net/protocol/consts.py,sha256=bisbVEojPIHlLhkLafBzfIhH25TjNfvTORF1g6YXzIM,243
|
|
29
|
-
koi_net/protocol/edge.py,sha256=
|
|
30
|
-
koi_net/protocol/envelope.py,sha256=
|
|
31
|
-
koi_net/protocol/errors.py,sha256=
|
|
32
|
-
koi_net/protocol/event.py,sha256=
|
|
29
|
+
koi_net/protocol/edge.py,sha256=PzdEhC43T1KO5iMSEu7I4tiz-7sZxtz41dJfWf-oHA0,1034
|
|
30
|
+
koi_net/protocol/envelope.py,sha256=UVHlO2BDyDiP5eixqx9xD6xUsCfFRi0kZyzC4BC-DOw,1886
|
|
31
|
+
koi_net/protocol/errors.py,sha256=uKPQ-TGLouZuK0xd2pXuCQoRTyu_JFsydSCLml13Cz8,595
|
|
32
|
+
koi_net/protocol/event.py,sha256=HxzLN-iCXPyr2YzrswMIkgZYeUdFbBpa5v98dAB06lQ,1328
|
|
33
33
|
koi_net/protocol/node.py,sha256=7GQzHORFr9cP4BqJgir6EGSWCskL-yqmvJksIiLfcWU,409
|
|
34
|
-
koi_net/protocol/secure.py,sha256=
|
|
35
|
-
koi_net-1.1.
|
|
36
|
-
koi_net-1.1.
|
|
37
|
-
koi_net-1.1.
|
|
38
|
-
koi_net-1.1.
|
|
34
|
+
koi_net/protocol/secure.py,sha256=6sRLWxG5EDF0QLBj29gk3hPmZnPXATrTTFdwx39wQfY,5127
|
|
35
|
+
koi_net-1.1.0b7.dist-info/METADATA,sha256=nHdoaFbZodVbTgjEuZeMxi8as2JOWP0Fyhoj05tn7e8,37118
|
|
36
|
+
koi_net-1.1.0b7.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
37
|
+
koi_net-1.1.0b7.dist-info/licenses/LICENSE,sha256=03mgCL5qth2aD9C3F3qNVs4sFJSpK9kjtYCyOwdSp7s,1069
|
|
38
|
+
koi_net-1.1.0b7.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|