iobroker.bee 0.0.0-stage → 0.2.2
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/README.md +111 -2
- package/admin/bee.svg +1 -0
- package/admin/jsonConfig.json +321 -0
- package/build/lib/commands.js +96 -0
- package/build/lib/commands.js.map +1 -0
- package/build/lib/console.js +218 -0
- package/build/lib/console.js.map +1 -0
- package/build/lib/enrollment.js +37 -0
- package/build/lib/enrollment.js.map +1 -0
- package/build/lib/inventory.js +136 -0
- package/build/lib/inventory.js.map +1 -0
- package/build/lib/jobs.js +251 -0
- package/build/lib/jobs.js.map +1 -0
- package/build/lib/packages.js +139 -0
- package/build/lib/packages.js.map +1 -0
- package/build/lib/planner.js +128 -0
- package/build/lib/planner.js.map +1 -0
- package/build/lib/preflight.js +90 -0
- package/build/lib/preflight.js.map +1 -0
- package/build/lib/protocol.js +70 -0
- package/build/lib/protocol.js.map +1 -0
- package/build/lib/remote.js +211 -0
- package/build/lib/remote.js.map +1 -0
- package/build/lib/transport.js +158 -0
- package/build/lib/transport.js.map +1 -0
- package/build/lib/tunnel.js +293 -0
- package/build/lib/tunnel.js.map +1 -0
- package/build/lib/util.js +102 -0
- package/build/lib/util.js.map +1 -0
- package/build/main.js +835 -0
- package/build/main.js.map +1 -0
- package/build/runner.js +193 -0
- package/build/runner.js.map +1 -0
- package/io-package.json +434 -0
- package/package.json +54 -4
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.TunnelClient = exports.ACCESS_LABEL = void 0;
|
|
7
|
+
exports.findTargets = findTargets;
|
|
8
|
+
exports.describeTargets = describeTargets;
|
|
9
|
+
exports.chooseTarget = chooseTarget;
|
|
10
|
+
exports.trustedTunnelUrl = trustedTunnelUrl;
|
|
11
|
+
const node_net_1 = __importDefault(require("node:net"));
|
|
12
|
+
const node_tls_1 = __importDefault(require("node:tls"));
|
|
13
|
+
const ws_1 = __importDefault(require("ws"));
|
|
14
|
+
const tunnel_1 = require("./tunnel");
|
|
15
|
+
exports.ACCESS_LABEL = { admin: 'admin', vis: 'vis-2', console: 'Konsole' };
|
|
16
|
+
/**
|
|
17
|
+
* Local web interfaces for a kind: the enabled admin instances, or web instances for vis-2 (only with vis-2
|
|
18
|
+
* installed), on this host, in the order of the instance number.
|
|
19
|
+
*/
|
|
20
|
+
async function findTargets(adapter, kind) {
|
|
21
|
+
if (kind === 'console' || (kind === 'vis' && !(await adapter.getForeignObjectAsync('system.adapter.vis-2')))) {
|
|
22
|
+
return [];
|
|
23
|
+
}
|
|
24
|
+
const name = kind === 'admin' ? 'admin' : 'web';
|
|
25
|
+
const res = await adapter.getObjectViewAsync('system', 'instance', {
|
|
26
|
+
startkey: `system.adapter.${name}.`,
|
|
27
|
+
endkey: `system.adapter.${name}.香`,
|
|
28
|
+
});
|
|
29
|
+
return res.rows
|
|
30
|
+
.map(r => r.value)
|
|
31
|
+
.filter((o) => !!o?.common.enabled && o.common.host === adapter.host)
|
|
32
|
+
.sort((a, b) => a._id.localeCompare(b._id, undefined, { numeric: true }))
|
|
33
|
+
.map(obj => {
|
|
34
|
+
const native = obj.native;
|
|
35
|
+
// an interface listening on all addresses is reached over loopback
|
|
36
|
+
const bind = (native.bind || '').trim();
|
|
37
|
+
const defaultUser = (native.defaultUser || 'admin').replace(/^system\.user\./, '');
|
|
38
|
+
return {
|
|
39
|
+
instance: obj._id.replace(/^system\.adapter\./, ''),
|
|
40
|
+
host: !bind || bind === '0.0.0.0' || bind === '::' ? '127.0.0.1' : bind,
|
|
41
|
+
port: parseInt(String(native.port || (kind === 'admin' ? 8081 : 8082)), 10),
|
|
42
|
+
secure: !!native.secure,
|
|
43
|
+
auth: !!native.auth,
|
|
44
|
+
...(native.auth ? {} : { defaultUser }),
|
|
45
|
+
};
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
/** What the server learns about the targets: without the local address */
|
|
49
|
+
function describeTargets(targets) {
|
|
50
|
+
return targets.map(({ host: _host, ...t }) => t);
|
|
51
|
+
}
|
|
52
|
+
/** The instance asked for, or the first one; null if it is not among the targets */
|
|
53
|
+
function chooseTarget(targets, instance) {
|
|
54
|
+
return (instance ? targets.find(t => t.instance === instance) : targets[0]) ?? null;
|
|
55
|
+
}
|
|
56
|
+
/** Is the tunnel URL one of our own server? The job came over the broker, this is a second check. */
|
|
57
|
+
function trustedTunnelUrl(url, serverUrls) {
|
|
58
|
+
let u;
|
|
59
|
+
try {
|
|
60
|
+
u = new URL(url);
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
const local = u.hostname === 'localhost' || u.hostname === '127.0.0.1';
|
|
66
|
+
if (u.protocol !== 'wss:' && !(u.protocol === 'ws:' && local)) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
return serverUrls.some(s => {
|
|
70
|
+
try {
|
|
71
|
+
return new URL(s).hostname === u.hostname;
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
const MAX_BACKOFF = 60_000;
|
|
79
|
+
/** The server pings every 25 s; without a ping for this long the connection is dead */
|
|
80
|
+
const DEAD_AFTER = 90_000;
|
|
81
|
+
/** Longest session the agent accepts, whatever the server says */
|
|
82
|
+
const MAX_SESSION = 4 * 3600_000;
|
|
83
|
+
/** Tunnel of one access session. Reconnects after a connection loss until the session expires. */
|
|
84
|
+
class TunnelClient {
|
|
85
|
+
req;
|
|
86
|
+
opts;
|
|
87
|
+
ws = null;
|
|
88
|
+
mux = null;
|
|
89
|
+
stopped = false;
|
|
90
|
+
backoff = 2000;
|
|
91
|
+
retryTimer = null;
|
|
92
|
+
endTimer;
|
|
93
|
+
watchdog = null;
|
|
94
|
+
lastPing = 0;
|
|
95
|
+
constructor(req, opts) {
|
|
96
|
+
this.req = req;
|
|
97
|
+
this.opts = opts;
|
|
98
|
+
const lifetime = Math.max(0, Math.min(req.expiresAt - Date.now(), MAX_SESSION));
|
|
99
|
+
this.endTimer = setTimeout(() => this.stop('expired'), lifetime);
|
|
100
|
+
}
|
|
101
|
+
/** Payload bytes so far */
|
|
102
|
+
get bytes() {
|
|
103
|
+
return (this.mux?.bytesIn ?? 0) + (this.mux?.bytesOut ?? 0);
|
|
104
|
+
}
|
|
105
|
+
start() {
|
|
106
|
+
this.connect();
|
|
107
|
+
}
|
|
108
|
+
stop(reason) {
|
|
109
|
+
if (this.stopped) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
this.stopped = true;
|
|
113
|
+
clearTimeout(this.endTimer);
|
|
114
|
+
if (this.retryTimer) {
|
|
115
|
+
clearTimeout(this.retryTimer);
|
|
116
|
+
}
|
|
117
|
+
if (this.watchdog) {
|
|
118
|
+
clearInterval(this.watchdog);
|
|
119
|
+
}
|
|
120
|
+
this.mux?.close('Fernzugriff beendet');
|
|
121
|
+
if (this.ws && this.ws.readyState === ws_1.default.OPEN) {
|
|
122
|
+
this.ws.close(1000, 'agent stop');
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
this.ws?.terminate();
|
|
126
|
+
}
|
|
127
|
+
this.opts.onEnd(this, reason);
|
|
128
|
+
}
|
|
129
|
+
connect() {
|
|
130
|
+
if (this.stopped) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
const headers = { authorization: `Bearer ${this.req.ticket}` };
|
|
134
|
+
if (this.opts.refusal) {
|
|
135
|
+
headers[tunnel_1.REFUSE_HEADER] = encodeURIComponent(this.opts.refusal);
|
|
136
|
+
}
|
|
137
|
+
const ws = new ws_1.default(this.req.url, {
|
|
138
|
+
headers,
|
|
139
|
+
ca: this.opts.ca,
|
|
140
|
+
handshakeTimeout: 30_000,
|
|
141
|
+
// mobile data: compress, but cheaply (level 1) for the CPU of the device
|
|
142
|
+
perMessageDeflate: { threshold: 1024, zlibDeflateOptions: { level: 1 } },
|
|
143
|
+
});
|
|
144
|
+
this.ws = ws;
|
|
145
|
+
ws.on('open', () => {
|
|
146
|
+
this.backoff = 2000;
|
|
147
|
+
this.lastPing = Date.now();
|
|
148
|
+
this.mux = new tunnel_1.Mux(frame => ws.send(frame), stream => this.onStream(stream));
|
|
149
|
+
this.watchdog ??= setInterval(() => {
|
|
150
|
+
if (this.ws?.readyState === ws_1.default.OPEN && Date.now() - this.lastPing > DEAD_AFTER) {
|
|
151
|
+
this.opts.log.info('Remote access: no sign of the server, reconnecting');
|
|
152
|
+
this.ws.terminate();
|
|
153
|
+
}
|
|
154
|
+
}, 15_000);
|
|
155
|
+
this.opts.log.debug(`Remote access ${this.req.id}: tunnel open`);
|
|
156
|
+
});
|
|
157
|
+
ws.on('ping', () => (this.lastPing = Date.now()));
|
|
158
|
+
ws.on('message', (data, isBinary) => {
|
|
159
|
+
if (isBinary) {
|
|
160
|
+
this.mux?.receive(data);
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
ws.on('unexpected-response', (_request, res) => {
|
|
164
|
+
res.resume();
|
|
165
|
+
// 410: session unknown or ended, 403: refusal accepted; neither gets better by trying again
|
|
166
|
+
const reason = this.opts.refusal ? 'refused' : `server answered HTTP ${res.statusCode}`;
|
|
167
|
+
this.stop(reason);
|
|
168
|
+
});
|
|
169
|
+
ws.on('error', err => this.opts.log.debug(`Remote access ${this.req.id}: ${err.message}`));
|
|
170
|
+
ws.on('close', code => {
|
|
171
|
+
this.mux?.close('Verbindung zum Server unterbrochen');
|
|
172
|
+
this.mux = null;
|
|
173
|
+
if (this.ws !== ws || this.stopped) {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
if (code === tunnel_1.CLOSE.ENDED || code === tunnel_1.CLOSE.REPLACED) {
|
|
177
|
+
this.stop(code === tunnel_1.CLOSE.ENDED ? 'ended by the server' : 'replaced');
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
const delay = this.backoff;
|
|
181
|
+
this.backoff = Math.min(this.backoff * 2, MAX_BACKOFF);
|
|
182
|
+
this.opts.log.info(`Remote access: connection lost, reconnecting in ${Math.round(delay / 1000)} s`);
|
|
183
|
+
this.retryTimer = setTimeout(() => {
|
|
184
|
+
this.retryTimer = null;
|
|
185
|
+
this.connect();
|
|
186
|
+
}, delay);
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
onStream(stream) {
|
|
190
|
+
if (this.opts.handler) {
|
|
191
|
+
this.opts.handler(stream);
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
const t = this.opts.target;
|
|
195
|
+
if (!t) {
|
|
196
|
+
stream.destroy(new Error('no target'));
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
// a local HTTPS interface has its own, usually self-signed certificate: loopback, nothing to verify
|
|
200
|
+
const sock = t.secure
|
|
201
|
+
? node_tls_1.default.connect({ host: t.host, port: t.port, rejectUnauthorized: false })
|
|
202
|
+
: node_net_1.default.connect(t.port, t.host);
|
|
203
|
+
stream.pipe(sock);
|
|
204
|
+
sock.pipe(stream);
|
|
205
|
+
// a regular end runs through the pipes in both directions (half close); only errors cut off
|
|
206
|
+
sock.on('error', err => stream.destroy(err));
|
|
207
|
+
stream.on('error', () => sock.destroy());
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
exports.TunnelClient = TunnelClient;
|
|
211
|
+
//# sourceMappingURL=remote.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remote.js","sourceRoot":"","sources":["../../src/lib/remote.ts"],"names":[],"mappings":";;;;;;AAwBA,kCAiCC;AAGD,0CAEC;AAGD,oCAEC;AAGD,4CAkBC;AAxFD,wDAA2B;AAC3B,wDAA2B;AAC3B,4CAA2B;AAE3B,qCAAwE;AAc3D,QAAA,YAAY,GAA+B,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;AAE7G;;;GAGG;AACI,KAAK,UAAU,WAAW,CAAC,OAAyB,EAAE,IAAgB;IACzE,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC,MAAM,OAAO,CAAC,qBAAqB,CAAC,sBAAsB,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3G,OAAO,EAAE,CAAC;IACd,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;IAChD,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,kBAAkB,CAAC,QAAQ,EAAE,UAAU,EAAE;QAC/D,QAAQ,EAAE,kBAAkB,IAAI,GAAG;QACnC,MAAM,EAAE,kBAAkB,IAAI,IAAI;KACrC,CAAC,CAAC;IACH,OAAO,GAAG,CAAC,IAAI;SACV,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAA4C,CAAC;SACxD,MAAM,CAAC,CAAC,CAAC,EAAgC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,OAAO,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC;SAClG,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;SACxE,GAAG,CAAC,GAAG,CAAC,EAAE;QACP,MAAM,MAAM,GAAG,GAAG,CAAC,MAMlB,CAAC;QACF,mEAAmE;QACnE,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QACxC,MAAM,WAAW,GAAG,CAAC,MAAM,CAAC,WAAW,IAAI,OAAO,CAAC,CAAC,OAAO,CAAC,iBAAiB,EAAE,EAAE,CAAC,CAAC;QACnF,OAAO;YACH,QAAQ,EAAE,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,oBAAoB,EAAE,EAAE,CAAC;YACnD,IAAI,EAAE,CAAC,IAAI,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI;YACvE,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC;YAC3E,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM;YACvB,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI;YACnB,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC;SAC1C,CAAC;IACN,CAAC,CAAC,CAAC;AACX,CAAC;AAED,0EAA0E;AAC1E,SAAgB,eAAe,CAAC,OAAuB;IACnD,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;AACrD,CAAC;AAED,oFAAoF;AACpF,SAAgB,YAAY,CAAC,OAAuB,EAAE,QAA4B;IAC9E,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;AACxF,CAAC;AAED,qGAAqG;AACrG,SAAgB,gBAAgB,CAAC,GAAW,EAAE,UAAoB;IAC9D,IAAI,CAAM,CAAC;IACX,IAAI,CAAC;QACD,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IACrB,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,KAAK,CAAC;IACjB,CAAC;IACD,MAAM,KAAK,GAAG,CAAC,CAAC,QAAQ,KAAK,WAAW,IAAI,CAAC,CAAC,QAAQ,KAAK,WAAW,CAAC;IACvE,IAAI,CAAC,CAAC,QAAQ,KAAK,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,KAAK,KAAK,IAAI,KAAK,CAAC,EAAE,CAAC;QAC5D,OAAO,KAAK,CAAC;IACjB,CAAC;IACD,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;QACvB,IAAI,CAAC;YACD,OAAO,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,QAAQ,CAAC;QAC9C,CAAC;QAAC,MAAM,CAAC;YACL,OAAO,KAAK,CAAC;QACjB,CAAC;IACL,CAAC,CAAC,CAAC;AACP,CAAC;AAeD,MAAM,WAAW,GAAG,MAAM,CAAC;AAC3B,uFAAuF;AACvF,MAAM,UAAU,GAAG,MAAM,CAAC;AAC1B,kEAAkE;AAClE,MAAM,WAAW,GAAG,CAAC,GAAG,QAAQ,CAAC;AAEjC,kGAAkG;AAClG,MAAa,YAAY;IAWR;IACQ;IAXb,EAAE,GAAqB,IAAI,CAAC;IAC5B,GAAG,GAAe,IAAI,CAAC;IACvB,OAAO,GAAG,KAAK,CAAC;IAChB,OAAO,GAAG,IAAI,CAAC;IACf,UAAU,GAA0B,IAAI,CAAC;IAChC,QAAQ,CAAiB;IAClC,QAAQ,GAA0B,IAAI,CAAC;IACvC,QAAQ,GAAG,CAAC,CAAC;IAErB,YACa,GAAkB,EACV,IAAyB;QADjC,QAAG,GAAH,GAAG,CAAe;QACV,SAAI,GAAJ,IAAI,CAAqB;QAE1C,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,EAAE,WAAW,CAAC,CAAC,CAAC;QAChF,IAAI,CAAC,QAAQ,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC,CAAC;IACrE,CAAC;IAED,2BAA2B;IAC3B,IAAI,KAAK;QACL,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,IAAI,CAAC,CAAC,CAAC;IAChE,CAAC;IAED,KAAK;QACD,IAAI,CAAC,OAAO,EAAE,CAAC;IACnB,CAAC;IAED,IAAI,CAAC,MAAc;QACf,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACf,OAAO;QACX,CAAC;QACD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC5B,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YAClB,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAClC,CAAC;QACD,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAChB,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACjC,CAAC;QACD,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,qBAAqB,CAAC,CAAC;QACvC,IAAI,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,EAAE,CAAC,UAAU,KAAK,YAAS,CAAC,IAAI,EAAE,CAAC;YACnD,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;QACtC,CAAC;aAAM,CAAC;YACJ,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,CAAC;QACzB,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAClC,CAAC;IAEO,OAAO;QACX,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACf,OAAO;QACX,CAAC;QACD,MAAM,OAAO,GAA2B,EAAE,aAAa,EAAE,UAAU,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC;QACvF,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,CAAC,sBAAa,CAAC,GAAG,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACnE,CAAC;QACD,MAAM,EAAE,GAAG,IAAI,YAAS,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE;YACnC,OAAO;YACP,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE;YAChB,gBAAgB,EAAE,MAAM;YACxB,yEAAyE;YACzE,iBAAiB,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,kBAAkB,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;SAC3E,CAAC,CAAC;QACH,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE;YACf,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;YACpB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC3B,IAAI,CAAC,GAAG,GAAG,IAAI,YAAG,CACd,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EACvB,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAClC,CAAC;YACF,IAAI,CAAC,QAAQ,KAAK,WAAW,CAAC,GAAG,EAAE;gBAC/B,IAAI,IAAI,CAAC,EAAE,EAAE,UAAU,KAAK,YAAS,CAAC,IAAI,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,QAAQ,GAAG,UAAU,EAAE,CAAC;oBACpF,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,oDAAoD,CAAC,CAAC;oBACzE,IAAI,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC;gBACxB,CAAC;YACL,CAAC,EAAE,MAAM,CAAC,CAAC;YACX,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,iBAAiB,IAAI,CAAC,GAAG,CAAC,EAAE,eAAe,CAAC,CAAC;QACrE,CAAC,CAAC,CAAC;QACH,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QAClD,EAAE,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE;YAChC,IAAI,QAAQ,EAAE,CAAC;gBACX,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,IAAc,CAAC,CAAC;YACtC,CAAC;QACL,CAAC,CAAC,CAAC;QACH,EAAE,CAAC,EAAE,CAAC,qBAAqB,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,EAAE;YAC3C,GAAG,CAAC,MAAM,EAAE,CAAC;YACb,4FAA4F;YAC5F,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,wBAAwB,GAAG,CAAC,UAAU,EAAE,CAAC;YACxF,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACtB,CAAC,CAAC,CAAC;QACH,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,iBAAiB,IAAI,CAAC,GAAG,CAAC,EAAE,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAC3F,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE;YAClB,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,oCAAoC,CAAC,CAAC;YACtD,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC;YAChB,IAAI,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;gBACjC,OAAO;YACX,CAAC;YACD,IAAI,IAAI,KAAK,cAAK,CAAC,KAAK,IAAI,IAAI,KAAK,cAAK,CAAC,QAAQ,EAAE,CAAC;gBAClD,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,cAAK,CAAC,KAAK,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;gBACrE,OAAO;YACX,CAAC;YACD,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC;YAC3B,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,EAAE,WAAW,CAAC,CAAC;YACvD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,mDAAmD,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;YACpG,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC,GAAG,EAAE;gBAC9B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;gBACvB,IAAI,CAAC,OAAO,EAAE,CAAC;YACnB,CAAC,EAAE,KAAK,CAAC,CAAC;QACd,CAAC,CAAC,CAAC;IACP,CAAC;IAEO,QAAQ,CAAC,MAAoB;QACjC,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YACpB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YAC1B,OAAO;QACX,CAAC;QACD,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;QAC3B,IAAI,CAAC,CAAC,EAAE,CAAC;YACL,MAAM,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC;YACvC,OAAO;QACX,CAAC;QACD,oGAAoG;QACpG,MAAM,IAAI,GAAG,CAAC,CAAC,MAAM;YACjB,CAAC,CAAC,kBAAG,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,kBAAkB,EAAE,KAAK,EAAE,CAAC;YACxE,CAAC,CAAC,kBAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAClB,4FAA4F;QAC5F,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;QAC7C,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;IAC7C,CAAC;CACJ;AApID,oCAoIC"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.Transport = void 0;
|
|
7
|
+
exports.trustedCas = trustedCas;
|
|
8
|
+
const node_events_1 = require("node:events");
|
|
9
|
+
const node_tls_1 = __importDefault(require("node:tls"));
|
|
10
|
+
const mqtt_1 = __importDefault(require("mqtt"));
|
|
11
|
+
const protocol_1 = require("./protocol");
|
|
12
|
+
const util_1 = require("./util");
|
|
13
|
+
const MIN_BACKOFF = 10_000;
|
|
14
|
+
const MAX_BACKOFF = 24 * 3600_000;
|
|
15
|
+
/**
|
|
16
|
+
* CAs the broker certificate may come from: the platform CA handed out at enrollment, plus the
|
|
17
|
+
* public root certificates shipped with Node.js (Mozilla list). So the broker can run with a
|
|
18
|
+
* certificate of the platform CA or of a public CA (e.g. Let's Encrypt), and the public roots
|
|
19
|
+
* are kept up to date with Node.js instead of a copy in this adapter.
|
|
20
|
+
*/
|
|
21
|
+
function trustedCas(platformCa) {
|
|
22
|
+
return [...node_tls_1.default.rootCertificates, platformCa];
|
|
23
|
+
}
|
|
24
|
+
class Transport extends node_events_1.EventEmitter {
|
|
25
|
+
creds;
|
|
26
|
+
opts;
|
|
27
|
+
client = null;
|
|
28
|
+
backoff = MIN_BACKOFF;
|
|
29
|
+
timer = null;
|
|
30
|
+
stopped = false;
|
|
31
|
+
constructor(creds, opts) {
|
|
32
|
+
super();
|
|
33
|
+
this.creds = creds;
|
|
34
|
+
this.opts = opts;
|
|
35
|
+
}
|
|
36
|
+
get connected() {
|
|
37
|
+
return !!this.client?.connected;
|
|
38
|
+
}
|
|
39
|
+
start() {
|
|
40
|
+
this.stopped = false;
|
|
41
|
+
this.connect();
|
|
42
|
+
}
|
|
43
|
+
async stop() {
|
|
44
|
+
this.stopped = true;
|
|
45
|
+
if (this.timer) {
|
|
46
|
+
clearTimeout(this.timer);
|
|
47
|
+
this.timer = null;
|
|
48
|
+
}
|
|
49
|
+
const client = this.client;
|
|
50
|
+
this.client = null;
|
|
51
|
+
if (client) {
|
|
52
|
+
// regular disconnect: publish offline ourselves, the Last Will only fires on connection loss
|
|
53
|
+
if (client.connected) {
|
|
54
|
+
await client
|
|
55
|
+
.publishAsync(this.topic('state'), (0, util_1.encodePayload)(this.offline()), { qos: 1 })
|
|
56
|
+
.catch(() => { });
|
|
57
|
+
}
|
|
58
|
+
await client.endAsync().catch(() => { });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
topic(t) {
|
|
62
|
+
return (0, protocol_1.deviceTopic)(this.creds.tenantId, this.creds.deviceId, t);
|
|
63
|
+
}
|
|
64
|
+
offline() {
|
|
65
|
+
return { v: protocol_1.PROTOCOL_VERSION, ts: Date.now(), online: false };
|
|
66
|
+
}
|
|
67
|
+
scheduleReconnect() {
|
|
68
|
+
if (this.stopped || this.timer) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const delay = Math.round(this.backoff * (0.8 + Math.random() * 0.4));
|
|
72
|
+
this.opts.log.info(`Broker not reachable, next attempt in ${Math.round(delay / 1000)} s`);
|
|
73
|
+
this.backoff = Math.min(this.backoff * 2, MAX_BACKOFF);
|
|
74
|
+
this.timer = setTimeout(() => {
|
|
75
|
+
this.timer = null;
|
|
76
|
+
this.connect();
|
|
77
|
+
}, delay);
|
|
78
|
+
}
|
|
79
|
+
connect() {
|
|
80
|
+
if (this.stopped) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const client = mqtt_1.default.connect(this.creds.mqttUrl, {
|
|
84
|
+
clientId: this.creds.deviceId,
|
|
85
|
+
key: this.creds.key,
|
|
86
|
+
cert: this.creds.cert,
|
|
87
|
+
ca: trustedCas(this.creds.ca),
|
|
88
|
+
rejectUnauthorized: true,
|
|
89
|
+
protocolVersion: 4,
|
|
90
|
+
clean: false,
|
|
91
|
+
keepalive: this.opts.keepalive,
|
|
92
|
+
reconnectPeriod: 0,
|
|
93
|
+
connectTimeout: 30_000,
|
|
94
|
+
will: { topic: this.topic('state'), payload: (0, util_1.encodePayload)(this.offline()), qos: 1, retain: false },
|
|
95
|
+
});
|
|
96
|
+
this.client = client;
|
|
97
|
+
let rejected = false;
|
|
98
|
+
client.on('connect', () => {
|
|
99
|
+
this.backoff = MIN_BACKOFF;
|
|
100
|
+
client.subscribe([this.topic('desired'), this.topic('job'), (0, protocol_1.controlTopic)(this.creds.tenantId)], { qos: 1 }, err => err && this.opts.log.warn(`Subscribe failed: ${err.message}`));
|
|
101
|
+
this.emit('connected');
|
|
102
|
+
});
|
|
103
|
+
client.on('message', (topic, payload) => {
|
|
104
|
+
try {
|
|
105
|
+
if (topic === this.topic('desired')) {
|
|
106
|
+
this.emit('desired', payload.length ? (0, util_1.decodePayload)(payload) : null);
|
|
107
|
+
}
|
|
108
|
+
else if (topic === (0, protocol_1.controlTopic)(this.creds.tenantId)) {
|
|
109
|
+
if (payload.length) {
|
|
110
|
+
this.emit('control', (0, util_1.decodePayload)(payload));
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
else if (topic === this.topic('job')) {
|
|
114
|
+
this.emit('job', (0, util_1.decodePayload)(payload));
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
catch (e) {
|
|
118
|
+
this.opts.log.warn(`Invalid message on ${topic}: ${e.message}`);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
client.on('error', err => {
|
|
122
|
+
const code = err.code;
|
|
123
|
+
// CONNACK 4/5: the broker knows who we are and says no (certificate revoked)
|
|
124
|
+
if (code === 4 || code === 5 || /Not authorized|Bad username/i.test(err.message)) {
|
|
125
|
+
rejected = true;
|
|
126
|
+
this.stopped = true;
|
|
127
|
+
this.emit('rejected', err.message);
|
|
128
|
+
client.end(true);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
this.opts.log.debug(`MQTT: ${err.message}`);
|
|
132
|
+
});
|
|
133
|
+
client.on('close', () => {
|
|
134
|
+
if (this.client !== client) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
this.emit('disconnected');
|
|
138
|
+
if (!rejected) {
|
|
139
|
+
this.scheduleReconnect();
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
async publish(topic, msg) {
|
|
144
|
+
if (!this.client?.connected) {
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
try {
|
|
148
|
+
await this.client.publishAsync(this.topic(topic), (0, util_1.encodePayload)(msg), { qos: 1 });
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
catch (e) {
|
|
152
|
+
this.opts.log.debug(`Publish ${topic} failed: ${e.message}`);
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
exports.Transport = Transport;
|
|
158
|
+
//# sourceMappingURL=transport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../../src/lib/transport.ts"],"names":[],"mappings":"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"}
|