smart-home-engine 1.6.1 → 1.8.0
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.
- package/dist/web/assets/{index-D-Rifjr_.css → index-CmpNIegY.css} +1 -1
- package/dist/web/assets/{index-DBAKaUFL.js → index-DLsurhm_.js} +72 -72
- package/dist/web/assets/{tsMode-C5T2U6K3.js → tsMode-Ca6ze8bD.js} +1 -1
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/src/lib/mosquitto-conf.js +55 -2
- package/src/web/broker-api.js +37 -1
|
@@ -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-DLsurhm_.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,10 +172,10 @@
|
|
|
172
172
|
}
|
|
173
173
|
})();
|
|
174
174
|
</script>
|
|
175
|
-
<script type="module" crossorigin src="/assets/index-
|
|
175
|
+
<script type="module" crossorigin src="/assets/index-DLsurhm_.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
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
178
|
+
<link rel="stylesheet" crossorigin href="/assets/index-CmpNIegY.css">
|
|
179
179
|
</head>
|
|
180
180
|
<body>
|
|
181
181
|
<div id="app"></div>
|
package/package.json
CHANGED
|
@@ -29,7 +29,19 @@ const execFileAsync = promisify(execFile);
|
|
|
29
29
|
// NOTE: 'plugin_opt_dynsec_config_file' is kept here only for migration —
|
|
30
30
|
// when read from an old conf it is normalised to 'plugin_opt_config_file' on
|
|
31
31
|
// the same line that recognises it (see parseText below).
|
|
32
|
-
const MANAGED_SINGLE_KEYS = new Set([
|
|
32
|
+
const MANAGED_SINGLE_KEYS = new Set([
|
|
33
|
+
'per_listener_settings', 'allow_anonymous',
|
|
34
|
+
'persistence', 'persistence_location',
|
|
35
|
+
'log_dest', 'log_type',
|
|
36
|
+
'plugin', 'plugin_opt_config_file', 'plugin_opt_dynsec_config_file',
|
|
37
|
+
// Connection limits
|
|
38
|
+
'max_connections', 'max_inflight_messages', 'max_queued_messages',
|
|
39
|
+
'max_packet_size', 'message_size_limit', 'max_keepalive',
|
|
40
|
+
// Sessions
|
|
41
|
+
'persistent_client_expiration', 'retain_available',
|
|
42
|
+
// Performance / misc
|
|
43
|
+
'set_tcp_nodelay', 'connection_messages',
|
|
44
|
+
]);
|
|
33
45
|
|
|
34
46
|
/**
|
|
35
47
|
* Parse mosquitto.conf text into a structured object.
|
|
@@ -112,6 +124,9 @@ function isListenerSubkey(key) {
|
|
|
112
124
|
return [
|
|
113
125
|
'protocol',
|
|
114
126
|
'socket_domain',
|
|
127
|
+
'mount_point',
|
|
128
|
+
'max_connections',
|
|
129
|
+
'max_qos',
|
|
115
130
|
'certfile',
|
|
116
131
|
'keyfile',
|
|
117
132
|
'cafile',
|
|
@@ -119,9 +134,12 @@ function isListenerSubkey(key) {
|
|
|
119
134
|
'crlfile',
|
|
120
135
|
'require_certificate',
|
|
121
136
|
'use_identity_as_username',
|
|
137
|
+
'use_subject_as_username',
|
|
122
138
|
'tls_version',
|
|
123
139
|
'websockets_log_level',
|
|
124
140
|
'allow_anonymous',
|
|
141
|
+
'password_file',
|
|
142
|
+
'acl_file',
|
|
125
143
|
].includes(key);
|
|
126
144
|
}
|
|
127
145
|
|
|
@@ -130,6 +148,15 @@ function applyListenerKey(listener, key, value) {
|
|
|
130
148
|
case 'protocol':
|
|
131
149
|
listener.protocol = value;
|
|
132
150
|
break;
|
|
151
|
+
case 'mount_point':
|
|
152
|
+
listener.mount_point = value;
|
|
153
|
+
break;
|
|
154
|
+
case 'max_connections':
|
|
155
|
+
listener.max_connections = parseInt(value, 10);
|
|
156
|
+
break;
|
|
157
|
+
case 'max_qos':
|
|
158
|
+
listener.max_qos = parseInt(value, 10);
|
|
159
|
+
break;
|
|
133
160
|
case 'certfile':
|
|
134
161
|
case 'keyfile':
|
|
135
162
|
case 'cafile':
|
|
@@ -144,9 +171,18 @@ function applyListenerKey(listener, key, value) {
|
|
|
144
171
|
case 'use_identity_as_username':
|
|
145
172
|
listener.tls.use_identity_as_username = value === 'true';
|
|
146
173
|
break;
|
|
174
|
+
case 'use_subject_as_username':
|
|
175
|
+
listener.tls.use_subject_as_username = value === 'true';
|
|
176
|
+
break;
|
|
147
177
|
case 'allow_anonymous':
|
|
148
178
|
listener.allow_anonymous = value === 'true';
|
|
149
179
|
break;
|
|
180
|
+
case 'password_file':
|
|
181
|
+
listener.password_file = value;
|
|
182
|
+
break;
|
|
183
|
+
case 'acl_file':
|
|
184
|
+
listener.acl_file = value;
|
|
185
|
+
break;
|
|
150
186
|
default:
|
|
151
187
|
break;
|
|
152
188
|
}
|
|
@@ -164,7 +200,16 @@ function serialise(conf) {
|
|
|
164
200
|
// Managed single-key entries first
|
|
165
201
|
const { managed = {}, listeners = [], passthrough = [] } = conf;
|
|
166
202
|
|
|
167
|
-
const keyOrder = [
|
|
203
|
+
const keyOrder = [
|
|
204
|
+
'per_listener_settings', 'allow_anonymous',
|
|
205
|
+
'persistence', 'persistence_location',
|
|
206
|
+
'max_connections', 'max_inflight_messages', 'max_queued_messages',
|
|
207
|
+
'max_packet_size', 'message_size_limit', 'max_keepalive',
|
|
208
|
+
'persistent_client_expiration', 'retain_available',
|
|
209
|
+
'set_tcp_nodelay', 'connection_messages',
|
|
210
|
+
'log_dest', 'log_type',
|
|
211
|
+
'plugin', 'plugin_opt_config_file',
|
|
212
|
+
];
|
|
168
213
|
for (const key of keyOrder) {
|
|
169
214
|
if (managed[key] === undefined) continue;
|
|
170
215
|
const val = managed[key];
|
|
@@ -182,6 +227,9 @@ function serialise(conf) {
|
|
|
182
227
|
const addr = l.bindAddress ? ` ${l.bindAddress}` : '';
|
|
183
228
|
lines.push(`listener ${l.port}${addr}`);
|
|
184
229
|
if (l.protocol && l.protocol !== 'mqtt') lines.push(`protocol ${l.protocol}`);
|
|
230
|
+
if (l.mount_point) lines.push(`mount_point ${l.mount_point}`);
|
|
231
|
+
if (l.max_connections !== undefined && l.max_connections !== null) lines.push(`max_connections ${l.max_connections}`);
|
|
232
|
+
if (l.max_qos !== undefined && l.max_qos !== null) lines.push(`max_qos ${l.max_qos}`);
|
|
185
233
|
const tls = l.tls || {};
|
|
186
234
|
for (const tlsKey of ['certfile', 'keyfile', 'cafile', 'capath', 'crlfile', 'tls_version']) {
|
|
187
235
|
if (tls[tlsKey]) lines.push(`${tlsKey} ${tls[tlsKey]}`);
|
|
@@ -192,9 +240,14 @@ function serialise(conf) {
|
|
|
192
240
|
if (tls.use_identity_as_username !== undefined) {
|
|
193
241
|
lines.push(`use_identity_as_username ${tls.use_identity_as_username ? 'true' : 'false'}`);
|
|
194
242
|
}
|
|
243
|
+
if (tls.use_subject_as_username !== undefined) {
|
|
244
|
+
lines.push(`use_subject_as_username ${tls.use_subject_as_username ? 'true' : 'false'}`);
|
|
245
|
+
}
|
|
195
246
|
if (l.allow_anonymous !== undefined) {
|
|
196
247
|
lines.push(`allow_anonymous ${l.allow_anonymous ? 'true' : 'false'}`);
|
|
197
248
|
}
|
|
249
|
+
if (l.password_file) lines.push(`password_file ${l.password_file}`);
|
|
250
|
+
if (l.acl_file) lines.push(`acl_file ${l.acl_file}`);
|
|
198
251
|
lines.push('');
|
|
199
252
|
}
|
|
200
253
|
|
package/src/web/broker-api.js
CHANGED
|
@@ -17,6 +17,9 @@ const express = require('express');
|
|
|
17
17
|
const path = require('path');
|
|
18
18
|
const fs = require('fs');
|
|
19
19
|
const crypto = require('crypto');
|
|
20
|
+
const { execFile, spawn } = require('child_process');
|
|
21
|
+
const { promisify } = require('util');
|
|
22
|
+
const execFileAsync = promisify(execFile);
|
|
20
23
|
const dynsec = require('../lib/dynsec');
|
|
21
24
|
const mosquittoConf = require('../lib/mosquitto-conf');
|
|
22
25
|
const ca = require('../lib/ca');
|
|
@@ -947,7 +950,7 @@ module.exports = { router, setLogger, setStore };
|
|
|
947
950
|
router.get('/local/check', async (req, res) => {
|
|
948
951
|
function probe(cmd) {
|
|
949
952
|
return new Promise((resolve) => {
|
|
950
|
-
const cp =
|
|
953
|
+
const cp = spawn(cmd, ['--help'], { stdio: 'ignore' });
|
|
951
954
|
cp.on('error', (e) => resolve(e.code !== 'ENOENT'));
|
|
952
955
|
cp.on('close', () => resolve(true));
|
|
953
956
|
});
|
|
@@ -960,6 +963,39 @@ router.get('/local/check', async (req, res) => {
|
|
|
960
963
|
}
|
|
961
964
|
});
|
|
962
965
|
|
|
966
|
+
// ── IP address listing ────────────────────────────────────────────────────────
|
|
967
|
+
|
|
968
|
+
/**
|
|
969
|
+
* GET /she/broker/ip-addresses
|
|
970
|
+
* List host IP addresses for bind-address autocomplete.
|
|
971
|
+
* Runs `ip a` locally or via SSH depending on broker.ssh configuration.
|
|
972
|
+
*/
|
|
973
|
+
router.get('/ip-addresses', async (req, res) => {
|
|
974
|
+
const bc = getBrokerConfig(req);
|
|
975
|
+
try {
|
|
976
|
+
let stdout = '';
|
|
977
|
+
if (bc.ssh && bc.ssh.host) {
|
|
978
|
+
const result = await sshDeploy.runCommand(bc.ssh, 'ip a 2>/dev/null || ip addr 2>/dev/null');
|
|
979
|
+
stdout = result.stdout;
|
|
980
|
+
} else {
|
|
981
|
+
const result = await execFileAsync('ip', ['a'], { timeout: 5000 }).catch(() =>
|
|
982
|
+
execFileAsync('ip', ['addr'], { timeout: 5000 }),
|
|
983
|
+
);
|
|
984
|
+
stdout = result.stdout;
|
|
985
|
+
}
|
|
986
|
+
// Extract IPv4 and IPv6 addresses; skip loopback
|
|
987
|
+
const addresses = [];
|
|
988
|
+
for (const m of stdout.matchAll(/inet6?\s+([\da-f.:]+)(?:\/\d+)?/gi)) {
|
|
989
|
+
const addr = m[1];
|
|
990
|
+
if (addr === '127.0.0.1' || addr === '::1') continue;
|
|
991
|
+
addresses.push(addr);
|
|
992
|
+
}
|
|
993
|
+
res.json({ addresses: [...new Set(addresses)] });
|
|
994
|
+
} catch {
|
|
995
|
+
res.json({ addresses: [] });
|
|
996
|
+
}
|
|
997
|
+
});
|
|
998
|
+
|
|
963
999
|
// ── SSH routes ─────────────────────────────────────────────────────────────────
|
|
964
1000
|
// Note: these routes are mounted on the same router but defined after module.exports
|
|
965
1001
|
// because they add to `router` (which is already exported by reference).
|