node-opcua-client 2.163.1 → 2.164.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/dist/client_base.js +1 -1
  2. package/dist/client_base.js.map +1 -1
  3. package/dist/client_monitored_item.js +1 -1
  4. package/dist/client_monitored_item.js.map +1 -1
  5. package/dist/client_monitored_item_group.js +1 -1
  6. package/dist/client_monitored_item_group.js.map +1 -1
  7. package/dist/client_monitored_item_toolbox.js +4 -4
  8. package/dist/client_monitored_item_toolbox.js.map +1 -1
  9. package/dist/client_session_keepalive_manager.js +3 -3
  10. package/dist/client_session_keepalive_manager.js.map +1 -1
  11. package/dist/client_subscription.js +1 -1
  12. package/dist/client_subscription.js.map +1 -1
  13. package/dist/private/client_base_impl.js +33 -28
  14. package/dist/private/client_base_impl.js.map +1 -1
  15. package/dist/private/client_monitored_item_impl.js +1 -2
  16. package/dist/private/client_monitored_item_impl.js.map +1 -1
  17. package/dist/private/client_publish_engine.js +14 -3
  18. package/dist/private/client_publish_engine.js.map +1 -1
  19. package/dist/private/client_session_impl.js +58 -58
  20. package/dist/private/client_session_impl.js.map +1 -1
  21. package/dist/private/client_subscription_impl.js +11 -11
  22. package/dist/private/client_subscription_impl.js.map +1 -1
  23. package/dist/private/opcua_client_impl.js +15 -15
  24. package/dist/private/opcua_client_impl.js.map +1 -1
  25. package/dist/private/reconnection/client_publish_engine_reconnection.js +2 -2
  26. package/dist/private/reconnection/client_publish_engine_reconnection.js.map +1 -1
  27. package/dist/private/reconnection/client_subscription_reconnection.js +9 -9
  28. package/dist/private/reconnection/client_subscription_reconnection.js.map +1 -1
  29. package/dist/private/reconnection/reconnection.js +8 -8
  30. package/dist/private/reconnection/reconnection.js.map +1 -1
  31. package/dist/tools/read_history_server_capabilities.js +3 -3
  32. package/dist/tools/read_history_server_capabilities.js.map +1 -1
  33. package/dist/verify.js +14 -2
  34. package/dist/verify.js.map +1 -1
  35. package/package.json +46 -46
  36. package/source/client_base.ts +1 -1
  37. package/source/client_monitored_item.ts +1 -1
  38. package/source/client_monitored_item_group.ts +1 -1
  39. package/source/client_monitored_item_toolbox.ts +4 -4
  40. package/source/client_session_keepalive_manager.ts +3 -3
  41. package/source/client_subscription.ts +1 -1
  42. package/source/private/client_base_impl.ts +35 -29
  43. package/source/private/client_monitored_item_impl.ts +1 -2
  44. package/source/private/client_publish_engine.ts +18 -3
  45. package/source/private/client_session_impl.ts +58 -58
  46. package/source/private/client_subscription_impl.ts +11 -11
  47. package/source/private/opcua_client_impl.ts +15 -15
  48. package/source/private/reconnection/client_publish_engine_reconnection.ts +2 -2
  49. package/source/private/reconnection/client_subscription_reconnection.ts +6 -6
  50. package/source/private/reconnection/reconnection.ts +8 -8
  51. package/source/tools/read_history_server_capabilities.ts +3 -3
  52. package/source/verify.ts +37 -27
@@ -42,7 +42,7 @@ import {
42
42
  } from "node-opcua-service-endpoints";
43
43
  import { ChannelSecurityToken, coerceMessageSecurityMode, MessageSecurityMode } from "node-opcua-service-secure-channel";
44
44
  import { ErrorCallback, StatusCode, StatusCodes } from "node-opcua-status-code";
45
- import { matchUri } from "node-opcua-utils";
45
+ import { matchUri, checkFileExistsAndIsNotEmpty } from "node-opcua-utils";
46
46
 
47
47
  import { getDefaultCertificateManager, makeSubject, OPCUACertificateManager } from "node-opcua-certificate-manager";
48
48
  import { VerificationStatus } from "node-opcua-pki";
@@ -124,7 +124,7 @@ function __findEndpoint(this: ClientBaseImpl, endpointUrl: string, params: FindE
124
124
  // rebind backoff handler
125
125
  masterClient.listeners("backoff").forEach((handler: any) => client.on("backoff", handler));
126
126
 
127
- // istanbul ignore next
127
+ // c8 ignore next
128
128
  if (doDebug) {
129
129
  client.on("backoff", (retryCount: number, delay: number) => {
130
130
  debugLog(
@@ -160,7 +160,7 @@ function __findEndpoint(this: ClientBaseImpl, endpointUrl: string, params: FindE
160
160
  err.message = "error in getEndpoints \n" + err.message;
161
161
  return innerCallback(err);
162
162
  }
163
- // istanbul ignore next
163
+ // c8 ignore next
164
164
  if (!endpoints) {
165
165
  return innerCallback(new Error("Internal Error"));
166
166
  }
@@ -206,7 +206,7 @@ function __findEndpoint(this: ClientBaseImpl, endpointUrl: string, params: FindE
206
206
  );
207
207
  }
208
208
 
209
- // istanbul ignore next
209
+ // c8 ignore next
210
210
  if (doDebug) {
211
211
  debugLog(chalk.bgWhite.red("xxxxxxxxxxxxxxxxxxxxx => selected EndPoint = "), selectedEndpoint.toString());
212
212
  }
@@ -228,7 +228,7 @@ async function _verify_serverCertificate(
228
228
  serverCertificate: Certificate) {
229
229
  const status = await certificateManager.checkCertificate(serverCertificate);
230
230
  if (status !== StatusCodes.Good) {
231
- // istanbul ignore next
231
+ // c8 ignore next
232
232
  if (doDebug) {
233
233
  // do it again for debug purposes
234
234
  const status1 = await certificateManager.verifyCertificate(serverCertificate);
@@ -413,7 +413,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
413
413
  this._internalState = internalState;
414
414
  }
415
415
  public emit(eventName: string | symbol, ...others: any[]): boolean {
416
- // istanbul ignore next
416
+ // c8 ignore next
417
417
  if (doDebug) {
418
418
  debugLog(chalk.cyan(` Client ${this._instanceNumber} ${this.clientName} emitting `), chalk.magentaBright(eventName));
419
419
  }
@@ -442,6 +442,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
442
442
  this._applicationUri = options.applicationUri || this._getBuiltApplicationUri();
443
443
 
444
444
  this.clientCertificateManager = options.clientCertificateManager;
445
+ this.clientCertificateManager.referenceCounter++;
445
446
 
446
447
  this._secureChannel = null;
447
448
 
@@ -497,7 +498,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
497
498
  // _cancel_reconnection is invoked during disconnection
498
499
  // when we detect that a reconnection is in progress...
499
500
 
500
- // istanbul ignore next
501
+ // c8 ignore next
501
502
  if (!this.isReconnecting) {
502
503
  warningLog("internal error: _cancel_reconnection should only be used when reconnecting is in progress");
503
504
  }
@@ -506,7 +507,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
506
507
 
507
508
  this._reconnectionIsCanceled = true;
508
509
 
509
- // istanbul ignore next
510
+ // c8 ignore next
510
511
  if (!this._secureChannel) {
511
512
  debugLog("_cancel_reconnection: Nothing to do for !", this.clientName, " because secure channel doesn't exist");
512
513
  return callback(); // nothing to do
@@ -587,7 +588,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
587
588
 
588
589
  this._internal_create_secure_channel(infiniteConnectionRetry, (err?: Error | null) => {
589
590
  if (err) {
590
- // istanbul ignore next
591
+ // c8 ignore next
591
592
  if (this._secureChannel) {
592
593
  const err = new Error("_internal_create_secure_channel failed, expecting this._secureChannel not to exist");
593
594
  return _when_internal_error(err, callback);
@@ -773,21 +774,22 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
773
774
  validity: 365 * 10 // 10 years
774
775
  });
775
776
  }
776
- // istanbul ignore next
777
+ // c8 ignore next
777
778
  if (!fs.existsSync(certificateFile)) {
778
779
  throw new Error(" cannot locate certificate file " + certificateFile);
779
780
  }
780
781
  }
781
782
 
782
783
  public async createDefaultCertificate(): Promise<void> {
783
- // istanbul ignore next
784
+ // c8 ignore next
784
785
  if ((this as any)._inCreateDefaultCertificate) {
785
786
  errorLog("Internal error : re-entrancy in createDefaultCertificate!");
786
787
  }
787
788
  (this as any)._inCreateDefaultCertificate = true;
788
- if (!fs.existsSync(this.certificateFile)) {
789
+
790
+ if (!checkFileExistsAndIsNotEmpty(this.certificateFile)) {
789
791
  await withLock({ fileToLock: this.certificateFile + ".mutex" }, async () => {
790
- if (fs.existsSync(this.certificateFile)) {
792
+ if (checkFileExistsAndIsNotEmpty(this.certificateFile)) {
791
793
  // the file may have been created in between
792
794
  return;
793
795
  }
@@ -829,15 +831,17 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
829
831
  }
830
832
  await this.clientCertificateManager.initialize();
831
833
  await this.createDefaultCertificate();
832
- // istanbul ignore next
834
+ // c8 ignore next
833
835
  if (!fs.existsSync(this.privateKeyFile)) {
834
836
  throw new Error(" cannot locate private key file " + this.privateKeyFile);
835
837
  }
836
838
  if (this.isUnusable()) return;
837
839
 
838
- await this.clientCertificateManager.withLock2(async () => {
839
- await performCertificateSanityCheck(this, "client", this.clientCertificateManager, this._getBuiltApplicationUri());
840
- });
840
+ // Note: do NOT wrap this in withLock2 performCertificateSanityCheck
841
+ // calls trustCertificate and verifyCertificate which each acquire
842
+ // withLock2 internally, so an outer withLock2 would cause a deadlock
843
+ // on the same file-based mutex.
844
+ await performCertificateSanityCheck(this, "client", this.clientCertificateManager, this._getBuiltApplicationUri());
841
845
  }
842
846
 
843
847
  protected _internalState: InternalClientState = "uninitialized";
@@ -877,7 +881,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
877
881
  }
878
882
  assert(typeof endpointUrl === "string" && endpointUrl.length > 0);
879
883
 
880
- // istanbul ignore next
884
+ // c8 ignore next
881
885
  if (this._internalState !== "disconnected") {
882
886
  callback(new Error(`client#connect failed, as invalid internal state = ${this._internalState}`));
883
887
  return;
@@ -1075,7 +1079,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
1075
1079
  return callback(err);
1076
1080
  }
1077
1081
  this._serverEndpoints = [];
1078
- // istanbul ignore next
1082
+ // c8 ignore next
1079
1083
  if (!response || !(response instanceof GetEndpointsResponse)) {
1080
1084
  return callback(new Error("Internal Error"));
1081
1085
  }
@@ -1117,7 +1121,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
1117
1121
  if (err) {
1118
1122
  return callback(err);
1119
1123
  }
1120
- /* istanbul ignore next */
1124
+ /* c8 ignore next */
1121
1125
  if (!response || !(response instanceof FindServersResponse)) {
1122
1126
  return callback(new Error("Internal Error"));
1123
1127
  }
@@ -1142,7 +1146,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
1142
1146
  if (err) {
1143
1147
  return callback(err);
1144
1148
  }
1145
- /* istanbul ignore next */
1149
+ /* c8 ignore next */
1146
1150
  if (!response || !(response instanceof FindServersOnNetworkResponse)) {
1147
1151
  return new Error("Internal Error");
1148
1152
  }
@@ -1170,7 +1174,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
1170
1174
  assert(typeof callback === "function");
1171
1175
  assert(typeof deleteSubscriptions === "boolean");
1172
1176
 
1173
- // istanbul ignore next
1177
+ // c8 ignore next
1174
1178
  if (!this._secureChannel) {
1175
1179
  return callback(null); // new Error("no channel"));
1176
1180
  }
@@ -1276,7 +1280,9 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
1276
1280
  if (this.clientCertificateManager) {
1277
1281
  const tmp = this.clientCertificateManager;
1278
1282
  // (this as any).clientCertificateManager = null;
1279
- tmp.dispose();
1283
+ tmp.dispose().catch((err: Error) => {
1284
+ debugLog("Error disposing clientCertificateManager", err.message);
1285
+ });
1280
1286
  }
1281
1287
 
1282
1288
  if (this._sessions.length) {
@@ -1411,7 +1417,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
1411
1417
  return callback(err);
1412
1418
  }
1413
1419
 
1414
- // istanbul ignore next
1420
+ // c8 ignore next
1415
1421
  if (!result) {
1416
1422
  const err1 = new Error("internal error");
1417
1423
  return callback(err1);
@@ -1471,7 +1477,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
1471
1477
  this._byteRead += this._secureChannel.bytesRead;
1472
1478
  this._transactionsPerformed += this._secureChannel.transactionsPerformed;
1473
1479
  this._timedOutRequestCount += this._secureChannel.timedOutRequestCount;
1474
- // istanbul ignore next
1480
+ // c8 ignore next
1475
1481
  if (doDebug) {
1476
1482
  const h = `Client ${this._instanceNumber} ${this.clientName}`;
1477
1483
  debugLog(chalk.cyan(`${h} byteWritten = `), this._byteWritten);
@@ -1483,7 +1489,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
1483
1489
  }
1484
1490
  private _destroy_secure_channel() {
1485
1491
  if (this._secureChannel) {
1486
- // istanbul ignore next
1492
+ // c8 ignore next
1487
1493
  if (doDebug) {
1488
1494
  debugLog(
1489
1495
  " DESTROYING SECURE CHANNEL (isTransactionInProgress ?",
@@ -1525,7 +1531,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
1525
1531
  });
1526
1532
  },
1527
1533
  (err) => {
1528
- // istanbul ignore next
1534
+ // c8 ignore next
1529
1535
  if (this._sessions.length > 0) {
1530
1536
  debugLog(
1531
1537
  this._sessions
@@ -1694,7 +1700,7 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
1694
1700
  if (this.isUnusable()) return;
1695
1701
  this._finalReconnectionStep((err2?: Error | null) => {
1696
1702
  if (err2) {
1697
- // istanbul ignore next
1703
+ // c8 ignore next
1698
1704
  if (doDebug) {
1699
1705
  debugLog("connection_reestablished has failed");
1700
1706
  debugLog("err= ", err2.message);
@@ -1768,7 +1774,7 @@ class TmpClient extends ClientBaseImpl {
1768
1774
  connect(endpoint: string, callback?: ErrorCallback): any {
1769
1775
  debugLog("connecting to TmpClient");
1770
1776
 
1771
- // istanbul ignore next
1777
+ // c8 ignore next
1772
1778
  if (this._internalState !== "disconnected") {
1773
1779
  callback!(new Error("TmpClient#connect: invalid internal state = " + this._internalState));
1774
1780
  return;
@@ -265,7 +265,7 @@ export class ClientMonitoredItemImpl extends EventEmitter implements ClientMonit
265
265
 
266
266
  const filter = this.monitoringParameters.filter;
267
267
 
268
- // istanbul ignore next
268
+ // c8 ignore next
269
269
  if (!filter) {
270
270
  return { error: "Internal Error" };
271
271
  }
@@ -310,7 +310,6 @@ export class ClientMonitoredItemImpl extends EventEmitter implements ClientMonit
310
310
  public _applyResult(monitoredItemResult: MonitoredItemCreateResult): void {
311
311
  this.statusCode = monitoredItemResult.statusCode;
312
312
 
313
- /* istanbul ignore else */
314
313
  if (monitoredItemResult.statusCode.isGood()) {
315
314
  this.result = monitoredItemResult;
316
315
  this.monitoredItemId = monitoredItemResult.monitoredItemId;
@@ -281,7 +281,7 @@ export class ClientSidePublishEngine {
281
281
  // There is no need to send more publish request for the time being until reconnection is completed
282
282
  active = false;
283
283
  }
284
- // istanbul ignore next
284
+ // c8 ignore next
285
285
  if (err.message.match(/BadNoSubscription/) && this.activeSubscriptionCount >= 1) {
286
286
  // there is something wrong happening here.
287
287
  // the server tells us that there is no subscription for this session
@@ -325,8 +325,23 @@ export class ClientSidePublishEngine {
325
325
  warningLog(" => nbMaxPublishRequestsAcceptedByServer =", this.nbMaxPublishRequestsAcceptedByServer);
326
326
  }
327
327
  }
328
+ if (err.message.match(/BadSecureChannelIdInvalid/)) {
329
+ // This can happen transiently during session transfer to a new
330
+ // SecureChannel (e.g. after server certificate change). The
331
+ // PublishRequest arrived on the new channel before ActivateSession
332
+ // completed the session transfer. We should pause and let the
333
+ // reconnection flow replenish publish requests once the session
334
+ // transfer completes.
335
+ debugLog(
336
+ chalk.bgWhite.yellow(
337
+ " WARNING: BadSecureChannelIdInvalid on PublishRequest"
338
+ + " - session transfer may be in progress"
339
+ )
340
+ );
341
+ active = false;
342
+ }
328
343
  } else {
329
- // istanbul ignore next
344
+ // c8 ignore next
330
345
  if (doDebug) {
331
346
  debugLog(chalk.cyan("ClientSidePublishEngine.prototype.internalSendPublishRequest callback "));
332
347
  }
@@ -380,7 +395,7 @@ export class ClientSidePublishEngine {
380
395
  // delegate notificationData to the subscription callback
381
396
  subscription.onNotificationMessage(notificationMessage);
382
397
  } catch (err) {
383
- // istanbul ignore next
398
+ // c8 ignore next
384
399
  if (doDebug) {
385
400
  debugLog(err);
386
401
  debugLog("Exception in onNotificationMessage");