distributed-state-network 0.4.0__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.
Files changed (32) hide show
  1. {distributed_state_network-0.4.0 → distributed_state_network-0.4.2}/PKG-INFO +1 -6
  2. {distributed_state_network-0.4.0 → distributed_state_network-0.4.2}/README.md +0 -5
  3. {distributed_state_network-0.4.0 → distributed_state_network-0.4.2}/pyproject.toml +1 -1
  4. {distributed_state_network-0.4.0 → distributed_state_network-0.4.2}/src/distributed_state_network/create_key.py +2 -2
  5. {distributed_state_network-0.4.0 → distributed_state_network-0.4.2}/src/distributed_state_network/dsnode.py +16 -10
  6. {distributed_state_network-0.4.0 → distributed_state_network-0.4.2}/src/distributed_state_network/handler.py +11 -9
  7. {distributed_state_network-0.4.0 → distributed_state_network-0.4.2}/src/distributed_state_network/objects/config.py +2 -2
  8. {distributed_state_network-0.4.0 → distributed_state_network-0.4.2/tests}/test.py +2 -2
  9. {distributed_state_network-0.4.0 → distributed_state_network-0.4.2}/.github/workflows/publish.yml +0 -0
  10. {distributed_state_network-0.4.0 → distributed_state_network-0.4.2}/.gitignore +0 -0
  11. {distributed_state_network-0.4.0 → distributed_state_network-0.4.2}/LICENSE +0 -0
  12. {distributed_state_network-0.4.0 → distributed_state_network-0.4.2}/coverage.sh +0 -0
  13. {distributed_state_network-0.4.0 → distributed_state_network-0.4.2}/documentation/ds-node-config.md +0 -0
  14. {distributed_state_network-0.4.0 → distributed_state_network-0.4.2}/documentation/ds-node-server.md +0 -0
  15. {distributed_state_network-0.4.0 → distributed_state_network-0.4.2}/documentation/ds-node.md +0 -0
  16. {distributed_state_network-0.4.0 → distributed_state_network-0.4.2}/documentation/protocol.md +0 -0
  17. {distributed_state_network-0.4.0 → distributed_state_network-0.4.2}/documentation/usage.md +0 -0
  18. {distributed_state_network-0.4.0 → distributed_state_network-0.4.2}/src/distributed_state_network/__init__.py +0 -0
  19. {distributed_state_network-0.4.0 → distributed_state_network-0.4.2}/src/distributed_state_network/objects/endpoint.py +0 -0
  20. {distributed_state_network-0.4.0 → distributed_state_network-0.4.2}/src/distributed_state_network/objects/hello_packet.py +0 -0
  21. {distributed_state_network-0.4.0 → distributed_state_network-0.4.2}/src/distributed_state_network/objects/msg_types.py +0 -0
  22. {distributed_state_network-0.4.0 → distributed_state_network-0.4.2}/src/distributed_state_network/objects/peers_packet.py +0 -0
  23. {distributed_state_network-0.4.0 → distributed_state_network-0.4.2}/src/distributed_state_network/objects/signed_packet.py +0 -0
  24. {distributed_state_network-0.4.0 → distributed_state_network-0.4.2}/src/distributed_state_network/objects/state_packet.py +0 -0
  25. {distributed_state_network-0.4.0 → distributed_state_network-0.4.2}/src/distributed_state_network/util/__init__.py +0 -0
  26. {distributed_state_network-0.4.0 → distributed_state_network-0.4.2}/src/distributed_state_network/util/aes.py +0 -0
  27. {distributed_state_network-0.4.0 → distributed_state_network-0.4.2}/src/distributed_state_network/util/byte_helper.py +0 -0
  28. {distributed_state_network-0.4.0 → distributed_state_network-0.4.2}/src/distributed_state_network/util/ecdsa.py +0 -0
  29. {distributed_state_network-0.4.0 → distributed_state_network-0.4.2}/src/distributed_state_network/util/https.py +0 -0
  30. {distributed_state_network-0.4.0 → distributed_state_network-0.4.2}/src/distributed_state_network/util/key_manager.py +0 -0
  31. {distributed_state_network-0.4.0 → distributed_state_network-0.4.2}/technical.md +0 -0
  32. {distributed_state_network-0.4.0 → 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.0
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.0"
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"]
@@ -6,5 +6,5 @@ if len(sys.argv) < 2:
6
6
 
7
7
  location = sys.argv[1]
8
8
 
9
- with open(location, 'wb') as f:
10
- f.write(generate_aes_key())
9
+ with open(location, 'w') as f:
10
+ f.write(generate_aes_key().hex())
@@ -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,8 +75,11 @@ class DSNode:
75
75
  self.server = server
76
76
 
77
77
  def get_aes_key(self):
78
- with open(self.config.aes_key_file, 'rb') as f:
79
- return f.read()
78
+ if not os.path.exists(self.config.aes_key_file):
79
+ raise Exception("Could not find aes key file")
80
+ with open(self.config.aes_key_file, 'r') as f:
81
+ key_hex = f.read()
82
+ return bytes.fromhex(key_hex)
80
83
 
81
84
  def network_tick(self):
82
85
  time.sleep(TICK_INTERVAL)
@@ -109,8 +112,9 @@ class DSNode:
109
112
  """Send HTTP request and wait for response"""
110
113
  try:
111
114
  # Prepend message type to payload
112
- data_with_type = bytes([msg_type]) + payload
113
- encrypted_data = self.encrypt_data(data_with_type)
115
+ data = bytes([msg_type]) + payload
116
+ if self.config.aes_key_file is not None:
117
+ data = self.encrypt_data(data)
114
118
 
115
119
  # Determine the URL path based on message type
116
120
  path = MSG_TYPE_TO_PATH.get(msg_type, '/unknown')
@@ -119,7 +123,7 @@ class DSNode:
119
123
  # Send HTTP POST request
120
124
  response = requests.post(
121
125
  url,
122
- data=encrypted_data,
126
+ data=data,
123
127
  headers={'Content-Type': 'application/octet-stream'},
124
128
  timeout=HTTP_TIMEOUT
125
129
  )
@@ -131,19 +135,21 @@ class DSNode:
131
135
  elif response.status_code != 200:
132
136
  raise Exception(f"HTTP error: {response.status_code}")
133
137
 
138
+ response_data = response.content
134
139
  # Decrypt the response
135
- decrypted = self.decrypt_data(response.content)
140
+ if self.config.aes_key_file is not None:
141
+ response_data = self.decrypt_data(response_data)
136
142
 
137
- if len(decrypted) < 1:
143
+ if len(response_data) < 1:
138
144
  raise Exception("Empty response")
139
145
 
140
146
  # First byte is message type
141
- response_msg_type = decrypted[0]
147
+ response_msg_type = response_data[0]
142
148
  if response_msg_type != msg_type:
143
149
  raise Exception(f"Response message type mismatch: expected {msg_type}, got {response_msg_type}")
144
150
 
145
151
  # Return the body (everything after the message type byte)
146
- return decrypted[1:]
152
+ return response_data[1:]
147
153
 
148
154
  except requests.exceptions.Timeout:
149
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.0"
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
- decrypted = self.node.decrypt_data(data)
69
+ if self.config.aes_key_file is not None:
70
+ data = self.node.decrypt_data(data)
70
71
 
71
- if len(decrypted) < 1:
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 = decrypted[0]
76
- body = decrypted[1:]
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
- encrypted_response = self.node.encrypt_data(response_with_type)
102
- return Response(encrypted_response, status=200, mimetype='application/octet-stream')
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, 'wb') as f:
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__), './src'))
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(32, len(key))
314
+ self.assertEqual(64, len(key))
315
315
  os.remove(test_key_file)
316
316
 
317
317
  def test_write_cert(self):