@camstack/system 1.2.387 → 1.2.389
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.
|
@@ -87517,6 +87517,9 @@ var TlsTcpTransporter = class extends TcpTransporter {
|
|
|
87517
87517
|
/** Node id (certificate CN) → serial of every peer that completed a mutual-TLS handshake. */
|
|
87518
87518
|
tlsPeers = /* @__PURE__ */ new Map();
|
|
87519
87519
|
clearDisabled = false;
|
|
87520
|
+
/** Clear-text `TcpWriter.connect` captured once before the TLS wrap (A→B). */
|
|
87521
|
+
clearWriterConnect = null;
|
|
87522
|
+
writerTlsPatched = false;
|
|
87520
87523
|
constructor(opts = {}) {
|
|
87521
87524
|
super({ ...opts });
|
|
87522
87525
|
this.meshTls = opts.meshTls ?? null;
|
|
@@ -87539,20 +87542,43 @@ var TlsTcpTransporter = class extends TcpTransporter {
|
|
|
87539
87542
|
}).then(() => this.onConnected());
|
|
87540
87543
|
}
|
|
87541
87544
|
/**
|
|
87542
|
-
*
|
|
87543
|
-
*
|
|
87545
|
+
* Outbound dial uses mTLS when the peer is already known on TLS (inbound
|
|
87546
|
+
* handshake), or when dialling the hub node id (agent → hub). Everyone else
|
|
87547
|
+
* (runners, unenrolled agents) stays on the clear writer — the hub must not
|
|
87548
|
+
* TLS-wrap every `connect` after deferred `enableMeshTls`.
|
|
87549
|
+
*/
|
|
87550
|
+
shouldDialPeerWithTls(nodeID) {
|
|
87551
|
+
if (nodeID === "hub") return true;
|
|
87552
|
+
return this.tlsPeers.has(nodeID);
|
|
87553
|
+
}
|
|
87554
|
+
peerTlsDialPort() {
|
|
87555
|
+
return this.opts.tlsPort ?? 6443;
|
|
87556
|
+
}
|
|
87557
|
+
/**
|
|
87558
|
+
* Wrap `TcpWriter.connect` so TLS peers are dialed with mutual TLS on the
|
|
87559
|
+
* well-known mesh TLS port (default 6443). Idempotent: the clear connect is
|
|
87560
|
+
* captured once; material refresh rebinds the wrapper.
|
|
87544
87561
|
*/
|
|
87545
87562
|
patchWriterForTlsClient() {
|
|
87546
|
-
|
|
87547
|
-
if (material === null) return;
|
|
87563
|
+
if (this.meshTls === null) return;
|
|
87548
87564
|
const writer = this.writer;
|
|
87549
87565
|
if (writer === null || typeof writer.connect !== "function") return;
|
|
87566
|
+
if (!this.writerTlsPatched) {
|
|
87567
|
+
this.clearWriterConnect = writer.connect.bind(writer);
|
|
87568
|
+
this.writerTlsPatched = true;
|
|
87569
|
+
}
|
|
87570
|
+
const clearConnect = this.clearWriterConnect;
|
|
87571
|
+
if (clearConnect === null) return;
|
|
87550
87572
|
const crl = this.crl;
|
|
87573
|
+
const self = this;
|
|
87551
87574
|
writer.connect = (nodeID) => {
|
|
87575
|
+
if (!self.shouldDialPeerWithTls(nodeID)) return clearConnect(nodeID);
|
|
87576
|
+
const material = self.meshTls;
|
|
87577
|
+
if (material === null) return clearConnect(nodeID);
|
|
87552
87578
|
const node = writer.transporter.getNode(nodeID);
|
|
87553
87579
|
if (!node) return writer.Promise.reject(/* @__PURE__ */ new Error(`Missing node info for '${nodeID}'!`));
|
|
87554
87580
|
const host = writer.transporter.getNodeAddress(node);
|
|
87555
|
-
const port =
|
|
87581
|
+
const port = self.peerTlsDialPort();
|
|
87556
87582
|
writer.logger.debug(`Connecting (TLS) to '${nodeID}' via ${host}:${port}`);
|
|
87557
87583
|
return new writer.Promise((resolve, reject) => {
|
|
87558
87584
|
const socket = node_tls.connect({
|
|
@@ -87581,6 +87607,11 @@ var TlsTcpTransporter = class extends TcpTransporter {
|
|
|
87581
87607
|
if (identity) {
|
|
87582
87608
|
tlsSock.meshPeerCn = identity.cn;
|
|
87583
87609
|
tlsSock.meshPeerSerial = identity.serial;
|
|
87610
|
+
self.tlsPeers.set(identity.cn, identity.serial);
|
|
87611
|
+
self.tlsSockets.add(tlsSock);
|
|
87612
|
+
tlsSock.on("close", () => {
|
|
87613
|
+
self.tlsSockets.delete(tlsSock);
|
|
87614
|
+
});
|
|
87584
87615
|
}
|
|
87585
87616
|
writer.addSocket(nodeID, tlsSock, true);
|
|
87586
87617
|
writer.logger.debug(`Connected successfully (TLS) to '${nodeID}'.`);
|
|
@@ -87603,11 +87634,13 @@ var TlsTcpTransporter = class extends TcpTransporter {
|
|
|
87603
87634
|
}
|
|
87604
87635
|
/**
|
|
87605
87636
|
* Enable (or refresh) the TLS listener once the mesh CA / hub leaf are ready.
|
|
87606
|
-
* Safe to call after connect — starts listening on `tlsPort` alongside clear
|
|
87637
|
+
* Safe to call after connect — starts listening on `tlsPort` alongside clear
|
|
87638
|
+
* and patches the writer so hub→agent dials use mTLS (Release A→B).
|
|
87607
87639
|
*/
|
|
87608
87640
|
async enableMeshTls(material) {
|
|
87609
87641
|
this.meshTls = material;
|
|
87610
87642
|
await this.startTlsServerIfReady();
|
|
87643
|
+
this.patchWriterForTlsClient();
|
|
87611
87644
|
}
|
|
87612
87645
|
/**
|
|
87613
87646
|
* How `nodeId` reaches this transporter: `tls` once it completed a mutual-TLS
|
|
@@ -87508,6 +87508,9 @@ var TlsTcpTransporter = class extends TcpTransporter {
|
|
|
87508
87508
|
/** Node id (certificate CN) → serial of every peer that completed a mutual-TLS handshake. */
|
|
87509
87509
|
tlsPeers = /* @__PURE__ */ new Map();
|
|
87510
87510
|
clearDisabled = false;
|
|
87511
|
+
/** Clear-text `TcpWriter.connect` captured once before the TLS wrap (A→B). */
|
|
87512
|
+
clearWriterConnect = null;
|
|
87513
|
+
writerTlsPatched = false;
|
|
87511
87514
|
constructor(opts = {}) {
|
|
87512
87515
|
super({ ...opts });
|
|
87513
87516
|
this.meshTls = opts.meshTls ?? null;
|
|
@@ -87530,20 +87533,43 @@ var TlsTcpTransporter = class extends TcpTransporter {
|
|
|
87530
87533
|
}).then(() => this.onConnected());
|
|
87531
87534
|
}
|
|
87532
87535
|
/**
|
|
87533
|
-
*
|
|
87534
|
-
*
|
|
87536
|
+
* Outbound dial uses mTLS when the peer is already known on TLS (inbound
|
|
87537
|
+
* handshake), or when dialling the hub node id (agent → hub). Everyone else
|
|
87538
|
+
* (runners, unenrolled agents) stays on the clear writer — the hub must not
|
|
87539
|
+
* TLS-wrap every `connect` after deferred `enableMeshTls`.
|
|
87540
|
+
*/
|
|
87541
|
+
shouldDialPeerWithTls(nodeID) {
|
|
87542
|
+
if (nodeID === "hub") return true;
|
|
87543
|
+
return this.tlsPeers.has(nodeID);
|
|
87544
|
+
}
|
|
87545
|
+
peerTlsDialPort() {
|
|
87546
|
+
return this.opts.tlsPort ?? 6443;
|
|
87547
|
+
}
|
|
87548
|
+
/**
|
|
87549
|
+
* Wrap `TcpWriter.connect` so TLS peers are dialed with mutual TLS on the
|
|
87550
|
+
* well-known mesh TLS port (default 6443). Idempotent: the clear connect is
|
|
87551
|
+
* captured once; material refresh rebinds the wrapper.
|
|
87535
87552
|
*/
|
|
87536
87553
|
patchWriterForTlsClient() {
|
|
87537
|
-
|
|
87538
|
-
if (material === null) return;
|
|
87554
|
+
if (this.meshTls === null) return;
|
|
87539
87555
|
const writer = this.writer;
|
|
87540
87556
|
if (writer === null || typeof writer.connect !== "function") return;
|
|
87557
|
+
if (!this.writerTlsPatched) {
|
|
87558
|
+
this.clearWriterConnect = writer.connect.bind(writer);
|
|
87559
|
+
this.writerTlsPatched = true;
|
|
87560
|
+
}
|
|
87561
|
+
const clearConnect = this.clearWriterConnect;
|
|
87562
|
+
if (clearConnect === null) return;
|
|
87541
87563
|
const crl = this.crl;
|
|
87564
|
+
const self = this;
|
|
87542
87565
|
writer.connect = (nodeID) => {
|
|
87566
|
+
if (!self.shouldDialPeerWithTls(nodeID)) return clearConnect(nodeID);
|
|
87567
|
+
const material = self.meshTls;
|
|
87568
|
+
if (material === null) return clearConnect(nodeID);
|
|
87543
87569
|
const node = writer.transporter.getNode(nodeID);
|
|
87544
87570
|
if (!node) return writer.Promise.reject(/* @__PURE__ */ new Error(`Missing node info for '${nodeID}'!`));
|
|
87545
87571
|
const host = writer.transporter.getNodeAddress(node);
|
|
87546
|
-
const port =
|
|
87572
|
+
const port = self.peerTlsDialPort();
|
|
87547
87573
|
writer.logger.debug(`Connecting (TLS) to '${nodeID}' via ${host}:${port}`);
|
|
87548
87574
|
return new writer.Promise((resolve, reject) => {
|
|
87549
87575
|
const socket = tls.connect({
|
|
@@ -87572,6 +87598,11 @@ var TlsTcpTransporter = class extends TcpTransporter {
|
|
|
87572
87598
|
if (identity) {
|
|
87573
87599
|
tlsSock.meshPeerCn = identity.cn;
|
|
87574
87600
|
tlsSock.meshPeerSerial = identity.serial;
|
|
87601
|
+
self.tlsPeers.set(identity.cn, identity.serial);
|
|
87602
|
+
self.tlsSockets.add(tlsSock);
|
|
87603
|
+
tlsSock.on("close", () => {
|
|
87604
|
+
self.tlsSockets.delete(tlsSock);
|
|
87605
|
+
});
|
|
87575
87606
|
}
|
|
87576
87607
|
writer.addSocket(nodeID, tlsSock, true);
|
|
87577
87608
|
writer.logger.debug(`Connected successfully (TLS) to '${nodeID}'.`);
|
|
@@ -87594,11 +87625,13 @@ var TlsTcpTransporter = class extends TcpTransporter {
|
|
|
87594
87625
|
}
|
|
87595
87626
|
/**
|
|
87596
87627
|
* Enable (or refresh) the TLS listener once the mesh CA / hub leaf are ready.
|
|
87597
|
-
* Safe to call after connect — starts listening on `tlsPort` alongside clear
|
|
87628
|
+
* Safe to call after connect — starts listening on `tlsPort` alongside clear
|
|
87629
|
+
* and patches the writer so hub→agent dials use mTLS (Release A→B).
|
|
87598
87630
|
*/
|
|
87599
87631
|
async enableMeshTls(material) {
|
|
87600
87632
|
this.meshTls = material;
|
|
87601
87633
|
await this.startTlsServerIfReady();
|
|
87634
|
+
this.patchWriterForTlsClient();
|
|
87602
87635
|
}
|
|
87603
87636
|
/**
|
|
87604
87637
|
* How `nodeId` reaches this transporter: `tls` once it completed a mutual-TLS
|
package/dist/index.js
CHANGED
|
@@ -11608,7 +11608,7 @@ function delay(ms, signal) {
|
|
|
11608
11608
|
*/
|
|
11609
11609
|
async function callRegisterNodeWithRetry(broker, params, opts) {
|
|
11610
11610
|
const action = opts.target === "hub" ? "$hub.registerNode" : "$agent.registerNode";
|
|
11611
|
-
const callOpts = opts.target === "agent" && opts.targetNodeId ? { nodeID: opts.targetNodeId } : void 0;
|
|
11611
|
+
const callOpts = opts.target === "hub" ? { nodeID: "hub" } : opts.target === "agent" && opts.targetNodeId ? { nodeID: opts.targetNodeId } : void 0;
|
|
11612
11612
|
const base = opts.baseDelayMs ?? 250;
|
|
11613
11613
|
let attempt = 0;
|
|
11614
11614
|
for (;;) {
|
package/dist/index.mjs
CHANGED
|
@@ -11605,7 +11605,7 @@ function delay(ms, signal) {
|
|
|
11605
11605
|
*/
|
|
11606
11606
|
async function callRegisterNodeWithRetry(broker, params, opts) {
|
|
11607
11607
|
const action = opts.target === "hub" ? "$hub.registerNode" : "$agent.registerNode";
|
|
11608
|
-
const callOpts = opts.target === "agent" && opts.targetNodeId ? { nodeID: opts.targetNodeId } : void 0;
|
|
11608
|
+
const callOpts = opts.target === "hub" ? { nodeID: "hub" } : opts.target === "agent" && opts.targetNodeId ? { nodeID: opts.targetNodeId } : void 0;
|
|
11609
11609
|
const base = opts.baseDelayMs ?? 250;
|
|
11610
11610
|
let attempt = 0;
|
|
11611
11611
|
for (;;) {
|
|
@@ -77,17 +77,30 @@ export declare class TlsTcpTransporter extends TlsTcpTransporter_base {
|
|
|
77
77
|
/** Node id (certificate CN) → serial of every peer that completed a mutual-TLS handshake. */
|
|
78
78
|
private readonly tlsPeers;
|
|
79
79
|
private clearDisabled;
|
|
80
|
+
/** Clear-text `TcpWriter.connect` captured once before the TLS wrap (A→B). */
|
|
81
|
+
private clearWriterConnect;
|
|
82
|
+
private writerTlsPatched;
|
|
80
83
|
constructor(opts?: TlsTcpTransporterOptions);
|
|
81
84
|
startTcpServer(): Promise<number>;
|
|
82
85
|
connect(): Promise<void>;
|
|
83
86
|
/**
|
|
84
|
-
*
|
|
85
|
-
*
|
|
87
|
+
* Outbound dial uses mTLS when the peer is already known on TLS (inbound
|
|
88
|
+
* handshake), or when dialling the hub node id (agent → hub). Everyone else
|
|
89
|
+
* (runners, unenrolled agents) stays on the clear writer — the hub must not
|
|
90
|
+
* TLS-wrap every `connect` after deferred `enableMeshTls`.
|
|
91
|
+
*/
|
|
92
|
+
private shouldDialPeerWithTls;
|
|
93
|
+
private peerTlsDialPort;
|
|
94
|
+
/**
|
|
95
|
+
* Wrap `TcpWriter.connect` so TLS peers are dialed with mutual TLS on the
|
|
96
|
+
* well-known mesh TLS port (default 6443). Idempotent: the clear connect is
|
|
97
|
+
* captured once; material refresh rebinds the wrapper.
|
|
86
98
|
*/
|
|
87
99
|
private patchWriterForTlsClient;
|
|
88
100
|
/**
|
|
89
101
|
* Enable (or refresh) the TLS listener once the mesh CA / hub leaf are ready.
|
|
90
|
-
* Safe to call after connect — starts listening on `tlsPort` alongside clear
|
|
102
|
+
* Safe to call after connect — starts listening on `tlsPort` alongside clear
|
|
103
|
+
* and patches the writer so hub→agent dials use mTLS (Release A→B).
|
|
91
104
|
*/
|
|
92
105
|
enableMeshTls(material: MeshTlsMaterial): Promise<void>;
|
|
93
106
|
/**
|