distributed-state-network 0.4.1__tar.gz → 0.5.0__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.5.0}/PKG-INFO +1 -6
- {distributed_state_network-0.4.1 → distributed_state_network-0.5.0}/README.md +0 -5
- {distributed_state_network-0.4.1 → distributed_state_network-0.5.0}/documentation/ds-node-config.md +2 -4
- {distributed_state_network-0.4.1 → distributed_state_network-0.5.0}/documentation/ds-node-server.md +8 -10
- {distributed_state_network-0.4.1 → distributed_state_network-0.5.0}/documentation/usage.md +0 -6
- {distributed_state_network-0.4.1 → distributed_state_network-0.5.0}/pyproject.toml +1 -1
- distributed_state_network-0.5.0/src/distributed_state_network/create_key.py +4 -0
- {distributed_state_network-0.4.1 → distributed_state_network-0.5.0}/src/distributed_state_network/dsnode.py +13 -15
- {distributed_state_network-0.4.1 → distributed_state_network-0.5.0}/src/distributed_state_network/handler.py +11 -11
- {distributed_state_network-0.4.1 → distributed_state_network-0.5.0}/src/distributed_state_network/objects/config.py +2 -2
- {distributed_state_network-0.4.1 → distributed_state_network-0.5.0}/src/distributed_state_network/util/key_manager.py +2 -6
- {distributed_state_network-0.4.1 → distributed_state_network-0.5.0}/technical.md +5 -3
- {distributed_state_network-0.4.1 → distributed_state_network-0.5.0}/tests/connections.py +2 -5
- {distributed_state_network-0.4.1 → distributed_state_network-0.5.0/tests}/test.py +7 -33
- distributed_state_network-0.4.1/src/distributed_state_network/create_key.py +0 -10
- {distributed_state_network-0.4.1 → distributed_state_network-0.5.0}/.github/workflows/publish.yml +0 -0
- {distributed_state_network-0.4.1 → distributed_state_network-0.5.0}/.gitignore +0 -0
- {distributed_state_network-0.4.1 → distributed_state_network-0.5.0}/LICENSE +0 -0
- {distributed_state_network-0.4.1 → distributed_state_network-0.5.0}/coverage.sh +0 -0
- {distributed_state_network-0.4.1 → distributed_state_network-0.5.0}/documentation/ds-node.md +0 -0
- {distributed_state_network-0.4.1 → distributed_state_network-0.5.0}/documentation/protocol.md +0 -0
- {distributed_state_network-0.4.1 → distributed_state_network-0.5.0}/src/distributed_state_network/__init__.py +0 -0
- {distributed_state_network-0.4.1 → distributed_state_network-0.5.0}/src/distributed_state_network/objects/endpoint.py +0 -0
- {distributed_state_network-0.4.1 → distributed_state_network-0.5.0}/src/distributed_state_network/objects/hello_packet.py +0 -0
- {distributed_state_network-0.4.1 → distributed_state_network-0.5.0}/src/distributed_state_network/objects/msg_types.py +0 -0
- {distributed_state_network-0.4.1 → distributed_state_network-0.5.0}/src/distributed_state_network/objects/peers_packet.py +0 -0
- {distributed_state_network-0.4.1 → distributed_state_network-0.5.0}/src/distributed_state_network/objects/signed_packet.py +0 -0
- {distributed_state_network-0.4.1 → distributed_state_network-0.5.0}/src/distributed_state_network/objects/state_packet.py +0 -0
- {distributed_state_network-0.4.1 → distributed_state_network-0.5.0}/src/distributed_state_network/util/__init__.py +0 -0
- {distributed_state_network-0.4.1 → distributed_state_network-0.5.0}/src/distributed_state_network/util/aes.py +0 -0
- {distributed_state_network-0.4.1 → distributed_state_network-0.5.0}/src/distributed_state_network/util/byte_helper.py +0 -0
- {distributed_state_network-0.4.1 → distributed_state_network-0.5.0}/src/distributed_state_network/util/ecdsa.py +0 -0
- {distributed_state_network-0.4.1 → distributed_state_network-0.5.0}/src/distributed_state_network/util/https.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: distributed-state-network
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
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
|
|
{distributed_state_network-0.4.1 → distributed_state_network-0.5.0}/documentation/ds-node-config.md
RENAMED
|
@@ -12,14 +12,14 @@ from distributed_state_network import DSNodeConfig
|
|
|
12
12
|
class DSNodeConfig:
|
|
13
13
|
node_id: str
|
|
14
14
|
port: int
|
|
15
|
-
|
|
15
|
+
aes_key: str
|
|
16
16
|
bootstrap_nodes: List[Endpoint]
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
### Attributes
|
|
20
20
|
- **node_id** (`str`): Unique identifier for the node
|
|
21
21
|
- **port** (`int`): Port number for the node to listen on (UDP)
|
|
22
|
-
- **
|
|
22
|
+
- **aes_key** (`str`): Hexidecimal encoded AES key for network encryption
|
|
23
23
|
- **bootstrap_nodes** (`List[Endpoint]`): List of initial nodes to connect to when joining the network
|
|
24
24
|
|
|
25
25
|
**Note:** The node's public IP address is automatically detected by the bootstrap server during the initial handshake.
|
|
@@ -40,7 +40,6 @@ Creates a DSNodeConfig instance from a dictionary.
|
|
|
40
40
|
config_dict = {
|
|
41
41
|
"node_id": "node1",
|
|
42
42
|
"port": 8000,
|
|
43
|
-
"aes_key_file": "/path/to/key.aes",
|
|
44
43
|
"bootstrap_nodes": [
|
|
45
44
|
{"address": "127.0.0.1", "port": 8001}
|
|
46
45
|
]
|
|
@@ -53,7 +52,6 @@ config = DSNodeConfig.from_dict(config_dict)
|
|
|
53
52
|
config_dict = {
|
|
54
53
|
"node_id": "bootstrap",
|
|
55
54
|
"port": 8000,
|
|
56
|
-
"aes_key_file": "/path/to/key.aes",
|
|
57
55
|
"bootstrap_nodes": [] # Empty for first node
|
|
58
56
|
}
|
|
59
57
|
config = DSNodeConfig.from_dict(config_dict)
|
{distributed_state_network-0.4.1 → distributed_state_network-0.5.0}/documentation/ds-node-server.md
RENAMED
|
@@ -59,7 +59,6 @@ server = DSNodeServer.start(config)
|
|
|
59
59
|
bootstrap_config = DSNodeConfig(
|
|
60
60
|
node_id="bootstrap",
|
|
61
61
|
port=8000,
|
|
62
|
-
aes_key_file="network.key",
|
|
63
62
|
bootstrap_nodes=[]
|
|
64
63
|
)
|
|
65
64
|
bootstrap = DSNodeServer.start(bootstrap_config)
|
|
@@ -68,21 +67,20 @@ bootstrap = DSNodeServer.start(bootstrap_config)
|
|
|
68
67
|
connector_config = DSNodeConfig(
|
|
69
68
|
node_id="connector",
|
|
70
69
|
port=8001,
|
|
71
|
-
aes_key_file="network.key",
|
|
72
70
|
bootstrap_nodes=[Endpoint("127.0.0.1", 8000)]
|
|
73
71
|
)
|
|
74
72
|
connector = DSNodeServer.start(connector_config)
|
|
75
73
|
```
|
|
76
74
|
|
|
77
|
-
### `generate_key(
|
|
78
|
-
Generates a new AES key
|
|
75
|
+
### `generate_key() -> str`
|
|
76
|
+
Generates a new hexadecimal encoded AES key for network encryption. All nodes in the same network must share the same AES key.
|
|
79
77
|
|
|
80
78
|
**Parameters:**
|
|
81
|
-
-
|
|
79
|
+
- None
|
|
82
80
|
|
|
83
81
|
**Example:**
|
|
84
82
|
```python
|
|
85
|
-
DSNodeServer.generate_key(
|
|
83
|
+
DSNodeServer.generate_key()
|
|
86
84
|
```
|
|
87
85
|
|
|
88
86
|
### Instance Methods
|
|
@@ -145,13 +143,13 @@ All shared state is protected with appropriate locks.
|
|
|
145
143
|
from distributed_state_network import DSNodeServer, DSNodeConfig, Endpoint
|
|
146
144
|
|
|
147
145
|
# Generate shared AES key (only once)
|
|
148
|
-
DSNodeServer.generate_key(
|
|
146
|
+
key = DSNodeServer.generate_key()
|
|
149
147
|
|
|
150
148
|
# Start bootstrap node
|
|
151
149
|
bootstrap = DSNodeServer.start(DSNodeConfig(
|
|
152
150
|
node_id="bootstrap",
|
|
153
151
|
port=8000,
|
|
154
|
-
|
|
152
|
+
aes_key=key,
|
|
155
153
|
bootstrap_nodes=[]
|
|
156
154
|
))
|
|
157
155
|
|
|
@@ -159,14 +157,14 @@ bootstrap = DSNodeServer.start(DSNodeConfig(
|
|
|
159
157
|
node1 = DSNodeServer.start(DSNodeConfig(
|
|
160
158
|
node_id="node1",
|
|
161
159
|
port=8001,
|
|
162
|
-
|
|
160
|
+
aes_key=key,
|
|
163
161
|
bootstrap_nodes=[Endpoint("192.168.1.100", 8000)]
|
|
164
162
|
))
|
|
165
163
|
|
|
166
164
|
node2 = DSNodeServer.start(DSNodeConfig(
|
|
167
165
|
node_id="node2",
|
|
168
166
|
port=8002,
|
|
169
|
-
|
|
167
|
+
aes_key=key,
|
|
170
168
|
bootstrap_nodes=[Endpoint("192.168.1.100", 8000)]
|
|
171
169
|
))
|
|
172
170
|
|
|
@@ -9,7 +9,6 @@ from distributed_state_network import DSNodeServer, DSNodeConfig, Endpoint
|
|
|
9
9
|
config = DSNodeConfig(
|
|
10
10
|
node_id="node1",
|
|
11
11
|
port=8000,
|
|
12
|
-
aes_key_file="/path/to/shared.key",
|
|
13
12
|
bootstrap_nodes=[] # Empty for first node
|
|
14
13
|
)
|
|
15
14
|
|
|
@@ -38,7 +37,6 @@ server.stop()
|
|
|
38
37
|
config2 = DSNodeConfig(
|
|
39
38
|
node_id="node2",
|
|
40
39
|
port=8001,
|
|
41
|
-
aes_key_file="/path/to/shared.key", # Same key file as network
|
|
42
40
|
bootstrap_nodes=[
|
|
43
41
|
Endpoint("127.0.0.1", 8000) # Node 1's endpoint
|
|
44
42
|
]
|
|
@@ -65,7 +63,6 @@ custom_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
|
|
65
63
|
config = DSNodeConfig(
|
|
66
64
|
node_id="node3",
|
|
67
65
|
port=8003, # Should match the bound port
|
|
68
|
-
aes_key_file="/path/to/shared.key",
|
|
69
66
|
bootstrap_nodes=[Endpoint("127.0.0.1", 8000)]
|
|
70
67
|
)
|
|
71
68
|
|
|
@@ -83,7 +80,6 @@ def handle_disconnect():
|
|
|
83
80
|
config = DSNodeConfig(
|
|
84
81
|
node_id="node4",
|
|
85
82
|
port=8004,
|
|
86
|
-
aes_key_file="/path/to/shared.key",
|
|
87
83
|
bootstrap_nodes=[Endpoint("127.0.0.1", 8000)]
|
|
88
84
|
)
|
|
89
85
|
|
|
@@ -100,7 +96,6 @@ def handle_update():
|
|
|
100
96
|
config = DSNodeConfig(
|
|
101
97
|
node_id="node5",
|
|
102
98
|
port=8005,
|
|
103
|
-
aes_key_file="/path/to/shared.key",
|
|
104
99
|
bootstrap_nodes=[Endpoint("127.0.0.1", 8000)]
|
|
105
100
|
)
|
|
106
101
|
|
|
@@ -126,7 +121,6 @@ custom_sock.bind(("0.0.0.0", 8006))
|
|
|
126
121
|
config = DSNodeConfig(
|
|
127
122
|
node_id="node6",
|
|
128
123
|
port=8006,
|
|
129
|
-
aes_key_file="/path/to/shared.key",
|
|
130
124
|
bootstrap_nodes=[
|
|
131
125
|
Endpoint("127.0.0.1", 8000),
|
|
132
126
|
Endpoint("127.0.0.1", 8001) # Multiple bootstrap options
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "distributed-state-network"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.5.0"
|
|
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"]
|
|
@@ -49,7 +49,7 @@ class DSNode:
|
|
|
49
49
|
self.version = version
|
|
50
50
|
self.server = None # Reference to the Flask server
|
|
51
51
|
|
|
52
|
-
self.cred_manager = CredentialManager(config.node_id)
|
|
52
|
+
self.cred_manager = CredentialManager("credentials", config.node_id)
|
|
53
53
|
self.cred_manager.generate_keys()
|
|
54
54
|
|
|
55
55
|
self.node_states = {
|
|
@@ -65,19 +65,14 @@ 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):
|
|
69
|
-
raise Exception(f"Could not find aes key file in {config.aes_key_file}")
|
|
70
68
|
|
|
71
69
|
threading.Thread(target=self.network_tick, daemon=True).start()
|
|
72
70
|
|
|
73
71
|
def set_server(self, server):
|
|
74
|
-
"""Set reference to the Flask server"""
|
|
75
72
|
self.server = server
|
|
76
73
|
|
|
77
|
-
def get_aes_key(self):
|
|
78
|
-
|
|
79
|
-
key_hex = f.read()
|
|
80
|
-
return bytes.fromhex(key_hex)
|
|
74
|
+
def get_aes_key(self) -> bytes:
|
|
75
|
+
return bytes.fromhex(self.config.aes_key)
|
|
81
76
|
|
|
82
77
|
def network_tick(self):
|
|
83
78
|
time.sleep(TICK_INTERVAL)
|
|
@@ -110,8 +105,9 @@ class DSNode:
|
|
|
110
105
|
"""Send HTTP request and wait for response"""
|
|
111
106
|
try:
|
|
112
107
|
# Prepend message type to payload
|
|
113
|
-
|
|
114
|
-
|
|
108
|
+
data = bytes([msg_type]) + payload
|
|
109
|
+
if self.config.aes_key is not None:
|
|
110
|
+
data = self.encrypt_data(data)
|
|
115
111
|
|
|
116
112
|
# Determine the URL path based on message type
|
|
117
113
|
path = MSG_TYPE_TO_PATH.get(msg_type, '/unknown')
|
|
@@ -120,7 +116,7 @@ class DSNode:
|
|
|
120
116
|
# Send HTTP POST request
|
|
121
117
|
response = requests.post(
|
|
122
118
|
url,
|
|
123
|
-
data=
|
|
119
|
+
data=data,
|
|
124
120
|
headers={'Content-Type': 'application/octet-stream'},
|
|
125
121
|
timeout=HTTP_TIMEOUT
|
|
126
122
|
)
|
|
@@ -132,19 +128,21 @@ class DSNode:
|
|
|
132
128
|
elif response.status_code != 200:
|
|
133
129
|
raise Exception(f"HTTP error: {response.status_code}")
|
|
134
130
|
|
|
131
|
+
response_data = response.content
|
|
135
132
|
# Decrypt the response
|
|
136
|
-
|
|
133
|
+
if self.config.aes_key is not None:
|
|
134
|
+
response_data = self.decrypt_data(response_data)
|
|
137
135
|
|
|
138
|
-
if len(
|
|
136
|
+
if len(response_data) < 1:
|
|
139
137
|
raise Exception("Empty response")
|
|
140
138
|
|
|
141
139
|
# First byte is message type
|
|
142
|
-
response_msg_type =
|
|
140
|
+
response_msg_type = response_data[0]
|
|
143
141
|
if response_msg_type != msg_type:
|
|
144
142
|
raise Exception(f"Response message type mismatch: expected {msg_type}, got {response_msg_type}")
|
|
145
143
|
|
|
146
144
|
# Return the body (everything after the message type byte)
|
|
147
|
-
return
|
|
145
|
+
return response_data[1:]
|
|
148
146
|
|
|
149
147
|
except requests.exceptions.Timeout:
|
|
150
148
|
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.
|
|
11
|
+
VERSION = "0.5.0"
|
|
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 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 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
|
|
|
@@ -130,10 +132,8 @@ class DSNodeServer:
|
|
|
130
132
|
self.node.logger.info(f'Started DSNode on HTTP port {port}')
|
|
131
133
|
|
|
132
134
|
@staticmethod
|
|
133
|
-
def generate_key(
|
|
134
|
-
|
|
135
|
-
with open(out_file_path, 'wb') as f:
|
|
136
|
-
f.write(key)
|
|
135
|
+
def generate_key() -> str:
|
|
136
|
+
return generate_aes_key().hex()
|
|
137
137
|
|
|
138
138
|
@staticmethod
|
|
139
139
|
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
|
-
|
|
10
|
+
aes_key: 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["
|
|
18
|
+
data["aes_key"] if "aes_key" in data else None,
|
|
19
19
|
[Endpoint.from_json(e) for e in data["bootstrap_nodes"]]
|
|
20
20
|
)
|
|
@@ -77,10 +77,6 @@ class KeyManager:
|
|
|
77
77
|
with open(f'{self.folder}/{self.node_id}/{self.node_id}.{self.private_extension}', 'wb') as f:
|
|
78
78
|
f.write(key_bytes)
|
|
79
79
|
|
|
80
|
-
class CertManager(KeyManager):
|
|
81
|
-
def __init__(self, node_id: str):
|
|
82
|
-
KeyManager.__init__(self, "HTTPS", node_id, "certs", "crt", "key", generate_cert)
|
|
83
|
-
|
|
84
80
|
class CredentialManager(KeyManager):
|
|
85
|
-
def __init__(self, node_id: str):
|
|
86
|
-
KeyManager.__init__(self, "ECDSA", node_id,
|
|
81
|
+
def __init__(self, folder: str, node_id: str):
|
|
82
|
+
KeyManager.__init__(self, "ECDSA", node_id, folder, "pub", "key", generate_key_pair)
|
|
@@ -9,13 +9,13 @@ This is intended to be used as a middleware for another application rather than
|
|
|
9
9
|
from distributed_state_network import DSNodeServer, DSNodeConfig
|
|
10
10
|
|
|
11
11
|
# Write a new aes key to the current directory
|
|
12
|
-
DSNodeServer.generate_key(
|
|
12
|
+
aes_key = DSNodeServer.generate_key()
|
|
13
13
|
|
|
14
14
|
# Use the key to start a new network
|
|
15
15
|
bootstrap = DSNodeServer(DSNodeConfig(
|
|
16
16
|
node_id="bootstrap", # Network ID for the node
|
|
17
17
|
port=8000, # Port to host the server on
|
|
18
|
-
|
|
18
|
+
aes_key=aes_key # Key file for authentication to the network
|
|
19
19
|
))
|
|
20
20
|
```
|
|
21
21
|
|
|
@@ -26,10 +26,12 @@ To connect another node to we will copy the AES key file to the new machine and
|
|
|
26
26
|
```python
|
|
27
27
|
from distributed_state_network import DSNodeServer, DSNodeConfig
|
|
28
28
|
|
|
29
|
+
KEY = "..."
|
|
30
|
+
|
|
29
31
|
connector = DSNodeServer(DSNodeConfig(
|
|
30
32
|
node_id="connector", # New node ID
|
|
31
33
|
port=8000, # Port to host the new server on
|
|
32
|
-
|
|
34
|
+
aes_key= KEY, # Key file that was copied from first machine
|
|
33
35
|
bootstrap_nodes= [
|
|
34
36
|
{
|
|
35
37
|
# IP address of bootstrap node
|
|
@@ -8,10 +8,7 @@ sys.path.append(os.path.join(os.path.dirname(__file__), '../src'))
|
|
|
8
8
|
|
|
9
9
|
from distributed_state_network import DSNodeServer, DSNodeConfig, Endpoint
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
if not os.path.exists(KEY_FILE):
|
|
14
|
-
DSNodeServer.generate_key("network.key")
|
|
11
|
+
aes_key = DSNodeServer.generate_key()
|
|
15
12
|
|
|
16
13
|
cb_test = 0
|
|
17
14
|
|
|
@@ -22,7 +19,7 @@ def start_node(node_id: str, bootstrap_port: int = None, disconnect_cb: Optional
|
|
|
22
19
|
args = {
|
|
23
20
|
"node_id": node_id,
|
|
24
21
|
"port": current_port,
|
|
25
|
-
"
|
|
22
|
+
"aes_key": aes_key
|
|
26
23
|
}
|
|
27
24
|
current_port += 1
|
|
28
25
|
if bootstrap_port is not None:
|
|
@@ -7,23 +7,19 @@ 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
|
|
|
14
14
|
from distributed_state_network.objects.state_packet import StatePacket
|
|
15
15
|
from distributed_state_network.objects.hello_packet import HelloPacket
|
|
16
16
|
|
|
17
|
-
from distributed_state_network.util.key_manager import CertManager
|
|
18
17
|
from distributed_state_network.util.aes import generate_aes_key
|
|
19
18
|
|
|
20
19
|
current_port = 8000
|
|
21
20
|
nodes = []
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
if not os.path.exists(key_file):
|
|
26
|
-
DSNodeServer.generate_key(key_file)
|
|
22
|
+
aes_key = DSNodeServer.generate_key()
|
|
27
23
|
|
|
28
24
|
def spawn_node(node_id: str, bootstrap_nodes: List[Dict] = []):
|
|
29
25
|
global current_port
|
|
@@ -31,7 +27,7 @@ def spawn_node(node_id: str, bootstrap_nodes: List[Dict] = []):
|
|
|
31
27
|
n = DSNodeServer.start(DSNodeConfig.from_dict({
|
|
32
28
|
"node_id": node_id,
|
|
33
29
|
"port": current_port,
|
|
34
|
-
"
|
|
30
|
+
"aes_key": aes_key,
|
|
35
31
|
"bootstrap_nodes": bootstrap_nodes
|
|
36
32
|
}))
|
|
37
33
|
global nodes
|
|
@@ -264,7 +260,7 @@ class TestNode(unittest.TestCase):
|
|
|
264
260
|
config_dict = {
|
|
265
261
|
"node_id": "node",
|
|
266
262
|
"port": 8000,
|
|
267
|
-
"
|
|
263
|
+
"aes_key": "XXX",
|
|
268
264
|
"bootstrap_nodes": [
|
|
269
265
|
{
|
|
270
266
|
"address": "127.0.0.1",
|
|
@@ -276,7 +272,7 @@ class TestNode(unittest.TestCase):
|
|
|
276
272
|
config = DSNodeConfig.from_dict(config_dict)
|
|
277
273
|
self.assertEqual(config_dict["node_id"], config.node_id)
|
|
278
274
|
self.assertEqual(config_dict["port"], config.port)
|
|
279
|
-
self.assertEqual(config_dict["
|
|
275
|
+
self.assertEqual(config_dict["aes_key"], config.aes_key)
|
|
280
276
|
self.assertTrue(len(config.bootstrap_nodes) > 0)
|
|
281
277
|
self.assertEqual(config_dict["bootstrap_nodes"][0]["address"], config.bootstrap_nodes[0].address)
|
|
282
278
|
self.assertEqual(config_dict["bootstrap_nodes"][0]["port"], config.bootstrap_nodes[0].port)
|
|
@@ -307,30 +303,8 @@ class TestNode(unittest.TestCase):
|
|
|
307
303
|
print(e)
|
|
308
304
|
|
|
309
305
|
def test_aes(self):
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
with open(test_key_file, 'rb') as f:
|
|
313
|
-
key = f.read()
|
|
314
|
-
self.assertEqual(32, len(key))
|
|
315
|
-
os.remove(test_key_file)
|
|
316
|
-
|
|
317
|
-
def test_write_cert(self):
|
|
318
|
-
if os.path.exists('certs'):
|
|
319
|
-
shutil.rmtree('certs')
|
|
320
|
-
cm = CertManager('test')
|
|
321
|
-
cm.write_public('test', b'TEST')
|
|
322
|
-
self.assertTrue(os.path.exists('certs/test/test.crt'))
|
|
323
|
-
shutil.rmtree('certs')
|
|
324
|
-
|
|
325
|
-
def test_read_public(self):
|
|
326
|
-
if os.path.exists('certs'):
|
|
327
|
-
shutil.rmtree('certs')
|
|
328
|
-
cm = CertManager('test')
|
|
329
|
-
try:
|
|
330
|
-
cm.read_public('test')
|
|
331
|
-
except Exception as e:
|
|
332
|
-
self.assertEqual(e.args[0], 401)
|
|
333
|
-
self.assertEqual(e.args[1], "Cannot find public ECDSA key for test")
|
|
306
|
+
key = DSNodeServer.generate_key()
|
|
307
|
+
self.assertEqual(64, len(key))
|
|
334
308
|
|
|
335
309
|
def test_authentication_reset(self):
|
|
336
310
|
bootstrap = spawn_node("bootstrap")
|
{distributed_state_network-0.4.1 → distributed_state_network-0.5.0}/.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.5.0}/documentation/ds-node.md
RENAMED
|
File without changes
|
{distributed_state_network-0.4.1 → distributed_state_network-0.5.0}/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
|