neuronum 8.0.0__tar.gz → 8.1.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.
Potentially problematic release.
This version of neuronum might be problematic. Click here for more details.
- {neuronum-8.0.0 → neuronum-8.1.0}/PKG-INFO +3 -5
- {neuronum-8.0.0 → neuronum-8.1.0}/README.md +2 -4
- {neuronum-8.0.0 → neuronum-8.1.0}/cli/main.py +8 -8
- neuronum-8.1.0/neuronum/__init__.py +1 -0
- {neuronum-8.0.0 → neuronum-8.1.0}/neuronum/neuronum.py +9 -136
- {neuronum-8.0.0 → neuronum-8.1.0}/neuronum.egg-info/PKG-INFO +3 -5
- {neuronum-8.0.0 → neuronum-8.1.0}/setup.py +1 -1
- neuronum-8.0.0/neuronum/__init__.py +0 -2
- {neuronum-8.0.0 → neuronum-8.1.0}/LICENSE.md +0 -0
- {neuronum-8.0.0 → neuronum-8.1.0}/cli/__init__.py +0 -0
- {neuronum-8.0.0 → neuronum-8.1.0}/neuronum.egg-info/SOURCES.txt +0 -0
- {neuronum-8.0.0 → neuronum-8.1.0}/neuronum.egg-info/dependency_links.txt +0 -0
- {neuronum-8.0.0 → neuronum-8.1.0}/neuronum.egg-info/entry_points.txt +0 -0
- {neuronum-8.0.0 → neuronum-8.1.0}/neuronum.egg-info/requires.txt +0 -0
- {neuronum-8.0.0 → neuronum-8.1.0}/neuronum.egg-info/top_level.txt +0 -0
- {neuronum-8.0.0 → neuronum-8.1.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: neuronum
|
|
3
|
-
Version: 8.
|
|
3
|
+
Version: 8.1.0
|
|
4
4
|
Summary: The E2E Web Engine
|
|
5
5
|
Home-page: https://neuronum.net
|
|
6
6
|
Author: Neuronum Cybernetics
|
|
@@ -71,7 +71,7 @@ Neuronum is a real-time web engine designed for developers to build E2E-native a
|
|
|
71
71
|
### **Tools & Features**
|
|
72
72
|
- Cell: Account to interact with Neuronum
|
|
73
73
|
- Nodes: Apps & Services built on Neuronum
|
|
74
|
-
- Browser:
|
|
74
|
+
- Browser: Web Browser built on Neuronum -> [build from source](https://github.com/neuronumcybernetics/neuronum_browser)
|
|
75
75
|
|
|
76
76
|
### Requirements
|
|
77
77
|
- Python >= 3.8
|
|
@@ -100,8 +100,6 @@ neuronum connect-cell
|
|
|
100
100
|
|
|
101
101
|
|
|
102
102
|
### **Build On Neuronum**
|
|
103
|
-
Visit & build with [Node Examples](https://github.com/neuronumcybernetics/neuronum/tree/main/features/nodes/examples) to gain deeper knowledge on how to build on Neuronum.
|
|
104
|
-
|
|
105
103
|
To get started, initialize a new Node with the command below.
|
|
106
104
|
```sh
|
|
107
105
|
neuronum init-node
|
|
@@ -123,4 +121,4 @@ neuronum start-node
|
|
|
123
121
|
|
|
124
122
|
### **Interact with your Node**
|
|
125
123
|
|
|
126
|
-
The **Neuronum Browser** is an open source web
|
|
124
|
+
The **Neuronum Browser** is an open source E2E web browser that allows you to interact with your nodes -> [build from source](https://github.com/neuronumcybernetics/neuronum_browser)
|
|
@@ -36,7 +36,7 @@ Neuronum is a real-time web engine designed for developers to build E2E-native a
|
|
|
36
36
|
### **Tools & Features**
|
|
37
37
|
- Cell: Account to interact with Neuronum
|
|
38
38
|
- Nodes: Apps & Services built on Neuronum
|
|
39
|
-
- Browser:
|
|
39
|
+
- Browser: Web Browser built on Neuronum -> [build from source](https://github.com/neuronumcybernetics/neuronum_browser)
|
|
40
40
|
|
|
41
41
|
### Requirements
|
|
42
42
|
- Python >= 3.8
|
|
@@ -65,8 +65,6 @@ neuronum connect-cell
|
|
|
65
65
|
|
|
66
66
|
|
|
67
67
|
### **Build On Neuronum**
|
|
68
|
-
Visit & build with [Node Examples](https://github.com/neuronumcybernetics/neuronum/tree/main/features/nodes/examples) to gain deeper knowledge on how to build on Neuronum.
|
|
69
|
-
|
|
70
68
|
To get started, initialize a new Node with the command below.
|
|
71
69
|
```sh
|
|
72
70
|
neuronum init-node
|
|
@@ -88,4 +86,4 @@ neuronum start-node
|
|
|
88
86
|
|
|
89
87
|
### **Interact with your Node**
|
|
90
88
|
|
|
91
|
-
The **Neuronum Browser** is an open source web
|
|
89
|
+
The **Neuronum Browser** is an open source E2E web browser that allows you to interact with your nodes -> [build from source](https://github.com/neuronumcybernetics/neuronum_browser)
|
|
@@ -340,21 +340,21 @@ async def async_init_node(descr):
|
|
|
340
340
|
app_path = project_path / "app.py"
|
|
341
341
|
app_path.write_text(f"""\
|
|
342
342
|
import asyncio
|
|
343
|
-
import
|
|
343
|
+
from neuronum import Node
|
|
344
344
|
from jinja2 import Environment, FileSystemLoader
|
|
345
345
|
|
|
346
346
|
env = Environment(loader=FileSystemLoader('.'))
|
|
347
347
|
template = env.get_template('ping.html')
|
|
348
348
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
349
|
+
node = Node(
|
|
350
|
+
id="{node_id}",
|
|
351
|
+
private_key="{private_key_file}",
|
|
352
|
+
public_key="{public_key_file}"
|
|
352
353
|
)
|
|
353
354
|
|
|
354
355
|
async def main():
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
async for transmitter in cell.sync(node_id):
|
|
356
|
+
|
|
357
|
+
async for transmitter in node.sync():
|
|
358
358
|
ts = transmitter.get("time")
|
|
359
359
|
data = transmitter.get("data")
|
|
360
360
|
transmitter_id = transmitter.get("transmitter_id")
|
|
@@ -373,7 +373,7 @@ async def main():
|
|
|
373
373
|
"html": html_content
|
|
374
374
|
}}
|
|
375
375
|
|
|
376
|
-
await
|
|
376
|
+
await node.tx_response(transmitter_id, response_data, client_public_key)
|
|
377
377
|
|
|
378
378
|
asyncio.run(main())
|
|
379
379
|
""")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .neuronum import Node
|
|
@@ -14,10 +14,11 @@ from cryptography.hazmat.primitives.kdf.hkdf import HKDF
|
|
|
14
14
|
from cryptography.hazmat.backends import default_backend
|
|
15
15
|
|
|
16
16
|
|
|
17
|
-
class
|
|
18
|
-
def __init__(self,
|
|
19
|
-
self.
|
|
20
|
-
self.
|
|
17
|
+
class Node:
|
|
18
|
+
def __init__(self, id: str, private_key: str, public_key: str):
|
|
19
|
+
self.node_id = id
|
|
20
|
+
self.private_key_path = private_key
|
|
21
|
+
self.public_key_path = public_key
|
|
21
22
|
self.queue = asyncio.Queue()
|
|
22
23
|
self.host = self._load_host()
|
|
23
24
|
self.network = self._load_network()
|
|
@@ -184,8 +185,8 @@ class Cell:
|
|
|
184
185
|
return None
|
|
185
186
|
|
|
186
187
|
|
|
187
|
-
async def sync(self
|
|
188
|
-
full_url = f"wss://{self.network}/sync/{node_id}"
|
|
188
|
+
async def sync(self) -> AsyncGenerator[str, None]:
|
|
189
|
+
full_url = f"wss://{self.network}/sync/{self.node_id}"
|
|
189
190
|
auth_payload = {
|
|
190
191
|
"host": self.host,
|
|
191
192
|
"password": self.password,
|
|
@@ -261,108 +262,7 @@ class Cell:
|
|
|
261
262
|
print(f"Error sending request: {e}")
|
|
262
263
|
except Exception as e:
|
|
263
264
|
print(f"Unexpected error: {e}")
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
async def activate_tx(self, node_id: str, data: dict):
|
|
267
|
-
url = f"https://{self.network}/api/activate_tx/{node_id}"
|
|
268
|
-
|
|
269
|
-
nodes = await self.list_nodes()
|
|
270
|
-
|
|
271
|
-
target_public_key_pem = None
|
|
272
|
-
target_node = node_id
|
|
273
|
-
|
|
274
|
-
for node in nodes:
|
|
275
|
-
node_ids = node.get('config', {}).get('data_gateways', [])
|
|
276
|
-
for node_id_entry in node_ids:
|
|
277
|
-
if node_id_entry.get('node_id') == target_node:
|
|
278
|
-
target_public_key_pem = node.get('config', {}).get('public_key')
|
|
279
|
-
break
|
|
280
|
-
if target_public_key_pem:
|
|
281
|
-
break
|
|
282
|
-
|
|
283
|
-
if not target_public_key_pem:
|
|
284
|
-
print(f"Target node not found or public key is missing.")
|
|
285
|
-
return None
|
|
286
|
-
|
|
287
|
-
try:
|
|
288
|
-
print(target_public_key_pem)
|
|
289
|
-
partner_public_key_jwk = self._load_public_key_from_pem(target_public_key_pem)
|
|
290
|
-
if not partner_public_key_jwk:
|
|
291
|
-
print("Failed to convert public key to JWK format. Aborting.")
|
|
292
|
-
return None
|
|
293
|
-
|
|
294
|
-
partner_public_key = self._load_public_key_from_jwk(partner_public_key_jwk)
|
|
295
|
-
if not partner_public_key:
|
|
296
|
-
print("Failed to load partner's public key. Aborting.")
|
|
297
|
-
return None
|
|
298
|
-
|
|
299
|
-
data_to_encrypt = data.copy()
|
|
300
|
-
data_to_encrypt["publicKey"] = self.get_public_key_jwk()
|
|
301
|
-
|
|
302
|
-
encrypted_payload = self._encrypt_with_ecdh_aesgcm(partner_public_key, data_to_encrypt)
|
|
303
|
-
|
|
304
|
-
TX = {
|
|
305
|
-
"data": {
|
|
306
|
-
"encrypted": encrypted_payload
|
|
307
|
-
},
|
|
308
|
-
"cell": self.to_dict()
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
async with aiohttp.ClientSession() as session:
|
|
312
|
-
async with session.post(url, json=TX) as response:
|
|
313
|
-
if response.status == 504:
|
|
314
|
-
print(f"Gateway Timeout: No response from transmitter for txID: {node_id}")
|
|
315
|
-
return None
|
|
316
|
-
|
|
317
|
-
response.raise_for_status()
|
|
318
|
-
|
|
319
|
-
response_data = await response.json()
|
|
320
|
-
|
|
321
|
-
if "response" in response_data:
|
|
322
|
-
inner_response = response_data["response"]
|
|
323
|
-
|
|
324
|
-
if "ciphertext" in inner_response:
|
|
325
|
-
ephemeral_public_key_b64 = inner_response["ephemeralPublicKey"]
|
|
326
|
-
ephemeral_public_key_b64 += '=' * ((4 - len(ephemeral_public_key_b64) % 4) % 4)
|
|
327
|
-
ephemeral_public_key_bytes = base64.urlsafe_b64decode(ephemeral_public_key_b64)
|
|
328
|
-
|
|
329
|
-
nonce_b64 = inner_response["nonce"]
|
|
330
|
-
nonce_b64 += '=' * ((4 - len(nonce_b64) % 4) % 4)
|
|
331
|
-
nonce = base64.urlsafe_b64decode(nonce_b64)
|
|
332
|
-
|
|
333
|
-
ciphertext_b64 = inner_response["ciphertext"]
|
|
334
|
-
ciphertext_b64 += '=' * ((4 - len(ciphertext_b64) % 4) % 4)
|
|
335
|
-
ciphertext = base64.urlsafe_b64decode(ciphertext_b64)
|
|
336
|
-
|
|
337
|
-
decrypted_response = self._decrypt_with_ecdh_aesgcm(
|
|
338
|
-
ephemeral_public_key_bytes, nonce, ciphertext
|
|
339
|
-
)
|
|
340
|
-
|
|
341
|
-
if decrypted_response:
|
|
342
|
-
return decrypted_response
|
|
343
|
-
else:
|
|
344
|
-
print("Failed to decrypt server response.")
|
|
345
|
-
return None
|
|
346
|
-
else:
|
|
347
|
-
print("Server response was not encrypted as expected.")
|
|
348
|
-
return inner_response
|
|
349
|
-
|
|
350
|
-
else:
|
|
351
|
-
print("Unexpected response format.")
|
|
352
|
-
return response_data
|
|
353
|
-
|
|
354
|
-
except aiohttp.ClientResponseError as e:
|
|
355
|
-
print(f"HTTP Error: {e.status}, Message: {e.message}, URL: {e.request_info.url}")
|
|
356
|
-
return None
|
|
357
|
-
|
|
358
|
-
except aiohttp.ClientError as e:
|
|
359
|
-
print(f"Connection Error: {e}")
|
|
360
|
-
return None
|
|
361
|
-
|
|
362
|
-
except Exception as e:
|
|
363
|
-
print(f"Unexpected error: {e}")
|
|
364
|
-
return None
|
|
365
|
-
|
|
265
|
+
|
|
366
266
|
|
|
367
267
|
def _load_public_key_from_jwk(self, jwk):
|
|
368
268
|
try:
|
|
@@ -378,31 +278,6 @@ class Cell:
|
|
|
378
278
|
except (KeyError, ValueError, TypeError) as e:
|
|
379
279
|
print(f"Error loading public key from JWK string: {e}")
|
|
380
280
|
return None
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
def _load_public_key_from_pem(self, pem_string: str):
|
|
384
|
-
try:
|
|
385
|
-
print(pem_string)
|
|
386
|
-
corrected_pem_string = pem_string.replace("-----BEGINPUBLICKEY-----", "-----BEGIN PUBLIC KEY-----")
|
|
387
|
-
corrected_pem_string = corrected_pem_string.replace("-----ENDPUBLICKEY-----", "-----END PUBLIC KEY-----")
|
|
388
|
-
|
|
389
|
-
public_key = serialization.load_pem_public_key(
|
|
390
|
-
corrected_pem_string.encode(),
|
|
391
|
-
backend=default_backend()
|
|
392
|
-
)
|
|
393
|
-
|
|
394
|
-
public_numbers = public_key.public_numbers()
|
|
395
|
-
x_bytes = public_numbers.x.to_bytes((public_numbers.x.bit_length() + 7) // 8, 'big')
|
|
396
|
-
y_bytes = public_numbers.y.to_bytes((public_numbers.y.bit_length() + 7) // 8, 'big')
|
|
397
|
-
return {
|
|
398
|
-
"kty": "EC",
|
|
399
|
-
"crv": "P-256",
|
|
400
|
-
"x": base64.urlsafe_b64encode(x_bytes).rstrip(b'=').decode('utf-8'),
|
|
401
|
-
"y": base64.urlsafe_b64encode(y_bytes).rstrip(b'=').decode('utf-8')
|
|
402
|
-
}
|
|
403
|
-
except Exception as e:
|
|
404
|
-
print(f"Error loading public key from PEM string: {e}")
|
|
405
|
-
return None
|
|
406
281
|
|
|
407
282
|
|
|
408
283
|
def _encrypt_with_ecdh_aesgcm(self, public_key, plaintext_dict):
|
|
@@ -462,6 +337,4 @@ class Cell:
|
|
|
462
337
|
except aiohttp.ClientError as e:
|
|
463
338
|
print(f"Error sending request: {e}")
|
|
464
339
|
except Exception as e:
|
|
465
|
-
print(f"Unexpected error: {e}")
|
|
466
|
-
|
|
467
|
-
__all__ = ['Cell']
|
|
340
|
+
print(f"Unexpected error: {e}")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: neuronum
|
|
3
|
-
Version: 8.
|
|
3
|
+
Version: 8.1.0
|
|
4
4
|
Summary: The E2E Web Engine
|
|
5
5
|
Home-page: https://neuronum.net
|
|
6
6
|
Author: Neuronum Cybernetics
|
|
@@ -71,7 +71,7 @@ Neuronum is a real-time web engine designed for developers to build E2E-native a
|
|
|
71
71
|
### **Tools & Features**
|
|
72
72
|
- Cell: Account to interact with Neuronum
|
|
73
73
|
- Nodes: Apps & Services built on Neuronum
|
|
74
|
-
- Browser:
|
|
74
|
+
- Browser: Web Browser built on Neuronum -> [build from source](https://github.com/neuronumcybernetics/neuronum_browser)
|
|
75
75
|
|
|
76
76
|
### Requirements
|
|
77
77
|
- Python >= 3.8
|
|
@@ -100,8 +100,6 @@ neuronum connect-cell
|
|
|
100
100
|
|
|
101
101
|
|
|
102
102
|
### **Build On Neuronum**
|
|
103
|
-
Visit & build with [Node Examples](https://github.com/neuronumcybernetics/neuronum/tree/main/features/nodes/examples) to gain deeper knowledge on how to build on Neuronum.
|
|
104
|
-
|
|
105
103
|
To get started, initialize a new Node with the command below.
|
|
106
104
|
```sh
|
|
107
105
|
neuronum init-node
|
|
@@ -123,4 +121,4 @@ neuronum start-node
|
|
|
123
121
|
|
|
124
122
|
### **Interact with your Node**
|
|
125
123
|
|
|
126
|
-
The **Neuronum Browser** is an open source web
|
|
124
|
+
The **Neuronum Browser** is an open source E2E web browser that allows you to interact with your nodes -> [build from source](https://github.com/neuronumcybernetics/neuronum_browser)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|