node-opcua-client 2.183.0 → 2.184.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.d.ts +1 -0
- package/dist/alarms_and_conditions/client_alarm_tools.d.ts.map +1 -0
- package/dist/alarms_and_conditions/client_alarm_tools.js +23 -27
- package/dist/alarms_and_conditions/client_alarm_tools.js.map +1 -1
- package/dist/alarms_and_conditions/client_tools.d.ts +1 -0
- package/dist/alarms_and_conditions/client_tools.d.ts.map +1 -0
- package/dist/alarms_and_conditions/client_tools.js +17 -19
- package/dist/alarms_and_conditions/client_tools.js.map +1 -1
- package/dist/client_base.d.ts +1 -0
- package/dist/client_base.d.ts.map +1 -0
- package/dist/client_base.js +3 -6
- package/dist/client_base.js.map +1 -1
- package/dist/client_monitored_item.d.ts +1 -0
- package/dist/client_monitored_item.d.ts.map +1 -0
- package/dist/client_monitored_item.js +4 -7
- package/dist/client_monitored_item.js.map +1 -1
- package/dist/client_monitored_item_base.d.ts +1 -0
- package/dist/client_monitored_item_base.d.ts.map +1 -0
- package/dist/client_monitored_item_base.js +1 -2
- package/dist/client_monitored_item_group.d.ts +1 -0
- package/dist/client_monitored_item_group.d.ts.map +1 -0
- package/dist/client_monitored_item_group.js +2 -5
- package/dist/client_monitored_item_group.js.map +1 -1
- package/dist/client_monitored_item_toolbox.d.ts +1 -0
- package/dist/client_monitored_item_toolbox.d.ts.map +1 -0
- package/dist/client_monitored_item_toolbox.js +21 -27
- package/dist/client_monitored_item_toolbox.js.map +1 -1
- package/dist/client_session.d.ts +2 -1
- package/dist/client_session.d.ts.map +1 -0
- package/dist/client_session.js +2 -7
- package/dist/client_session.js.map +1 -1
- package/dist/client_session_keepalive_manager.d.ts +1 -0
- package/dist/client_session_keepalive_manager.d.ts.map +1 -0
- package/dist/client_session_keepalive_manager.js +24 -31
- package/dist/client_session_keepalive_manager.js.map +1 -1
- package/dist/client_subscription.d.ts +1 -0
- package/dist/client_subscription.d.ts.map +1 -0
- package/dist/client_subscription.js +1 -5
- package/dist/client_subscription.js.map +1 -1
- package/dist/client_utils.d.ts +1 -0
- package/dist/client_utils.d.ts.map +1 -0
- package/dist/client_utils.js +7 -10
- package/dist/client_utils.js.map +1 -1
- package/dist/common.d.ts +1 -0
- package/dist/common.d.ts.map +1 -0
- package/dist/common.js +1 -2
- package/dist/common.js.map +1 -1
- package/dist/index.d.ts +7 -3
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +52 -118
- package/dist/index.js.map +1 -1
- package/dist/opcua_client.d.ts +1 -0
- package/dist/opcua_client.d.ts.map +1 -0
- package/dist/opcua_client.js +6 -10
- package/dist/opcua_client.js.map +1 -1
- package/dist/private/client_base_impl.d.ts +1 -0
- package/dist/private/client_base_impl.d.ts.map +1 -0
- package/dist/private/client_base_impl.js +146 -150
- package/dist/private/client_base_impl.js.map +1 -1
- package/dist/private/client_monitored_item_base_impl.d.ts +1 -0
- package/dist/private/client_monitored_item_base_impl.d.ts.map +1 -0
- package/dist/private/client_monitored_item_base_impl.js +1 -2
- package/dist/private/client_monitored_item_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.d.ts.map +1 -0
- package/dist/private/client_monitored_item_group_impl.js +31 -35
- package/dist/private/client_monitored_item_group_impl.js.map +1 -1
- package/dist/private/client_monitored_item_impl.d.ts +1 -0
- package/dist/private/client_monitored_item_impl.d.ts.map +1 -0
- package/dist/private/client_monitored_item_impl.js +41 -45
- package/dist/private/client_monitored_item_impl.js.map +1 -1
- package/dist/private/client_publish_engine.d.ts +1 -0
- package/dist/private/client_publish_engine.d.ts.map +1 -0
- package/dist/private/client_publish_engine.js +47 -54
- package/dist/private/client_publish_engine.js.map +1 -1
- package/dist/private/client_session_impl.d.ts +1 -0
- package/dist/private/client_session_impl.d.ts.map +1 -0
- package/dist/private/client_session_impl.js +231 -238
- package/dist/private/client_session_impl.js.map +1 -1
- package/dist/private/client_subscription_impl.d.ts +1 -0
- package/dist/private/client_subscription_impl.d.ts.map +1 -0
- package/dist/private/client_subscription_impl.js +93 -102
- package/dist/private/client_subscription_impl.js.map +1 -1
- package/dist/private/i_private_client.d.ts +1 -0
- package/dist/private/i_private_client.d.ts.map +1 -0
- package/dist/private/i_private_client.js +1 -2
- package/dist/private/opcua_client_impl.d.ts +1 -0
- package/dist/private/opcua_client_impl.d.ts.map +1 -0
- package/dist/private/opcua_client_impl.js +138 -145
- package/dist/private/opcua_client_impl.js.map +1 -1
- package/dist/private/performance.d.ts +1 -0
- package/dist/private/performance.d.ts.map +1 -0
- package/dist/private/performance.js +1 -4
- package/dist/private/performance.js.map +1 -1
- package/dist/private/reconnection/client_publish_engine_reconnection.d.ts +1 -0
- package/dist/private/reconnection/client_publish_engine_reconnection.d.ts.map +1 -0
- package/dist/private/reconnection/client_publish_engine_reconnection.js +28 -34
- package/dist/private/reconnection/client_publish_engine_reconnection.js.map +1 -1
- package/dist/private/reconnection/client_reconnection.d.ts +1 -0
- package/dist/private/reconnection/client_reconnection.d.ts.map +1 -0
- package/dist/private/reconnection/client_reconnection.js +1 -4
- package/dist/private/reconnection/client_reconnection.js.map +1 -1
- package/dist/private/reconnection/client_subscription_reconnection.d.ts +1 -0
- package/dist/private/reconnection/client_subscription_reconnection.d.ts.map +1 -0
- package/dist/private/reconnection/client_subscription_reconnection.js +25 -31
- package/dist/private/reconnection/client_subscription_reconnection.js.map +1 -1
- package/dist/private/reconnection/reconnection.d.ts +1 -0
- package/dist/private/reconnection/reconnection.d.ts.map +1 -0
- package/dist/private/reconnection/reconnection.js +50 -59
- package/dist/private/reconnection/reconnection.js.map +1 -1
- package/dist/reverse/client_reverse_connect.d.ts +1 -0
- package/dist/reverse/client_reverse_connect.d.ts.map +1 -0
- package/dist/reverse/client_reverse_connect.js +20 -24
- package/dist/reverse/client_reverse_connect.js.map +1 -1
- package/dist/tools/findservers.d.ts +1 -0
- package/dist/tools/findservers.d.ts.map +1 -0
- package/dist/tools/findservers.js +7 -13
- package/dist/tools/findservers.js.map +1 -1
- package/dist/tools/read_history_server_capabilities.d.ts +1 -0
- package/dist/tools/read_history_server_capabilities.d.ts.map +1 -0
- package/dist/tools/read_history_server_capabilities.js +13 -16
- package/dist/tools/read_history_server_capabilities.js.map +1 -1
- package/dist/user_identity_info.d.ts +2 -1
- package/dist/user_identity_info.d.ts.map +1 -0
- package/dist/user_identity_info.js +1 -2
- package/dist/verify.d.ts +1 -0
- package/dist/verify.d.ts.map +1 -0
- package/dist/verify.js +15 -19
- package/dist/verify.js.map +1 -1
- package/package.json +48 -47
- package/source/alarms_and_conditions/client_alarm_tools.ts +1 -1
- package/source/client_monitored_item_toolbox.ts +1 -1
- package/source/client_session.ts +1 -1
- package/source/index.ts +5 -3
- package/source/private/client_base_impl.ts +5 -2
- package/source/private/client_publish_engine.ts +16 -16
- package/source/private/client_subscription_impl.ts +1 -1
- package/source/private/opcua_client_impl.ts +4 -4
- package/source/private/reconnection/client_publish_engine_reconnection.ts +7 -7
- package/source/private/reconnection/client_subscription_reconnection.ts +5 -5
- package/source/private/reconnection/reconnection.ts +3 -3
- package/source/reverse/client_reverse_connect.ts +1 -1
- package/source/user_identity_info.ts +1 -1
|
@@ -1,42 +1,36 @@
|
|
|
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.ClientBaseImpl = void 0;
|
|
7
1
|
/**
|
|
8
2
|
* @module node-opcua-client-private
|
|
9
3
|
*/
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const debugLog =
|
|
33
|
-
const doDebug =
|
|
34
|
-
const errorLog =
|
|
35
|
-
const warningLog =
|
|
4
|
+
import fs from "node:fs";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { withLock } from "@ster5/global-mutex";
|
|
7
|
+
import chalk from "chalk";
|
|
8
|
+
import { assert } from "node-opcua-assert";
|
|
9
|
+
import { getDefaultCertificateManager } from "node-opcua-certificate-manager";
|
|
10
|
+
import { InMemoryCertificateStore, makeApplicationUrn, makeSubject, OPCUASecureObject, resolvePrivateKeyProviderIfNeeded } from "node-opcua-common";
|
|
11
|
+
import { PrivateKeyPassphraseRequiredError } from "node-opcua-crypto";
|
|
12
|
+
import { exploreCertificate, makeSHA1Thumbprint, split_der } from "node-opcua-crypto/web";
|
|
13
|
+
import { installPeriodicClockAdjustment, periodicClockAdjustment, uninstallPeriodicClockAdjustment } from "node-opcua-date-time";
|
|
14
|
+
import { checkDebugFlag, make_debugLog, make_errorLog, make_warningLog } from "node-opcua-debug";
|
|
15
|
+
import { getHostname } from "node-opcua-hostname";
|
|
16
|
+
import { ClientSecureChannelLayer, coerceConnectionStrategy, coerceSecurityPolicy } from "node-opcua-secure-channel";
|
|
17
|
+
import { FindServersOnNetworkRequest, FindServersOnNetworkResponse, FindServersRequest, FindServersResponse } from "node-opcua-service-discovery";
|
|
18
|
+
import { GetEndpointsRequest, GetEndpointsResponse } from "node-opcua-service-endpoints";
|
|
19
|
+
import { coerceMessageSecurityMode, MessageSecurityMode, ServiceFault } from "node-opcua-service-secure-channel";
|
|
20
|
+
import { CloseSessionRequest } from "node-opcua-service-session";
|
|
21
|
+
import { StatusCodes } from "node-opcua-status-code";
|
|
22
|
+
import { makeReverseClientTransportFactory } from "node-opcua-transport";
|
|
23
|
+
import { checkFileExistsAndIsNotEmpty, matchUri } from "node-opcua-utils";
|
|
24
|
+
import { OPCUAClientBase } from "../client_base.js";
|
|
25
|
+
import { performCertificateSanityCheck } from "../verify.js";
|
|
26
|
+
const debugLog = make_debugLog("client_base_impl");
|
|
27
|
+
const doDebug = checkDebugFlag("client_base_impl");
|
|
28
|
+
const errorLog = make_errorLog("client_base_impl");
|
|
29
|
+
const warningLog = make_warningLog("client_base_impl");
|
|
36
30
|
function makeCertificateThumbPrint(certificate) {
|
|
37
31
|
if (!certificate)
|
|
38
32
|
return null;
|
|
39
|
-
return
|
|
33
|
+
return makeSHA1Thumbprint(Array.isArray(certificate) ? certificate[0] : certificate);
|
|
40
34
|
}
|
|
41
35
|
const traceInternalState = false;
|
|
42
36
|
const defaultConnectionStrategy = {
|
|
@@ -52,7 +46,7 @@ function __findEndpoint(endpointUrl, params, _callback) {
|
|
|
52
46
|
const masterClient = this;
|
|
53
47
|
doDebug && debugLog("findEndpoint : endpointUrl = ", endpointUrl);
|
|
54
48
|
doDebug && debugLog(" params ", params);
|
|
55
|
-
|
|
49
|
+
assert(!masterClient._tmpClient);
|
|
56
50
|
const callback = (err, result) => {
|
|
57
51
|
masterClient._tmpClient = undefined;
|
|
58
52
|
_callback(err, result);
|
|
@@ -91,7 +85,7 @@ function __findEndpoint(endpointUrl, params, _callback) {
|
|
|
91
85
|
masterClient.listeners("backoff").forEach((handler) => {
|
|
92
86
|
client.on("backoff", handler);
|
|
93
87
|
});
|
|
94
|
-
|
|
88
|
+
/* c8 ignore next */
|
|
95
89
|
if (doDebug) {
|
|
96
90
|
client.on("backoff", (retryCount, delay) => {
|
|
97
91
|
debugLog("finding Endpoint => reconnecting ", " retry count", retryCount, " next attempt in ", delay / 1000, "seconds");
|
|
@@ -154,7 +148,7 @@ function __findEndpoint(endpointUrl, params, _callback) {
|
|
|
154
148
|
}
|
|
155
149
|
// c8 ignore next
|
|
156
150
|
if (doDebug) {
|
|
157
|
-
debugLog(
|
|
151
|
+
debugLog(chalk.bgWhite.red("xxxxxxxxxxxxxxxxxxxxx => selected EndPoint = "), selectedEndpoint.toString());
|
|
158
152
|
}
|
|
159
153
|
callback(null, { endpoints: allEndpoints, selectedEndpoint });
|
|
160
154
|
})
|
|
@@ -187,13 +181,13 @@ doDebug && debugLog("forceEndpointDiscoveryOnConnect = ", forceEndpointDiscovery
|
|
|
187
181
|
class ClockAdjustment {
|
|
188
182
|
constructor() {
|
|
189
183
|
// c8 ignore next
|
|
190
|
-
doDebug && debugLog("installPeriodicClockAdjustment ",
|
|
191
|
-
|
|
184
|
+
doDebug && debugLog("installPeriodicClockAdjustment ", periodicClockAdjustment.timerInstallationCount);
|
|
185
|
+
installPeriodicClockAdjustment();
|
|
192
186
|
}
|
|
193
187
|
dispose() {
|
|
194
|
-
|
|
188
|
+
uninstallPeriodicClockAdjustment();
|
|
195
189
|
// c8 ignore next
|
|
196
|
-
doDebug && debugLog("uninstallPeriodicClockAdjustment ",
|
|
190
|
+
doDebug && debugLog("uninstallPeriodicClockAdjustment ", periodicClockAdjustment.timerInstallationCount);
|
|
197
191
|
}
|
|
198
192
|
}
|
|
199
193
|
/*
|
|
@@ -219,7 +213,7 @@ let g_ClientCounter = 0;
|
|
|
219
213
|
/**
|
|
220
214
|
* @internal
|
|
221
215
|
*/
|
|
222
|
-
class ClientBaseImpl extends
|
|
216
|
+
export class ClientBaseImpl extends OPCUASecureObject {
|
|
223
217
|
/**
|
|
224
218
|
* total number of requests that been canceled due to timeout
|
|
225
219
|
*/
|
|
@@ -314,7 +308,7 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
314
308
|
_setInternalState(internalState) {
|
|
315
309
|
const previousState = this._internalState;
|
|
316
310
|
if (doDebug || traceInternalState) {
|
|
317
|
-
(traceInternalState ? warningLog : debugLog)(
|
|
311
|
+
(traceInternalState ? warningLog : debugLog)(chalk.cyan(` Client ${this._instanceNumber} ${this.clientName} : _internalState from `), chalk.yellow(previousState), "to", chalk.yellow(internalState));
|
|
318
312
|
}
|
|
319
313
|
if (this._internalState === "disconnecting" || this._internalState === "disconnected") {
|
|
320
314
|
if (internalState === "reconnecting") {
|
|
@@ -326,7 +320,7 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
326
320
|
emit(eventName, ...others) {
|
|
327
321
|
// c8 ignore next
|
|
328
322
|
if (doDebug) {
|
|
329
|
-
debugLog(
|
|
323
|
+
debugLog(chalk.cyan(` Client ${this._instanceNumber} ${this.clientName} emitting `), chalk.magentaBright(eventName));
|
|
330
324
|
}
|
|
331
325
|
// @ts-expect-error
|
|
332
326
|
return super.emit(eventName, ...others);
|
|
@@ -338,26 +332,26 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
338
332
|
// In-memory path — use a lightweight in-memory store
|
|
339
333
|
// when no cert manager was explicitly provided.
|
|
340
334
|
if (!options.clientCertificateManager) {
|
|
341
|
-
options.clientCertificateManager = new
|
|
335
|
+
options.clientCertificateManager = new InMemoryCertificateStore();
|
|
342
336
|
}
|
|
343
337
|
super(options);
|
|
344
338
|
}
|
|
345
339
|
else {
|
|
346
340
|
// Disk path — derive cert/key paths from certificate manager
|
|
347
341
|
if (!options.clientCertificateManager) {
|
|
348
|
-
options.clientCertificateManager =
|
|
342
|
+
options.clientCertificateManager = getDefaultCertificateManager("PKI");
|
|
349
343
|
}
|
|
350
344
|
const cm = options.clientCertificateManager;
|
|
351
345
|
options.privateKeyFile = options.privateKeyFile || cm.privateKey;
|
|
352
|
-
options.certificateFile = options.certificateFile ||
|
|
346
|
+
options.certificateFile = options.certificateFile || path.join(cm.rootDir, "own/certs/client_certificate.pem");
|
|
353
347
|
super(options);
|
|
354
348
|
}
|
|
355
349
|
this.#hasUserProvidedProvider = hasUserProvidedProvider;
|
|
356
350
|
this._setInternalState("uninitialized");
|
|
357
351
|
this._instanceNumber = g_ClientCounter++;
|
|
358
352
|
this.applicationName = options.applicationName || "NodeOPCUA-Client";
|
|
359
|
-
|
|
360
|
-
|
|
353
|
+
assert(!this.applicationName.match(/^locale=/), "applicationName badly converted from LocalizedText");
|
|
354
|
+
assert(!this.applicationName.match(/urn:/), "applicationName should not be a URI");
|
|
361
355
|
// we need to delay _applicationUri initialization
|
|
362
356
|
this._applicationUri = options.applicationUri || this._getBuiltApplicationUri();
|
|
363
357
|
if (!options.clientCertificateManager) {
|
|
@@ -376,9 +370,9 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
376
370
|
this.defaultSecureTokenLifetime = options.defaultSecureTokenLifetime || 600000;
|
|
377
371
|
this.defaultTransactionTimeout = options.defaultTransactionTimeout;
|
|
378
372
|
this.tokenRenewalInterval = options.tokenRenewalInterval || 0;
|
|
379
|
-
|
|
380
|
-
this.securityMode =
|
|
381
|
-
this.securityPolicy =
|
|
373
|
+
assert(Number.isFinite(this.tokenRenewalInterval) && this.tokenRenewalInterval >= 0);
|
|
374
|
+
this.securityMode = coerceMessageSecurityMode(options.securityMode);
|
|
375
|
+
this.securityPolicy = coerceSecurityPolicy(options.securityPolicy);
|
|
382
376
|
this.serverCertificate = options.serverCertificate;
|
|
383
377
|
this.keepSessionAlive = typeof options.keepSessionAlive === "boolean" ? options.keepSessionAlive : false;
|
|
384
378
|
this.keepAliveInterval = options.keepAliveInterval;
|
|
@@ -387,7 +381,7 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
387
381
|
this._byteWritten = 0;
|
|
388
382
|
this._transactionsPerformed = 0;
|
|
389
383
|
this._timedOutRequestCount = 0;
|
|
390
|
-
this.connectionStrategy =
|
|
384
|
+
this.connectionStrategy = coerceConnectionStrategy(options.connectionStrategy || defaultConnectionStrategy);
|
|
391
385
|
/***
|
|
392
386
|
* @property keepPendingSessionsOnDisconnect²
|
|
393
387
|
* @type {boolean}
|
|
@@ -430,7 +424,7 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
430
424
|
callback(new Error("Cannot reconnect, server endpoint is unknown - this.knowsServerEndpoint = false"));
|
|
431
425
|
return;
|
|
432
426
|
}
|
|
433
|
-
|
|
427
|
+
assert(this.knowsServerEndpoint);
|
|
434
428
|
this._setInternalState("reconnecting");
|
|
435
429
|
this.emit("start_reconnection"); // send after callback
|
|
436
430
|
const infiniteConnectionRetry = {
|
|
@@ -462,10 +456,10 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
462
456
|
};
|
|
463
457
|
const _when_connected = (callback) => {
|
|
464
458
|
this.emit("after_reconnection", null); // send after callback
|
|
465
|
-
|
|
459
|
+
assert(this._secureChannel, "expecting a secureChannel here ");
|
|
466
460
|
// a new channel has be created and a new connection is established
|
|
467
461
|
// c8 ignore next
|
|
468
|
-
doDebug && debugLog(
|
|
462
|
+
doDebug && debugLog(chalk.bgWhite.red("ClientBaseImpl: RECONNECTED !!!"));
|
|
469
463
|
this._setInternalState("reconnecting_newchannel_connected");
|
|
470
464
|
return callback();
|
|
471
465
|
};
|
|
@@ -481,7 +475,7 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
481
475
|
const err = new Error("_internal_create_secure_channel failed, this._secureChannel is supposed to be null");
|
|
482
476
|
return _when_internal_error(err, callback);
|
|
483
477
|
}
|
|
484
|
-
|
|
478
|
+
assert(!this._secureChannel, "_attempt_to_recreate_secure_channel, expecting this._secureChannel not to exist");
|
|
485
479
|
this._internal_create_secure_channel(infiniteConnectionRetry, (err) => {
|
|
486
480
|
if (err) {
|
|
487
481
|
// c8 ignore next
|
|
@@ -545,12 +539,12 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
545
539
|
_attempt_to_recreate_secure_channel(callback);
|
|
546
540
|
}
|
|
547
541
|
_internal_create_secure_channel(connectionStrategy, callback) {
|
|
548
|
-
|
|
549
|
-
|
|
542
|
+
assert(this._secureChannel === null);
|
|
543
|
+
assert(typeof this.endpointUrl === "string");
|
|
550
544
|
// c8 ignore next
|
|
551
545
|
doDebug &&
|
|
552
546
|
debugLog("_internal_create_secure_channel creating new ClientSecureChannelLayer _internalState =", this._internalState, this.clientName);
|
|
553
|
-
const secureChannel = new
|
|
547
|
+
const secureChannel = new ClientSecureChannelLayer({
|
|
554
548
|
connectionStrategy,
|
|
555
549
|
defaultSecureTokenLifetime: this.defaultSecureTokenLifetime,
|
|
556
550
|
parent: this,
|
|
@@ -594,7 +588,7 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
594
588
|
};
|
|
595
589
|
const step3_getEndpoints = () => {
|
|
596
590
|
return new Promise((resolve, reject) => {
|
|
597
|
-
|
|
591
|
+
assert(this._secureChannel !== null);
|
|
598
592
|
if (!this.knowsServerEndpoint) {
|
|
599
593
|
this._setInternalState("connecting");
|
|
600
594
|
this.getEndpoints((err /*, endpoints?: EndpointDescription[]*/) => {
|
|
@@ -618,7 +612,7 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
618
612
|
step2_openSecureChannel()
|
|
619
613
|
.then(() => step3_getEndpoints())
|
|
620
614
|
.then(() => {
|
|
621
|
-
|
|
615
|
+
assert(this._secureChannel !== null);
|
|
622
616
|
callback(null, secureChannel);
|
|
623
617
|
})
|
|
624
618
|
.catch((err) => {
|
|
@@ -635,8 +629,8 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
635
629
|
});
|
|
636
630
|
}
|
|
637
631
|
static async createCertificate(clientCertificateManager, certificateFile, applicationName, applicationUri) {
|
|
638
|
-
if (!
|
|
639
|
-
const hostname =
|
|
632
|
+
if (!fs.existsSync(certificateFile)) {
|
|
633
|
+
const hostname = getHostname();
|
|
640
634
|
// this.serverInfo.applicationUri!;
|
|
641
635
|
// Cast is safe: createDefaultCertificate only calls
|
|
642
636
|
// this in the disk path, where the manager is always
|
|
@@ -647,13 +641,13 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
647
641
|
dns: [hostname],
|
|
648
642
|
// ip: await getIpAddresses(),
|
|
649
643
|
outputFile: certificateFile,
|
|
650
|
-
subject:
|
|
644
|
+
subject: makeSubject(applicationName, hostname),
|
|
651
645
|
startDate: new Date(),
|
|
652
646
|
validity: 365 * 10 // 10 years
|
|
653
647
|
});
|
|
654
648
|
}
|
|
655
649
|
// c8 ignore next
|
|
656
|
-
if (!
|
|
650
|
+
if (!fs.existsSync(certificateFile)) {
|
|
657
651
|
throw new Error(` cannot locate certificate file ${certificateFile}`);
|
|
658
652
|
}
|
|
659
653
|
}
|
|
@@ -663,9 +657,9 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
663
657
|
errorLog("Internal error : re-entrancy in createDefaultCertificate!");
|
|
664
658
|
}
|
|
665
659
|
this._inCreateDefaultCertificate = true;
|
|
666
|
-
if (!
|
|
667
|
-
await
|
|
668
|
-
if (
|
|
660
|
+
if (!checkFileExistsAndIsNotEmpty(this.certificateFile)) {
|
|
661
|
+
await withLock({ fileToLock: `${this.certificateFile}.mutex` }, async () => {
|
|
662
|
+
if (checkFileExistsAndIsNotEmpty(this.certificateFile)) {
|
|
669
663
|
// the file may have been created in between
|
|
670
664
|
return;
|
|
671
665
|
}
|
|
@@ -693,7 +687,7 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
693
687
|
}
|
|
694
688
|
_getBuiltApplicationUri() {
|
|
695
689
|
if (!this._applicationUri) {
|
|
696
|
-
this._applicationUri =
|
|
690
|
+
this._applicationUri = makeApplicationUrn(getHostname(), this.applicationName);
|
|
697
691
|
}
|
|
698
692
|
return this._applicationUri;
|
|
699
693
|
}
|
|
@@ -724,7 +718,7 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
724
718
|
"function" &&
|
|
725
719
|
this.clientCertificateManager.isPrivateKeyOpaque();
|
|
726
720
|
// c8 ignore next
|
|
727
|
-
if (!hasOpaqueKey && !
|
|
721
|
+
if (!hasOpaqueKey && !fs.existsSync(this.privateKeyFile)) {
|
|
728
722
|
throw new Error(` cannot locate private key file ${this.privateKeyFile}`);
|
|
729
723
|
}
|
|
730
724
|
// Resolve the (possibly passphrase-encrypted) private key once,
|
|
@@ -735,11 +729,11 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
735
729
|
// certificateKeyPairProvider, or when clientCertificateManager
|
|
736
730
|
// doesn't expose an async getPrivateKey() (e.g. a bare
|
|
737
731
|
// ICertificateStore).
|
|
738
|
-
await
|
|
732
|
+
await resolvePrivateKeyProviderIfNeeded(this, this.clientCertificateManager, this.#hasUserProvidedProvider);
|
|
739
733
|
}
|
|
740
734
|
}
|
|
741
735
|
catch (err) {
|
|
742
|
-
if (err instanceof
|
|
736
|
+
if (err instanceof PrivateKeyPassphraseRequiredError) {
|
|
743
737
|
throw new Error(`[NODE-OPCUA-E31] private key ${this.privateKeyFile} is encrypted; ` +
|
|
744
738
|
"set privateKeyPassphrase on the OPCUACertificateManager passed as clientCertificateManager");
|
|
745
739
|
}
|
|
@@ -751,7 +745,7 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
751
745
|
// calls trustCertificate and verifyCertificate which each acquire
|
|
752
746
|
// withLock2 internally, so an outer withLock2 would cause a deadlock
|
|
753
747
|
// on the same file-based mutex.
|
|
754
|
-
await
|
|
748
|
+
await performCertificateSanityCheck(this, "client", this.clientCertificateManager, this._getBuiltApplicationUri());
|
|
755
749
|
}
|
|
756
750
|
_internalState = "uninitialized";
|
|
757
751
|
_handleUnrecoverableConnectionFailure(err, callback) {
|
|
@@ -761,7 +755,7 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
761
755
|
// synchronous throw out of _connectStep2 (e.g. an invalid SecureChannel config) lands here
|
|
762
756
|
// WITHOUT the error-branch unregister ever running, which would otherwise leak the client.
|
|
763
757
|
// unregister() is idempotent (a no-op when the client was never registered or already removed).
|
|
764
|
-
|
|
758
|
+
OPCUAClientBase.registry.unregister(this);
|
|
765
759
|
this.emit("connection_failed", err);
|
|
766
760
|
this._setInternalState("disconnected");
|
|
767
761
|
callback(err);
|
|
@@ -771,7 +765,7 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
771
765
|
doDebug && debugLog(err.message);
|
|
772
766
|
// see _handleUnrecoverableConnectionFailure: idempotent unregister guards against a leaked
|
|
773
767
|
// client when a connect attempt fails before the error-branch unregister runs.
|
|
774
|
-
|
|
768
|
+
OPCUAClientBase.registry.unregister(this);
|
|
775
769
|
this.emit("connection_failed", err);
|
|
776
770
|
this._setInternalState("disconnected");
|
|
777
771
|
callback(err);
|
|
@@ -786,13 +780,13 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
786
780
|
connect(...args) {
|
|
787
781
|
const endpointUrl = args[0];
|
|
788
782
|
const callback = args[1];
|
|
789
|
-
|
|
783
|
+
assert(typeof callback === "function", "expecting a callback");
|
|
790
784
|
if (typeof endpointUrl !== "string" || endpointUrl.length <= 0) {
|
|
791
785
|
errorLog(`[NODE-OPCUA-E03] OPCUAClient#connect expects a valid endpoint : ${endpointUrl}`);
|
|
792
786
|
callback(new Error("Invalid endpoint"));
|
|
793
787
|
return;
|
|
794
788
|
}
|
|
795
|
-
|
|
789
|
+
assert(typeof endpointUrl === "string" && endpointUrl.length > 0);
|
|
796
790
|
// c8 ignore next
|
|
797
791
|
if (this._internalState !== "disconnected") {
|
|
798
792
|
callback(new Error(`client#connect failed, as invalid internal state = ${this._internalState}`));
|
|
@@ -812,7 +806,7 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
812
806
|
return this._handleDisconnectionWhileConnecting(new Error("premature disconnection 1"), callback);
|
|
813
807
|
}
|
|
814
808
|
if (!this.serverCertificate &&
|
|
815
|
-
(forceEndpointDiscoveryOnConnect || this.securityMode !==
|
|
809
|
+
(forceEndpointDiscoveryOnConnect || this.securityMode !== MessageSecurityMode.None)) {
|
|
816
810
|
// c8 ignore next
|
|
817
811
|
doDebug && debugLog("Fetching certificates from endpoints");
|
|
818
812
|
this.fetchServerCertificate(endpointUrl, (err, adjustedEndpointUrl) => {
|
|
@@ -847,7 +841,7 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
847
841
|
const reverseConnect = args[0];
|
|
848
842
|
const callback = args[args.length - 1];
|
|
849
843
|
const expectation = (args.length >= 3 ? args[1] : undefined);
|
|
850
|
-
|
|
844
|
+
assert(typeof callback === "function", "expecting a callback");
|
|
851
845
|
if (!reverseConnect) {
|
|
852
846
|
callback(new Error("connectReverse expects a ClientReverseConnect instance"));
|
|
853
847
|
return;
|
|
@@ -866,9 +860,9 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
866
860
|
// front via OPCUAClientOptions.serverCertificate. Reject early with a clear message rather than
|
|
867
861
|
// letting the SecureChannel layer fail deep inside with an opaque error (which also used to leak
|
|
868
862
|
// the client, since that failure path never reached the connect-failure unregister).
|
|
869
|
-
if (this.securityMode !==
|
|
863
|
+
if (this.securityMode !== MessageSecurityMode.None && !this.serverCertificate) {
|
|
870
864
|
callback(new Error("connectReverse: a secure connection (securityMode=" +
|
|
871
|
-
|
|
865
|
+
MessageSecurityMode[this.securityMode] +
|
|
872
866
|
") requires the server certificate to be supplied up front " +
|
|
873
867
|
"(OPCUAClientOptions.serverCertificate), because a reverse-connect client cannot dial the server to fetch it."));
|
|
874
868
|
return;
|
|
@@ -879,7 +873,7 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
879
873
|
// EACH attempt so every attempt waits for the server to (re-)dial in. We keep the current
|
|
880
874
|
// waiter registration so it can be cancelled on disconnect — otherwise a leaked waiter would
|
|
881
875
|
// later hijack an incoming server socket on this (by-then disposed) transport.
|
|
882
|
-
this._transportFactory =
|
|
876
|
+
this._transportFactory = makeReverseClientTransportFactory(() => new Promise((resolve, reject) => {
|
|
883
877
|
// drop any stale waiter from a previous attempt before registering a new one
|
|
884
878
|
this._reverseConnectRegistration?.cancel();
|
|
885
879
|
this._reverseConnectRegistration = reverseConnect.waitForConnection(expectation, (err, accepted) => {
|
|
@@ -918,10 +912,10 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
918
912
|
*/
|
|
919
913
|
_connectStep2(endpointUrl, callback) {
|
|
920
914
|
// prevent illegal call to connect
|
|
921
|
-
|
|
915
|
+
assert(this._secureChannel === null);
|
|
922
916
|
this.endpointUrl = endpointUrl;
|
|
923
917
|
this._clockAdjuster = this._clockAdjuster || new ClockAdjustment();
|
|
924
|
-
|
|
918
|
+
OPCUAClientBase.registry.register(this);
|
|
925
919
|
// c8 ignore next
|
|
926
920
|
doDebug && debugLog("__connectStep2 ", this._internalState);
|
|
927
921
|
this._internal_create_secure_channel(this.connectionStrategy, (err) => {
|
|
@@ -929,22 +923,22 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
929
923
|
this._handleSuccessfulConnection(callback);
|
|
930
924
|
}
|
|
931
925
|
else {
|
|
932
|
-
|
|
926
|
+
OPCUAClientBase.registry.unregister(this);
|
|
933
927
|
if (this._clockAdjuster) {
|
|
934
928
|
this._clockAdjuster.dispose();
|
|
935
929
|
this._clockAdjuster = undefined;
|
|
936
930
|
}
|
|
937
931
|
// c8 ignore next
|
|
938
|
-
doDebug && debugLog(
|
|
932
|
+
doDebug && debugLog(chalk.red("SecureChannel creation has failed with error :", err.message));
|
|
939
933
|
if (err.message.match(/ECONNABORTED/)) {
|
|
940
934
|
// c8 ignore next
|
|
941
|
-
doDebug && debugLog(
|
|
935
|
+
doDebug && debugLog(chalk.yellow(`- The client cannot to :${endpointUrl}. Connection has been aborted.`));
|
|
942
936
|
err = new Error("The connection has been aborted");
|
|
943
937
|
this._handleUnrecoverableConnectionFailure(err, callback);
|
|
944
938
|
}
|
|
945
939
|
else if (err.message.match(/ECONNREF/)) {
|
|
946
940
|
// c8 ignore next
|
|
947
|
-
doDebug && debugLog(
|
|
941
|
+
doDebug && debugLog(chalk.yellow(`- The client cannot to :${endpointUrl}. Server is not reachable.`));
|
|
948
942
|
err = new Error(`The connection cannot be established with server ${endpointUrl} .\n` +
|
|
949
943
|
"Please check that the server is up and running or your network configuration.\n" +
|
|
950
944
|
"Err = (" +
|
|
@@ -958,7 +952,7 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
958
952
|
}
|
|
959
953
|
else {
|
|
960
954
|
const fault = err.response;
|
|
961
|
-
if (fault instanceof
|
|
955
|
+
if (fault instanceof ServiceFault) {
|
|
962
956
|
// the server answered the OpenSecureChannel with a ServiceFault (Part 6 6.7.4):
|
|
963
957
|
// it refused the connection and said why - typically a client certificate it
|
|
964
958
|
// does not trust (BadSecurityChecksFailed) or that is out of date
|
|
@@ -995,10 +989,10 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
995
989
|
request.schema.name));
|
|
996
990
|
return;
|
|
997
991
|
}
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
992
|
+
assert(this._secureChannel);
|
|
993
|
+
assert(request);
|
|
994
|
+
assert(request.requestHeader);
|
|
995
|
+
assert(typeof callback === "function");
|
|
1002
996
|
this._secureChannel.performMessageTransaction(request, callback);
|
|
1003
997
|
}
|
|
1004
998
|
/**
|
|
@@ -1007,9 +1001,9 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
1007
1001
|
|
|
1008
1002
|
*/
|
|
1009
1003
|
findEndpointForSecurity(securityMode, securityPolicy) {
|
|
1010
|
-
securityMode =
|
|
1011
|
-
securityPolicy =
|
|
1012
|
-
|
|
1004
|
+
securityMode = coerceMessageSecurityMode(securityMode);
|
|
1005
|
+
securityPolicy = coerceSecurityPolicy(securityPolicy);
|
|
1006
|
+
assert(this.knowsServerEndpoint, "Server end point are not known yet");
|
|
1013
1007
|
return this._serverEndpoints.find((endpoint) => {
|
|
1014
1008
|
return endpoint.securityMode === securityMode && endpoint.securityPolicyUri === securityPolicy;
|
|
1015
1009
|
});
|
|
@@ -1020,12 +1014,12 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
1020
1014
|
|
|
1021
1015
|
*/
|
|
1022
1016
|
findEndpoint(endpointUrl, securityMode, securityPolicy) {
|
|
1023
|
-
|
|
1017
|
+
assert(this.knowsServerEndpoint, "Server end point are not known yet");
|
|
1024
1018
|
if (!this._serverEndpoints || this._serverEndpoints.length === 0) {
|
|
1025
1019
|
return undefined;
|
|
1026
1020
|
}
|
|
1027
1021
|
return this._serverEndpoints.find((endpoint) => {
|
|
1028
|
-
return (
|
|
1022
|
+
return (matchUri(endpoint.endpointUrl, endpointUrl) &&
|
|
1029
1023
|
endpoint.securityMode === securityMode &&
|
|
1030
1024
|
endpoint.securityPolicyUri === securityPolicy);
|
|
1031
1025
|
});
|
|
@@ -1037,10 +1031,10 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
1037
1031
|
}
|
|
1038
1032
|
const options = args[0];
|
|
1039
1033
|
const callback = args[1];
|
|
1040
|
-
|
|
1034
|
+
assert(typeof callback === "function");
|
|
1041
1035
|
options.localeIds = options.localeIds || [];
|
|
1042
1036
|
options.profileUris = options.profileUris || [];
|
|
1043
|
-
const request = new
|
|
1037
|
+
const request = new GetEndpointsRequest({
|
|
1044
1038
|
endpointUrl: options.endpointUrl || this.endpointUrl,
|
|
1045
1039
|
localeIds: options.localeIds,
|
|
1046
1040
|
profileUris: options.profileUris,
|
|
@@ -1055,7 +1049,7 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
1055
1049
|
}
|
|
1056
1050
|
this._serverEndpoints = [];
|
|
1057
1051
|
// c8 ignore next
|
|
1058
|
-
if (!response || !(response instanceof
|
|
1052
|
+
if (!response || !(response instanceof GetEndpointsResponse)) {
|
|
1059
1053
|
callback(new Error("Internal Error"));
|
|
1060
1054
|
return;
|
|
1061
1055
|
}
|
|
@@ -1083,7 +1077,7 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
1083
1077
|
}
|
|
1084
1078
|
const options = args[0];
|
|
1085
1079
|
const callback = args[1];
|
|
1086
|
-
const request = new
|
|
1080
|
+
const request = new FindServersRequest({
|
|
1087
1081
|
endpointUrl: options.endpointUrl || this.endpointUrl,
|
|
1088
1082
|
localeIds: options.localeIds || [],
|
|
1089
1083
|
serverUris: options.serverUris || []
|
|
@@ -1094,7 +1088,7 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
1094
1088
|
return;
|
|
1095
1089
|
}
|
|
1096
1090
|
/* c8 ignore next */
|
|
1097
|
-
if (!response || !(response instanceof
|
|
1091
|
+
if (!response || !(response instanceof FindServersResponse)) {
|
|
1098
1092
|
callback(new Error("Internal Error"));
|
|
1099
1093
|
return;
|
|
1100
1094
|
}
|
|
@@ -1110,14 +1104,14 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
1110
1104
|
}
|
|
1111
1105
|
const options = args[0];
|
|
1112
1106
|
const callback = args[1];
|
|
1113
|
-
const request = new
|
|
1107
|
+
const request = new FindServersOnNetworkRequest(options);
|
|
1114
1108
|
this.performMessageTransaction(request, (err, response) => {
|
|
1115
1109
|
if (err) {
|
|
1116
1110
|
callback(err);
|
|
1117
1111
|
return;
|
|
1118
1112
|
}
|
|
1119
1113
|
/* c8 ignore next */
|
|
1120
|
-
if (!response || !(response instanceof
|
|
1114
|
+
if (!response || !(response instanceof FindServersOnNetworkResponse)) {
|
|
1121
1115
|
callback(new Error("Internal Error"));
|
|
1122
1116
|
return;
|
|
1123
1117
|
}
|
|
@@ -1134,22 +1128,22 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
1134
1128
|
// assert(session._client === this);
|
|
1135
1129
|
session._client = null;
|
|
1136
1130
|
}
|
|
1137
|
-
|
|
1131
|
+
assert(this._sessions.indexOf(session) === -1);
|
|
1138
1132
|
}
|
|
1139
1133
|
_closeSession(session, deleteSubscriptions, callback) {
|
|
1140
|
-
|
|
1141
|
-
|
|
1134
|
+
assert(typeof callback === "function");
|
|
1135
|
+
assert(typeof deleteSubscriptions === "boolean");
|
|
1142
1136
|
// c8 ignore next
|
|
1143
1137
|
if (!this._secureChannel) {
|
|
1144
1138
|
return callback(null); // new Error("no channel"));
|
|
1145
1139
|
}
|
|
1146
|
-
|
|
1140
|
+
assert(this._secureChannel);
|
|
1147
1141
|
if (!this._secureChannel.isValid()) {
|
|
1148
1142
|
return callback(null);
|
|
1149
1143
|
}
|
|
1150
1144
|
// c8 ignore next
|
|
1151
|
-
doDebug && debugLog(
|
|
1152
|
-
const request = new
|
|
1145
|
+
doDebug && debugLog(chalk.bgWhite.green("_closeSession ") + this._secureChannel.channelId);
|
|
1146
|
+
const request = new CloseSessionRequest({
|
|
1153
1147
|
deleteSubscriptions
|
|
1154
1148
|
});
|
|
1155
1149
|
session.performMessageTransaction(request, (err, response) => {
|
|
@@ -1162,23 +1156,23 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
1162
1156
|
});
|
|
1163
1157
|
}
|
|
1164
1158
|
closeSession(session, deleteSubscriptions, callback) {
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1159
|
+
assert(typeof deleteSubscriptions === "boolean");
|
|
1160
|
+
assert(session);
|
|
1161
|
+
assert(session._client === this, "session must be attached to this");
|
|
1168
1162
|
session._closed = true;
|
|
1169
1163
|
// todo : send close session on secure channel
|
|
1170
1164
|
this._closeSession(session, deleteSubscriptions, (err, _response) => {
|
|
1171
|
-
session.emitCloseEvent(
|
|
1165
|
+
session.emitCloseEvent(StatusCodes.Good);
|
|
1172
1166
|
this._removeSession(session);
|
|
1173
1167
|
session.dispose();
|
|
1174
|
-
|
|
1175
|
-
|
|
1168
|
+
assert(this._sessions.indexOf(session) === -1);
|
|
1169
|
+
assert(session._closed, "session must indicate it is closed");
|
|
1176
1170
|
callback?.(err ? err : undefined);
|
|
1177
1171
|
});
|
|
1178
1172
|
}
|
|
1179
1173
|
disconnect(...args) {
|
|
1180
1174
|
const callback = args[0];
|
|
1181
|
-
|
|
1175
|
+
assert(typeof callback === "function", "expecting a callback function here");
|
|
1182
1176
|
this._reconnectionIsCanceled = true;
|
|
1183
1177
|
// cancel any outstanding reverse-connect waiter so it cannot later hijack an incoming
|
|
1184
1178
|
// server socket on this (now disconnecting) client.
|
|
@@ -1215,7 +1209,7 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
1215
1209
|
this._cancel_reconnection((err) => {
|
|
1216
1210
|
// c8 ignore next
|
|
1217
1211
|
doDebug && debugLog("ClientBaseImpl#disconnect reconnection has been canceled", this.applicationName);
|
|
1218
|
-
|
|
1212
|
+
assert(!err, " why would this fail ?");
|
|
1219
1213
|
// sessions cannot be cancelled properly and must be discarded.
|
|
1220
1214
|
this.disconnect(callback);
|
|
1221
1215
|
});
|
|
@@ -1250,8 +1244,8 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
1250
1244
|
}
|
|
1251
1245
|
this._sessions = [];
|
|
1252
1246
|
}
|
|
1253
|
-
|
|
1254
|
-
|
|
1247
|
+
assert(this._sessions.length === 0, " attempt to disconnect a client with live sessions ");
|
|
1248
|
+
OPCUAClientBase.registry.unregister(this);
|
|
1255
1249
|
if (this._clockAdjuster) {
|
|
1256
1250
|
this._clockAdjuster.dispose();
|
|
1257
1251
|
this._clockAdjuster = undefined;
|
|
@@ -1283,7 +1277,7 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
1283
1277
|
toString() {
|
|
1284
1278
|
let str = "\n";
|
|
1285
1279
|
str += ` defaultSecureTokenLifetime.... ${this.defaultSecureTokenLifetime}\n`;
|
|
1286
|
-
str += ` securityMode.................. ${
|
|
1280
|
+
str += ` securityMode.................. ${MessageSecurityMode[this.securityMode]}\n`;
|
|
1287
1281
|
str += ` securityPolicy................ ${this.securityPolicy.toString()}\n`;
|
|
1288
1282
|
str += ` certificate fingerprint....... ${makeCertificateThumbPrint(this.getCertificate())?.toString("hex") || "none"}\n`;
|
|
1289
1283
|
str += ` server certificate fingerprint ${makeCertificateThumbPrint(this.serverCertificate)?.toString("hex") || "none"}\n`;
|
|
@@ -1318,8 +1312,8 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
1318
1312
|
return this._secureChannel?.getTransportSettings() || {};
|
|
1319
1313
|
}
|
|
1320
1314
|
_addSession(session) {
|
|
1321
|
-
|
|
1322
|
-
|
|
1315
|
+
assert(!session._client || session._client === this);
|
|
1316
|
+
assert(this._sessions.indexOf(session) === -1, "session already added");
|
|
1323
1317
|
session._client = this;
|
|
1324
1318
|
this._sessions.push(session);
|
|
1325
1319
|
}
|
|
@@ -1357,7 +1351,10 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
1357
1351
|
privateKeyFile,
|
|
1358
1352
|
clientCertificateManager: this.clientCertificateManager
|
|
1359
1353
|
};
|
|
1360
|
-
|
|
1354
|
+
// through unknown: see the note in base_server.ts, `this` is ClientBaseImpl<Events> and
|
|
1355
|
+
// Events could be a narrower subtype than the helper's parameter declares.
|
|
1356
|
+
const self = this;
|
|
1357
|
+
__findEndpoint.call(self, discoveryUrl, params, (err, result) => {
|
|
1361
1358
|
if (err) {
|
|
1362
1359
|
callback(err);
|
|
1363
1360
|
return;
|
|
@@ -1372,13 +1369,13 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
1372
1369
|
if (!endpoint) {
|
|
1373
1370
|
// no matching end point can be found ...
|
|
1374
1371
|
const err1 = new Error("cannot find endpoint for securityMode=" +
|
|
1375
|
-
|
|
1372
|
+
MessageSecurityMode[this.securityMode] +
|
|
1376
1373
|
" policy = " +
|
|
1377
1374
|
this.securityPolicy);
|
|
1378
1375
|
callback(err1);
|
|
1379
1376
|
return;
|
|
1380
1377
|
}
|
|
1381
|
-
|
|
1378
|
+
assert(endpoint);
|
|
1382
1379
|
_verify_serverCertificate(this.clientCertificateManager, endpoint.serverCertificate)
|
|
1383
1380
|
.then(() => {
|
|
1384
1381
|
this.serverCertificate = endpoint.serverCertificate;
|
|
@@ -1389,13 +1386,13 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
1389
1386
|
if ("rootDir" in this.clientCertificateManager) {
|
|
1390
1387
|
warningLog(" clientCertificateManager.rootDir = ", this.clientCertificateManager.rootDir);
|
|
1391
1388
|
}
|
|
1392
|
-
const chain =
|
|
1389
|
+
const chain = split_der(endpoint.serverCertificate);
|
|
1393
1390
|
warningLog(` server certificate chain contains ${chain.length} element(s)`);
|
|
1394
1391
|
for (let i = 0; i < chain.length; i++) {
|
|
1395
1392
|
const c = chain[i];
|
|
1396
|
-
const thumbprint =
|
|
1393
|
+
const thumbprint = makeSHA1Thumbprint(c).toString("hex");
|
|
1397
1394
|
try {
|
|
1398
|
-
const info =
|
|
1395
|
+
const info = exploreCertificate(c);
|
|
1399
1396
|
const tbs = info.tbsCertificate;
|
|
1400
1397
|
const cn = tbs.subject?.commonName ?? "unknown";
|
|
1401
1398
|
const issuerCN = tbs.issuer?.commonName ?? "unknown";
|
|
@@ -1446,10 +1443,10 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
1446
1443
|
// c8 ignore next
|
|
1447
1444
|
if (doDebug) {
|
|
1448
1445
|
const h = `Client ${this._instanceNumber} ${this.clientName}`;
|
|
1449
|
-
debugLog(
|
|
1450
|
-
debugLog(
|
|
1451
|
-
debugLog(
|
|
1452
|
-
debugLog(
|
|
1446
|
+
debugLog(chalk.cyan(`${h} byteWritten = `), this._byteWritten);
|
|
1447
|
+
debugLog(chalk.cyan(`${h} byteRead = `), this._byteRead);
|
|
1448
|
+
debugLog(chalk.cyan(`${h} transactions = `), this._transactionsPerformed);
|
|
1449
|
+
debugLog(chalk.cyan(`${h} timedOutRequestCount = `), this._timedOutRequestCount);
|
|
1453
1450
|
}
|
|
1454
1451
|
}
|
|
1455
1452
|
}
|
|
@@ -1470,7 +1467,7 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
1470
1467
|
const sessions = [...this._sessions];
|
|
1471
1468
|
const closeAll = async () => {
|
|
1472
1469
|
for (const session of sessions) {
|
|
1473
|
-
|
|
1470
|
+
assert(session._client === this);
|
|
1474
1471
|
await new Promise((resolve) => {
|
|
1475
1472
|
let resolved = false;
|
|
1476
1473
|
session.close((err) => {
|
|
@@ -1497,13 +1494,13 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
1497
1494
|
.map((s) => (s.authenticationToken ? s.authenticationToken.toString() : ""))
|
|
1498
1495
|
.join(" "));
|
|
1499
1496
|
}
|
|
1500
|
-
|
|
1497
|
+
assert(this._sessions.length === 0, " failed to disconnect exiting sessions ");
|
|
1501
1498
|
callback();
|
|
1502
1499
|
})
|
|
1503
1500
|
.catch((err) => callback(err));
|
|
1504
1501
|
}
|
|
1505
1502
|
_install_secure_channel_event_handlers(secureChannel) {
|
|
1506
|
-
|
|
1503
|
+
assert(this instanceof ClientBaseImpl);
|
|
1507
1504
|
secureChannel.on("send_chunk", (chunk) => {
|
|
1508
1505
|
/**
|
|
1509
1506
|
* notify the observer that a message_chunk has been sent
|
|
@@ -1553,7 +1550,7 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
1553
1550
|
this._setInternalState("panic");
|
|
1554
1551
|
}
|
|
1555
1552
|
// c8 ignore next
|
|
1556
|
-
doDebug && debugLog(
|
|
1553
|
+
doDebug && debugLog(chalk.yellow.bold(" ClientBaseImpl emitting close"), err?.message);
|
|
1557
1554
|
this._destroy_secure_channel();
|
|
1558
1555
|
if (!err || !this.reconnectOnFailure) {
|
|
1559
1556
|
if (err) {
|
|
@@ -1661,13 +1658,13 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
1661
1658
|
// c8 ignore next
|
|
1662
1659
|
if (doDebug) {
|
|
1663
1660
|
debugLog("Disconnected following reconnection failure", err2.message);
|
|
1664
|
-
debugLog(`I will retry OPCUA client reconnection in ${
|
|
1661
|
+
debugLog(`I will retry OPCUA client reconnection in ${OPCUAClientBase.retryDelay / 1000} seconds`);
|
|
1665
1662
|
}
|
|
1666
1663
|
this.#insideRepairConnection = false;
|
|
1667
1664
|
this.#shouldRepairAgain = false;
|
|
1668
1665
|
this._destroy_secure_channel();
|
|
1669
1666
|
// this._setInternalState("reconnecting_failed");
|
|
1670
|
-
setTimeout(() => this._repairConnection(),
|
|
1667
|
+
setTimeout(() => this._repairConnection(), OPCUAClientBase.retryDelay);
|
|
1671
1668
|
return;
|
|
1672
1669
|
}
|
|
1673
1670
|
else {
|
|
@@ -1687,7 +1684,7 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
1687
1684
|
_finalReconnectionStep(callback) {
|
|
1688
1685
|
// now delegate to upper class the
|
|
1689
1686
|
if (this._on_connection_reestablished) {
|
|
1690
|
-
|
|
1687
|
+
assert(typeof this._on_connection_reestablished === "function");
|
|
1691
1688
|
this._on_connection_reestablished((err2) => {
|
|
1692
1689
|
callback(err2);
|
|
1693
1690
|
});
|
|
@@ -1708,7 +1705,6 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
1708
1705
|
throw new Error("Please override");
|
|
1709
1706
|
}
|
|
1710
1707
|
}
|
|
1711
|
-
exports.ClientBaseImpl = ClientBaseImpl;
|
|
1712
1708
|
class TmpClient extends ClientBaseImpl {
|
|
1713
1709
|
constructor(options) {
|
|
1714
1710
|
options.clientName = `${options.clientName || ""}_TmpClient`;
|
|
@@ -1732,14 +1728,14 @@ class TmpClient extends ClientBaseImpl {
|
|
|
1732
1728
|
});
|
|
1733
1729
|
}
|
|
1734
1730
|
}
|
|
1735
|
-
|
|
1736
|
-
ClientBaseImpl.prototype.connect =
|
|
1737
|
-
ClientBaseImpl.prototype.connectReverse =
|
|
1738
|
-
ClientBaseImpl.prototype.disconnect =
|
|
1739
|
-
ClientBaseImpl.prototype.getEndpoints =
|
|
1740
|
-
ClientBaseImpl.prototype.findServers =
|
|
1741
|
-
ClientBaseImpl.prototype.findServersOnNetwork =
|
|
1742
|
-
|
|
1731
|
+
import { withCallback } from "thenify-ex";
|
|
1732
|
+
ClientBaseImpl.prototype.connect = withCallback(ClientBaseImpl.prototype.connect);
|
|
1733
|
+
ClientBaseImpl.prototype.connectReverse = withCallback(ClientBaseImpl.prototype.connectReverse);
|
|
1734
|
+
ClientBaseImpl.prototype.disconnect = withCallback(ClientBaseImpl.prototype.disconnect);
|
|
1735
|
+
ClientBaseImpl.prototype.getEndpoints = withCallback(ClientBaseImpl.prototype.getEndpoints);
|
|
1736
|
+
ClientBaseImpl.prototype.findServers = withCallback(ClientBaseImpl.prototype.findServers);
|
|
1737
|
+
ClientBaseImpl.prototype.findServersOnNetwork = withCallback(ClientBaseImpl.prototype.findServersOnNetwork);
|
|
1738
|
+
OPCUAClientBase.create = (options) => {
|
|
1743
1739
|
return new ClientBaseImpl(options);
|
|
1744
1740
|
};
|
|
1745
1741
|
//# sourceMappingURL=client_base_impl.js.map
|