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
@@ -1,8 +1,7 @@
1
- import { promisify } from "util";
1
+ import { promisify } from "node:util";
2
2
  import assert from "node-opcua-assert";
3
3
  import { TimestampsToReturn } from "node-opcua-data-value";
4
- import { make_debugLog, checkDebugFlag } from "node-opcua-debug";
5
- import { warningLog } from "node-opcua-pki";
4
+ import { make_debugLog, checkDebugFlag, make_warningLog } from "node-opcua-debug";
6
5
  import { MonitoredItemCreateRequestOptions, CreateMonitoredItemsRequest, CreateMonitoredItemsResponse } from "node-opcua-types";
7
6
 
8
7
  import {
@@ -18,6 +17,7 @@ import { _shouldNotContinue } from "./reconnection";
18
17
 
19
18
  const debugLog = make_debugLog("RECONNECTION");
20
19
  const doDebug = checkDebugFlag("RECONNECTION");
20
+ const warningLog = make_warningLog("RECONNECTION");
21
21
 
22
22
  async function createMonitoredItemsAndRespectOperationalLimits(
23
23
  session: IBasicSessionReadAsync & IBasicSessionWithSubscription,
@@ -82,7 +82,7 @@ export async function recreateSubscriptionAndMonitoredItem(_subscription: Client
82
82
  });
83
83
 
84
84
  const session = subscription.session;
85
- // istanbul ignore next
85
+ // c8 ignore next
86
86
  if (!session) {
87
87
  throw new Error("no session");
88
88
  }
@@ -97,13 +97,13 @@ export async function recreateSubscriptionAndMonitoredItem(_subscription: Client
97
97
  let _errCount = 0;
98
98
  monitoredItemResults.forEach((monitoredItemResult, index) => {
99
99
  const itemToCreate = itemsToCreate[index];
100
- /* istanbul ignore next */
100
+ /* c8 ignore next */
101
101
  if (!itemToCreate || !itemToCreate.requestedParameters) {
102
102
  _errCount++;
103
103
  return;
104
104
  }
105
105
  const clientHandle = itemToCreate.requestedParameters.clientHandle;
106
- /* istanbul ignore next */
106
+ /* c8 ignore next */
107
107
  if (!clientHandle) {
108
108
  _errCount++;
109
109
  return;
@@ -192,7 +192,7 @@ function repair_client_session_by_recreating_a_new_session(
192
192
  // and may be upgraded in between, we have to invalidate the extra data type manager
193
193
  invalidateExtraDataTypeManager(session);
194
194
 
195
- // istanbul ignore next
195
+ // c8 ignore next
196
196
  if (doDebug) {
197
197
  debugLog(" repairing client session by_recreating a new session for old session ", session.sessionId.toString());
198
198
  }
@@ -247,7 +247,7 @@ function repair_client_session_by_recreating_a_new_session(
247
247
  // prettier-ignore
248
248
  { const err = _shouldNotContinue(session); if (err) { return innerCallback(err); } }
249
249
 
250
- // istanbul ignore next
250
+ // c8 ignore next
251
251
  doDebug && debugLog(chalk.bgWhite.red(" => suspend old session publish engine...."));
252
252
  session.getPublishEngine().suspend(true);
253
253
  innerCallback();
@@ -275,7 +275,7 @@ function repair_client_session_by_recreating_a_new_session(
275
275
  newSession,
276
276
  newSession.userIdentityInfo!,
277
277
  (err: Error | null, session1?: ClientSessionImpl) => {
278
- // istanbul ignore next
278
+ // c8 ignore next
279
279
  doDebug && debugLog(" => activating a new session .... Done err=", err ? err.message : "null");
280
280
  if (err) {
281
281
  doDebug &&
@@ -293,9 +293,9 @@ function repair_client_session_by_recreating_a_new_session(
293
293
  if (err2) {
294
294
  warningLog("closing session", err2.message);
295
295
  }
296
- // istanbul ignore next
296
+ // c8 ignore next
297
297
  doDebug && debugLog("the temporary replacement session is now closed");
298
- // istanbul ignore next
298
+ // c8 ignore next
299
299
  doDebug && debugLog(" err ", err.message, "propagated upwards");
300
300
  innerCallback(err);
301
301
  });
@@ -372,7 +372,7 @@ function repair_client_session_by_recreating_a_new_session(
372
372
  }
373
373
 
374
374
  const results = transferSubscriptionsResponse.results || [];
375
- // istanbul ignore next
375
+ // c8 ignore next
376
376
  if (doDebug) {
377
377
  debugLog(
378
378
  chalk.cyan(" => transfer subscriptions done"),
@@ -550,7 +550,7 @@ export function repair_client_session(client: IClientBase, session: ClientSessio
550
550
  return;
551
551
  }
552
552
 
553
- // istanbul ignore next
553
+ // c8 ignore next
554
554
  doDebug && debugLog(chalk.yellow("session has been restored"), session.sessionId.toString());
555
555
  session.emit("session_restored");
556
556
  callback(err);
@@ -561,7 +561,7 @@ export function repair_client_session(client: IClientBase, session: ClientSessio
561
561
  const otherCallbacks = privateSession._reconnecting.pendingCallbacks.splice(0);
562
562
  // re-inject element in queue
563
563
 
564
- // istanbul ignore next
564
+ // c8 ignore next
565
565
  if (transactionQueue.length > 0) {
566
566
  doDebug && debugLog(chalk.yellow("re-injecting transaction queue"), transactionQueue.length);
567
567
  transactionQueue.forEach((e: any) => privateSession._reconnecting.pendingTransactions.push(e));
@@ -37,7 +37,7 @@ export function readHistoryServerCapabilities(
37
37
  if (err) {
38
38
  return callback(err);
39
39
  }
40
- /* istanbul ignore next */
40
+ /* c8 ignore next */
41
41
  if (!result) {
42
42
  return callback(new Error("Internal Error"));
43
43
  }
@@ -89,7 +89,7 @@ export function readHistoryServerCapabilities(
89
89
  if (innerErr) {
90
90
  return callback(innerErr);
91
91
  }
92
- /* istanbul ignore next */
92
+ /* c8 ignore next */
93
93
  if (!results) {
94
94
  return callback(new Error("Internal Error"));
95
95
  }
@@ -111,7 +111,7 @@ export function readHistoryServerCapabilities(
111
111
  if (err2) {
112
112
  return callback(err2);
113
113
  }
114
- /* istanbul ignore next */
114
+ /* c8 ignore next */
115
115
  if (!dataValues) {
116
116
  return callback(new Error("Internal Error"));
117
117
  }
package/source/verify.ts CHANGED
@@ -29,8 +29,8 @@ export function verifyIsOPCUAValidCertificate(
29
29
  // certificate is not active yet
30
30
  warningLog(
31
31
  `[NODE-OPCUA-W02] The certificate is not active yet\n` +
32
- `notBefore ${certificateInfo.tbsCertificate.validity.notBefore.toISOString()}\n` +
33
- `certificateFile ${certificateFile}`
32
+ `notBefore ${certificateInfo.tbsCertificate.validity.notBefore.toISOString()}\n` +
33
+ `certificateFile ${certificateFile}`
34
34
  );
35
35
  }
36
36
  // check that certificate has not expired
@@ -38,9 +38,9 @@ export function verifyIsOPCUAValidCertificate(
38
38
  // certificate is obsolete
39
39
  warningLog(
40
40
  `[NODE-OPCUA-W03] The certificate has expired\n` +
41
- `Please regenerate a valid certificate\n` +
42
- `notAfter = ${certificateInfo.tbsCertificate.validity.notAfter.toISOString()}\n` +
43
- `certificateFile= ${certificateFile}`
41
+ `Please regenerate a valid certificate\n` +
42
+ `notAfter = ${certificateInfo.tbsCertificate.validity.notAfter.toISOString()}\n` +
43
+ `certificateFile= ${certificateFile}`
44
44
  );
45
45
  } else {
46
46
  const tenDays = 10 * 24 * 60 * 60 * 1000;
@@ -48,9 +48,9 @@ export function verifyIsOPCUAValidCertificate(
48
48
  // certificate is going to expired very soon
49
49
  warningLog(
50
50
  `[NODE-OPCUA-W05] The certificate is about to expire in less than 10 days.\n` +
51
- `Please regenerate a valid certificate as soon as possible\n` +
52
- `notAfter = ${certificateInfo.tbsCertificate.validity.notAfter.toISOString()}\n` +
53
- `certificateFile= ${certificateFile}\n`
51
+ `Please regenerate a valid certificate as soon as possible\n` +
52
+ `notAfter = ${certificateInfo.tbsCertificate.validity.notAfter.toISOString()}\n` +
53
+ `certificateFile= ${certificateFile}\n`
54
54
  );
55
55
  }
56
56
  }
@@ -59,18 +59,18 @@ export function verifyIsOPCUAValidCertificate(
59
59
  if (!uniformResourceIdentifier) {
60
60
  warningLog(
61
61
  `[NODE-OPCUA-W14] The certificate subjectAltName uniformResourceIdentifier is missing.\n` +
62
- `Please regenerate a specific certificate with a uniformResourceIdentifier that matches your ${type} applicationUri\n` +
63
- `applicationUri = ${applicationUri}\n` +
64
- `certificateFile = ${certificateFile}\n`
62
+ `Please regenerate a specific certificate with a uniformResourceIdentifier that matches your ${type} applicationUri\n` +
63
+ `applicationUri = ${applicationUri}\n` +
64
+ `certificateFile = ${certificateFile}\n`
65
65
  );
66
66
  return;
67
67
  } else if (uniformResourceIdentifier[0] !== applicationUri) {
68
68
  warningLog(
69
69
  `[NODE-OPCUA-W06] The certificate subjectAltName does not match the ${type} applicationUri\n` +
70
- `Please regenerate a specific certificate that matches your ${type} applicationUri\n` +
71
- `certificate subjectAltName = ${uniformResourceIdentifier[0]}\n` +
72
- `${type} applicationUri = ${applicationUri}\n` +
73
- `certificateFile = ${certificateFile}\n`
70
+ `Please regenerate a specific certificate that matches your ${type} applicationUri\n` +
71
+ `certificate subjectAltName = ${uniformResourceIdentifier[0]}\n` +
72
+ `${type} applicationUri = ${applicationUri}\n` +
73
+ `certificateFile = ${certificateFile}\n`
74
74
  );
75
75
  }
76
76
  const keyUsage = certificateInfo.tbsCertificate.extensions?.keyUsage;
@@ -82,8 +82,8 @@ export function verifyIsOPCUAValidCertificate(
82
82
  if (!keyUsage.digitalSignature || !keyUsage.nonRepudiation || !keyUsage.keyEncipherment || !keyUsage.dataEncipherment) {
83
83
  warningLog(
84
84
  `[NODE-OPCUA-W16] The certificate keyUsage must include digitalSignature, nonRepudiation, keyEncipherment and dataEncipherment.\n` +
85
- `see https://reference.opcfoundation.org/v104/Core/docs/Part6/6.2.2/\n` +
86
- `certificateFile = ${certificateFile}`
85
+ `see https://reference.opcfoundation.org/v104/Core/docs/Part6/6.2.2/\n` +
86
+ `certificateFile = ${certificateFile}`
87
87
  );
88
88
  warningLog(`keyUsage = ${JSON.stringify(keyUsage, null, " ")}`);
89
89
  }
@@ -97,8 +97,8 @@ export function verifyIsOPCUAValidCertificate(
97
97
  if (!extKeyUsage.clientAuth && !extKeyUsage.serverAuth) {
98
98
  warningLog(
99
99
  `[NODE-OPCUA-W18] The certificate extKeyUsage must include clientAuth and/or serverAuth.\n` +
100
- `see https://reference.opcfoundation.org/v104/Core/docs/Part6/6.2.2/\n` +
101
- `certificateFile = ${certificateFile}`
100
+ `see https://reference.opcfoundation.org/v104/Core/docs/Part6/6.2.2/\n` +
101
+ `certificateFile = ${certificateFile}`
102
102
  );
103
103
  }
104
104
  }
@@ -107,14 +107,14 @@ export function verifyIsOPCUAValidCertificate(
107
107
  if (keyLengthInBits < 1024) {
108
108
  errorLog(
109
109
  `[NODE-OPCUA-W19] The public key length shall be greater than or equal to 1024 bits. key length is ${keyLengthInBits}.\n` +
110
- `see https://reference.opcfoundation.org/v104/GDS/docs/7.6.3/\n` +
111
- `certificateFile = ${certificateFile}`
110
+ `see https://reference.opcfoundation.org/v104/GDS/docs/7.6.3/\n` +
111
+ `certificateFile = ${certificateFile}`
112
112
  );
113
113
  } else if (keyLengthInBits < 2048) {
114
114
  warningLog(
115
115
  `[NODE-OPCUA-W23] key lengths less than 2048 are considered insecure. key length is ${keyLengthInBits}\n` +
116
- `see https://reference.opcfoundation.org/v104/Core/docs/Part2/6.8/\n` +
117
- `certificateFile = ${certificateFile}`
116
+ `see https://reference.opcfoundation.org/v104/Core/docs/Part2/6.8/\n` +
117
+ `certificateFile = ${certificateFile}`
118
118
  );
119
119
  }
120
120
  }
@@ -145,12 +145,22 @@ export async function performCertificateSanityCheck(
145
145
  if (keyLengthInBits <= 1024) {
146
146
  warningLog(
147
147
  `[NODE-OPCUA-W04] The public/private key pair uses a key length which is equal or lower than 1024 bits. ( key length was ${keyLengthInBits} )\n` +
148
- `OPCUA version 1.04 requires that security key length are greater or equal to 2048 bits.\n` +
149
- `The ${serverOrClient} is operating at risk. `
148
+ `OPCUA version 1.04 requires that security key length are greater or equal to 2048 bits.\n` +
149
+ `The ${serverOrClient} is operating at risk. `
150
150
  );
151
151
  }
152
- // verify that the certificate has a valid date and has expected extensions fields such as DNS and IP.
153
- const status1 = await certificateManager.trustCertificate(certificate);
152
+ try {
153
+ const _status1 = await certificateManager.trustCertificate(certificate);
154
+ } catch (err: any) {
155
+ if (err.code === "ENOENT" && err.syscall === "rename") {
156
+ // Under heavily concurrent circumstances (e.g. 50 clients sharing the same CertificateManager connecting simultaneously),
157
+ // a benign race condition occurs in node-opcua-pki's CertificateManager.trustCertificate where a client tries to rename
158
+ // the missing (already trusted and thus renamed) rejected certificate. We can safely ignore this!
159
+ debugLog("Swallowing benign ENOENT on concurrent trustCertificate");
160
+ } else {
161
+ throw err;
162
+ }
163
+ }
154
164
 
155
165
  const options: VerifyCertificateOptions = {
156
166
  acceptOutdatedCertificate: false,