node-opcua-client 2.163.1 → 2.165.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/client_base.js +1 -1
- package/dist/client_base.js.map +1 -1
- package/dist/client_monitored_item.js +1 -1
- package/dist/client_monitored_item.js.map +1 -1
- package/dist/client_monitored_item_group.js +1 -1
- package/dist/client_monitored_item_group.js.map +1 -1
- package/dist/client_monitored_item_toolbox.js +4 -4
- package/dist/client_monitored_item_toolbox.js.map +1 -1
- package/dist/client_session_keepalive_manager.js +3 -3
- package/dist/client_session_keepalive_manager.js.map +1 -1
- package/dist/client_subscription.js +1 -1
- package/dist/client_subscription.js.map +1 -1
- package/dist/private/client_base_impl.js +33 -28
- package/dist/private/client_base_impl.js.map +1 -1
- package/dist/private/client_monitored_item_impl.js +1 -2
- package/dist/private/client_monitored_item_impl.js.map +1 -1
- package/dist/private/client_publish_engine.js +14 -3
- package/dist/private/client_publish_engine.js.map +1 -1
- package/dist/private/client_session_impl.js +58 -58
- package/dist/private/client_session_impl.js.map +1 -1
- package/dist/private/client_subscription_impl.js +11 -11
- package/dist/private/client_subscription_impl.js.map +1 -1
- package/dist/private/opcua_client_impl.js +15 -15
- package/dist/private/opcua_client_impl.js.map +1 -1
- package/dist/private/reconnection/client_publish_engine_reconnection.js +2 -2
- package/dist/private/reconnection/client_publish_engine_reconnection.js.map +1 -1
- package/dist/private/reconnection/client_subscription_reconnection.js +9 -9
- package/dist/private/reconnection/client_subscription_reconnection.js.map +1 -1
- package/dist/private/reconnection/reconnection.js +8 -8
- package/dist/private/reconnection/reconnection.js.map +1 -1
- package/dist/tools/read_history_server_capabilities.js +3 -3
- package/dist/tools/read_history_server_capabilities.js.map +1 -1
- package/dist/verify.d.ts +3 -3
- package/dist/verify.js +11 -9
- package/dist/verify.js.map +1 -1
- package/package.json +46 -46
- package/source/client_base.ts +1 -1
- package/source/client_monitored_item.ts +1 -1
- package/source/client_monitored_item_group.ts +1 -1
- package/source/client_monitored_item_toolbox.ts +4 -4
- package/source/client_session_keepalive_manager.ts +3 -3
- package/source/client_subscription.ts +1 -1
- package/source/private/client_base_impl.ts +35 -29
- package/source/private/client_monitored_item_impl.ts +1 -2
- package/source/private/client_publish_engine.ts +18 -3
- package/source/private/client_session_impl.ts +58 -58
- package/source/private/client_subscription_impl.ts +11 -11
- package/source/private/opcua_client_impl.ts +15 -15
- package/source/private/reconnection/client_publish_engine_reconnection.ts +2 -2
- package/source/private/reconnection/client_subscription_reconnection.ts +6 -6
- package/source/private/reconnection/reconnection.ts +8 -8
- package/source/tools/read_history_server_capabilities.ts +3 -3
- package/source/verify.ts +40 -43
|
@@ -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
|
-
//
|
|
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
|
-
/*
|
|
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
|
-
/*
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
296
|
+
// c8 ignore next
|
|
297
297
|
doDebug && debugLog("the temporary replacement session is now closed");
|
|
298
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
/*
|
|
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
|
-
/*
|
|
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
|
-
/*
|
|
114
|
+
/* c8 ignore next */
|
|
115
115
|
if (!dataValues) {
|
|
116
116
|
return callback(new Error("Internal Error"));
|
|
117
117
|
}
|
package/source/verify.ts
CHANGED
|
@@ -1,17 +1,12 @@
|
|
|
1
|
-
import { OPCUACertificateManager } from "node-opcua-certificate-manager";
|
|
2
|
-
import { OPCUASecureObject } from "node-opcua-common";
|
|
1
|
+
import type { OPCUACertificateManager } from "node-opcua-certificate-manager";
|
|
2
|
+
import type { OPCUASecureObject } from "node-opcua-common";
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
Certificate,
|
|
6
|
-
exploreCertificate,
|
|
7
|
-
explorePrivateKey,
|
|
8
|
-
publicKeyAndPrivateKeyMatches
|
|
9
|
-
} from "node-opcua-crypto/web";
|
|
4
|
+
import { type Certificate, exploreCertificate, explorePrivateKey, publicKeyAndPrivateKeyMatches } from "node-opcua-crypto/web";
|
|
10
5
|
import { checkDebugFlag, make_debugLog, make_errorLog, make_warningLog } from "node-opcua-debug";
|
|
11
|
-
import { VerifyCertificateOptions } from "node-opcua-pki";
|
|
6
|
+
import type { VerifyCertificateOptions } from "node-opcua-pki";
|
|
12
7
|
|
|
13
|
-
const
|
|
14
|
-
const
|
|
8
|
+
const _doDebug = checkDebugFlag(__filename);
|
|
9
|
+
const _debugLog = make_debugLog(__filename);
|
|
15
10
|
const errorLog = make_errorLog(__filename);
|
|
16
11
|
const warningLog = make_warningLog(__filename);
|
|
17
12
|
|
|
@@ -29,8 +24,8 @@ export function verifyIsOPCUAValidCertificate(
|
|
|
29
24
|
// certificate is not active yet
|
|
30
25
|
warningLog(
|
|
31
26
|
`[NODE-OPCUA-W02] The certificate is not active yet\n` +
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
`notBefore ${certificateInfo.tbsCertificate.validity.notBefore.toISOString()}\n` +
|
|
28
|
+
`certificateFile ${certificateFile}`
|
|
34
29
|
);
|
|
35
30
|
}
|
|
36
31
|
// check that certificate has not expired
|
|
@@ -38,9 +33,9 @@ export function verifyIsOPCUAValidCertificate(
|
|
|
38
33
|
// certificate is obsolete
|
|
39
34
|
warningLog(
|
|
40
35
|
`[NODE-OPCUA-W03] The certificate has expired\n` +
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
36
|
+
`Please regenerate a valid certificate\n` +
|
|
37
|
+
`notAfter = ${certificateInfo.tbsCertificate.validity.notAfter.toISOString()}\n` +
|
|
38
|
+
`certificateFile= ${certificateFile}`
|
|
44
39
|
);
|
|
45
40
|
} else {
|
|
46
41
|
const tenDays = 10 * 24 * 60 * 60 * 1000;
|
|
@@ -48,9 +43,9 @@ export function verifyIsOPCUAValidCertificate(
|
|
|
48
43
|
// certificate is going to expired very soon
|
|
49
44
|
warningLog(
|
|
50
45
|
`[NODE-OPCUA-W05] The certificate is about to expire in less than 10 days.\n` +
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
46
|
+
`Please regenerate a valid certificate as soon as possible\n` +
|
|
47
|
+
`notAfter = ${certificateInfo.tbsCertificate.validity.notAfter.toISOString()}\n` +
|
|
48
|
+
`certificateFile= ${certificateFile}\n`
|
|
54
49
|
);
|
|
55
50
|
}
|
|
56
51
|
}
|
|
@@ -59,46 +54,46 @@ export function verifyIsOPCUAValidCertificate(
|
|
|
59
54
|
if (!uniformResourceIdentifier) {
|
|
60
55
|
warningLog(
|
|
61
56
|
`[NODE-OPCUA-W14] The certificate subjectAltName uniformResourceIdentifier is missing.\n` +
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
57
|
+
`Please regenerate a specific certificate with a uniformResourceIdentifier that matches your ${type} applicationUri\n` +
|
|
58
|
+
`applicationUri = ${applicationUri}\n` +
|
|
59
|
+
`certificateFile = ${certificateFile}\n`
|
|
65
60
|
);
|
|
66
61
|
return;
|
|
67
62
|
} else if (uniformResourceIdentifier[0] !== applicationUri) {
|
|
68
63
|
warningLog(
|
|
69
64
|
`[NODE-OPCUA-W06] The certificate subjectAltName does not match the ${type} applicationUri\n` +
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
65
|
+
`Please regenerate a specific certificate that matches your ${type} applicationUri\n` +
|
|
66
|
+
`certificate subjectAltName = ${uniformResourceIdentifier[0]}\n` +
|
|
67
|
+
`${type} applicationUri = ${applicationUri}\n` +
|
|
68
|
+
`certificateFile = ${certificateFile}\n`
|
|
74
69
|
);
|
|
75
70
|
}
|
|
76
71
|
const keyUsage = certificateInfo.tbsCertificate.extensions?.keyUsage;
|
|
77
72
|
if (!keyUsage) {
|
|
78
|
-
warningLog(`[NODE-OPCUA-W15] The certificate keyUsage is missing\
|
|
73
|
+
warningLog(`[NODE-OPCUA-W15] The certificate keyUsage is missing\ncertificateFile = ${certificateFile}`);
|
|
79
74
|
} else {
|
|
80
75
|
// spec says that certificate shall include digitalSignature, nonRepudiation, keyEncipherment and dataEncipherment.
|
|
81
76
|
// Other key uses are allowed.
|
|
82
77
|
if (!keyUsage.digitalSignature || !keyUsage.nonRepudiation || !keyUsage.keyEncipherment || !keyUsage.dataEncipherment) {
|
|
83
78
|
warningLog(
|
|
84
79
|
`[NODE-OPCUA-W16] The certificate keyUsage must include digitalSignature, nonRepudiation, keyEncipherment and dataEncipherment.\n` +
|
|
85
|
-
|
|
86
|
-
|
|
80
|
+
`see https://reference.opcfoundation.org/v104/Core/docs/Part6/6.2.2/\n` +
|
|
81
|
+
`certificateFile = ${certificateFile}`
|
|
87
82
|
);
|
|
88
83
|
warningLog(`keyUsage = ${JSON.stringify(keyUsage, null, " ")}`);
|
|
89
84
|
}
|
|
90
85
|
}
|
|
91
86
|
const extKeyUsage = certificateInfo.tbsCertificate.extensions?.extKeyUsage;
|
|
92
87
|
if (!extKeyUsage) {
|
|
93
|
-
warningLog(`[NODE-OPCUA-W17] The certificate extKeyUsage is missing\
|
|
88
|
+
warningLog(`[NODE-OPCUA-W17] The certificate extKeyUsage is missing\ncertificateFile = ${certificateFile}`);
|
|
94
89
|
} else {
|
|
95
90
|
// spec says that certificate shall include digitalSignature, nonRepudiation, keyEncipherment and dataEncipherment.
|
|
96
91
|
// Other key uses are allowed.
|
|
97
92
|
if (!extKeyUsage.clientAuth && !extKeyUsage.serverAuth) {
|
|
98
93
|
warningLog(
|
|
99
94
|
`[NODE-OPCUA-W18] The certificate extKeyUsage must include clientAuth and/or serverAuth.\n` +
|
|
100
|
-
|
|
101
|
-
|
|
95
|
+
`see https://reference.opcfoundation.org/v104/Core/docs/Part6/6.2.2/\n` +
|
|
96
|
+
`certificateFile = ${certificateFile}`
|
|
102
97
|
);
|
|
103
98
|
}
|
|
104
99
|
}
|
|
@@ -107,14 +102,14 @@ export function verifyIsOPCUAValidCertificate(
|
|
|
107
102
|
if (keyLengthInBits < 1024) {
|
|
108
103
|
errorLog(
|
|
109
104
|
`[NODE-OPCUA-W19] The public key length shall be greater than or equal to 1024 bits. key length is ${keyLengthInBits}.\n` +
|
|
110
|
-
|
|
111
|
-
|
|
105
|
+
`see https://reference.opcfoundation.org/v104/GDS/docs/7.6.3/\n` +
|
|
106
|
+
`certificateFile = ${certificateFile}`
|
|
112
107
|
);
|
|
113
108
|
} else if (keyLengthInBits < 2048) {
|
|
114
109
|
warningLog(
|
|
115
110
|
`[NODE-OPCUA-W23] key lengths less than 2048 are considered insecure. key length is ${keyLengthInBits}\n` +
|
|
116
|
-
|
|
117
|
-
|
|
111
|
+
`see https://reference.opcfoundation.org/v104/Core/docs/Part2/6.8/\n` +
|
|
112
|
+
`certificateFile = ${certificateFile}`
|
|
118
113
|
);
|
|
119
114
|
}
|
|
120
115
|
}
|
|
@@ -145,23 +140,25 @@ export async function performCertificateSanityCheck(
|
|
|
145
140
|
if (keyLengthInBits <= 1024) {
|
|
146
141
|
warningLog(
|
|
147
142
|
`[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
|
-
|
|
149
|
-
|
|
143
|
+
`OPCUA version 1.04 requires that security key length are greater or equal to 2048 bits.\n` +
|
|
144
|
+
`The ${serverOrClient} is operating at risk. `
|
|
150
145
|
);
|
|
151
146
|
}
|
|
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);
|
|
154
147
|
|
|
155
148
|
const options: VerifyCertificateOptions = {
|
|
156
149
|
acceptOutdatedCertificate: false,
|
|
157
150
|
acceptOutDatedIssuerCertificate: false,
|
|
158
|
-
acceptPendingCertificate: false
|
|
151
|
+
acceptPendingCertificate: false
|
|
159
152
|
};
|
|
160
153
|
|
|
161
154
|
const status = await certificateManager.verifyCertificate(certificate, options);
|
|
162
155
|
|
|
163
|
-
|
|
164
|
-
|
|
156
|
+
// BadCertificateUntrusted is expected for the application's own
|
|
157
|
+
// certificate — it does not need to be in its own trust list.
|
|
158
|
+
// Only warn about genuinely problematic statuses (expired,
|
|
159
|
+
// revoked, invalid signature, etc.).
|
|
160
|
+
if (status !== "Good" && status !== "BadCertificateUntrusted") {
|
|
161
|
+
warningLog("[NODE-OPCUA-W35] Warning: the certificate status is = ", status, " file = ", secureObject.certificateFile);
|
|
165
162
|
}
|
|
166
163
|
|
|
167
164
|
verifyIsOPCUAValidCertificate(certificate, secureObject.certificateFile, serverOrClient, applicationUri);
|