smart-home-engine 1.1.16 → 1.1.18
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-BH6XhdRK.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-BH6XhdRK.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
|
@@ -26,7 +26,10 @@ const { promisify } = require('util');
|
|
|
26
26
|
const execFileAsync = promisify(execFile);
|
|
27
27
|
|
|
28
28
|
// Keys that she manages — all others are treated as passthrough
|
|
29
|
-
|
|
29
|
+
// NOTE: 'plugin_opt_dynsec_config_file' is kept here only for migration —
|
|
30
|
+
// when read from an old conf it is normalised to 'plugin_opt_config_file' on
|
|
31
|
+
// the same line that recognises it (see parseText below).
|
|
32
|
+
const MANAGED_SINGLE_KEYS = new Set(['allow_anonymous', 'persistence', 'persistence_location', 'log_dest', 'log_type', 'plugin', 'plugin_opt_config_file', 'plugin_opt_dynsec_config_file']);
|
|
30
33
|
|
|
31
34
|
/**
|
|
32
35
|
* Parse mosquitto.conf text into a structured object.
|
|
@@ -70,10 +73,12 @@ function parseText(raw) {
|
|
|
70
73
|
} else if (currentListener && isListenerSubkey(key)) {
|
|
71
74
|
applyListenerKey(currentListener, key, value);
|
|
72
75
|
} else if (MANAGED_SINGLE_KEYS.has(key)) {
|
|
73
|
-
|
|
74
|
-
|
|
76
|
+
// Normalise the old (incorrect) key name written by earlier she versions
|
|
77
|
+
const managedKey = key === 'plugin_opt_dynsec_config_file' ? 'plugin_opt_config_file' : key;
|
|
78
|
+
if (managed[managedKey] !== undefined) {
|
|
79
|
+
managed[managedKey] = [].concat(managed[managedKey]).concat(value);
|
|
75
80
|
} else {
|
|
76
|
-
managed[
|
|
81
|
+
managed[managedKey] = value;
|
|
77
82
|
}
|
|
78
83
|
currentListener = null;
|
|
79
84
|
} else {
|
|
@@ -155,7 +160,7 @@ function serialise(conf) {
|
|
|
155
160
|
// Managed single-key entries first
|
|
156
161
|
const { managed = {}, listeners = [], passthrough = [] } = conf;
|
|
157
162
|
|
|
158
|
-
const keyOrder = ['allow_anonymous', 'persistence', 'persistence_location', 'log_dest', 'log_type', 'plugin', '
|
|
163
|
+
const keyOrder = ['allow_anonymous', 'persistence', 'persistence_location', 'log_dest', 'log_type', 'plugin', 'plugin_opt_config_file'];
|
|
159
164
|
for (const key of keyOrder) {
|
|
160
165
|
if (managed[key] === undefined) continue;
|
|
161
166
|
const val = managed[key];
|
|
@@ -186,10 +191,24 @@ function serialise(conf) {
|
|
|
186
191
|
lines.push('');
|
|
187
192
|
}
|
|
188
193
|
|
|
189
|
-
// Passthrough (comments, blanks, unmanaged keys)
|
|
190
|
-
|
|
194
|
+
// Passthrough (comments, blanks, unmanaged keys) — strip leading blank lines
|
|
195
|
+
// to avoid a double-blank at the managed/passthrough boundary.
|
|
196
|
+
const trimmedPassthrough = [...passthrough];
|
|
197
|
+
while (trimmedPassthrough.length > 0 && trimmedPassthrough[0].trim() === '') {
|
|
198
|
+
trimmedPassthrough.shift();
|
|
199
|
+
}
|
|
200
|
+
for (const l of trimmedPassthrough) lines.push(l);
|
|
191
201
|
|
|
192
|
-
|
|
202
|
+
// Collapse runs of more than one consecutive blank line into a single blank line.
|
|
203
|
+
const result = [];
|
|
204
|
+
let prevBlank = false;
|
|
205
|
+
for (const line of lines) {
|
|
206
|
+
const isBlank = line.trim() === '';
|
|
207
|
+
if (isBlank && prevBlank) continue;
|
|
208
|
+
result.push(line);
|
|
209
|
+
prevBlank = isBlank;
|
|
210
|
+
}
|
|
211
|
+
return result.join('\n');
|
|
193
212
|
}
|
|
194
213
|
|
|
195
214
|
/**
|
package/src/web/broker-api.js
CHANGED
|
@@ -831,6 +831,16 @@ router.post('/wizard/bootstrap', async (req, res) => {
|
|
|
831
831
|
_log?.warn(`broker: could not verify dynamic-security.json after init: ${e.message}`);
|
|
832
832
|
}
|
|
833
833
|
|
|
834
|
+
// Fix ownership and permissions: mosquitto_ctrl creates the file owned by the
|
|
835
|
+
// SSH user (typically mode 600). Mosquitto runs as the 'mosquitto' system user
|
|
836
|
+
// and must be able to read it. Chown to mosquitto:mosquitto and set 644.
|
|
837
|
+
try {
|
|
838
|
+
await sshDeploy.runCommand(bc.ssh, `sudo chown mosquitto:mosquitto "${dynSecPath}" && sudo chmod 644 "${dynSecPath}"`);
|
|
839
|
+
_log?.debug(`broker: fixed ownership and permissions on remote ${dynSecPath}`);
|
|
840
|
+
} catch (e) {
|
|
841
|
+
_log?.warn(`broker: could not chown/chmod remote ${dynSecPath}: ${e.message} — mosquitto may fail with 'File is not readable'`);
|
|
842
|
+
}
|
|
843
|
+
|
|
834
844
|
// Discover the full path to the .so on the remote host.
|
|
835
845
|
let soPath = 'mosquitto_dynamic_security.so'; // fallback: rely on LD_LIBRARY_PATH
|
|
836
846
|
try {
|
|
@@ -855,7 +865,7 @@ router.post('/wizard/bootstrap', async (req, res) => {
|
|
|
855
865
|
const parsed = mosquittoConf.parseText(remoteConfRaw);
|
|
856
866
|
if (!parsed.managed.plugin || !String(parsed.managed.plugin).includes('mosquitto_dynamic_security')) {
|
|
857
867
|
parsed.managed.plugin = soPath;
|
|
858
|
-
parsed.managed.
|
|
868
|
+
parsed.managed.plugin_opt_config_file = dynSecPath;
|
|
859
869
|
const content = mosquittoConf.serialise(parsed);
|
|
860
870
|
_log?.debug(`broker: uploading updated conf to ${bc.ssh.host}:${confFilePath}`);
|
|
861
871
|
await sshDeploy.uploadContent(bc.ssh, content, confFilePath);
|
|
@@ -892,6 +902,22 @@ router.post('/wizard/bootstrap', async (req, res) => {
|
|
|
892
902
|
} catch (e) {
|
|
893
903
|
_log?.warn(`broker: could not verify dynamic-security.json after init: ${e.message}`);
|
|
894
904
|
}
|
|
905
|
+
|
|
906
|
+
// Fix ownership and permissions: mosquitto_ctrl creates the file owned by the
|
|
907
|
+
// current user. Mosquitto runs as the 'mosquitto' system user and needs read access.
|
|
908
|
+
try {
|
|
909
|
+
await execFileAsync('sudo', ['chown', 'mosquitto:mosquitto', dynSecPath], { timeout: 5000 });
|
|
910
|
+
_log?.debug(`broker: fixed ownership on local ${dynSecPath}`);
|
|
911
|
+
} catch (e) {
|
|
912
|
+
_log?.warn(`broker: could not chown local ${dynSecPath}: ${e.message}`);
|
|
913
|
+
}
|
|
914
|
+
try {
|
|
915
|
+
fs.chmodSync(dynSecPath, 0o644);
|
|
916
|
+
_log?.debug(`broker: fixed permissions on local ${dynSecPath}`);
|
|
917
|
+
} catch (e) {
|
|
918
|
+
_log?.warn(`broker: could not chmod local ${dynSecPath}: ${e.message}`);
|
|
919
|
+
}
|
|
920
|
+
|
|
895
921
|
let soPath = 'mosquitto_dynamic_security.so'; // fallback: rely on LD_LIBRARY_PATH
|
|
896
922
|
try {
|
|
897
923
|
const r2 = await execFileAsync('find', ['/usr', '/lib', '-maxdepth', '8', '-name', 'mosquitto_dynamic_security.so'], { timeout: 8000 });
|
|
@@ -908,7 +934,7 @@ router.post('/wizard/bootstrap', async (req, res) => {
|
|
|
908
934
|
const parsed = mosquittoConf.parse(confFilePath);
|
|
909
935
|
if (!parsed.managed.plugin || !String(parsed.managed.plugin).includes('mosquitto_dynamic_security')) {
|
|
910
936
|
parsed.managed.plugin = soPath;
|
|
911
|
-
parsed.managed.
|
|
937
|
+
parsed.managed.plugin_opt_config_file = dynSecPath;
|
|
912
938
|
const content = mosquittoConf.serialise(parsed);
|
|
913
939
|
_log?.debug(`broker: writing updated local conf to ${confFilePath}`);
|
|
914
940
|
mosquittoConf.write(confFilePath, content);
|
|
@@ -946,12 +972,16 @@ router.post('/wizard/deactivate', async (req, res) => {
|
|
|
946
972
|
const raw = await sshDeploy.readRemoteFile(bc.ssh, fp);
|
|
947
973
|
const parsed = mosquittoConf.parseText(raw);
|
|
948
974
|
delete parsed.managed.plugin;
|
|
975
|
+
delete parsed.managed.plugin_opt_config_file;
|
|
976
|
+
// Also remove old key name in case conf was written by an earlier she version
|
|
949
977
|
delete parsed.managed.plugin_opt_dynsec_config_file;
|
|
950
978
|
const content = mosquittoConf.serialise(parsed);
|
|
951
979
|
await sshDeploy.uploadContent(bc.ssh, content, fp);
|
|
952
980
|
} else {
|
|
953
981
|
const parsed = mosquittoConf.parse(fp);
|
|
954
982
|
delete parsed.managed.plugin;
|
|
983
|
+
delete parsed.managed.plugin_opt_config_file;
|
|
984
|
+
// Also remove old key name in case conf was written by an earlier she version
|
|
955
985
|
delete parsed.managed.plugin_opt_dynsec_config_file;
|
|
956
986
|
const content = mosquittoConf.serialise(parsed);
|
|
957
987
|
mosquittoConf.write(fp, content);
|