syntaxmatrix 2.6.4.3__py3-none-any.whl → 3.0.0__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.
- syntaxmatrix/__init__.py +6 -4
- syntaxmatrix/agentic/agents.py +195 -15
- syntaxmatrix/agentic/agents_orchestrer.py +16 -10
- syntaxmatrix/client_docs.py +237 -0
- syntaxmatrix/commentary.py +96 -25
- syntaxmatrix/core.py +156 -54
- syntaxmatrix/dataset_preprocessing.py +2 -2
- syntaxmatrix/db.py +60 -0
- syntaxmatrix/db_backends/__init__.py +1 -0
- syntaxmatrix/db_backends/postgres_backend.py +14 -0
- syntaxmatrix/db_backends/sqlite_backend.py +258 -0
- syntaxmatrix/db_contract.py +71 -0
- syntaxmatrix/kernel_manager.py +174 -150
- syntaxmatrix/page_builder_generation.py +654 -50
- syntaxmatrix/page_layout_contract.py +25 -3
- syntaxmatrix/page_patch_publish.py +368 -15
- syntaxmatrix/plugins/__init__.py +0 -0
- syntaxmatrix/plugins/plugin_manager.py +114 -0
- syntaxmatrix/premium/__init__.py +18 -0
- syntaxmatrix/premium/catalogue/__init__.py +121 -0
- syntaxmatrix/premium/gate.py +119 -0
- syntaxmatrix/premium/state.py +507 -0
- syntaxmatrix/premium/verify.py +222 -0
- syntaxmatrix/profiles.py +1 -1
- syntaxmatrix/routes.py +9782 -8004
- syntaxmatrix/settings/model_map.py +50 -65
- syntaxmatrix/settings/prompts.py +1435 -380
- syntaxmatrix/settings/string_navbar.py +4 -4
- syntaxmatrix/static/icons/bot_icon.png +0 -0
- syntaxmatrix/static/icons/bot_icon2.png +0 -0
- syntaxmatrix/templates/admin_billing.html +408 -0
- syntaxmatrix/templates/admin_branding.html +65 -2
- syntaxmatrix/templates/admin_features.html +54 -0
- syntaxmatrix/templates/dashboard.html +285 -8
- syntaxmatrix/templates/edit_page.html +199 -18
- syntaxmatrix/themes.py +17 -17
- syntaxmatrix/workspace_db.py +0 -23
- syntaxmatrix-3.0.0.dist-info/METADATA +219 -0
- {syntaxmatrix-2.6.4.3.dist-info → syntaxmatrix-3.0.0.dist-info}/RECORD +42 -30
- {syntaxmatrix-2.6.4.3.dist-info → syntaxmatrix-3.0.0.dist-info}/WHEEL +1 -1
- syntaxmatrix/settings/default.yaml +0 -13
- syntaxmatrix-2.6.4.3.dist-info/METADATA +0 -539
- syntaxmatrix-2.6.4.3.dist-info/licenses/LICENSE.txt +0 -21
- /syntaxmatrix/static/icons/{logo3.png → logo2.png} +0 -0
- {syntaxmatrix-2.6.4.3.dist-info → syntaxmatrix-3.0.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import base64
|
|
4
|
+
import hashlib
|
|
5
|
+
import json
|
|
6
|
+
import os
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from datetime import datetime
|
|
9
|
+
from typing import Any, Dict, Optional
|
|
10
|
+
|
|
11
|
+
from syntaxmatrix.project_root import detect_project_root
|
|
12
|
+
|
|
13
|
+
try:
|
|
14
|
+
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
|
|
15
|
+
except Exception:
|
|
16
|
+
Ed25519PublicKey = None
|
|
17
|
+
|
|
18
|
+
DEFAULT_PUBLIC_KEY_B64 = (
|
|
19
|
+
(os.environ.get("SMX_PREMIUM_PUBLIC_KEY_B64") or "").strip()
|
|
20
|
+
or "Pne3EX_NoOo6pZ4UB87kpXaTf78A6tEfuwoTBZvVRbg"
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
_CACHED_PUBLIC_KEY_B64: Optional[str] = None
|
|
24
|
+
SECRET_KEY_FILENAME = ".smx_secret_key"
|
|
25
|
+
|
|
26
|
+
def _utcnow() -> datetime:
|
|
27
|
+
return datetime.utcnow()
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _resolved_client_dir() -> str:
|
|
31
|
+
return str(detect_project_root())
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _parse_iso_utc(s: str) -> Optional[datetime]:
|
|
35
|
+
if not s:
|
|
36
|
+
return None
|
|
37
|
+
s = str(s).strip()
|
|
38
|
+
if not s:
|
|
39
|
+
return None
|
|
40
|
+
s2 = s.replace(" ", "T")
|
|
41
|
+
if s2.endswith("Z"):
|
|
42
|
+
s2 = s2[:-1]
|
|
43
|
+
try:
|
|
44
|
+
return datetime.fromisoformat(s2)
|
|
45
|
+
except Exception:
|
|
46
|
+
return None
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _b64url_decode(s: str) -> bytes:
|
|
50
|
+
s = (s or "").strip()
|
|
51
|
+
if not s:
|
|
52
|
+
return b""
|
|
53
|
+
pad = "=" * (-len(s) % 4)
|
|
54
|
+
return base64.urlsafe_b64decode((s + pad).encode("utf-8"))
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _b64url_encode(b: bytes) -> str:
|
|
58
|
+
return base64.urlsafe_b64encode(b).decode("utf-8").rstrip("=")
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _safe_json(obj: Any) -> bytes:
|
|
62
|
+
return json.dumps(obj, sort_keys=True, separators=(",", ":"), ensure_ascii=False).encode("utf-8")
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _truthy(v: Any) -> bool:
|
|
66
|
+
return str(v).strip().lower() in ("1", "true", "yes", "on", "y")
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def instance_fingerprint() -> str:
|
|
70
|
+
client_dir = _resolved_client_dir()
|
|
71
|
+
p = os.path.join(client_dir, SECRET_KEY_FILENAME)
|
|
72
|
+
try:
|
|
73
|
+
secret = open(p, "r", encoding="utf-8").read().strip()
|
|
74
|
+
except Exception:
|
|
75
|
+
return ""
|
|
76
|
+
if not secret:
|
|
77
|
+
return ""
|
|
78
|
+
digest = hashlib.sha256(secret.encode("utf-8")).digest()
|
|
79
|
+
return _b64url_encode(digest)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@dataclass
|
|
83
|
+
class VerifiedLicence:
|
|
84
|
+
ok: bool
|
|
85
|
+
entitlements: Dict[str, Any]
|
|
86
|
+
plan: str
|
|
87
|
+
error: str
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def _normalise_payload(payload: Dict[str, Any]) -> Dict[str, Any]:
|
|
91
|
+
if not isinstance(payload, dict):
|
|
92
|
+
return {}
|
|
93
|
+
if isinstance(payload.get("entitlements"), dict):
|
|
94
|
+
ent = dict(payload.get("entitlements") or {})
|
|
95
|
+
for k in ("plan_id", "plan", "entitlement_version", "addons"):
|
|
96
|
+
if payload.get(k) is not None and ent.get(k) is None:
|
|
97
|
+
ent[k] = payload.get(k)
|
|
98
|
+
return ent
|
|
99
|
+
return dict(payload)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def _get_public_key_b64() -> str:
|
|
103
|
+
"""
|
|
104
|
+
Resolve Ed25519 public key used for licence verification.
|
|
105
|
+
|
|
106
|
+
Order:
|
|
107
|
+
1) SMX_PREMIUM_PUBLIC_KEY_B64 env var
|
|
108
|
+
2) in-process cache
|
|
109
|
+
3) <client_dir>/premium/public_key.b64 (cached file)
|
|
110
|
+
4) GET <SMX_LICENCE_SERVER_URL>/v1/public-key (then cache to file)
|
|
111
|
+
5) DEFAULT_PUBLIC_KEY_B64 fallback
|
|
112
|
+
"""
|
|
113
|
+
global _CACHED_PUBLIC_KEY_B64
|
|
114
|
+
|
|
115
|
+
env = os.environ.get("SMX_PREMIUM_PUBLIC_KEY_B64")
|
|
116
|
+
if env and env.strip():
|
|
117
|
+
_CACHED_PUBLIC_KEY_B64 = env.strip()
|
|
118
|
+
return _CACHED_PUBLIC_KEY_B64
|
|
119
|
+
if _CACHED_PUBLIC_KEY_B64 and _CACHED_PUBLIC_KEY_B64.strip():
|
|
120
|
+
return _CACHED_PUBLIC_KEY_B64.strip()
|
|
121
|
+
client_dir = _resolved_client_dir()
|
|
122
|
+
try:
|
|
123
|
+
p = os.path.join(client_dir, "premium", "public_key.b64")
|
|
124
|
+
if os.path.exists(p):
|
|
125
|
+
key = open(p, "r", encoding="utf-8").read().strip()
|
|
126
|
+
if key:
|
|
127
|
+
_CACHED_PUBLIC_KEY_B64 = key
|
|
128
|
+
return key
|
|
129
|
+
except Exception:
|
|
130
|
+
pass
|
|
131
|
+
licence_server = (os.environ.get("SMX_LICENCE_SERVER_URL") or "").strip()
|
|
132
|
+
if licence_server:
|
|
133
|
+
url = licence_server.rstrip("/") + "/v1/public-key"
|
|
134
|
+
try:
|
|
135
|
+
import urllib.request
|
|
136
|
+
|
|
137
|
+
req = urllib.request.Request(url, method="GET")
|
|
138
|
+
with urllib.request.urlopen(req, timeout=10) as resp:
|
|
139
|
+
raw = resp.read().decode("utf-8", errors="replace").strip()
|
|
140
|
+
|
|
141
|
+
data = json.loads(raw) if raw else {}
|
|
142
|
+
key = str(data.get("public_key_b64") or "").strip()
|
|
143
|
+
if key:
|
|
144
|
+
_CACHED_PUBLIC_KEY_B64 = key
|
|
145
|
+
try:
|
|
146
|
+
os.makedirs(os.path.join(client_dir, "premium"), exist_ok=True)
|
|
147
|
+
with open(os.path.join(client_dir, "premium", "public_key.b64"), "w", encoding="utf-8") as f:
|
|
148
|
+
f.write(key)
|
|
149
|
+
except Exception:
|
|
150
|
+
pass
|
|
151
|
+
return key
|
|
152
|
+
except Exception:
|
|
153
|
+
pass
|
|
154
|
+
return (DEFAULT_PUBLIC_KEY_B64 or "").strip()
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def _licence_message(payload: Dict[str, Any]) -> bytes:
|
|
158
|
+
body = {k: v for k, v in payload.items() if k != "sig"}
|
|
159
|
+
return _safe_json(body)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def verify_licence_payload(
|
|
163
|
+
payload: Dict[str, Any],
|
|
164
|
+
*,
|
|
165
|
+
now: Optional[datetime] = None,
|
|
166
|
+
allow_unsigned: Optional[bool] = None,
|
|
167
|
+
) -> VerifiedLicence:
|
|
168
|
+
if not isinstance(payload, dict) or not payload:
|
|
169
|
+
return VerifiedLicence(False, {}, "free", "Licence payload is empty or not a JSON object")
|
|
170
|
+
|
|
171
|
+
allow_unsigned_eff = _truthy(os.environ.get("SMX_PREMIUM_ALLOW_UNSIGNED", "0"))
|
|
172
|
+
if allow_unsigned is not None:
|
|
173
|
+
allow_unsigned_eff = bool(allow_unsigned)
|
|
174
|
+
|
|
175
|
+
fp = instance_fingerprint()
|
|
176
|
+
if not fp:
|
|
177
|
+
return VerifiedLicence(False, {}, "free", "Cannot compute instance fingerprint (missing .smx_secret_key)")
|
|
178
|
+
|
|
179
|
+
lic_inst = str(payload.get("instance_id") or payload.get("instanceId") or "").strip()
|
|
180
|
+
if not lic_inst:
|
|
181
|
+
if not allow_unsigned_eff:
|
|
182
|
+
return VerifiedLicence(False, {}, "free", "Licence missing instance_id")
|
|
183
|
+
elif lic_inst != fp:
|
|
184
|
+
return VerifiedLicence(False, {}, "free", "Instance mismatch (licence is for a different install)")
|
|
185
|
+
|
|
186
|
+
now_dt = now or _utcnow()
|
|
187
|
+
exp_raw = payload.get("expires_at") or payload.get("expiresAt")
|
|
188
|
+
exp_dt = _parse_iso_utc(str(exp_raw)) if exp_raw else None
|
|
189
|
+
if exp_dt and now_dt > exp_dt:
|
|
190
|
+
return VerifiedLicence(False, {}, "free", "Licence has expired")
|
|
191
|
+
|
|
192
|
+
sig_b64 = str(payload.get("sig") or "").strip()
|
|
193
|
+
if not sig_b64:
|
|
194
|
+
if not allow_unsigned_eff:
|
|
195
|
+
return VerifiedLicence(False, {}, "free", "Licence is unsigned (sig missing)")
|
|
196
|
+
ent = _normalise_payload(payload)
|
|
197
|
+
plan = str(ent.get("plan_id") or ent.get("plan") or payload.get("plan_id") or payload.get("plan") or "free").strip().lower() or "free"
|
|
198
|
+
return VerifiedLicence(True, ent, plan, "")
|
|
199
|
+
|
|
200
|
+
if Ed25519PublicKey is None:
|
|
201
|
+
return VerifiedLicence(False, {}, "free", "cryptography package is required for licence verification")
|
|
202
|
+
|
|
203
|
+
pub_b64 = _get_public_key_b64()
|
|
204
|
+
if not pub_b64:
|
|
205
|
+
return VerifiedLicence(False, {}, "free", "Public key not configured (SMX_PREMIUM_PUBLIC_KEY_B64)")
|
|
206
|
+
|
|
207
|
+
try:
|
|
208
|
+
pub_bytes = _b64url_decode(pub_b64)
|
|
209
|
+
pub = Ed25519PublicKey.from_public_bytes(pub_bytes)
|
|
210
|
+
except Exception:
|
|
211
|
+
return VerifiedLicence(False, {}, "free", "Public key is invalid")
|
|
212
|
+
|
|
213
|
+
try:
|
|
214
|
+
sig = _b64url_decode(sig_b64)
|
|
215
|
+
msg = _licence_message(payload)
|
|
216
|
+
pub.verify(sig, msg)
|
|
217
|
+
except Exception:
|
|
218
|
+
return VerifiedLicence(False, {}, "free", "Signature verification failed")
|
|
219
|
+
|
|
220
|
+
ent = _normalise_payload(payload)
|
|
221
|
+
plan = str(ent.get("plan_id") or ent.get("plan") or payload.get("plan_id") or payload.get("plan") or "free").strip().lower() or "free"
|
|
222
|
+
return VerifiedLicence(True, ent, plan, "")
|