@livedesk/hub 0.1.54 → 0.1.55
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/package.json +2 -2
- package/src/remote-hub.js +94 -28
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@livedesk/hub",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.55",
|
|
4
4
|
"description": "VuvoDesk local Hub API and browser frame bridge",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/server.js",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"@ffmpeg-installer/ffmpeg": "^1.1.0",
|
|
19
|
-
"@livedesk/runtime-core": "0.1.
|
|
19
|
+
"@livedesk/runtime-core": "0.1.7",
|
|
20
20
|
"@openai/codex-sdk": "0.145.0",
|
|
21
21
|
"cors": "^2.8.5",
|
|
22
22
|
"express": "^4.21.2",
|
package/src/remote-hub.js
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
|
-
import net from 'net';
|
|
2
|
-
import os from 'os';
|
|
3
|
-
import crypto from 'crypto';
|
|
4
|
-
import {
|
|
1
|
+
import net from 'net';
|
|
2
|
+
import os from 'os';
|
|
3
|
+
import crypto from 'crypto';
|
|
4
|
+
import {
|
|
5
|
+
acceptSecureDirectSocket,
|
|
6
|
+
isDirectSecureChannel,
|
|
7
|
+
isLoopbackSocketAddress,
|
|
8
|
+
isPrivateSocketAddress,
|
|
9
|
+
isSecureDirectHandshakeStart
|
|
10
|
+
} from '../../runtime-core/src/direct-secure-transport.js';
|
|
11
|
+
import { createHubRelayControl } from './transport/relay-hub-control.js';
|
|
5
12
|
import { parseExactLiveStreamMonitorIndex } from './live-stream-monitor-contract.js';
|
|
6
13
|
import {
|
|
7
14
|
BoundedSegmentedBuffer,
|
|
@@ -2397,9 +2404,12 @@ export function createRemoteHub(options = {}) {
|
|
|
2397
2404
|
const hostInstanceId = safeString(options.hostInstanceId ?? env.LIVEDESK_HUB_INSTANCE_ID ?? env.MINDEXEC_BRIDGE_INSTANCE_ID ?? crypto.randomUUID(), 128) || crypto.randomUUID();
|
|
2398
2405
|
const publicEndpoint = safeString(env.LIVEDESK_REMOTE_PUBLIC_ENDPOINT || env.MINDEXEC_REMOTE_PUBLIC_ENDPOINT || env.REMOTE_HUB_PUBLIC_ENDPOINT, 256);
|
|
2399
2406
|
const publicHost = safeString(env.LIVEDESK_REMOTE_PUBLIC_HOST || env.MINDEXEC_REMOTE_PUBLIC_HOST || env.REMOTE_HUB_PUBLIC_HOST, 128);
|
|
2400
|
-
const pairToken = safeString(
|
|
2401
|
-
options.pairToken || env.REMOTE_HUB_PAIR_TOKEN || env.LIVEDESK_CLIENT_PAIR_TOKEN || env.MINDEXEC_REMOTE_PAIR_TOKEN || crypto.randomBytes(
|
|
2402
|
-
256);
|
|
2407
|
+
const pairToken = safeString(
|
|
2408
|
+
options.pairToken || env.REMOTE_HUB_PAIR_TOKEN || env.LIVEDESK_CLIENT_PAIR_TOKEN || env.MINDEXEC_REMOTE_PAIR_TOKEN || crypto.randomBytes(32).toString('hex'),
|
|
2409
|
+
256);
|
|
2410
|
+
const allowInsecurePrivateDirect = isEnabledValue(
|
|
2411
|
+
options.allowInsecureDirect ?? env.LIVEDESK_ALLOW_INSECURE_DIRECT,
|
|
2412
|
+
false);
|
|
2403
2413
|
const relayControl = options.relayControl && typeof options.relayControl === 'object'
|
|
2404
2414
|
? options.relayControl
|
|
2405
2415
|
: createHubRelayControl({
|
|
@@ -7949,10 +7959,24 @@ export function createRemoteHub(options = {}) {
|
|
|
7949
7959
|
function handleAgentMessage(socket, state, message) {
|
|
7950
7960
|
if (!message || typeof message !== 'object') {
|
|
7951
7961
|
return;
|
|
7952
|
-
}
|
|
7953
|
-
|
|
7954
|
-
if (!state.authenticated) {
|
|
7955
|
-
if (
|
|
7962
|
+
}
|
|
7963
|
+
|
|
7964
|
+
if (!state.authenticated) {
|
|
7965
|
+
if (socket.__liveDeskSecureDirect === true) {
|
|
7966
|
+
const applicationChannel = message.type === 'slot.assign'
|
|
7967
|
+
? 'control'
|
|
7968
|
+
: message.type === 'hello'
|
|
7969
|
+
? (safeString(message.channel || message.Channel, 40).toLowerCase() || 'control')
|
|
7970
|
+
: '';
|
|
7971
|
+
if (applicationChannel
|
|
7972
|
+
&& (!isDirectSecureChannel(applicationChannel)
|
|
7973
|
+
|| applicationChannel !== socket.__liveDeskSecureChannel)) {
|
|
7974
|
+
writeJsonLine(socket, { type: 'error', error: 'direct-secure-channel-mismatch' });
|
|
7975
|
+
socket.end();
|
|
7976
|
+
return;
|
|
7977
|
+
}
|
|
7978
|
+
}
|
|
7979
|
+
if (message.type === 'hello' && socket.__liveDeskRelayControl === true) {
|
|
7956
7980
|
message = {
|
|
7957
7981
|
...message,
|
|
7958
7982
|
capabilities: {
|
|
@@ -7988,7 +8012,7 @@ export function createRemoteHub(options = {}) {
|
|
|
7988
8012
|
return;
|
|
7989
8013
|
}
|
|
7990
8014
|
|
|
7991
|
-
const channel = safeString(message.channel || message.Channel, 40).toLowerCase();
|
|
8015
|
+
const channel = safeString(message.channel || message.Channel, 40).toLowerCase() || 'control';
|
|
7992
8016
|
if (channel === 'input') {
|
|
7993
8017
|
const device = attachInputSocket(socket, message);
|
|
7994
8018
|
if (!device) {
|
|
@@ -8538,18 +8562,60 @@ export function createRemoteHub(options = {}) {
|
|
|
8538
8562
|
if (firstChunk) {
|
|
8539
8563
|
processData(firstChunk);
|
|
8540
8564
|
}
|
|
8541
|
-
}
|
|
8542
|
-
|
|
8543
|
-
function handleSocket(socket) {
|
|
8544
|
-
|
|
8545
|
-
|
|
8546
|
-
if (
|
|
8547
|
-
|
|
8548
|
-
|
|
8549
|
-
|
|
8550
|
-
|
|
8551
|
-
|
|
8552
|
-
});
|
|
8565
|
+
}
|
|
8566
|
+
|
|
8567
|
+
function handleSocket(socket) {
|
|
8568
|
+
allSockets.add(socket);
|
|
8569
|
+
const prefaceTimer = setTimeout(() => {
|
|
8570
|
+
if (!socket.destroyed) socket.destroy();
|
|
8571
|
+
}, 10_000);
|
|
8572
|
+
prefaceTimer.unref?.();
|
|
8573
|
+
socket.once('close', () => {
|
|
8574
|
+
clearTimeout(prefaceTimer);
|
|
8575
|
+
allSockets.delete(socket);
|
|
8576
|
+
});
|
|
8577
|
+
socket.once('data', chunk => {
|
|
8578
|
+
clearTimeout(prefaceTimer);
|
|
8579
|
+
const firstChunk = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
8580
|
+
if (isSecureDirectHandshakeStart(firstChunk)) {
|
|
8581
|
+
void acceptSecureDirectSocket(socket, firstChunk, pairToken)
|
|
8582
|
+
.then(secureSocket => {
|
|
8583
|
+
allSockets.delete(socket);
|
|
8584
|
+
handleTcpAgentSocket(secureSocket);
|
|
8585
|
+
})
|
|
8586
|
+
.catch(error => {
|
|
8587
|
+
if (socket.destroyed) return;
|
|
8588
|
+
if (error?.code === 'LIVEDESK_INVALID_PAIR_TOKEN_REJECTED') {
|
|
8589
|
+
const forcedCloseTimer = setTimeout(() => socket.destroy(), 1_000);
|
|
8590
|
+
forcedCloseTimer.unref?.();
|
|
8591
|
+
socket.once('close', () => clearTimeout(forcedCloseTimer));
|
|
8592
|
+
if (typeof socket.destroySoon === 'function') socket.destroySoon();
|
|
8593
|
+
else socket.end();
|
|
8594
|
+
return;
|
|
8595
|
+
}
|
|
8596
|
+
socket.destroy();
|
|
8597
|
+
});
|
|
8598
|
+
return;
|
|
8599
|
+
}
|
|
8600
|
+
|
|
8601
|
+
const remoteAddress = socket.remoteAddress;
|
|
8602
|
+
const allowLegacyPlaintext = isLoopbackSocketAddress(remoteAddress)
|
|
8603
|
+
|| (allowInsecurePrivateDirect && isPrivateSocketAddress(remoteAddress));
|
|
8604
|
+
if (isRemoteHubWebSocketUpgradeStart(firstChunk)) {
|
|
8605
|
+
if (!allowLegacyPlaintext) {
|
|
8606
|
+
socket.destroy();
|
|
8607
|
+
return;
|
|
8608
|
+
}
|
|
8609
|
+
handleWebSocketUpgradeSocket(socket, firstChunk);
|
|
8610
|
+
return;
|
|
8611
|
+
}
|
|
8612
|
+
|
|
8613
|
+
if (!allowLegacyPlaintext) {
|
|
8614
|
+
socket.destroy();
|
|
8615
|
+
return;
|
|
8616
|
+
}
|
|
8617
|
+
handleTcpAgentSocket(socket, firstChunk);
|
|
8618
|
+
});
|
|
8553
8619
|
|
|
8554
8620
|
socket.once('error', () => {
|
|
8555
8621
|
// The transport-specific handler owns logging after the first byte.
|
|
@@ -8571,10 +8637,10 @@ export function createRemoteHub(options = {}) {
|
|
|
8571
8637
|
started = true;
|
|
8572
8638
|
boundPort = candidateServer.address()?.port || port;
|
|
8573
8639
|
lastError = '';
|
|
8574
|
-
logEvent('remote', `VuvoDesk Hub client endpoint listening on tcp://${host}:${boundPort}`, 'success');
|
|
8575
|
-
if (host === '0.0.0.0' || host === '::') {
|
|
8576
|
-
logWarn('remote', 'VuvoDesk Hub client endpoint is externally reachable.
|
|
8577
|
-
}
|
|
8640
|
+
logEvent('remote', `VuvoDesk Hub client endpoint listening on tcp://${host}:${boundPort}`, 'success');
|
|
8641
|
+
if (host === '0.0.0.0' || host === '::') {
|
|
8642
|
+
logWarn('remote', 'VuvoDesk Hub client endpoint is externally reachable. Non-loopback Direct connections require authenticated encryption.');
|
|
8643
|
+
}
|
|
8578
8644
|
emitRemoteEvent('RemoteHubStarted', null);
|
|
8579
8645
|
resolve();
|
|
8580
8646
|
});
|