node-opcua-client 2.177.0 → 2.179.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/alarms_and_conditions/client_alarm_tools.js +7 -5
- package/dist/alarms_and_conditions/client_alarm_tools.js.map +1 -1
- package/dist/alarms_and_conditions/client_tools.js +38 -28
- package/dist/alarms_and_conditions/client_tools.js.map +1 -1
- package/dist/client_base.d.ts +5 -0
- package/dist/client_base.js.map +1 -1
- package/dist/client_monitored_item.d.ts +1 -1
- package/dist/client_monitored_item.js +4 -2
- package/dist/client_monitored_item.js.map +1 -1
- package/dist/client_monitored_item_group.d.ts +4 -3
- package/dist/client_monitored_item_group.js +8 -5
- package/dist/client_monitored_item_group.js.map +1 -1
- package/dist/client_monitored_item_toolbox.js +4 -2
- package/dist/client_monitored_item_toolbox.js.map +1 -1
- package/dist/client_session.d.ts +9 -2
- package/dist/client_session_keepalive_manager.d.ts +1 -1
- package/dist/client_session_keepalive_manager.js +50 -29
- package/dist/client_session_keepalive_manager.js.map +1 -1
- package/dist/client_subscription.d.ts +2 -2
- package/dist/client_subscription.js +3 -1
- package/dist/client_subscription.js.map +1 -1
- package/dist/common.d.ts +3 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/opcua_client.js +1 -0
- package/dist/opcua_client.js.map +1 -1
- package/dist/private/client_base_impl.js +178 -77
- package/dist/private/client_base_impl.js.map +1 -1
- package/dist/private/client_monitored_item_group_impl.d.ts +1 -0
- package/dist/private/client_monitored_item_group_impl.js +6 -8
- package/dist/private/client_monitored_item_group_impl.js.map +1 -1
- package/dist/private/client_monitored_item_impl.js +0 -4
- package/dist/private/client_monitored_item_impl.js.map +1 -1
- package/dist/private/client_publish_engine.js +62 -28
- package/dist/private/client_publish_engine.js.map +1 -1
- package/dist/private/client_session_impl.d.ts +49 -17
- package/dist/private/client_session_impl.js +240 -143
- package/dist/private/client_session_impl.js.map +1 -1
- package/dist/private/client_subscription_impl.js +15 -12
- package/dist/private/client_subscription_impl.js.map +1 -1
- package/dist/private/i_private_client.d.ts +1 -1
- package/dist/private/opcua_client_impl.js +44 -9
- package/dist/private/opcua_client_impl.js.map +1 -1
- package/dist/private/reconnection/client_publish_engine_reconnection.js +17 -7
- package/dist/private/reconnection/client_publish_engine_reconnection.js.map +1 -1
- package/dist/private/reconnection/client_subscription_reconnection.js +11 -7
- package/dist/private/reconnection/client_subscription_reconnection.js.map +1 -1
- package/dist/private/reconnection/reconnection.js +31 -14
- package/dist/private/reconnection/reconnection.js.map +1 -1
- package/dist/reverse/client_reverse_connect.js.map +1 -1
- package/dist/tools/findservers.js.map +1 -1
- package/dist/tools/read_history_server_capabilities.d.ts +2 -1
- package/dist/tools/read_history_server_capabilities.js +6 -3
- package/dist/tools/read_history_server_capabilities.js.map +1 -1
- package/package.json +50 -50
- package/source/alarms_and_conditions/client_alarm_tools.ts +10 -8
- package/source/alarms_and_conditions/client_tools.ts +71 -30
- package/source/client_base.ts +5 -1
- package/source/client_monitored_item.ts +10 -9
- package/source/client_monitored_item_base.ts +2 -8
- package/source/client_monitored_item_group.ts +13 -10
- package/source/client_monitored_item_toolbox.ts +4 -2
- package/source/client_session.ts +10 -3
- package/source/client_session_keepalive_manager.ts +72 -55
- package/source/client_subscription.ts +6 -3
- package/source/common.ts +4 -0
- package/source/index.ts +1 -1
- package/source/opcua_client.ts +1 -0
- package/source/private/client_base_impl.ts +244 -113
- package/source/private/client_monitored_item_group_impl.ts +17 -18
- package/source/private/client_monitored_item_impl.ts +0 -4
- package/source/private/client_publish_engine.ts +78 -40
- package/source/private/client_session_impl.ts +393 -236
- package/source/private/client_subscription_impl.ts +20 -25
- package/source/private/i_private_client.ts +1 -1
- package/source/private/opcua_client_impl.ts +51 -9
- package/source/private/reconnection/client_publish_engine_reconnection.ts +22 -21
- package/source/private/reconnection/client_subscription_reconnection.ts +12 -8
- package/source/private/reconnection/reconnection.ts +35 -18
- package/source/reverse/client_reverse_connect.ts +11 -3
- package/source/tools/findservers.ts +0 -1
- package/source/tools/read_history_server_capabilities.ts +9 -7
|
@@ -7,7 +7,6 @@ exports.ClientBaseImpl = void 0;
|
|
|
7
7
|
/**
|
|
8
8
|
* @module node-opcua-client-private
|
|
9
9
|
*/
|
|
10
|
-
// tslint:disable:no-unused-expression
|
|
11
10
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
12
11
|
const node_path_1 = __importDefault(require("node:path"));
|
|
13
12
|
const global_mutex_1 = require("@ster5/global-mutex");
|
|
@@ -15,17 +14,18 @@ const chalk_1 = __importDefault(require("chalk"));
|
|
|
15
14
|
const node_opcua_assert_1 = require("node-opcua-assert");
|
|
16
15
|
const node_opcua_certificate_manager_1 = require("node-opcua-certificate-manager");
|
|
17
16
|
const node_opcua_common_1 = require("node-opcua-common");
|
|
17
|
+
const node_opcua_crypto_1 = require("node-opcua-crypto");
|
|
18
18
|
const web_1 = require("node-opcua-crypto/web");
|
|
19
19
|
const node_opcua_date_time_1 = require("node-opcua-date-time");
|
|
20
20
|
const node_opcua_debug_1 = require("node-opcua-debug");
|
|
21
21
|
const node_opcua_hostname_1 = require("node-opcua-hostname");
|
|
22
22
|
const node_opcua_secure_channel_1 = require("node-opcua-secure-channel");
|
|
23
|
-
const node_opcua_transport_1 = require("node-opcua-transport");
|
|
24
23
|
const node_opcua_service_discovery_1 = require("node-opcua-service-discovery");
|
|
25
24
|
const node_opcua_service_endpoints_1 = require("node-opcua-service-endpoints");
|
|
26
25
|
const node_opcua_service_secure_channel_1 = require("node-opcua-service-secure-channel");
|
|
27
26
|
const node_opcua_service_session_1 = require("node-opcua-service-session");
|
|
28
27
|
const node_opcua_status_code_1 = require("node-opcua-status-code");
|
|
28
|
+
const node_opcua_transport_1 = require("node-opcua-transport");
|
|
29
29
|
const node_opcua_utils_1 = require("node-opcua-utils");
|
|
30
30
|
const client_base_1 = require("../client_base");
|
|
31
31
|
const verify_1 = require("../verify");
|
|
@@ -72,7 +72,14 @@ function __findEndpoint(endpointUrl, params, _callback) {
|
|
|
72
72
|
// maxRetry: 0 /* no- retry */,
|
|
73
73
|
// maxDelay: 2000
|
|
74
74
|
// },
|
|
75
|
-
privateKeyFile: params.privateKeyFile
|
|
75
|
+
privateKeyFile: params.privateKeyFile,
|
|
76
|
+
// TmpClient.connect() (below) calls _connectStep2() directly and never
|
|
77
|
+
// runs initializeCM() — so it never resolves a passphrase-encrypted
|
|
78
|
+
// private key on its own. Hand it the master client's own provider
|
|
79
|
+
// (already resolved, if needed) instead of letting it build a fresh
|
|
80
|
+
// disk provider from certificateFile/privateKeyFile, which would
|
|
81
|
+
// re-read the file and fail synchronously on an encrypted key.
|
|
82
|
+
certificateKeyPairProvider: masterClient.getProvider()
|
|
76
83
|
};
|
|
77
84
|
const client = new TmpClient(options);
|
|
78
85
|
masterClient._tmpClient = client;
|
|
@@ -175,15 +182,18 @@ async function _verify_serverCertificate(certificateManager, serverCertificate)
|
|
|
175
182
|
}
|
|
176
183
|
}
|
|
177
184
|
const forceEndpointDiscoveryOnConnect = !!parseInt(process.env.NODEOPCUA_CLIENT_FORCE_ENDPOINT_DISCOVERY || "0", 10);
|
|
178
|
-
|
|
185
|
+
// c8 ignore next
|
|
186
|
+
doDebug && debugLog("forceEndpointDiscoveryOnConnect = ", forceEndpointDiscoveryOnConnect);
|
|
179
187
|
class ClockAdjustment {
|
|
180
188
|
constructor() {
|
|
181
|
-
|
|
189
|
+
// c8 ignore next
|
|
190
|
+
doDebug && debugLog("installPeriodicClockAdjustment ", node_opcua_date_time_1.periodicClockAdjustment.timerInstallationCount);
|
|
182
191
|
(0, node_opcua_date_time_1.installPeriodicClockAdjustment)();
|
|
183
192
|
}
|
|
184
193
|
dispose() {
|
|
185
194
|
(0, node_opcua_date_time_1.uninstallPeriodicClockAdjustment)();
|
|
186
|
-
|
|
195
|
+
// c8 ignore next
|
|
196
|
+
doDebug && debugLog("uninstallPeriodicClockAdjustment ", node_opcua_date_time_1.periodicClockAdjustment.timerInstallationCount);
|
|
187
197
|
}
|
|
188
198
|
}
|
|
189
199
|
/*
|
|
@@ -209,7 +219,6 @@ let g_ClientCounter = 0;
|
|
|
209
219
|
/**
|
|
210
220
|
* @internal
|
|
211
221
|
*/
|
|
212
|
-
// tslint:disable-next-line: max-classes-per-file
|
|
213
222
|
class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
214
223
|
/**
|
|
215
224
|
* total number of requests that been canceled due to timeout
|
|
@@ -294,6 +303,8 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
294
303
|
/** the current reverse-connect waiter registration, cancelled on disconnect to avoid a leaked waiter */
|
|
295
304
|
_reverseConnectRegistration;
|
|
296
305
|
clientCertificateManager;
|
|
306
|
+
/** true when the caller supplied a certificateKeyPairProvider — the private-key resolution escape hatch. */
|
|
307
|
+
#hasUserProvidedProvider = false;
|
|
297
308
|
isUnusable() {
|
|
298
309
|
return (this._internalState === "disconnected" ||
|
|
299
310
|
this._internalState === "disconnecting" ||
|
|
@@ -322,6 +333,7 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
322
333
|
}
|
|
323
334
|
constructor(options) {
|
|
324
335
|
options = options || {};
|
|
336
|
+
const hasUserProvidedProvider = !!options.certificateKeyPairProvider;
|
|
325
337
|
if (options.certificateKeyPairProvider) {
|
|
326
338
|
// In-memory path — use a lightweight in-memory store
|
|
327
339
|
// when no cert manager was explicitly provided.
|
|
@@ -337,10 +349,10 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
337
349
|
}
|
|
338
350
|
const cm = options.clientCertificateManager;
|
|
339
351
|
options.privateKeyFile = options.privateKeyFile || cm.privateKey;
|
|
340
|
-
options.certificateFile =
|
|
341
|
-
options.certificateFile || node_path_1.default.join(cm.rootDir, "own/certs/client_certificate.pem");
|
|
352
|
+
options.certificateFile = options.certificateFile || node_path_1.default.join(cm.rootDir, "own/certs/client_certificate.pem");
|
|
342
353
|
super(options);
|
|
343
354
|
}
|
|
355
|
+
this.#hasUserProvidedProvider = hasUserProvidedProvider;
|
|
344
356
|
this._setInternalState("uninitialized");
|
|
345
357
|
this._instanceNumber = g_ClientCounter++;
|
|
346
358
|
this.applicationName = options.applicationName || "NodeOPCUA-Client";
|
|
@@ -348,6 +360,9 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
348
360
|
(0, node_opcua_assert_1.assert)(!this.applicationName.match(/urn:/), "applicationName should not be a URI");
|
|
349
361
|
// we need to delay _applicationUri initialization
|
|
350
362
|
this._applicationUri = options.applicationUri || this._getBuiltApplicationUri();
|
|
363
|
+
if (!options.clientCertificateManager) {
|
|
364
|
+
throw new Error("internal error: clientCertificateManager should have been set above");
|
|
365
|
+
}
|
|
351
366
|
this.clientCertificateManager = options.clientCertificateManager;
|
|
352
367
|
this.clientCertificateManager.referenceCounter++;
|
|
353
368
|
this._secureChannel = null;
|
|
@@ -391,11 +406,14 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
391
406
|
if (!this.isReconnecting) {
|
|
392
407
|
warningLog("internal error: _cancel_reconnection should only be used when reconnecting is in progress");
|
|
393
408
|
}
|
|
394
|
-
|
|
409
|
+
// c8 ignore next
|
|
410
|
+
doDebug && debugLog("canceling reconnection : ", this.clientName);
|
|
395
411
|
this._reconnectionIsCanceled = true;
|
|
396
412
|
// c8 ignore next
|
|
397
413
|
if (!this._secureChannel) {
|
|
398
|
-
|
|
414
|
+
// c8 ignore next
|
|
415
|
+
doDebug &&
|
|
416
|
+
debugLog("_cancel_reconnection: Nothing to do for !", this.clientName, " because secure channel doesn't exist");
|
|
399
417
|
return callback(); // nothing to do
|
|
400
418
|
}
|
|
401
419
|
this._secureChannel.abortConnection(( /*err?: Error*/) => {
|
|
@@ -404,9 +422,11 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
404
422
|
});
|
|
405
423
|
}
|
|
406
424
|
_recreate_secure_channel(callback) {
|
|
407
|
-
|
|
425
|
+
// c8 ignore next
|
|
426
|
+
doDebug && debugLog("_recreate_secure_channel... while internalState is", this._internalState);
|
|
408
427
|
if (!this.knowsServerEndpoint) {
|
|
409
|
-
|
|
428
|
+
// c8 ignore next
|
|
429
|
+
doDebug && debugLog("Cannot reconnect , server endpoint is unknown");
|
|
410
430
|
callback(new Error("Cannot reconnect, server endpoint is unknown - this.knowsServerEndpoint = false"));
|
|
411
431
|
return;
|
|
412
432
|
}
|
|
@@ -428,7 +448,8 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
428
448
|
return callback(new Error(`Reconnection has been canceled - ${this.clientName}`));
|
|
429
449
|
};
|
|
430
450
|
const _failAndRetry = (err, message, callback) => {
|
|
431
|
-
|
|
451
|
+
// c8 ignore next
|
|
452
|
+
doDebug && debugLog("failAndRetry; ", message);
|
|
432
453
|
if (this._reconnectionIsCanceled) {
|
|
433
454
|
return _when_reconnectionIsCanceled(callback);
|
|
434
455
|
}
|
|
@@ -443,12 +464,14 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
443
464
|
this.emit("after_reconnection", null); // send after callback
|
|
444
465
|
(0, node_opcua_assert_1.assert)(this._secureChannel, "expecting a secureChannel here ");
|
|
445
466
|
// a new channel has be created and a new connection is established
|
|
446
|
-
|
|
467
|
+
// c8 ignore next
|
|
468
|
+
doDebug && debugLog(chalk_1.default.bgWhite.red("ClientBaseImpl: RECONNECTED !!!"));
|
|
447
469
|
this._setInternalState("reconnecting_newchannel_connected");
|
|
448
470
|
return callback();
|
|
449
471
|
};
|
|
450
472
|
const _attempt_to_recreate_secure_channel = (callback) => {
|
|
451
|
-
|
|
473
|
+
// c8 ignore next
|
|
474
|
+
doDebug && debugLog("attempt to recreate a new secure channel");
|
|
452
475
|
if (this._reconnectionIsCanceled) {
|
|
453
476
|
return _when_reconnectionIsCanceled(callback);
|
|
454
477
|
}
|
|
@@ -524,7 +547,9 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
524
547
|
_internal_create_secure_channel(connectionStrategy, callback) {
|
|
525
548
|
(0, node_opcua_assert_1.assert)(this._secureChannel === null);
|
|
526
549
|
(0, node_opcua_assert_1.assert)(typeof this.endpointUrl === "string");
|
|
527
|
-
|
|
550
|
+
// c8 ignore next
|
|
551
|
+
doDebug &&
|
|
552
|
+
debugLog("_internal_create_secure_channel creating new ClientSecureChannelLayer _internalState =", this._internalState, this.clientName);
|
|
528
553
|
const secureChannel = new node_opcua_secure_channel_1.ClientSecureChannelLayer({
|
|
529
554
|
connectionStrategy,
|
|
530
555
|
defaultSecureTokenLifetime: this.defaultSecureTokenLifetime,
|
|
@@ -549,11 +574,14 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
549
574
|
this.emit("secure_channel_created", secureChannel);
|
|
550
575
|
const step2_openSecureChannel = () => {
|
|
551
576
|
return new Promise((resolve, reject) => {
|
|
552
|
-
|
|
577
|
+
// c8 ignore next
|
|
578
|
+
doDebug && debugLog("_internal_create_secure_channel before secureChannel.create");
|
|
553
579
|
secureChannel.create(this.endpointUrl, (err) => {
|
|
554
|
-
|
|
580
|
+
// c8 ignore next
|
|
581
|
+
doDebug && debugLog("_internal_create_secure_channel after secureChannel.create");
|
|
555
582
|
if (!this._secureChannel) {
|
|
556
|
-
|
|
583
|
+
// c8 ignore next
|
|
584
|
+
doDebug && debugLog("_secureChannel has been closed during the transaction !");
|
|
557
585
|
return reject(new Error("Secure Channel Closed"));
|
|
558
586
|
}
|
|
559
587
|
if (err) {
|
|
@@ -571,7 +599,8 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
571
599
|
this._setInternalState("connecting");
|
|
572
600
|
this.getEndpoints((err /*, endpoints?: EndpointDescription[]*/) => {
|
|
573
601
|
if (!this._secureChannel) {
|
|
574
|
-
|
|
602
|
+
// c8 ignore next
|
|
603
|
+
doDebug && debugLog("_secureChannel has been closed during the transaction ! (while getEndpoints)");
|
|
575
604
|
return reject(new Error("Secure Channel Closed"));
|
|
576
605
|
}
|
|
577
606
|
if (err) {
|
|
@@ -642,13 +671,22 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
642
671
|
}
|
|
643
672
|
warningLog("Creating default certificate ... please wait");
|
|
644
673
|
await ClientBaseImpl.createCertificate(this.clientCertificateManager, this.certificateFile, this.applicationName, this._getBuiltApplicationUri());
|
|
645
|
-
|
|
674
|
+
// c8 ignore next
|
|
675
|
+
doDebug && debugLog("privateKey = ", this.privateKeyFile);
|
|
646
676
|
if ("privateKey" in this.clientCertificateManager) {
|
|
647
|
-
|
|
677
|
+
// c8 ignore next
|
|
678
|
+
doDebug &&
|
|
679
|
+
debugLog(" = ", this.clientCertificateManager.privateKey);
|
|
648
680
|
}
|
|
649
|
-
|
|
681
|
+
// c8 ignore next
|
|
682
|
+
doDebug && debugLog("certificateFile = ", this.certificateFile);
|
|
650
683
|
const _certificate = this.getCertificate();
|
|
651
|
-
|
|
684
|
+
// Note: do NOT eagerly call this.getPrivateKey() here. A freshly
|
|
685
|
+
// generated key may already be passphrase-encrypted on disk (when
|
|
686
|
+
// clientCertificateManager is configured with privateKeyPassphrase),
|
|
687
|
+
// and the disk provider's getPrivateKey() is synchronous — it cannot
|
|
688
|
+
// decrypt. initializeCM() resolves the private key asynchronously
|
|
689
|
+
// (once) right after this method returns.
|
|
652
690
|
});
|
|
653
691
|
}
|
|
654
692
|
this._inCreateDefaultCertificate = false;
|
|
@@ -668,17 +706,41 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
668
706
|
" Please create a new OPCUAClient instance if you want to reconnect");
|
|
669
707
|
return;
|
|
670
708
|
}
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
709
|
+
// The pki-level initialize() itself already decrypts (or re-encrypts)
|
|
710
|
+
// the on-disk key when clientCertificateManager is configured with a
|
|
711
|
+
// privateKeyPassphrase, and fails closed with
|
|
712
|
+
// PrivateKeyPassphraseRequiredError on a mismatch — so this whole
|
|
713
|
+
// sequence, not just the resolve step below, needs the friendlier
|
|
714
|
+
// error message.
|
|
715
|
+
try {
|
|
716
|
+
await this.clientCertificateManager.initialize();
|
|
717
|
+
if (this.certificateFile === "<in-memory>" || this.certificateFile === "<unknown>") {
|
|
718
|
+
// In-memory provider — cert already available, skip disk operations
|
|
719
|
+
}
|
|
720
|
+
else {
|
|
721
|
+
// Disk path — create default cert if missing
|
|
722
|
+
await this.createDefaultCertificate();
|
|
723
|
+
// c8 ignore next
|
|
724
|
+
if (!node_fs_1.default.existsSync(this.privateKeyFile)) {
|
|
725
|
+
throw new Error(` cannot locate private key file ${this.privateKeyFile}`);
|
|
726
|
+
}
|
|
727
|
+
// Resolve the (possibly passphrase-encrypted) private key once,
|
|
728
|
+
// asynchronously, and install it as this client's provider — so
|
|
729
|
+
// that every later, synchronous getPrivateKey() call (secure
|
|
730
|
+
// channel layer, ...) succeeds without touching disk again.
|
|
731
|
+
// No-ops when the caller supplied its own
|
|
732
|
+
// certificateKeyPairProvider, or when clientCertificateManager
|
|
733
|
+
// doesn't expose an async getPrivateKey() (e.g. a bare
|
|
734
|
+
// ICertificateStore).
|
|
735
|
+
await (0, node_opcua_common_1.resolvePrivateKeyProviderIfNeeded)(this, this.clientCertificateManager, this.#hasUserProvidedProvider);
|
|
736
|
+
}
|
|
674
737
|
}
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
if (!node_fs_1.default.existsSync(this.privateKeyFile)) {
|
|
680
|
-
throw new Error(` cannot locate private key file ${this.privateKeyFile}`);
|
|
738
|
+
catch (err) {
|
|
739
|
+
if (err instanceof node_opcua_crypto_1.PrivateKeyPassphraseRequiredError) {
|
|
740
|
+
throw new Error(`[NODE-OPCUA-E31] private key ${this.privateKeyFile} is encrypted; ` +
|
|
741
|
+
"set privateKeyPassphrase on the OPCUACertificateManager passed as clientCertificateManager");
|
|
681
742
|
}
|
|
743
|
+
throw err;
|
|
682
744
|
}
|
|
683
745
|
if (this.isUnusable())
|
|
684
746
|
return;
|
|
@@ -690,7 +752,8 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
690
752
|
}
|
|
691
753
|
_internalState = "uninitialized";
|
|
692
754
|
_handleUnrecoverableConnectionFailure(err, callback) {
|
|
693
|
-
|
|
755
|
+
// c8 ignore next
|
|
756
|
+
doDebug && debugLog(err.message);
|
|
694
757
|
// Terminal connect failure: make sure the client is removed from the leak registry. A
|
|
695
758
|
// synchronous throw out of _connectStep2 (e.g. an invalid SecureChannel config) lands here
|
|
696
759
|
// WITHOUT the error-branch unregister ever running, which would otherwise leak the client.
|
|
@@ -701,7 +764,8 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
701
764
|
callback(err);
|
|
702
765
|
}
|
|
703
766
|
_handleDisconnectionWhileConnecting(err, callback) {
|
|
704
|
-
|
|
767
|
+
// c8 ignore next
|
|
768
|
+
doDebug && debugLog(err.message);
|
|
705
769
|
// see _handleUnrecoverableConnectionFailure: idempotent unregister guards against a leaked
|
|
706
770
|
// client when a connect attempt fails before the error-branch unregister runs.
|
|
707
771
|
client_base_1.OPCUAClientBase.registry.unregister(this);
|
|
@@ -710,7 +774,8 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
710
774
|
callback(err);
|
|
711
775
|
}
|
|
712
776
|
_handleSuccessfulConnection(callback) {
|
|
713
|
-
|
|
777
|
+
// c8 ignore next
|
|
778
|
+
doDebug && debugLog(" Connected successfully to ", this.endpointUrl);
|
|
714
779
|
this.emit("connected");
|
|
715
780
|
this._setInternalState("connected");
|
|
716
781
|
callback();
|
|
@@ -738,13 +803,15 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
738
803
|
this._setInternalState("connecting");
|
|
739
804
|
this.initializeCM()
|
|
740
805
|
.then(() => {
|
|
741
|
-
|
|
806
|
+
// c8 ignore next
|
|
807
|
+
doDebug && debugLog("ClientBaseImpl#connect ", endpointUrl, this.clientName);
|
|
742
808
|
if (this._internalState === "disconnecting" || this._internalState === "disconnected") {
|
|
743
809
|
return this._handleDisconnectionWhileConnecting(new Error("premature disconnection 1"), callback);
|
|
744
810
|
}
|
|
745
811
|
if (!this.serverCertificate &&
|
|
746
812
|
(forceEndpointDiscoveryOnConnect || this.securityMode !== node_opcua_service_secure_channel_1.MessageSecurityMode.None)) {
|
|
747
|
-
|
|
813
|
+
// c8 ignore next
|
|
814
|
+
doDebug && debugLog("Fetching certificates from endpoints");
|
|
748
815
|
this.fetchServerCertificate(endpointUrl, (err, adjustedEndpointUrl) => {
|
|
749
816
|
if (err) {
|
|
750
817
|
return this._handleUnrecoverableConnectionFailure(err, callback);
|
|
@@ -753,11 +820,14 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
753
820
|
return this._handleDisconnectionWhileConnecting(new Error("premature disconnection 2"), callback);
|
|
754
821
|
}
|
|
755
822
|
if (forceEndpointDiscoveryOnConnect) {
|
|
756
|
-
|
|
823
|
+
// c8 ignore next
|
|
824
|
+
doDebug &&
|
|
825
|
+
debugLog("connecting with adjusted endpoint : ", adjustedEndpointUrl, " was =", endpointUrl);
|
|
757
826
|
this._connectStep2(adjustedEndpointUrl || "", callback);
|
|
758
827
|
}
|
|
759
828
|
else {
|
|
760
|
-
|
|
829
|
+
// c8 ignore next
|
|
830
|
+
doDebug && debugLog("connecting with endpoint : ", endpointUrl);
|
|
761
831
|
this._connectStep2(endpointUrl, callback);
|
|
762
832
|
}
|
|
763
833
|
});
|
|
@@ -827,7 +897,8 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
827
897
|
this._setInternalState("connecting");
|
|
828
898
|
this.initializeCM()
|
|
829
899
|
.then(() => {
|
|
830
|
-
|
|
900
|
+
// c8 ignore next
|
|
901
|
+
doDebug && debugLog("ClientBaseImpl#connectReverse ", placeholderEndpointUrl, this.clientName);
|
|
831
902
|
if (this._internalState === "disconnecting" || this._internalState === "disconnected") {
|
|
832
903
|
return this._handleDisconnectionWhileConnecting(new Error("premature disconnection 1"), callback);
|
|
833
904
|
}
|
|
@@ -848,7 +919,8 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
848
919
|
this.endpointUrl = endpointUrl;
|
|
849
920
|
this._clockAdjuster = this._clockAdjuster || new ClockAdjustment();
|
|
850
921
|
client_base_1.OPCUAClientBase.registry.register(this);
|
|
851
|
-
|
|
922
|
+
// c8 ignore next
|
|
923
|
+
doDebug && debugLog("__connectStep2 ", this._internalState);
|
|
852
924
|
this._internal_create_secure_channel(this.connectionStrategy, (err) => {
|
|
853
925
|
if (!err) {
|
|
854
926
|
this._handleSuccessfulConnection(callback);
|
|
@@ -859,14 +931,17 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
859
931
|
this._clockAdjuster.dispose();
|
|
860
932
|
this._clockAdjuster = undefined;
|
|
861
933
|
}
|
|
862
|
-
|
|
934
|
+
// c8 ignore next
|
|
935
|
+
doDebug && debugLog(chalk_1.default.red("SecureChannel creation has failed with error :", err.message));
|
|
863
936
|
if (err.message.match(/ECONNABORTED/)) {
|
|
864
|
-
|
|
937
|
+
// c8 ignore next
|
|
938
|
+
doDebug && debugLog(chalk_1.default.yellow(`- The client cannot to :${endpointUrl}. Connection has been aborted.`));
|
|
865
939
|
err = new Error("The connection has been aborted");
|
|
866
940
|
this._handleUnrecoverableConnectionFailure(err, callback);
|
|
867
941
|
}
|
|
868
942
|
else if (err.message.match(/ECONNREF/)) {
|
|
869
|
-
|
|
943
|
+
// c8 ignore next
|
|
944
|
+
doDebug && debugLog(chalk_1.default.yellow(`- The client cannot to :${endpointUrl}. Server is not reachable.`));
|
|
870
945
|
err = new Error(`The connection cannot be established with server ${endpointUrl} .\n` +
|
|
871
946
|
"Please check that the server is up and running or your network configuration.\n" +
|
|
872
947
|
"Err = (" +
|
|
@@ -890,7 +965,8 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
890
965
|
// this may happen if the Server has closed the connection abruptly for some unknown reason
|
|
891
966
|
// or if the tcp connection has been broken.
|
|
892
967
|
callback(new Error("performMessageTransaction: No SecureChannel , connection may have been canceled abruptly by server" +
|
|
893
|
-
" while performing " +
|
|
968
|
+
" while performing " +
|
|
969
|
+
request.schema.name));
|
|
894
970
|
return;
|
|
895
971
|
}
|
|
896
972
|
if (this._internalState !== "connected" &&
|
|
@@ -1055,7 +1131,8 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
1055
1131
|
if (!this._secureChannel.isValid()) {
|
|
1056
1132
|
return callback(null);
|
|
1057
1133
|
}
|
|
1058
|
-
|
|
1134
|
+
// c8 ignore next
|
|
1135
|
+
doDebug && debugLog(chalk_1.default.bgWhite.green("_closeSession ") + this._secureChannel.channelId);
|
|
1059
1136
|
const request = new node_opcua_service_session_1.CloseSessionRequest({
|
|
1060
1137
|
deleteSubscriptions
|
|
1061
1138
|
});
|
|
@@ -1083,7 +1160,6 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
1083
1160
|
callback?.(err ? err : undefined);
|
|
1084
1161
|
});
|
|
1085
1162
|
}
|
|
1086
|
-
// eslint-disable-next-line max-statements
|
|
1087
1163
|
disconnect(...args) {
|
|
1088
1164
|
const callback = args[0];
|
|
1089
1165
|
(0, node_opcua_assert_1.assert)(typeof callback === "function", "expecting a callback function here");
|
|
@@ -1111,14 +1187,18 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
1111
1187
|
callback();
|
|
1112
1188
|
return undefined;
|
|
1113
1189
|
}
|
|
1114
|
-
|
|
1190
|
+
// c8 ignore next
|
|
1191
|
+
doDebug && debugLog("disconnecting client! (will set reconnectionIsCanceled to true");
|
|
1115
1192
|
this._reconnectionIsCanceled = true;
|
|
1116
|
-
|
|
1193
|
+
// c8 ignore next
|
|
1194
|
+
doDebug && debugLog("ClientBaseImpl#disconnect", this.endpointUrl);
|
|
1117
1195
|
if (this.isReconnecting && !this._reconnectionIsCanceled) {
|
|
1118
|
-
|
|
1196
|
+
// c8 ignore next
|
|
1197
|
+
doDebug && debugLog("ClientBaseImpl#disconnect called while reconnection is in progress");
|
|
1119
1198
|
// let's abort the reconnection process
|
|
1120
1199
|
this._cancel_reconnection((err) => {
|
|
1121
|
-
|
|
1200
|
+
// c8 ignore next
|
|
1201
|
+
doDebug && debugLog("ClientBaseImpl#disconnect reconnection has been canceled", this.applicationName);
|
|
1122
1202
|
(0, node_opcua_assert_1.assert)(!err, " why would this fail ?");
|
|
1123
1203
|
// sessions cannot be cancelled properly and must be discarded.
|
|
1124
1204
|
this.disconnect(callback);
|
|
@@ -1126,7 +1206,8 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
1126
1206
|
return undefined;
|
|
1127
1207
|
}
|
|
1128
1208
|
if (this._sessions.length && !this.keepPendingSessionsOnDisconnect) {
|
|
1129
|
-
|
|
1209
|
+
// c8 ignore next
|
|
1210
|
+
doDebug && debugLog("warning : disconnection : closing pending sessions");
|
|
1130
1211
|
// disconnect has been called whereas living session exists
|
|
1131
1212
|
// we need to close them first .... (unless keepPendingSessionsOnDisconnect)
|
|
1132
1213
|
this._close_pending_sessions(( /*err*/) => {
|
|
@@ -1134,13 +1215,15 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
1134
1215
|
});
|
|
1135
1216
|
return undefined;
|
|
1136
1217
|
}
|
|
1137
|
-
|
|
1218
|
+
// c8 ignore next
|
|
1219
|
+
doDebug && debugLog("Disconnecting !");
|
|
1138
1220
|
this._setInternalState("disconnecting");
|
|
1139
1221
|
if (this.clientCertificateManager) {
|
|
1140
1222
|
const tmp = this.clientCertificateManager;
|
|
1141
1223
|
// (this as any).clientCertificateManager = null;
|
|
1142
1224
|
tmp.dispose().catch((err) => {
|
|
1143
|
-
|
|
1225
|
+
// c8 ignore next
|
|
1226
|
+
doDebug && debugLog("Error disposing clientCertificateManager", err.message);
|
|
1144
1227
|
});
|
|
1145
1228
|
}
|
|
1146
1229
|
if (this._sessions.length) {
|
|
@@ -1160,7 +1243,8 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
1160
1243
|
if (this._secureChannel) {
|
|
1161
1244
|
let tmpChannel = this._secureChannel;
|
|
1162
1245
|
this._secureChannel = null;
|
|
1163
|
-
|
|
1246
|
+
// c8 ignore next
|
|
1247
|
+
doDebug && debugLog("Closing channel");
|
|
1164
1248
|
tmpChannel.close(() => {
|
|
1165
1249
|
this._secureChannel = tmpChannel;
|
|
1166
1250
|
tmpChannel = null;
|
|
@@ -1225,7 +1309,8 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
1225
1309
|
}
|
|
1226
1310
|
fetchServerCertificate(endpointUrl, callback) {
|
|
1227
1311
|
const discoveryUrl = this.discoveryUrl.length > 0 ? this.discoveryUrl : endpointUrl;
|
|
1228
|
-
|
|
1312
|
+
// c8 ignore next
|
|
1313
|
+
doDebug && debugLog("OPCUAClientImpl : getting serverCertificate");
|
|
1229
1314
|
// we have not been given the serverCertificate but this certificate
|
|
1230
1315
|
// is required as the connection is to be secured.
|
|
1231
1316
|
//
|
|
@@ -1302,8 +1387,12 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
1302
1387
|
const isCA = tbs.extensions?.basicConstraints?.cA === true;
|
|
1303
1388
|
const isSelfSigned = JSON.stringify(tbs.subject) === JSON.stringify(tbs.issuer);
|
|
1304
1389
|
const certType = isCA
|
|
1305
|
-
?
|
|
1306
|
-
|
|
1390
|
+
? isSelfSigned
|
|
1391
|
+
? "Root CA"
|
|
1392
|
+
: "Intermediate CA"
|
|
1393
|
+
: isSelfSigned
|
|
1394
|
+
? "Application (self-signed)"
|
|
1395
|
+
: "Application (CA-signed)";
|
|
1307
1396
|
const ski = tbs.extensions?.subjectKeyIdentifier ?? "-";
|
|
1308
1397
|
const aki = tbs.extensions?.authorityKeyIdentifier?.keyIdentifier ?? "-";
|
|
1309
1398
|
const notBefore = tbs.validity.notBefore.toISOString();
|
|
@@ -1375,7 +1464,8 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
1375
1464
|
resolved = true;
|
|
1376
1465
|
if (err) {
|
|
1377
1466
|
const msg = session.authenticationToken ? session.authenticationToken.toString() : "";
|
|
1378
|
-
|
|
1467
|
+
// c8 ignore next
|
|
1468
|
+
doDebug && debugLog(` failing to close session ${msg}`);
|
|
1379
1469
|
}
|
|
1380
1470
|
resolve();
|
|
1381
1471
|
});
|
|
@@ -1386,9 +1476,11 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
1386
1476
|
.then(() => {
|
|
1387
1477
|
// c8 ignore next
|
|
1388
1478
|
if (this._sessions.length > 0) {
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
.
|
|
1479
|
+
// c8 ignore next
|
|
1480
|
+
doDebug &&
|
|
1481
|
+
debugLog(this._sessions
|
|
1482
|
+
.map((s) => (s.authenticationToken ? s.authenticationToken.toString() : ""))
|
|
1483
|
+
.join(" "));
|
|
1392
1484
|
}
|
|
1393
1485
|
(0, node_opcua_assert_1.assert)(this._sessions.length === 0, " failed to disconnect exiting sessions ");
|
|
1394
1486
|
callback();
|
|
@@ -1431,7 +1523,9 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
1431
1523
|
});
|
|
1432
1524
|
secureChannel.on("lifetime_75", (token) => {
|
|
1433
1525
|
// secureChannel requests a new token
|
|
1434
|
-
|
|
1526
|
+
// c8 ignore next
|
|
1527
|
+
doDebug &&
|
|
1528
|
+
debugLog("SecureChannel Security Token ", token.tokenId, "live time was =", token.revisedLifetime, " is about to expired , it's time to request a new token");
|
|
1435
1529
|
// forward message to upper level
|
|
1436
1530
|
this.emit("lifetime_75", token);
|
|
1437
1531
|
});
|
|
@@ -1443,7 +1537,8 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
1443
1537
|
if (err) {
|
|
1444
1538
|
this._setInternalState("panic");
|
|
1445
1539
|
}
|
|
1446
|
-
|
|
1540
|
+
// c8 ignore next
|
|
1541
|
+
doDebug && debugLog(chalk_1.default.yellow.bold(" ClientBaseImpl emitting close"), err?.message);
|
|
1447
1542
|
this._destroy_secure_channel();
|
|
1448
1543
|
if (!err || !this.reconnectOnFailure) {
|
|
1449
1544
|
if (err) {
|
|
@@ -1459,7 +1554,8 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
1459
1554
|
if (this.reconnectOnFailure &&
|
|
1460
1555
|
this._internalState !== "reconnecting" &&
|
|
1461
1556
|
this._internalState !== "reconnecting_newchannel_connected") {
|
|
1462
|
-
|
|
1557
|
+
// c8 ignore next
|
|
1558
|
+
doDebug && debugLog(" ClientBaseImpl emitting connection_lost");
|
|
1463
1559
|
this._setInternalState("reconnecting");
|
|
1464
1560
|
/**
|
|
1465
1561
|
* @event connection_lost
|
|
@@ -1508,7 +1604,8 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
1508
1604
|
__innerRepairConnection() {
|
|
1509
1605
|
if (this.isUnusable())
|
|
1510
1606
|
return;
|
|
1511
|
-
|
|
1607
|
+
// c8 ignore next
|
|
1608
|
+
doDebug && debugLog("Entering _repairConnection ", this._internalState);
|
|
1512
1609
|
if (this.#insideRepairConnection) {
|
|
1513
1610
|
errorLog("_repairConnection already in progress internal state = ", this._internalState, "clientName =", this.clientName);
|
|
1514
1611
|
this.#shouldRepairAgain = true;
|
|
@@ -1516,11 +1613,14 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
1516
1613
|
}
|
|
1517
1614
|
this.emit("repairConnectionStarted");
|
|
1518
1615
|
this.#insideRepairConnection = true;
|
|
1519
|
-
|
|
1616
|
+
// c8 ignore next
|
|
1617
|
+
doDebug && debugLog("recreating new secure channel ", this._internalState);
|
|
1520
1618
|
this._recreate_secure_channel((err1) => {
|
|
1521
|
-
|
|
1619
|
+
// c8 ignore next
|
|
1620
|
+
doDebug && debugLog("secureChannel#on(close) => _recreate_secure_channel returns ", err1 ? err1.message : "OK");
|
|
1522
1621
|
if (err1) {
|
|
1523
|
-
|
|
1622
|
+
// c8 ignore next
|
|
1623
|
+
doDebug && debugLog("_recreate_secure_channel has failed: err = ", err1.message);
|
|
1524
1624
|
this.emit("close", err1);
|
|
1525
1625
|
this.#insideRepairConnection = false;
|
|
1526
1626
|
if (this.#shouldRepairAgain) {
|
|
@@ -1543,8 +1643,11 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
1543
1643
|
debugLog("err= ", err2.message);
|
|
1544
1644
|
}
|
|
1545
1645
|
// we still need to retry connecting here !!!
|
|
1546
|
-
|
|
1547
|
-
|
|
1646
|
+
// c8 ignore next
|
|
1647
|
+
if (doDebug) {
|
|
1648
|
+
debugLog("Disconnected following reconnection failure", err2.message);
|
|
1649
|
+
debugLog(`I will retry OPCUA client reconnection in ${client_base_1.OPCUAClientBase.retryDelay / 1000} seconds`);
|
|
1650
|
+
}
|
|
1548
1651
|
this.#insideRepairConnection = false;
|
|
1549
1652
|
this.#shouldRepairAgain = false;
|
|
1550
1653
|
this._destroy_secure_channel();
|
|
@@ -1591,14 +1694,14 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
1591
1694
|
}
|
|
1592
1695
|
}
|
|
1593
1696
|
exports.ClientBaseImpl = ClientBaseImpl;
|
|
1594
|
-
// tslint:disable-next-line: max-classes-per-file
|
|
1595
1697
|
class TmpClient extends ClientBaseImpl {
|
|
1596
1698
|
constructor(options) {
|
|
1597
1699
|
options.clientName = `${options.clientName || ""}_TmpClient`;
|
|
1598
1700
|
super(options);
|
|
1599
1701
|
}
|
|
1600
1702
|
connect(endpoint, callback) {
|
|
1601
|
-
|
|
1703
|
+
// c8 ignore next
|
|
1704
|
+
doDebug && debugLog("connecting to TmpClient");
|
|
1602
1705
|
// c8 ignore next
|
|
1603
1706
|
if (this._internalState !== "disconnected") {
|
|
1604
1707
|
callback?.(new Error(`TmpClient#connect: invalid internal state = ${this._internalState}`));
|
|
@@ -1614,8 +1717,6 @@ class TmpClient extends ClientBaseImpl {
|
|
|
1614
1717
|
});
|
|
1615
1718
|
}
|
|
1616
1719
|
}
|
|
1617
|
-
// tslint:disable:no-var-requires
|
|
1618
|
-
// tslint:disable:max-line-length
|
|
1619
1720
|
const thenify_ex_1 = require("thenify-ex");
|
|
1620
1721
|
ClientBaseImpl.prototype.connect = (0, thenify_ex_1.withCallback)(ClientBaseImpl.prototype.connect);
|
|
1621
1722
|
ClientBaseImpl.prototype.connectReverse = (0, thenify_ex_1.withCallback)(ClientBaseImpl.prototype.connectReverse);
|