arthexis 0.1.16__py3-none-any.whl → 0.1.26__py3-none-any.whl
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 arthexis might be problematic. Click here for more details.
- {arthexis-0.1.16.dist-info → arthexis-0.1.26.dist-info}/METADATA +84 -35
- arthexis-0.1.26.dist-info/RECORD +111 -0
- config/asgi.py +1 -15
- config/middleware.py +47 -1
- config/settings.py +15 -30
- config/urls.py +53 -1
- core/admin.py +540 -450
- core/apps.py +0 -6
- core/auto_upgrade.py +19 -4
- core/backends.py +13 -3
- core/changelog.py +66 -5
- core/environment.py +4 -5
- core/models.py +1566 -203
- core/notifications.py +1 -1
- core/reference_utils.py +10 -11
- core/release.py +55 -7
- core/sigil_builder.py +2 -2
- core/sigil_resolver.py +1 -66
- core/system.py +268 -2
- core/tasks.py +174 -48
- core/tests.py +314 -16
- core/user_data.py +42 -2
- core/views.py +278 -183
- nodes/admin.py +557 -65
- nodes/apps.py +11 -0
- nodes/models.py +658 -113
- nodes/rfid_sync.py +1 -1
- nodes/tasks.py +97 -2
- nodes/tests.py +1212 -116
- nodes/urls.py +15 -1
- nodes/utils.py +51 -3
- nodes/views.py +1239 -154
- ocpp/admin.py +979 -152
- ocpp/consumers.py +268 -28
- ocpp/models.py +488 -3
- ocpp/network.py +398 -0
- ocpp/store.py +6 -4
- ocpp/tasks.py +296 -2
- ocpp/test_export_import.py +1 -0
- ocpp/test_rfid.py +121 -4
- ocpp/tests.py +950 -11
- ocpp/transactions_io.py +9 -1
- ocpp/urls.py +3 -3
- ocpp/views.py +596 -51
- pages/admin.py +262 -30
- pages/apps.py +35 -0
- pages/context_processors.py +26 -21
- pages/defaults.py +1 -1
- pages/forms.py +31 -8
- pages/middleware.py +6 -2
- pages/models.py +77 -2
- pages/module_defaults.py +5 -5
- pages/site_config.py +137 -0
- pages/tests.py +885 -109
- pages/urls.py +13 -2
- pages/utils.py +70 -0
- pages/views.py +558 -55
- arthexis-0.1.16.dist-info/RECORD +0 -111
- core/workgroup_urls.py +0 -17
- core/workgroup_views.py +0 -94
- {arthexis-0.1.16.dist-info → arthexis-0.1.26.dist-info}/WHEEL +0 -0
- {arthexis-0.1.16.dist-info → arthexis-0.1.26.dist-info}/licenses/LICENSE +0 -0
- {arthexis-0.1.16.dist-info → arthexis-0.1.26.dist-info}/top_level.txt +0 -0
nodes/rfid_sync.py
CHANGED
|
@@ -99,7 +99,7 @@ def apply_rfid_payload(
|
|
|
99
99
|
last_seen = entry.get("last_seen_on")
|
|
100
100
|
defaults["last_seen_on"] = parse_datetime(last_seen) if last_seen else None
|
|
101
101
|
|
|
102
|
-
obj, created = RFID.
|
|
102
|
+
obj, created = RFID.update_or_create_from_code(rfid_value, defaults=defaults)
|
|
103
103
|
|
|
104
104
|
outcome.instance = obj
|
|
105
105
|
outcome.created = created
|
nodes/tasks.py
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
|
+
import base64
|
|
2
|
+
import json
|
|
1
3
|
import logging
|
|
2
4
|
from pathlib import Path
|
|
3
5
|
|
|
4
6
|
import pyperclip
|
|
5
|
-
|
|
7
|
+
import requests
|
|
6
8
|
from celery import shared_task
|
|
9
|
+
from cryptography.hazmat.primitives import hashes, serialization
|
|
10
|
+
from cryptography.hazmat.primitives.asymmetric import padding
|
|
11
|
+
from pyperclip import PyperclipException
|
|
7
12
|
|
|
8
|
-
from .models import ContentSample, Node
|
|
13
|
+
from .models import ContentSample, NetMessage, Node
|
|
9
14
|
from .utils import capture_screenshot, save_screenshot
|
|
10
15
|
|
|
11
16
|
logger = logging.getLogger(__name__)
|
|
@@ -44,3 +49,93 @@ def capture_node_screenshot(
|
|
|
44
49
|
node = Node.get_local()
|
|
45
50
|
save_screenshot(path, node=node, method=method)
|
|
46
51
|
return str(path)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@shared_task
|
|
55
|
+
def poll_unreachable_upstream() -> None:
|
|
56
|
+
"""Poll upstream nodes for queued NetMessages."""
|
|
57
|
+
|
|
58
|
+
local = Node.get_local()
|
|
59
|
+
if not local or not local.has_feature("celery-queue"):
|
|
60
|
+
return
|
|
61
|
+
|
|
62
|
+
private_key = local.get_private_key()
|
|
63
|
+
if not private_key:
|
|
64
|
+
logger.warning("Node %s cannot sign upstream polls", getattr(local, "pk", None))
|
|
65
|
+
return
|
|
66
|
+
|
|
67
|
+
requester_payload = {"requester": str(local.uuid)}
|
|
68
|
+
payload_json = json.dumps(requester_payload, separators=(",", ":"), sort_keys=True)
|
|
69
|
+
try:
|
|
70
|
+
signature = base64.b64encode(
|
|
71
|
+
private_key.sign(
|
|
72
|
+
payload_json.encode(),
|
|
73
|
+
padding.PKCS1v15(),
|
|
74
|
+
hashes.SHA256(),
|
|
75
|
+
)
|
|
76
|
+
).decode()
|
|
77
|
+
except Exception as exc:
|
|
78
|
+
logger.warning("Failed to sign upstream poll request: %s", exc)
|
|
79
|
+
return
|
|
80
|
+
|
|
81
|
+
headers = {"Content-Type": "application/json", "X-Signature": signature}
|
|
82
|
+
upstream_nodes = Node.objects.filter(current_relation=Node.Relation.UPSTREAM)
|
|
83
|
+
for upstream in upstream_nodes:
|
|
84
|
+
if not upstream.public_key:
|
|
85
|
+
continue
|
|
86
|
+
response = None
|
|
87
|
+
for url in upstream.iter_remote_urls("/nodes/net-message/pull/"):
|
|
88
|
+
try:
|
|
89
|
+
response = requests.post(
|
|
90
|
+
url, data=payload_json, headers=headers, timeout=5
|
|
91
|
+
)
|
|
92
|
+
except Exception as exc:
|
|
93
|
+
logger.warning("Polling upstream node %s via %s failed: %s", upstream.pk, url, exc)
|
|
94
|
+
continue
|
|
95
|
+
if response.ok:
|
|
96
|
+
break
|
|
97
|
+
logger.warning(
|
|
98
|
+
"Upstream node %s returned status %s", upstream.pk, response.status_code
|
|
99
|
+
)
|
|
100
|
+
response = None
|
|
101
|
+
if response is None or not response.ok:
|
|
102
|
+
continue
|
|
103
|
+
try:
|
|
104
|
+
body = response.json()
|
|
105
|
+
except ValueError:
|
|
106
|
+
logger.warning("Upstream node %s returned invalid JSON", upstream.pk)
|
|
107
|
+
continue
|
|
108
|
+
messages = body.get("messages", [])
|
|
109
|
+
if not isinstance(messages, list) or not messages:
|
|
110
|
+
continue
|
|
111
|
+
try:
|
|
112
|
+
public_key = serialization.load_pem_public_key(upstream.public_key.encode())
|
|
113
|
+
except Exception:
|
|
114
|
+
logger.warning("Upstream node %s has invalid public key", upstream.pk)
|
|
115
|
+
continue
|
|
116
|
+
for item in messages:
|
|
117
|
+
if not isinstance(item, dict):
|
|
118
|
+
continue
|
|
119
|
+
payload = item.get("payload")
|
|
120
|
+
payload_signature = item.get("signature")
|
|
121
|
+
if not isinstance(payload, dict) or not payload_signature:
|
|
122
|
+
continue
|
|
123
|
+
payload_text = json.dumps(payload, separators=(",", ":"), sort_keys=True)
|
|
124
|
+
try:
|
|
125
|
+
public_key.verify(
|
|
126
|
+
base64.b64decode(payload_signature),
|
|
127
|
+
payload_text.encode(),
|
|
128
|
+
padding.PKCS1v15(),
|
|
129
|
+
hashes.SHA256(),
|
|
130
|
+
)
|
|
131
|
+
except Exception:
|
|
132
|
+
logger.warning(
|
|
133
|
+
"Signature verification failed for upstream node %s", upstream.pk
|
|
134
|
+
)
|
|
135
|
+
continue
|
|
136
|
+
try:
|
|
137
|
+
NetMessage.receive_payload(payload, sender=upstream)
|
|
138
|
+
except ValueError as exc:
|
|
139
|
+
logger.warning(
|
|
140
|
+
"Discarded upstream message from node %s: %s", upstream.pk, exc
|
|
141
|
+
)
|