distributed-state-network 0.6.3__tar.gz → 0.6.4__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 (33) hide show
  1. {distributed_state_network-0.6.3 → distributed_state_network-0.6.4}/PKG-INFO +1 -1
  2. {distributed_state_network-0.6.3 → distributed_state_network-0.6.4}/pyproject.toml +1 -1
  3. {distributed_state_network-0.6.3 → distributed_state_network-0.6.4}/src/distributed_state_network/handler.py +10 -1
  4. {distributed_state_network-0.6.3 → distributed_state_network-0.6.4}/tests/test.py +53 -1
  5. {distributed_state_network-0.6.3 → distributed_state_network-0.6.4}/.github/workflows/publish.yml +0 -0
  6. {distributed_state_network-0.6.3 → distributed_state_network-0.6.4}/.gitignore +0 -0
  7. {distributed_state_network-0.6.3 → distributed_state_network-0.6.4}/LICENSE +0 -0
  8. {distributed_state_network-0.6.3 → distributed_state_network-0.6.4}/README.md +0 -0
  9. {distributed_state_network-0.6.3 → distributed_state_network-0.6.4}/coverage.sh +0 -0
  10. {distributed_state_network-0.6.3 → distributed_state_network-0.6.4}/documentation/ds-node-config.md +0 -0
  11. {distributed_state_network-0.6.3 → distributed_state_network-0.6.4}/documentation/ds-node-server.md +0 -0
  12. {distributed_state_network-0.6.3 → distributed_state_network-0.6.4}/documentation/ds-node.md +0 -0
  13. {distributed_state_network-0.6.3 → distributed_state_network-0.6.4}/documentation/protocol.md +0 -0
  14. {distributed_state_network-0.6.3 → distributed_state_network-0.6.4}/documentation/usage.md +0 -0
  15. {distributed_state_network-0.6.3 → distributed_state_network-0.6.4}/src/distributed_state_network/__init__.py +0 -0
  16. {distributed_state_network-0.6.3 → distributed_state_network-0.6.4}/src/distributed_state_network/create_key.py +0 -0
  17. {distributed_state_network-0.6.3 → distributed_state_network-0.6.4}/src/distributed_state_network/dsnode.py +0 -0
  18. {distributed_state_network-0.6.3 → distributed_state_network-0.6.4}/src/distributed_state_network/objects/config.py +0 -0
  19. {distributed_state_network-0.6.3 → distributed_state_network-0.6.4}/src/distributed_state_network/objects/data_packet.py +0 -0
  20. {distributed_state_network-0.6.3 → distributed_state_network-0.6.4}/src/distributed_state_network/objects/endpoint.py +0 -0
  21. {distributed_state_network-0.6.3 → distributed_state_network-0.6.4}/src/distributed_state_network/objects/hello_packet.py +0 -0
  22. {distributed_state_network-0.6.3 → distributed_state_network-0.6.4}/src/distributed_state_network/objects/msg_types.py +0 -0
  23. {distributed_state_network-0.6.3 → distributed_state_network-0.6.4}/src/distributed_state_network/objects/peers_packet.py +0 -0
  24. {distributed_state_network-0.6.3 → distributed_state_network-0.6.4}/src/distributed_state_network/objects/signed_packet.py +0 -0
  25. {distributed_state_network-0.6.3 → distributed_state_network-0.6.4}/src/distributed_state_network/objects/state_packet.py +0 -0
  26. {distributed_state_network-0.6.3 → distributed_state_network-0.6.4}/src/distributed_state_network/util/__init__.py +0 -0
  27. {distributed_state_network-0.6.3 → distributed_state_network-0.6.4}/src/distributed_state_network/util/aes.py +0 -0
  28. {distributed_state_network-0.6.3 → distributed_state_network-0.6.4}/src/distributed_state_network/util/byte_helper.py +0 -0
  29. {distributed_state_network-0.6.3 → distributed_state_network-0.6.4}/src/distributed_state_network/util/ecdsa.py +0 -0
  30. {distributed_state_network-0.6.3 → distributed_state_network-0.6.4}/src/distributed_state_network/util/https.py +0 -0
  31. {distributed_state_network-0.6.3 → distributed_state_network-0.6.4}/src/distributed_state_network/util/key_manager.py +0 -0
  32. {distributed_state_network-0.6.3 → distributed_state_network-0.6.4}/technical.md +0 -0
  33. {distributed_state_network-0.6.3 → distributed_state_network-0.6.4}/tests/connections.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: distributed-state-network
3
- Version: 0.6.3
3
+ Version: 0.6.4
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
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "distributed-state-network"
7
- version = "0.6.3"
7
+ version = "0.6.4"
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"]
@@ -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.6.3"
11
+ VERSION = "0.6.4"
12
12
  logging.basicConfig(level=logging.INFO)
13
13
 
14
14
  # Silence Flask and Werkzeug logging
@@ -19,6 +19,7 @@ MSG_HELLO = 1
19
19
  MSG_PEERS = 2
20
20
  MSG_UPDATE = 3
21
21
  MSG_PING = 4
22
+ MSG_DATA = 5
22
23
 
23
24
  class DSNodeServer:
24
25
  def __init__(
@@ -60,6 +61,11 @@ class DSNodeServer:
60
61
  def handle_ping_route():
61
62
  return self._handle_request(MSG_PING, request.data, request.remote_addr)
62
63
 
64
+ @self.app.route('/data', methods=['POST'])
65
+ def handle_data_route():
66
+ return self._handle_request(MSG_DATA, request.data, request.remote_addr)
67
+
68
+
63
69
  def _handle_request(self, msg_type: int, data: bytes, remote_addr: str) -> Response:
64
70
  if not self.running:
65
71
  return Response(status=500)
@@ -94,6 +100,9 @@ class DSNodeServer:
94
100
 
95
101
  elif msg_type == MSG_PING:
96
102
  response_data = b''
103
+
104
+ elif msg_type == MSG_DATA:
105
+ response_data = self.node.receive_data(body)
97
106
 
98
107
  # Send response if handler returned data
99
108
  if response_data is not None:
@@ -13,6 +13,7 @@ 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
+ from distributed_state_network.objects.data_packet import DataPacket
16
17
 
17
18
  from distributed_state_network.util.aes import generate_aes_key
18
19
 
@@ -481,7 +482,7 @@ class TestNode(unittest.TestCase):
481
482
  n = spawn_node("http-test-node")
482
483
 
483
484
  # Test that all endpoints exist
484
- endpoints = ['/hello', '/peers', '/update', '/ping']
485
+ endpoints = ['/hello', '/peers', '/update', '/ping', '/data']
485
486
 
486
487
  for endpoint in endpoints:
487
488
  # Send a request to each endpoint (will fail due to encryption, but should return 400/500, not 404)
@@ -497,5 +498,56 @@ class TestNode(unittest.TestCase):
497
498
  except Exception as e:
498
499
  print(f"Endpoint {endpoint} test failed: {e}")
499
500
 
501
+ def test_send_to_node_success(self):
502
+ bootstrap = spawn_node("bootstrap")
503
+ connector = spawn_node("connector", [bootstrap.node.my_con().to_json()])
504
+
505
+ # Direct DSNode API
506
+ resp = connector.node.send_to_node("bootstrap", b"Hello, world!")
507
+ self.assertEqual(resp, "OK")
508
+
509
+ def test_send_to_node_wrapper(self):
510
+ bootstrap = spawn_node("bootstrap")
511
+ connector = spawn_node("connector", [bootstrap.node.my_con().to_json()])
512
+
513
+ # DSNodeServer wrapper
514
+ resp = connector.send_to_node("bootstrap", b"Hello via wrapper")
515
+ self.assertEqual(resp, "OK")
516
+
517
+ def test_data_route_unknown_sender(self):
518
+ # Start a single node; it should reject data packets from unknown senders
519
+ n = spawn_node("node")
520
+ time.sleep(0.5) # Allow server to start
521
+
522
+ # Craft a DataPacket with a node_id that's not in address book
523
+ pkt = DataPacket("unknown", b"", b"payload")
524
+ encrypted = n.node.encrypt_data(bytes([5]) + pkt.to_bytes()) # MSG_DATA = 5
525
+
526
+ response = requests.post(
527
+ f'http://127.0.0.1:{n.config.port}/data',
528
+ data=encrypted,
529
+ headers={'Content-Type': 'application/octet-stream'},
530
+ timeout=2
531
+ )
532
+ self.assertEqual(response.status_code, 401)
533
+
534
+ def test_data_route_bad_signature(self):
535
+ # Connect two nodes so bootstrap knows connector's public key
536
+ bootstrap = spawn_node("bootstrap")
537
+ connector = spawn_node("connector", [bootstrap.node.my_con().to_json()])
538
+
539
+ # Create a packet claiming to be from connector but without a valid signature
540
+ pkt = DataPacket("connector", b"", b"payload")
541
+ encrypted = bootstrap.node.encrypt_data(bytes([5]) + pkt.to_bytes()) # MSG_DATA = 5
542
+
543
+ response = requests.post(
544
+ f'http://127.0.0.1:{bootstrap.config.port}/data',
545
+ data=encrypted,
546
+ headers={'Content-Type': 'application/octet-stream'},
547
+ timeout=2
548
+ )
549
+ # Should be unauthorized due to bad signature
550
+ self.assertEqual(response.status_code, 401)
551
+
500
552
  if __name__ == "__main__":
501
553
  unittest.main()