node-opcua-client 2.169.0 → 2.172.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.d.ts +20 -4
- package/dist/client_base.js.map +1 -1
- package/dist/client_session.d.ts +3 -3
- package/dist/client_session.js.map +1 -1
- package/dist/client_session_keepalive_manager.d.ts +2 -0
- package/dist/client_session_keepalive_manager.js +60 -5
- package/dist/client_session_keepalive_manager.js.map +1 -1
- package/dist/private/client_base_impl.d.ts +4 -4
- package/dist/private/client_base_impl.js +48 -16
- package/dist/private/client_base_impl.js.map +1 -1
- package/dist/verify.d.ts +2 -3
- package/dist/verify.js +3 -6
- package/dist/verify.js.map +1 -1
- package/package.json +44 -43
- package/source/client_base.ts +22 -4
- package/source/client_session.ts +19 -22
- package/source/client_session_keepalive_manager.ts +71 -11
- package/source/private/client_base_impl.ts +56 -22
- package/source/verify.ts +5 -10
package/dist/client_base.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import type { LocaleId } from "node-opcua-basic-types";
|
|
5
5
|
import type { OPCUACertificateManager } from "node-opcua-certificate-manager";
|
|
6
|
-
import type { OPCUASecureObject } from "node-opcua-common";
|
|
6
|
+
import type { ICertificateKeyPairProvider, ICertificateStore, OPCUASecureObject } from "node-opcua-common";
|
|
7
7
|
import type { Certificate } from "node-opcua-crypto/web";
|
|
8
8
|
import { ObjectRegistry } from "node-opcua-object-registry";
|
|
9
9
|
import type { ResponseCallback } from "node-opcua-pseudo-session";
|
|
@@ -12,6 +12,7 @@ import type { FindServersOnNetworkRequestOptions, FindServersRequestOptions, Ser
|
|
|
12
12
|
import type { ApplicationDescription, EndpointDescription } from "node-opcua-service-endpoints";
|
|
13
13
|
import type { ChannelSecurityToken, MessageSecurityMode } from "node-opcua-service-secure-channel";
|
|
14
14
|
import type { ErrorCallback } from "node-opcua-status-code";
|
|
15
|
+
import type { IClientTransportFactory } from "node-opcua-transport";
|
|
15
16
|
import type { Request, Response } from "./common";
|
|
16
17
|
export type FindServersRequestLike = FindServersRequestOptions;
|
|
17
18
|
export type FindServersOnNetworkRequestLike = FindServersOnNetworkRequestOptions;
|
|
@@ -24,7 +25,7 @@ export interface FindEndpointOptions {
|
|
|
24
25
|
privateKeyFile: string;
|
|
25
26
|
applicationName: string;
|
|
26
27
|
applicationUri: string;
|
|
27
|
-
clientCertificateManager: OPCUACertificateManager;
|
|
28
|
+
clientCertificateManager: OPCUACertificateManager | ICertificateStore;
|
|
28
29
|
}
|
|
29
30
|
export interface FindEndpointResult {
|
|
30
31
|
selectedEndpoint: EndpointDescription;
|
|
@@ -119,7 +120,7 @@ export interface OPCUAClientBaseOptions {
|
|
|
119
120
|
* - you want multiple instances of OPCUAClient to share the same OPCUACertificateManager
|
|
120
121
|
*
|
|
121
122
|
*/
|
|
122
|
-
clientCertificateManager?: OPCUACertificateManager;
|
|
123
|
+
clientCertificateManager?: OPCUACertificateManager | ICertificateStore;
|
|
123
124
|
/**
|
|
124
125
|
* The client certificate pem file.
|
|
125
126
|
*
|
|
@@ -166,6 +167,21 @@ export interface OPCUAClientBaseOptions {
|
|
|
166
167
|
* defaultTransactionTimeout
|
|
167
168
|
*/
|
|
168
169
|
defaultTransactionTimeout?: number;
|
|
170
|
+
/**
|
|
171
|
+
* An optional in-memory certificate/key provider.
|
|
172
|
+
*
|
|
173
|
+
* When supplied, the client skips disk-based certificate
|
|
174
|
+
* path resolution and uses the provider directly.
|
|
175
|
+
*/
|
|
176
|
+
certificateKeyPairProvider?: ICertificateKeyPairProvider;
|
|
177
|
+
/**
|
|
178
|
+
* Optional factory for the underlying client transport. When omitted, the
|
|
179
|
+
* secure-channel layer uses `defaultClientTransportFactory` (a Node-only
|
|
180
|
+
* TCP transport). Consumers that need a different transport — browser
|
|
181
|
+
* WebSocket, in-process stub, tracing wrapper — pass a factory here and
|
|
182
|
+
* it is threaded through to `ClientSecureChannelLayer`.
|
|
183
|
+
*/
|
|
184
|
+
transportFactory?: IClientTransportFactory;
|
|
169
185
|
}
|
|
170
186
|
export interface GetEndpointsOptions {
|
|
171
187
|
endpointUrl?: string;
|
|
@@ -176,7 +192,7 @@ export interface OPCUAClientBase<Events extends OPCUAClientBaseEvents = OPCUACli
|
|
|
176
192
|
/**
|
|
177
193
|
* certificate Manager
|
|
178
194
|
*/
|
|
179
|
-
readonly clientCertificateManager:
|
|
195
|
+
readonly clientCertificateManager: ICertificateStore;
|
|
180
196
|
/***
|
|
181
197
|
*
|
|
182
198
|
* @param endpointUrl the endpoint of the server to connect to ( i.e "opc.tcp://machine.name:3434/name" )
|
package/dist/client_base.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client_base.js","sourceRoot":"","sources":["../source/client_base.ts"],"names":[],"mappings":";;;AAQA,2EAA4D;
|
|
1
|
+
{"version":3,"file":"client_base.js","sourceRoot":"","sources":["../source/client_base.ts"],"names":[],"mappings":";;;AAQA,2EAA4D;AA4Y/C,QAAA,eAAe,GAAG;IAC3B,QAAQ,EAAE,IAAI,2CAAc,EAAE;IAC9B,UAAU,EAAE,IAAI,GAAG,CAAC;IAEpB,MAAM,CAAC,OAA+B;QAClC,mBAAmB;QACnB,OAAO,CAAC;QACR,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACvC,CAAC;CACJ,CAAC"}
|
package/dist/client_session.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @module node-opcua-client
|
|
3
3
|
*/
|
|
4
|
-
import type { EventEmitter } from "events";
|
|
4
|
+
import type { EventEmitter } from "node:events";
|
|
5
5
|
import type { DateTime, UInt8 } from "node-opcua-basic-types";
|
|
6
6
|
import type { ExtraDataTypeManager } from "node-opcua-client-dynamic-extension-object";
|
|
7
7
|
import type { ServerState } from "node-opcua-common";
|
|
@@ -11,13 +11,13 @@ import type { LocalizedTextLike } from "node-opcua-data-model";
|
|
|
11
11
|
import type { DataValue, TimestampsToReturn } from "node-opcua-data-value";
|
|
12
12
|
import type { ExtensionObject } from "node-opcua-extension-object";
|
|
13
13
|
import type { NodeId, NodeIdLike } from "node-opcua-nodeid";
|
|
14
|
-
import {
|
|
14
|
+
import type { ArgumentDefinition, IBasicSession, IBasicSessionBrowse, IBasicSessionBrowseNext, IBasicSessionCall, IBasicSessionChangeUser, IBasicSessionRead, IBasicSessionTranslateBrowsePath, IBasicSessionWrite, MethodId, ResponseCallback } from "node-opcua-pseudo-session";
|
|
15
15
|
import type { EndpointDescription } from "node-opcua-service-endpoints";
|
|
16
16
|
import type { HistoryReadResult } from "node-opcua-service-history";
|
|
17
17
|
import type { QueryFirstRequestOptions, QueryFirstResponse } from "node-opcua-service-query";
|
|
18
18
|
import type { CreateMonitoredItemsRequestOptions, CreateMonitoredItemsResponse, CreateSubscriptionRequestOptions, CreateSubscriptionResponse, DeleteMonitoredItemsRequestOptions, DeleteMonitoredItemsResponse, DeleteSubscriptionsRequestOptions, DeleteSubscriptionsResponse, ModifyMonitoredItemsRequestOptions, ModifyMonitoredItemsResponse, ModifySubscriptionRequestOptions, ModifySubscriptionResponse, PublishRequest, PublishResponse, RepublishRequest, RepublishResponse, SetMonitoringModeRequestOptions, SetMonitoringModeResponse, SetTriggeringRequestOptions, SetTriggeringResponse, TransferSubscriptionsRequestOptions, TransferSubscriptionsResponse } from "node-opcua-service-subscription";
|
|
19
19
|
import type { Callback, ErrorCallback, StatusCode } from "node-opcua-status-code";
|
|
20
|
-
import {
|
|
20
|
+
import type { AggregateConfigurationOptions, HistoryReadRequest, HistoryReadResponse, HistoryReadValueIdOptions, ReadValueIdOptions } from "node-opcua-types";
|
|
21
21
|
import type { DataType, Variant } from "node-opcua-variant";
|
|
22
22
|
export { ExtraDataTypeManager } from "node-opcua-client-dynamic-extension-object";
|
|
23
23
|
export { ExtensionObject } from "node-opcua-extension-object";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client_session.js","sourceRoot":"","sources":["../source/client_session.ts"],"names":[],"mappings":";AAAA;;GAEG;;;
|
|
1
|
+
{"version":3,"file":"client_session.js","sourceRoot":"","sources":["../source/client_session.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AA+DH,yGAAkF;AAAzE,kJAAA,oBAAoB,OAAA;AAE7B,2EAA8D;AAArD,8HAAA,eAAe,OAAA"}
|
|
@@ -7,6 +7,7 @@ import type { ClientSessionImpl } from "./private/client_session_impl";
|
|
|
7
7
|
export interface ClientSessionKeepAliveManagerEvents {
|
|
8
8
|
on(event: "keepalive", eventHandler: (lastKnownServerState: ServerState, count: number) => void): this;
|
|
9
9
|
on(event: "failure", eventHandler: () => void): this;
|
|
10
|
+
on(event: "keepalive_failure", eventHandler: () => void): this;
|
|
10
11
|
}
|
|
11
12
|
export declare class ClientSessionKeepAliveManager extends EventEmitter implements ClientSessionKeepAliveManagerEvents {
|
|
12
13
|
private readonly session;
|
|
@@ -14,6 +15,7 @@ export declare class ClientSessionKeepAliveManager extends EventEmitter implemen
|
|
|
14
15
|
private pingTimeout;
|
|
15
16
|
private lastKnownState?;
|
|
16
17
|
private transactionInProgress;
|
|
18
|
+
private consecutiveFailures;
|
|
17
19
|
count: number;
|
|
18
20
|
checkInterval: number;
|
|
19
21
|
constructor(session: ClientSessionImpl);
|
|
@@ -16,16 +16,19 @@ const node_opcua_constants_1 = require("node-opcua-constants");
|
|
|
16
16
|
const node_opcua_debug_1 = require("node-opcua-debug");
|
|
17
17
|
const node_opcua_nodeid_1 = require("node-opcua-nodeid");
|
|
18
18
|
const node_opcua_secure_channel_1 = require("node-opcua-secure-channel");
|
|
19
|
+
const node_opcua_status_code_1 = require("node-opcua-status-code");
|
|
19
20
|
const serverStatusStateNodeId = (0, node_opcua_nodeid_1.coerceNodeId)(node_opcua_constants_1.VariableIds.Server_ServerStatus_State);
|
|
20
21
|
const debugLog = (0, node_opcua_debug_1.make_debugLog)(__filename);
|
|
21
22
|
const doDebug = (0, node_opcua_debug_1.checkDebugFlag)(__filename);
|
|
22
23
|
const warningLog = (0, node_opcua_debug_1.make_warningLog)(__filename);
|
|
24
|
+
const maxBackoffInterval = 60_000;
|
|
23
25
|
class ClientSessionKeepAliveManager extends events_1.EventEmitter {
|
|
24
26
|
session;
|
|
25
27
|
timerId;
|
|
26
28
|
pingTimeout;
|
|
27
29
|
lastKnownState;
|
|
28
30
|
transactionInProgress = false;
|
|
31
|
+
consecutiveFailures = 0;
|
|
29
32
|
count = 0;
|
|
30
33
|
checkInterval;
|
|
31
34
|
constructor(session) {
|
|
@@ -69,7 +72,9 @@ class ClientSessionKeepAliveManager extends events_1.EventEmitter {
|
|
|
69
72
|
return; // stop here
|
|
70
73
|
}
|
|
71
74
|
if (this.timerId) {
|
|
72
|
-
|
|
75
|
+
// When delta exceeds checkInterval it is an explicit backoff requested by _ping_server;
|
|
76
|
+
// otherwise delta is the time already consumed this cycle.
|
|
77
|
+
const timeout = delta > this.checkInterval ? delta : Math.max(1, this.checkInterval - delta);
|
|
73
78
|
this.timerId = setTimeout(() => this.ping_server(), timeout);
|
|
74
79
|
}
|
|
75
80
|
});
|
|
@@ -118,17 +123,66 @@ class ClientSessionKeepAliveManager extends events_1.EventEmitter {
|
|
|
118
123
|
attributeId: node_opcua_basic_types_1.AttributeIds.Value
|
|
119
124
|
}, (err, dataValue) => {
|
|
120
125
|
this.transactionInProgress = false;
|
|
121
|
-
if (err
|
|
122
|
-
|
|
123
|
-
|
|
126
|
+
if (err) {
|
|
127
|
+
warningLog(chalk_1.default.cyan(" warning : ClientSessionKeepAliveManager#ping_server "), chalk_1.default.yellow(err.message));
|
|
128
|
+
const serviceFaultResponse = err.response;
|
|
129
|
+
if (serviceFaultResponse) {
|
|
130
|
+
const sc = serviceFaultResponse.responseHeader?.serviceResult;
|
|
131
|
+
if (sc?.equals(node_opcua_status_code_1.StatusCodes.BadSessionIdInvalid) || sc?.equals(node_opcua_status_code_1.StatusCodes.BadSessionClosed)) {
|
|
132
|
+
this.emit("failure");
|
|
133
|
+
warningLog("Keep alive has failed, considering a network outage is in place, forcing a reconnection");
|
|
134
|
+
terminateConnection(session._client);
|
|
135
|
+
resolve(0);
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
if (sc?.equals(node_opcua_status_code_1.StatusCodes.BadInvalidTimestamp)) {
|
|
139
|
+
// BadInvalidTimestamp (OPC UA Part 4 7.38.2, Table 178:
|
|
140
|
+
// "The timestamp is outside the range allowed by the Server")
|
|
141
|
+
// refers to the timestamp field of the RequestHeader
|
|
142
|
+
// (OPC UA Part 4 7.32), which the spec states is used
|
|
143
|
+
// "only for diagnostic and logging purposes in the Server".
|
|
144
|
+
//
|
|
145
|
+
// The server responded at the OPC UA application layer:
|
|
146
|
+
// the SecureChannel and Session are intact. The cause is
|
|
147
|
+
// clock skew between client and server; this is an
|
|
148
|
+
// infrastructure concern outside the scope of the keepalive
|
|
149
|
+
// manager.
|
|
150
|
+
//
|
|
151
|
+
// Treating this as a keepalive failure is semantically
|
|
152
|
+
// incorrect: the round-trip succeeded. Incrementing
|
|
153
|
+
// consecutiveFailures leads to unbounded exponential backoff
|
|
154
|
+
// and eventual session expiry server-side, triggering an
|
|
155
|
+
// unnecessary reconnect loop.
|
|
156
|
+
//
|
|
157
|
+
// See: https://reference.opcfoundation.org/Core/Part4/v105/docs/7.38.2
|
|
158
|
+
// https://reference.opcfoundation.org/Core/Part4/v105/docs/7.32
|
|
159
|
+
this.consecutiveFailures = 0;
|
|
160
|
+
debugLog("emit keepalive (BadInvalidTimestamp: session alive, clock skew on request timestamp)");
|
|
161
|
+
this.emit("keepalive", this.lastKnownState ?? node_opcua_common_1.ServerState.Unknown, this.count);
|
|
162
|
+
resolve(0);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
this.consecutiveFailures++;
|
|
166
|
+
warningLog("Keep alive received ServiceFault from server (session intact):", sc?.toString());
|
|
167
|
+
this.emit("keepalive_failure");
|
|
168
|
+
resolve(Math.min(this.checkInterval * 2 ** this.consecutiveFailures, maxBackoffInterval));
|
|
169
|
+
}
|
|
124
170
|
}
|
|
171
|
+
else {
|
|
172
|
+
this.emit("failure");
|
|
173
|
+
warningLog("Keep alive has failed, considering a network outage is in place, forcing a reconnection");
|
|
174
|
+
terminateConnection(session._client);
|
|
175
|
+
resolve(0);
|
|
176
|
+
}
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
if (!dataValue || !dataValue.value) {
|
|
125
180
|
/**
|
|
126
181
|
* @event failure
|
|
127
182
|
* raised when the server is not responding or is responding with en error to
|
|
128
183
|
* the keep alive read Variable value transaction
|
|
129
184
|
*/
|
|
130
185
|
this.emit("failure");
|
|
131
|
-
// also simulate a connection by closing the channel abruptly from our end ...
|
|
132
186
|
warningLog("Keep alive has failed, considering a network outage is in place, forcing a reconnection");
|
|
133
187
|
terminateConnection(session._client);
|
|
134
188
|
resolve(0);
|
|
@@ -143,6 +197,7 @@ class ClientSessionKeepAliveManager extends events_1.EventEmitter {
|
|
|
143
197
|
this.lastKnownState = newState;
|
|
144
198
|
this.count++; // increase successful counter
|
|
145
199
|
}
|
|
200
|
+
this.consecutiveFailures = 0;
|
|
146
201
|
debugLog("emit keepalive");
|
|
147
202
|
this.emit("keepalive", this.lastKnownState, this.count);
|
|
148
203
|
resolve(0);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client_session_keepalive_manager.js","sourceRoot":"","sources":["../source/client_session_keepalive_manager.ts"],"names":[],"mappings":";AAAA;;GAEG;;;;;;AAEH,kDAA0B;AAC1B,mCAAsC;AACtC,yDAA2C;AAC3C,mEAAsD;AACtD,yDAAgD;AAChD,+DAAmD;AAEnD,uDAAkF;AAClF,yDAAiD;AACjD,yEAAqE;
|
|
1
|
+
{"version":3,"file":"client_session_keepalive_manager.js","sourceRoot":"","sources":["../source/client_session_keepalive_manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
import { OPCUASecureObject } from "node-opcua-common";
|
|
1
|
+
import { type ICertificateStore, OPCUASecureObject } from "node-opcua-common";
|
|
3
2
|
import { type Certificate } from "node-opcua-crypto/web";
|
|
4
3
|
import type { IBasicTransportSettings, ResponseCallback } from "node-opcua-pseudo-session";
|
|
5
4
|
import { ClientSecureChannelLayer, type ConnectionStrategy, type ConnectionStrategyOptions, type SecurityPolicy } from "node-opcua-secure-channel";
|
|
@@ -78,7 +77,8 @@ export declare class ClientBaseImpl<Events extends OPCUAClientBaseEvents = OPCUA
|
|
|
78
77
|
private _instanceNumber;
|
|
79
78
|
private _transportSettings;
|
|
80
79
|
private _transportTimeout?;
|
|
81
|
-
|
|
80
|
+
private _transportFactory?;
|
|
81
|
+
clientCertificateManager: ICertificateStore;
|
|
82
82
|
isUnusable(): boolean;
|
|
83
83
|
protected _setInternalState(internalState: InternalClientState): void;
|
|
84
84
|
emit<K>(eventName: K, ...others: unknown[]): boolean;
|
|
@@ -86,7 +86,7 @@ export declare class ClientBaseImpl<Events extends OPCUAClientBaseEvents = OPCUA
|
|
|
86
86
|
private _cancel_reconnection;
|
|
87
87
|
_recreate_secure_channel(callback: ErrorCallback): void;
|
|
88
88
|
_internal_create_secure_channel(connectionStrategy: ConnectionStrategyOptions, callback: CreateSecureChannelCallbackFunc): void;
|
|
89
|
-
static createCertificate(clientCertificateManager:
|
|
89
|
+
static createCertificate(clientCertificateManager: ICertificateStore, certificateFile: string, applicationName: string, applicationUri: string): Promise<void>;
|
|
90
90
|
createDefaultCertificate(): Promise<void>;
|
|
91
91
|
protected _getBuiltApplicationUri(): string;
|
|
92
92
|
protected initializeCM(): Promise<void>;
|
|
@@ -287,6 +287,7 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
287
287
|
_instanceNumber;
|
|
288
288
|
_transportSettings;
|
|
289
289
|
_transportTimeout;
|
|
290
|
+
_transportFactory;
|
|
290
291
|
clientCertificateManager;
|
|
291
292
|
isUnusable() {
|
|
292
293
|
return (this._internalState === "disconnected" ||
|
|
@@ -316,13 +317,25 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
316
317
|
}
|
|
317
318
|
constructor(options) {
|
|
318
319
|
options = options || {};
|
|
319
|
-
if (
|
|
320
|
-
|
|
320
|
+
if (options.certificateKeyPairProvider) {
|
|
321
|
+
// In-memory path — use a lightweight in-memory store
|
|
322
|
+
// when no cert manager was explicitly provided.
|
|
323
|
+
if (!options.clientCertificateManager) {
|
|
324
|
+
options.clientCertificateManager = new node_opcua_common_1.InMemoryCertificateStore();
|
|
325
|
+
}
|
|
326
|
+
super(options);
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
// Disk path — derive cert/key paths from certificate manager
|
|
330
|
+
if (!options.clientCertificateManager) {
|
|
331
|
+
options.clientCertificateManager = (0, node_opcua_certificate_manager_1.getDefaultCertificateManager)("PKI");
|
|
332
|
+
}
|
|
333
|
+
const cm = options.clientCertificateManager;
|
|
334
|
+
options.privateKeyFile = options.privateKeyFile || cm.privateKey;
|
|
335
|
+
options.certificateFile =
|
|
336
|
+
options.certificateFile || node_path_1.default.join(cm.rootDir, "own/certs/client_certificate.pem");
|
|
337
|
+
super(options);
|
|
321
338
|
}
|
|
322
|
-
options.privateKeyFile = options.privateKeyFile || options.clientCertificateManager.privateKey;
|
|
323
|
-
options.certificateFile =
|
|
324
|
-
options.certificateFile || node_path_1.default.join(options.clientCertificateManager.rootDir, "own/certs/client_certificate.pem");
|
|
325
|
-
super(options);
|
|
326
339
|
this._setInternalState("uninitialized");
|
|
327
340
|
this._instanceNumber = g_ClientCounter++;
|
|
328
341
|
this.applicationName = options.applicationName || "NodeOPCUA-Client";
|
|
@@ -364,6 +377,7 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
364
377
|
this._setInternalState("disconnected");
|
|
365
378
|
this._transportSettings = options.transportSettings || {};
|
|
366
379
|
this._transportTimeout = options.transportTimeout;
|
|
380
|
+
this._transportFactory = options.transportFactory;
|
|
367
381
|
}
|
|
368
382
|
_cancel_reconnection(callback) {
|
|
369
383
|
// _cancel_reconnection is invoked during disconnection
|
|
@@ -510,6 +524,7 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
510
524
|
tokenRenewalInterval: this.tokenRenewalInterval,
|
|
511
525
|
transportSettings: this._transportSettings,
|
|
512
526
|
transportTimeout: this._transportTimeout,
|
|
527
|
+
transportFactory: this._transportFactory,
|
|
513
528
|
defaultTransactionTimeout: this.defaultTransactionTimeout
|
|
514
529
|
});
|
|
515
530
|
secureChannel.on("backoff", (count, delay) => {
|
|
@@ -583,12 +598,16 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
583
598
|
if (!node_fs_1.default.existsSync(certificateFile)) {
|
|
584
599
|
const hostname = (0, node_opcua_hostname_1.getHostname)();
|
|
585
600
|
// this.serverInfo.applicationUri!;
|
|
586
|
-
|
|
601
|
+
// Cast is safe: createDefaultCertificate only calls
|
|
602
|
+
// this in the disk path, where the manager is always
|
|
603
|
+
// an OPCUACertificateManager.
|
|
604
|
+
const cm = clientCertificateManager;
|
|
605
|
+
await cm.createSelfSignedCertificate({
|
|
587
606
|
applicationUri,
|
|
588
607
|
dns: [hostname],
|
|
589
608
|
// ip: await getIpAddresses(),
|
|
590
609
|
outputFile: certificateFile,
|
|
591
|
-
subject: (0,
|
|
610
|
+
subject: (0, node_opcua_common_1.makeSubject)(applicationName, hostname),
|
|
592
611
|
startDate: new Date(),
|
|
593
612
|
validity: 365 * 10 // 10 years
|
|
594
613
|
});
|
|
@@ -613,7 +632,9 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
613
632
|
warningLog("Creating default certificate ... please wait");
|
|
614
633
|
await ClientBaseImpl.createCertificate(this.clientCertificateManager, this.certificateFile, this.applicationName, this._getBuiltApplicationUri());
|
|
615
634
|
debugLog("privateKey = ", this.privateKeyFile);
|
|
616
|
-
|
|
635
|
+
if ("privateKey" in this.clientCertificateManager) {
|
|
636
|
+
debugLog(" = ", this.clientCertificateManager.privateKey);
|
|
637
|
+
}
|
|
617
638
|
debugLog("certificateFile = ", this.certificateFile);
|
|
618
639
|
const _certificate = this.getCertificate();
|
|
619
640
|
const _privateKey = this.getPrivateKey();
|
|
@@ -637,10 +658,16 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
637
658
|
return;
|
|
638
659
|
}
|
|
639
660
|
await this.clientCertificateManager.initialize();
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
661
|
+
if (this.certificateFile === "<in-memory>" || this.certificateFile === "<unknown>") {
|
|
662
|
+
// In-memory provider — cert already available, skip disk operations
|
|
663
|
+
}
|
|
664
|
+
else {
|
|
665
|
+
// Disk path — create default cert if missing
|
|
666
|
+
await this.createDefaultCertificate();
|
|
667
|
+
// c8 ignore next
|
|
668
|
+
if (!node_fs_1.default.existsSync(this.privateKeyFile)) {
|
|
669
|
+
throw new Error(` cannot locate private key file ${this.privateKeyFile}`);
|
|
670
|
+
}
|
|
644
671
|
}
|
|
645
672
|
if (this.isUnusable())
|
|
646
673
|
return;
|
|
@@ -774,7 +801,8 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
774
801
|
if (!this._secureChannel) {
|
|
775
802
|
// this may happen if the Server has closed the connection abruptly for some unknown reason
|
|
776
803
|
// or if the tcp connection has been broken.
|
|
777
|
-
callback(new Error("performMessageTransaction: No SecureChannel , connection may have been canceled abruptly by server"
|
|
804
|
+
callback(new Error("performMessageTransaction: No SecureChannel , connection may have been canceled abruptly by server" +
|
|
805
|
+
" while performing " + request.schema.name));
|
|
778
806
|
return;
|
|
779
807
|
}
|
|
780
808
|
if (this._internalState !== "connected" &&
|
|
@@ -1165,7 +1193,9 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
1165
1193
|
})
|
|
1166
1194
|
.catch((err1) => {
|
|
1167
1195
|
warningLog("[NODE-OPCUA-W25] client's server certificate verification has failed ", err1.message);
|
|
1168
|
-
|
|
1196
|
+
if ("rootDir" in this.clientCertificateManager) {
|
|
1197
|
+
warningLog(" clientCertificateManager.rootDir = ", this.clientCertificateManager.rootDir);
|
|
1198
|
+
}
|
|
1169
1199
|
const chain = (0, web_1.split_der)(endpoint.serverCertificate);
|
|
1170
1200
|
warningLog(` server certificate chain contains ${chain.length} element(s)`);
|
|
1171
1201
|
for (let i = 0; i < chain.length; i++) {
|
|
@@ -1199,7 +1229,9 @@ class ClientBaseImpl extends node_opcua_common_1.OPCUASecureObject {
|
|
|
1199
1229
|
}
|
|
1200
1230
|
if (chain.length > 1) {
|
|
1201
1231
|
warningLog(" verify also that the issuer certificate is trusted and the issuer's certificate is present in the issuer.cert folder\n" +
|
|
1202
|
-
" of the client certificate manager located in ", this.clientCertificateManager
|
|
1232
|
+
" of the client certificate manager located in ", "rootDir" in this.clientCertificateManager
|
|
1233
|
+
? this.clientCertificateManager.rootDir
|
|
1234
|
+
: "<in-memory>");
|
|
1203
1235
|
}
|
|
1204
1236
|
else {
|
|
1205
1237
|
warningLog(" verify that the server certificate is trusted or that server certificate issuer's certificate is present in the issuer folder");
|