smart-home-engine 1.1.18 → 1.1.20
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.
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{m as O}from"./monaco-langs-BW2J83t5.js";import{t as I}from"./index-
|
|
1
|
+
import{m as O}from"./monaco-langs-BW2J83t5.js";import{t as I}from"./index-BIDlQXlY.js";/*!-----------------------------------------------------------------------------
|
|
2
2
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3
3
|
* Version: 0.52.2(404545bded1df6ffa41ea0af4e8ddb219018c6c1)
|
|
4
4
|
* Released under the MIT license
|
package/dist/web/index.html
CHANGED
|
@@ -172,7 +172,7 @@
|
|
|
172
172
|
}
|
|
173
173
|
})();
|
|
174
174
|
</script>
|
|
175
|
-
<script type="module" crossorigin src="/assets/index-
|
|
175
|
+
<script type="module" crossorigin src="/assets/index-BIDlQXlY.js"></script>
|
|
176
176
|
<link rel="modulepreload" crossorigin href="/assets/monaco-langs-BW2J83t5.js">
|
|
177
177
|
<link rel="stylesheet" crossorigin href="/assets/monaco-langs-DyX1CsEw.css">
|
|
178
178
|
<link rel="stylesheet" crossorigin href="/assets/index-b3gdLMp3.css">
|
package/package.json
CHANGED
package/src/lib/dynsec.js
CHANGED
|
@@ -34,6 +34,10 @@ const _queue = [];
|
|
|
34
34
|
let _inflight = false;
|
|
35
35
|
let _inflightResolve = null;
|
|
36
36
|
|
|
37
|
+
// $SYS topic cache — populated by the she-admin MQTT connection which has
|
|
38
|
+
// the admin role and therefore $SYS/# subscribe + publishClientReceive ACLs.
|
|
39
|
+
const _sysData = {};
|
|
40
|
+
|
|
37
41
|
function _drain() {
|
|
38
42
|
if (_inflight || _queue.length === 0 || !_connected) return;
|
|
39
43
|
|
|
@@ -145,6 +149,12 @@ function init(config, log) {
|
|
|
145
149
|
});
|
|
146
150
|
}
|
|
147
151
|
});
|
|
152
|
+
// The admin role has subscribePattern + publishClientReceive for $SYS/#.
|
|
153
|
+
// Subscribe here so the broker status endpoint always has fresh $SYS data
|
|
154
|
+
// even when the main MQTT client lacks the necessary ACL permissions.
|
|
155
|
+
_client.subscribe('$SYS/#', (err) => {
|
|
156
|
+
if (err) _log.debug('dynsec: $SYS/# subscription failed (not critical):', err.message);
|
|
157
|
+
});
|
|
148
158
|
});
|
|
149
159
|
|
|
150
160
|
_client.on('close', () => {
|
|
@@ -160,6 +170,13 @@ function init(config, log) {
|
|
|
160
170
|
});
|
|
161
171
|
|
|
162
172
|
_client.on('message', (topic, payload) => {
|
|
173
|
+
if (topic.startsWith('$SYS/')) {
|
|
174
|
+
const val = payload.toString();
|
|
175
|
+
const now = Date.now();
|
|
176
|
+
const prev = _sysData[topic];
|
|
177
|
+
_sysData[topic] = { val, ts: now, lc: prev && prev.val !== val ? now : (prev ? prev.lc : now) };
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
163
180
|
if (topic !== RESPONSE_TOPIC) return;
|
|
164
181
|
let msg;
|
|
165
182
|
try {
|
|
@@ -192,6 +209,8 @@ function stop() {
|
|
|
192
209
|
_configured = false;
|
|
193
210
|
_connected = false;
|
|
194
211
|
_dynsecReady = false;
|
|
212
|
+
// Clear $SYS cache
|
|
213
|
+
Object.keys(_sysData).forEach((k) => delete _sysData[k]);
|
|
195
214
|
// Reject any in-flight / queued requests
|
|
196
215
|
if (_inflight && _inflightResolve) {
|
|
197
216
|
_inflightResolve = null;
|
|
@@ -223,11 +242,11 @@ function setClientPassword(username, password) {
|
|
|
223
242
|
}
|
|
224
243
|
|
|
225
244
|
function listClients(verbose = false) {
|
|
226
|
-
return _request('listClients', { verbose }).then((r) => r.clients
|
|
245
|
+
return _request('listClients', { verbose }).then((r) => r.data?.clients ?? r.clients ?? []);
|
|
227
246
|
}
|
|
228
247
|
|
|
229
248
|
function getClient(username) {
|
|
230
|
-
return _request('getClient', { username }).then((r) => r.client);
|
|
249
|
+
return _request('getClient', { username }).then((r) => r.data?.client ?? r.client);
|
|
231
250
|
}
|
|
232
251
|
|
|
233
252
|
// ── Role management ────────────────────────────────────────────────────────────
|
|
@@ -241,11 +260,11 @@ function deleteRole(rolename) {
|
|
|
241
260
|
}
|
|
242
261
|
|
|
243
262
|
function listRoles(verbose = false) {
|
|
244
|
-
return _request('listRoles', { verbose }).then((r) => r.roles
|
|
263
|
+
return _request('listRoles', { verbose }).then((r) => r.data?.roles ?? r.roles ?? []);
|
|
245
264
|
}
|
|
246
265
|
|
|
247
266
|
function getRole(rolename) {
|
|
248
|
-
return _request('getRole', { rolename }).then((r) => r.role);
|
|
267
|
+
return _request('getRole', { rolename }).then((r) => r.data?.role ?? r.role);
|
|
249
268
|
}
|
|
250
269
|
|
|
251
270
|
/**
|
|
@@ -286,11 +305,11 @@ function deleteGroup(groupname) {
|
|
|
286
305
|
}
|
|
287
306
|
|
|
288
307
|
function listGroups(verbose = false) {
|
|
289
|
-
return _request('listGroups', { verbose }).then((r) => r.groups
|
|
308
|
+
return _request('listGroups', { verbose }).then((r) => r.data?.groups ?? r.groups ?? []);
|
|
290
309
|
}
|
|
291
310
|
|
|
292
311
|
function getGroup(groupname) {
|
|
293
|
-
return _request('getGroup', { groupname }).then((r) => r.group);
|
|
312
|
+
return _request('getGroup', { groupname }).then((r) => r.data?.group ?? r.group);
|
|
294
313
|
}
|
|
295
314
|
|
|
296
315
|
function addGroupClient(groupname, username, priority = -1) {
|
|
@@ -312,7 +331,12 @@ function removeGroupRole(groupname, rolename) {
|
|
|
312
331
|
// ── Default ACL access ─────────────────────────────────────────────────────────
|
|
313
332
|
|
|
314
333
|
function getDefaultACLAccess() {
|
|
315
|
-
return _request('getDefaultACLAccess').then((r) => r.acls
|
|
334
|
+
return _request('getDefaultACLAccess').then((r) => r.data?.acls ?? r.acls ?? []);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/** Returns the $SYS topic cache collected by the she-admin MQTT client. */
|
|
338
|
+
function getSysData() {
|
|
339
|
+
return { ..._sysData };
|
|
316
340
|
}
|
|
317
341
|
|
|
318
342
|
function setDefaultACLAccess(acls) {
|
|
@@ -322,6 +346,7 @@ function setDefaultACLAccess(acls) {
|
|
|
322
346
|
module.exports = {
|
|
323
347
|
init,
|
|
324
348
|
getStatus,
|
|
349
|
+
getSysData,
|
|
325
350
|
stop,
|
|
326
351
|
// Users
|
|
327
352
|
createClient,
|
package/src/web/broker-api.js
CHANGED
|
@@ -79,11 +79,16 @@ function handleError(res, err) {
|
|
|
79
79
|
router.get('/status', (req, res) => {
|
|
80
80
|
const ds = dynsec.getStatus();
|
|
81
81
|
|
|
82
|
-
|
|
82
|
+
// Prefer $SYS data from the she-admin MQTT client: it has admin role ACLs
|
|
83
|
+
// that explicitly allow $SYS/# even when the main client is denied by
|
|
84
|
+
// default-deny subscribe ACLs.
|
|
85
|
+
const sys = dynsec.getSysData();
|
|
86
|
+
// Fall back to the main MQTT client's state store for any topics not yet
|
|
87
|
+
// received by the dynsec client (e.g. when dynsec is not configured).
|
|
83
88
|
if (_store) {
|
|
84
89
|
const sysPrefixes = ['$SYS/broker/version', '$SYS/broker/uptime', '$SYS/broker/clients/', '$SYS/broker/messages/'];
|
|
85
90
|
for (const [topic, entry] of _store.mqttEntries()) {
|
|
86
|
-
if (sysPrefixes.some((p) => topic.startsWith(p))) {
|
|
91
|
+
if (!sys[topic] && sysPrefixes.some((p) => topic.startsWith(p))) {
|
|
87
92
|
sys[topic] = entry;
|
|
88
93
|
}
|
|
89
94
|
}
|
|
@@ -801,6 +806,15 @@ router.post('/wizard/bootstrap', async (req, res) => {
|
|
|
801
806
|
|
|
802
807
|
if (isRemote) {
|
|
803
808
|
// mosquitto_ctrl must run on the broker host — invoke it via SSH.
|
|
809
|
+
// Delete any existing file first: mosquitto_ctrl init refuses to overwrite
|
|
810
|
+
// an existing file, which would leave the old credentials in place while
|
|
811
|
+
// config.json now holds new ones, causing "not authorised" on reconnect.
|
|
812
|
+
try {
|
|
813
|
+
await sshDeploy.runCommand(bc.ssh, `sudo rm -f "${dynSecPath}"`);
|
|
814
|
+
_log?.debug(`broker: removed existing ${dynSecPath} on remote (if any)`);
|
|
815
|
+
} catch (e) {
|
|
816
|
+
_log?.warn(`broker: could not remove existing ${dynSecPath} on remote: ${e.message}`);
|
|
817
|
+
}
|
|
804
818
|
const ctrlCmd = `mosquitto_ctrl dynsec init "${dynSecPath}" "${username}" "${password}"`;
|
|
805
819
|
_log?.debug(`broker: SSH mosquitto_ctrl on ${bc.ssh.host}: mosquitto_ctrl dynsec init "${dynSecPath}" "${username}" ***`);
|
|
806
820
|
try {
|
|
@@ -876,6 +890,13 @@ router.post('/wizard/bootstrap', async (req, res) => {
|
|
|
876
890
|
} else {
|
|
877
891
|
// Local mode: run mosquitto_ctrl on this host.
|
|
878
892
|
fs.mkdirSync(configDir, { recursive: true });
|
|
893
|
+
// Delete any existing file first so mosquitto_ctrl always writes fresh credentials.
|
|
894
|
+
try {
|
|
895
|
+
fs.rmSync(dynSecPath, { force: true });
|
|
896
|
+
_log?.debug(`broker: removed existing ${dynSecPath} on local host (if any)`);
|
|
897
|
+
} catch (e) {
|
|
898
|
+
_log?.warn(`broker: could not remove existing ${dynSecPath}: ${e.message}`);
|
|
899
|
+
}
|
|
879
900
|
_log?.debug(`broker: local mosquitto_ctrl dynsec init ${dynSecPath} ${username} ***`);
|
|
880
901
|
try {
|
|
881
902
|
const r = await execFileAsync('mosquitto_ctrl', ['dynsec', 'init', dynSecPath, username, password], { timeout: 10000 });
|