distributed-state-network 0.4.1__tar.gz → 0.4.2__tar.gz
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.
- {distributed_state_network-0.4.1 → distributed_state_network-0.4.2}/PKG-INFO +1 -6
- {distributed_state_network-0.4.1 → distributed_state_network-0.4.2}/README.md +0 -5
- {distributed_state_network-0.4.1 → distributed_state_network-0.4.2}/pyproject.toml +1 -1
- {distributed_state_network-0.4.1 → distributed_state_network-0.4.2}/src/distributed_state_network/create_key.py +2 -2
- {distributed_state_network-0.4.1 → distributed_state_network-0.4.2}/src/distributed_state_network/dsnode.py +13 -8
- {distributed_state_network-0.4.1 → distributed_state_network-0.4.2}/src/distributed_state_network/handler.py +11 -9
- {distributed_state_network-0.4.1 → distributed_state_network-0.4.2}/src/distributed_state_network/objects/config.py +2 -2
- {distributed_state_network-0.4.1 → distributed_state_network-0.4.2/tests}/test.py +2 -2
- {distributed_state_network-0.4.1 → distributed_state_network-0.4.2}/.github/workflows/publish.yml +0 -0
- {distributed_state_network-0.4.1 → distributed_state_network-0.4.2}/.gitignore +0 -0
- {distributed_state_network-0.4.1 → distributed_state_network-0.4.2}/LICENSE +0 -0
- {distributed_state_network-0.4.1 → distributed_state_network-0.4.2}/coverage.sh +0 -0
- {distributed_state_network-0.4.1 → distributed_state_network-0.4.2}/documentation/ds-node-config.md +0 -0
- {distributed_state_network-0.4.1 → distributed_state_network-0.4.2}/documentation/ds-node-server.md +0 -0
- {distributed_state_network-0.4.1 → distributed_state_network-0.4.2}/documentation/ds-node.md +0 -0
- {distributed_state_network-0.4.1 → distributed_state_network-0.4.2}/documentation/protocol.md +0 -0
- {distributed_state_network-0.4.1 → distributed_state_network-0.4.2}/documentation/usage.md +0 -0
- {distributed_state_network-0.4.1 → distributed_state_network-0.4.2}/src/distributed_state_network/__init__.py +0 -0
- {distributed_state_network-0.4.1 → distributed_state_network-0.4.2}/src/distributed_state_network/objects/endpoint.py +0 -0
- {distributed_state_network-0.4.1 → distributed_state_network-0.4.2}/src/distributed_state_network/objects/hello_packet.py +0 -0
- {distributed_state_network-0.4.1 → distributed_state_network-0.4.2}/src/distributed_state_network/objects/msg_types.py +0 -0
- {distributed_state_network-0.4.1 → distributed_state_network-0.4.2}/src/distributed_state_network/objects/peers_packet.py +0 -0
- {distributed_state_network-0.4.1 → distributed_state_network-0.4.2}/src/distributed_state_network/objects/signed_packet.py +0 -0
- {distributed_state_network-0.4.1 → distributed_state_network-0.4.2}/src/distributed_state_network/objects/state_packet.py +0 -0
- {distributed_state_network-0.4.1 → distributed_state_network-0.4.2}/src/distributed_state_network/util/__init__.py +0 -0
- {distributed_state_network-0.4.1 → distributed_state_network-0.4.2}/src/distributed_state_network/util/aes.py +0 -0
- {distributed_state_network-0.4.1 → distributed_state_network-0.4.2}/src/distributed_state_network/util/byte_helper.py +0 -0
- {distributed_state_network-0.4.1 → distributed_state_network-0.4.2}/src/distributed_state_network/util/ecdsa.py +0 -0
- {distributed_state_network-0.4.1 → distributed_state_network-0.4.2}/src/distributed_state_network/util/https.py +0 -0
- {distributed_state_network-0.4.1 → distributed_state_network-0.4.2}/src/distributed_state_network/util/key_manager.py +0 -0
- {distributed_state_network-0.4.1 → distributed_state_network-0.4.2}/technical.md +0 -0
- {distributed_state_network-0.4.1 → distributed_state_network-0.4.2}/tests/connections.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: distributed-state-network
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.2
|
|
4
4
|
Summary: A tool to distribute the state of a network device to other devices on the network
|
|
5
5
|
Project-URL: Homepage, https://github.com/erinclemmer/distributed_state_network
|
|
6
6
|
Project-URL: Issues, https://github.com/erinclemmer/distributed_state_network/issues
|
|
@@ -54,14 +54,10 @@ The simplest DSN network is a single node:
|
|
|
54
54
|
```python
|
|
55
55
|
from distributed_state_network import DSNodeServer, DSNodeConfig
|
|
56
56
|
|
|
57
|
-
# Generate a network key (do this once for your entire network)
|
|
58
|
-
DSNodeServer.generate_key("network.key")
|
|
59
|
-
|
|
60
57
|
# Start a node
|
|
61
58
|
node = DSNodeServer.start(DSNodeConfig(
|
|
62
59
|
node_id="my_first_node",
|
|
63
60
|
port=8000,
|
|
64
|
-
aes_key_file="network.key",
|
|
65
61
|
bootstrap_nodes=[] # Empty for the first node
|
|
66
62
|
))
|
|
67
63
|
|
|
@@ -89,7 +85,6 @@ Create a network of temperature sensors that share readings:
|
|
|
89
85
|
sensor_node = DSNodeServer.start(DSNodeConfig(
|
|
90
86
|
node_id=f"sensor_{location}",
|
|
91
87
|
port=8000,
|
|
92
|
-
aes_key_file="network.key",
|
|
93
88
|
bootstrap_nodes=[{"address": "coordinator.local", "port": 8000}]
|
|
94
89
|
))
|
|
95
90
|
|
|
@@ -28,14 +28,10 @@ The simplest DSN network is a single node:
|
|
|
28
28
|
```python
|
|
29
29
|
from distributed_state_network import DSNodeServer, DSNodeConfig
|
|
30
30
|
|
|
31
|
-
# Generate a network key (do this once for your entire network)
|
|
32
|
-
DSNodeServer.generate_key("network.key")
|
|
33
|
-
|
|
34
31
|
# Start a node
|
|
35
32
|
node = DSNodeServer.start(DSNodeConfig(
|
|
36
33
|
node_id="my_first_node",
|
|
37
34
|
port=8000,
|
|
38
|
-
aes_key_file="network.key",
|
|
39
35
|
bootstrap_nodes=[] # Empty for the first node
|
|
40
36
|
))
|
|
41
37
|
|
|
@@ -63,7 +59,6 @@ Create a network of temperature sensors that share readings:
|
|
|
63
59
|
sensor_node = DSNodeServer.start(DSNodeConfig(
|
|
64
60
|
node_id=f"sensor_{location}",
|
|
65
61
|
port=8000,
|
|
66
|
-
aes_key_file="network.key",
|
|
67
62
|
bootstrap_nodes=[{"address": "coordinator.local", "port": 8000}]
|
|
68
63
|
))
|
|
69
64
|
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "distributed-state-network"
|
|
7
|
-
version = "0.4.
|
|
7
|
+
version = "0.4.2"
|
|
8
8
|
authors = [{name="Erin Clemmer", email="erin.c.clemmer@gmail.com"}]
|
|
9
9
|
description = "A tool to distribute the state of a network device to other devices on the network"
|
|
10
10
|
keywords = ["distributed", "networking"]
|
|
@@ -65,7 +65,7 @@ class DSNode:
|
|
|
65
65
|
self.logger = logging.getLogger("DSN: " + config.node_id)
|
|
66
66
|
self.disconnect_cb = disconnect_callback
|
|
67
67
|
self.update_cb = update_callback
|
|
68
|
-
if not os.path.exists(config.aes_key_file):
|
|
68
|
+
if config.aes_key_file is not None and not os.path.exists(config.aes_key_file):
|
|
69
69
|
raise Exception(f"Could not find aes key file in {config.aes_key_file}")
|
|
70
70
|
|
|
71
71
|
threading.Thread(target=self.network_tick, daemon=True).start()
|
|
@@ -75,6 +75,8 @@ class DSNode:
|
|
|
75
75
|
self.server = server
|
|
76
76
|
|
|
77
77
|
def get_aes_key(self):
|
|
78
|
+
if not os.path.exists(self.config.aes_key_file):
|
|
79
|
+
raise Exception("Could not find aes key file")
|
|
78
80
|
with open(self.config.aes_key_file, 'r') as f:
|
|
79
81
|
key_hex = f.read()
|
|
80
82
|
return bytes.fromhex(key_hex)
|
|
@@ -110,8 +112,9 @@ class DSNode:
|
|
|
110
112
|
"""Send HTTP request and wait for response"""
|
|
111
113
|
try:
|
|
112
114
|
# Prepend message type to payload
|
|
113
|
-
|
|
114
|
-
|
|
115
|
+
data = bytes([msg_type]) + payload
|
|
116
|
+
if self.config.aes_key_file is not None:
|
|
117
|
+
data = self.encrypt_data(data)
|
|
115
118
|
|
|
116
119
|
# Determine the URL path based on message type
|
|
117
120
|
path = MSG_TYPE_TO_PATH.get(msg_type, '/unknown')
|
|
@@ -120,7 +123,7 @@ class DSNode:
|
|
|
120
123
|
# Send HTTP POST request
|
|
121
124
|
response = requests.post(
|
|
122
125
|
url,
|
|
123
|
-
data=
|
|
126
|
+
data=data,
|
|
124
127
|
headers={'Content-Type': 'application/octet-stream'},
|
|
125
128
|
timeout=HTTP_TIMEOUT
|
|
126
129
|
)
|
|
@@ -132,19 +135,21 @@ class DSNode:
|
|
|
132
135
|
elif response.status_code != 200:
|
|
133
136
|
raise Exception(f"HTTP error: {response.status_code}")
|
|
134
137
|
|
|
138
|
+
response_data = response.content
|
|
135
139
|
# Decrypt the response
|
|
136
|
-
|
|
140
|
+
if self.config.aes_key_file is not None:
|
|
141
|
+
response_data = self.decrypt_data(response_data)
|
|
137
142
|
|
|
138
|
-
if len(
|
|
143
|
+
if len(response_data) < 1:
|
|
139
144
|
raise Exception("Empty response")
|
|
140
145
|
|
|
141
146
|
# First byte is message type
|
|
142
|
-
response_msg_type =
|
|
147
|
+
response_msg_type = response_data[0]
|
|
143
148
|
if response_msg_type != msg_type:
|
|
144
149
|
raise Exception(f"Response message type mismatch: expected {msg_type}, got {response_msg_type}")
|
|
145
150
|
|
|
146
151
|
# Return the body (everything after the message type byte)
|
|
147
|
-
return
|
|
152
|
+
return response_data[1:]
|
|
148
153
|
|
|
149
154
|
except requests.exceptions.Timeout:
|
|
150
155
|
if retries < 2:
|
|
@@ -8,7 +8,7 @@ from distributed_state_network.objects.config import DSNodeConfig
|
|
|
8
8
|
from distributed_state_network.util.aes import generate_aes_key
|
|
9
9
|
from distributed_state_network.util import stop_thread
|
|
10
10
|
|
|
11
|
-
VERSION = "0.4.
|
|
11
|
+
VERSION = "0.4.2"
|
|
12
12
|
logging.basicConfig(level=logging.INFO)
|
|
13
13
|
|
|
14
14
|
# Silence Flask and Werkzeug logging
|
|
@@ -66,14 +66,15 @@ class DSNodeServer:
|
|
|
66
66
|
"""Handle incoming HTTP request"""
|
|
67
67
|
try:
|
|
68
68
|
# Decrypt the data
|
|
69
|
-
|
|
69
|
+
if self.config.aes_key_file is not None:
|
|
70
|
+
data = self.node.decrypt_data(data)
|
|
70
71
|
|
|
71
|
-
if len(
|
|
72
|
+
if len(data) < 1:
|
|
72
73
|
return Response(status=400)
|
|
73
74
|
|
|
74
75
|
# First byte should be message type (for verification)
|
|
75
|
-
received_msg_type =
|
|
76
|
-
body =
|
|
76
|
+
received_msg_type = data[0]
|
|
77
|
+
body = data[1:]
|
|
77
78
|
|
|
78
79
|
if received_msg_type != msg_type:
|
|
79
80
|
self.node.logger.error(f"Message type mismatch: expected {msg_type}, got {received_msg_type}")
|
|
@@ -98,8 +99,9 @@ class DSNodeServer:
|
|
|
98
99
|
if response_data is not None:
|
|
99
100
|
# Prepend message type to response
|
|
100
101
|
response_with_type = bytes([msg_type]) + response_data
|
|
101
|
-
|
|
102
|
-
|
|
102
|
+
if self.config.aes_key_file is not None:
|
|
103
|
+
response_with_type = self.node.encrypt_data(response_with_type)
|
|
104
|
+
return Response(response_with_type, status=200, mimetype='application/octet-stream')
|
|
103
105
|
else:
|
|
104
106
|
return Response(status=204) # No content
|
|
105
107
|
|
|
@@ -132,8 +134,8 @@ class DSNodeServer:
|
|
|
132
134
|
@staticmethod
|
|
133
135
|
def generate_key(out_file_path: str):
|
|
134
136
|
key = generate_aes_key()
|
|
135
|
-
with open(out_file_path, '
|
|
136
|
-
f.write(key)
|
|
137
|
+
with open(out_file_path, 'w', encoding='utf-8') as f:
|
|
138
|
+
f.write(key.hex())
|
|
137
139
|
|
|
138
140
|
@staticmethod
|
|
139
141
|
def start(
|
|
@@ -7,7 +7,7 @@ from distributed_state_network.objects.endpoint import Endpoint
|
|
|
7
7
|
class DSNodeConfig:
|
|
8
8
|
node_id: str
|
|
9
9
|
port: int
|
|
10
|
-
aes_key_file: str
|
|
10
|
+
aes_key_file: str | None
|
|
11
11
|
bootstrap_nodes: List[Endpoint]
|
|
12
12
|
|
|
13
13
|
@staticmethod
|
|
@@ -15,6 +15,6 @@ class DSNodeConfig:
|
|
|
15
15
|
return DSNodeConfig(
|
|
16
16
|
data["node_id"],
|
|
17
17
|
data["port"],
|
|
18
|
-
data["aes_key_file"],
|
|
18
|
+
data["aes_key_file"] if "aes_key_file" in data else None,
|
|
19
19
|
[Endpoint.from_json(e) for e in data["bootstrap_nodes"]]
|
|
20
20
|
)
|
|
@@ -7,7 +7,7 @@ import unittest
|
|
|
7
7
|
import requests
|
|
8
8
|
from typing import List, Dict
|
|
9
9
|
|
|
10
|
-
sys.path.append(os.path.join(os.path.dirname(__file__), '
|
|
10
|
+
sys.path.append(os.path.join(os.path.dirname(__file__), '../src'))
|
|
11
11
|
|
|
12
12
|
from distributed_state_network import DSNodeServer, Endpoint, DSNodeConfig
|
|
13
13
|
|
|
@@ -311,7 +311,7 @@ class TestNode(unittest.TestCase):
|
|
|
311
311
|
DSNodeServer.generate_key(test_key_file)
|
|
312
312
|
with open(test_key_file, 'rb') as f:
|
|
313
313
|
key = f.read()
|
|
314
|
-
self.assertEqual(
|
|
314
|
+
self.assertEqual(64, len(key))
|
|
315
315
|
os.remove(test_key_file)
|
|
316
316
|
|
|
317
317
|
def test_write_cert(self):
|
{distributed_state_network-0.4.1 → distributed_state_network-0.4.2}/.github/workflows/publish.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{distributed_state_network-0.4.1 → distributed_state_network-0.4.2}/documentation/ds-node-config.md
RENAMED
|
File without changes
|
{distributed_state_network-0.4.1 → distributed_state_network-0.4.2}/documentation/ds-node-server.md
RENAMED
|
File without changes
|
{distributed_state_network-0.4.1 → distributed_state_network-0.4.2}/documentation/ds-node.md
RENAMED
|
File without changes
|
{distributed_state_network-0.4.1 → distributed_state_network-0.4.2}/documentation/protocol.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|