node-opcua-server 2.53.0 → 2.56.1
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/LICENSE +20 -20
- package/dist/base_server.js +12 -14
- package/dist/base_server.js.map +1 -1
- package/dist/factory.d.ts +4 -2
- package/dist/factory.js.map +1 -1
- package/dist/history_server_capabilities.js.map +1 -1
- package/dist/i_server_side_publish_engine.d.ts +1 -1
- package/dist/i_server_side_publish_engine.js +1 -1
- package/dist/i_server_side_publish_engine.js.map +1 -1
- package/dist/monitored_item.d.ts +3 -0
- package/dist/monitored_item.js +7 -14
- package/dist/monitored_item.js.map +1 -1
- package/dist/node_sampler.js +1 -1
- package/dist/node_sampler.js.map +1 -1
- package/dist/opcua_server.d.ts +29 -44
- package/dist/opcua_server.js +218 -262
- package/dist/opcua_server.js.map +1 -1
- package/dist/queue.js +1 -0
- package/dist/queue.js.map +1 -1
- package/dist/register_server_manager.d.ts +4 -1
- package/dist/register_server_manager.js +5 -5
- package/dist/register_server_manager.js.map +1 -1
- package/dist/register_server_manager_hidden.d.ts +1 -1
- package/dist/register_server_manager_hidden.js.map +1 -1
- package/dist/register_server_manager_mdns_only.d.ts +4 -1
- package/dist/register_server_manager_mdns_only.js +1 -1
- package/dist/register_server_manager_mdns_only.js.map +1 -1
- package/dist/server_capabilities.js.map +1 -1
- package/dist/server_end_point.d.ts +4 -1
- package/dist/server_end_point.js +10 -11
- package/dist/server_end_point.js.map +1 -1
- package/dist/server_engine.d.ts +11 -7
- package/dist/server_engine.js +72 -74
- package/dist/server_engine.js.map +1 -1
- package/dist/server_publish_engine.d.ts +4 -1
- package/dist/server_publish_engine.js +5 -5
- package/dist/server_publish_engine.js.map +1 -1
- package/dist/server_publish_engine_for_orphan_subscriptions.d.ts +2 -2
- package/dist/server_publish_engine_for_orphan_subscriptions.js.map +1 -1
- package/dist/server_session.d.ts +1 -1
- package/dist/server_session.js +24 -29
- package/dist/server_session.js.map +1 -1
- package/dist/server_subscription.d.ts +3 -1
- package/dist/server_subscription.js +6 -6
- package/dist/server_subscription.js.map +1 -1
- package/dist/sessions_compatible_for_transfer.js +2 -1
- package/dist/sessions_compatible_for_transfer.js.map +1 -1
- package/dist/validate_filter.js +4 -7
- package/dist/validate_filter.js.map +1 -1
- package/package.json +45 -44
- package/source/base_server.ts +19 -22
- package/source/factory.ts +5 -2
- package/source/history_server_capabilities.ts +3 -4
- package/source/i_channel_data.ts +4 -8
- package/source/i_register_server_manager.ts +0 -3
- package/source/i_server_side_publish_engine.ts +5 -6
- package/source/i_socket_data.ts +1 -1
- package/source/index.ts +14 -14
- package/source/monitored_item.ts +32 -44
- package/source/node_sampler.ts +82 -82
- package/source/opcua_server.ts +326 -357
- package/source/queue.ts +6 -7
- package/source/register_server_manager.ts +35 -23
- package/source/register_server_manager_hidden.ts +8 -10
- package/source/register_server_manager_mdns_only.ts +8 -13
- package/source/server_capabilities.ts +0 -5
- package/source/server_end_point.ts +28 -30
- package/source/server_engine.ts +122 -122
- package/source/server_publish_engine.ts +24 -21
- package/source/server_publish_engine_for_orphan_subscriptions.ts +26 -26
- package/source/server_session.ts +44 -49
- package/source/server_subscription.ts +23 -23
- package/source/sessions_compatible_for_transfer.ts +26 -25
- package/source/validate_filter.ts +8 -22
- package/test_helpers/create_certificates.js +1 -1
package/source/opcua_server.ts
CHANGED
|
@@ -36,7 +36,9 @@ import {
|
|
|
36
36
|
UAObject,
|
|
37
37
|
UAVariable,
|
|
38
38
|
ISessionContext,
|
|
39
|
-
UAView
|
|
39
|
+
UAView,
|
|
40
|
+
EventTypeLike,
|
|
41
|
+
UAObjectType
|
|
40
42
|
} from "node-opcua-address-space";
|
|
41
43
|
import { getDefaultCertificateManager, OPCUACertificateManager } from "node-opcua-certificate-manager";
|
|
42
44
|
import { ServerState } from "node-opcua-common";
|
|
@@ -112,7 +114,6 @@ import {
|
|
|
112
114
|
SetMonitoringModeResponse,
|
|
113
115
|
SetPublishingModeRequest,
|
|
114
116
|
SetPublishingModeResponse,
|
|
115
|
-
SetTriggeringRequestOptions,
|
|
116
117
|
SetTriggeringRequest,
|
|
117
118
|
SetTriggeringResponse,
|
|
118
119
|
TransferSubscriptionsRequest,
|
|
@@ -135,15 +136,16 @@ import {
|
|
|
135
136
|
MonitoringMode,
|
|
136
137
|
UserIdentityToken,
|
|
137
138
|
UserTokenPolicy,
|
|
138
|
-
BrowseDescription,
|
|
139
139
|
BuildInfoOptions,
|
|
140
140
|
MonitoredItemCreateResult,
|
|
141
|
-
IssuedIdentityToken
|
|
141
|
+
IssuedIdentityToken,
|
|
142
|
+
BrowseResultOptions
|
|
142
143
|
} from "node-opcua-types";
|
|
143
144
|
import { DataType } from "node-opcua-variant";
|
|
144
145
|
import { VariantArrayType } from "node-opcua-variant";
|
|
145
146
|
import { matchUri } from "node-opcua-utils";
|
|
146
147
|
|
|
148
|
+
import { UAString } from "node-opcua-basic-types";
|
|
147
149
|
import { OPCUABaseServer, OPCUABaseServerOptions } from "./base_server";
|
|
148
150
|
import { Factory } from "./factory";
|
|
149
151
|
import { IRegisterServerManager } from "./i_register_server_manager";
|
|
@@ -153,7 +155,7 @@ import { RegisterServerManagerHidden } from "./register_server_manager_hidden";
|
|
|
153
155
|
import { RegisterServerManagerMDNSONLY } from "./register_server_manager_mdns_only";
|
|
154
156
|
import { ServerCapabilitiesOptions } from "./server_capabilities";
|
|
155
157
|
import { OPCUAServerEndPoint } from "./server_end_point";
|
|
156
|
-
import { ClosingReason, ServerEngine } from "./server_engine";
|
|
158
|
+
import { ClosingReason, CreateSessionOption, ServerEngine } from "./server_engine";
|
|
157
159
|
import { ServerSession } from "./server_session";
|
|
158
160
|
import { CreateMonitoredItemHook, DeleteMonitoredItemHook, Subscription } from "./server_subscription";
|
|
159
161
|
import { ISocketData } from "./i_socket_data";
|
|
@@ -178,6 +180,8 @@ export interface UserManagerOptions extends IUserManager {
|
|
|
178
180
|
isValidUserAsync?: ValidUserAsyncFunc;
|
|
179
181
|
}
|
|
180
182
|
|
|
183
|
+
// tslint:disable-next-line:no-var-requires
|
|
184
|
+
const thenify = require("thenify");
|
|
181
185
|
// tslint:disable-next-line:no-var-requires
|
|
182
186
|
const package_info = require("../package.json");
|
|
183
187
|
const debugLog = make_debugLog(__filename);
|
|
@@ -208,6 +212,26 @@ const minSessionTimeout = 100; // 100 milliseconds
|
|
|
208
212
|
const defaultSessionTimeout = 1000 * 30; // 30 seconds
|
|
209
213
|
const maxSessionTimeout = 1000 * 60 * 50; // 50 minutes
|
|
210
214
|
|
|
215
|
+
type ResponseClassType =
|
|
216
|
+
| typeof BrowseResponse
|
|
217
|
+
| typeof BrowseNextResponse
|
|
218
|
+
| typeof CallResponse
|
|
219
|
+
| typeof CreateMonitoredItemsResponse
|
|
220
|
+
| typeof CreateSubscriptionResponse
|
|
221
|
+
| typeof DeleteSubscriptionsResponse
|
|
222
|
+
| typeof HistoryReadResponse
|
|
223
|
+
| typeof ModifyMonitoredItemsResponse
|
|
224
|
+
| typeof ModifySubscriptionResponse
|
|
225
|
+
| typeof ReadResponse
|
|
226
|
+
| typeof RegisterNodesResponse
|
|
227
|
+
| typeof RepublishResponse
|
|
228
|
+
| typeof SetPublishingModeResponse
|
|
229
|
+
| typeof SetTriggeringResponse
|
|
230
|
+
| typeof TransferSubscriptionsResponse
|
|
231
|
+
| typeof TranslateBrowsePathsToNodeIdsResponse
|
|
232
|
+
| typeof UnregisterNodesResponse
|
|
233
|
+
| typeof WriteResponse;
|
|
234
|
+
|
|
211
235
|
function _adjust_session_timeout(sessionTimeout: number) {
|
|
212
236
|
let revisedSessionTimeout = sessionTimeout || defaultSessionTimeout;
|
|
213
237
|
revisedSessionTimeout = Math.min(revisedSessionTimeout, maxSessionTimeout);
|
|
@@ -217,7 +241,7 @@ function _adjust_session_timeout(sessionTimeout: number) {
|
|
|
217
241
|
|
|
218
242
|
function channel_has_session(channel: ServerSecureChannelLayer, session: ServerSession): boolean {
|
|
219
243
|
if (session.channel === channel) {
|
|
220
|
-
assert(
|
|
244
|
+
assert(Object.prototype.hasOwnProperty.call(channel.sessionTokens, session.authenticationToken.toString()));
|
|
221
245
|
return true;
|
|
222
246
|
}
|
|
223
247
|
return false;
|
|
@@ -292,10 +316,7 @@ function _serverEndpointsForCreateSessionResponse(server: OPCUAServer, endpointU
|
|
|
292
316
|
.map(getRequiredEndpointInfo);
|
|
293
317
|
}
|
|
294
318
|
|
|
295
|
-
function adjustSecurityPolicy(
|
|
296
|
-
channel: ServerSecureChannelLayer,
|
|
297
|
-
userTokenPolicy_securityPolicyUri: SecurityPolicy
|
|
298
|
-
): SecurityPolicy {
|
|
319
|
+
function adjustSecurityPolicy(channel: ServerSecureChannelLayer, userTokenPolicy_securityPolicyUri: UAString): SecurityPolicy {
|
|
299
320
|
// check that userIdentityToken
|
|
300
321
|
let securityPolicy = fromURI(userTokenPolicy_securityPolicyUri);
|
|
301
322
|
|
|
@@ -489,8 +510,7 @@ function build_scanning_node_function(
|
|
|
489
510
|
oldDataValue: DataValue,
|
|
490
511
|
callback: (err: Error | null, dataValue?: DataValue) => void
|
|
491
512
|
) {
|
|
492
|
-
|
|
493
|
-
assert(self instanceof MonitoredItem);
|
|
513
|
+
assert(this instanceof MonitoredItem);
|
|
494
514
|
assert(oldDataValue instanceof DataValue);
|
|
495
515
|
assert(typeof callback === "function");
|
|
496
516
|
const newDataValue = node.readAttribute(null, itemToMonitor.attributeId);
|
|
@@ -580,6 +600,83 @@ function _installRegisterServerManager(self: OPCUAServer) {
|
|
|
580
600
|
});
|
|
581
601
|
}
|
|
582
602
|
|
|
603
|
+
function validate_applicationUri(channel: ServerSecureChannelLayer, request: CreateSessionRequest): boolean {
|
|
604
|
+
const applicationUri = request.clientDescription.applicationUri!;
|
|
605
|
+
const clientCertificate = request.clientCertificate;
|
|
606
|
+
// if session is insecure there is no need to check certificate information
|
|
607
|
+
if (channel.securityMode === MessageSecurityMode.None) {
|
|
608
|
+
return true; // assume correct
|
|
609
|
+
}
|
|
610
|
+
if (!clientCertificate || clientCertificate.length === 0) {
|
|
611
|
+
return true; // can't check
|
|
612
|
+
}
|
|
613
|
+
const e = exploreCertificate(clientCertificate);
|
|
614
|
+
const applicationUriFromCert = e.tbsCertificate.extensions!.subjectAltName.uniformResourceIdentifier[0];
|
|
615
|
+
|
|
616
|
+
/* istanbul ignore next */
|
|
617
|
+
if (applicationUriFromCert !== applicationUri) {
|
|
618
|
+
errorLog("BadCertificateUriInvalid!");
|
|
619
|
+
errorLog("applicationUri = ", applicationUri);
|
|
620
|
+
errorLog("applicationUriFromCert = ", applicationUriFromCert);
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
return applicationUriFromCert === applicationUri;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
function validate_security_endpoint(
|
|
627
|
+
server: OPCUAServer,
|
|
628
|
+
request: CreateSessionRequest,
|
|
629
|
+
channel: ServerSecureChannelLayer
|
|
630
|
+
): {
|
|
631
|
+
errCode: StatusCode;
|
|
632
|
+
endpoint?: EndpointDescription;
|
|
633
|
+
} {
|
|
634
|
+
debugLog("validate_security_endpoint = ", request.endpointUrl);
|
|
635
|
+
let endpoints = server._get_endpoints(request.endpointUrl);
|
|
636
|
+
// endpointUrl String The network address that the Client used to access the Session Endpoint.
|
|
637
|
+
// The HostName portion of the URL should be one of the HostNames for the application that are
|
|
638
|
+
// specified in the Server’s ApplicationInstanceCertificate (see 7.2). The Server shall raise an
|
|
639
|
+
// AuditUrlMismatchEventType event if the URL does not match the Server’s HostNames.
|
|
640
|
+
// AuditUrlMismatchEventType event type is defined in Part 5.
|
|
641
|
+
// The Server uses this information for diagnostics and to determine the set of
|
|
642
|
+
// EndpointDescriptions to return in the response.
|
|
643
|
+
// ToDo: check endpointUrl validity and emit an AuditUrlMismatchEventType event if not
|
|
644
|
+
if (endpoints.length === 0) {
|
|
645
|
+
// we have a UrlMismatch here
|
|
646
|
+
const ua_server = server.engine.addressSpace!.rootFolder.objects.server;
|
|
647
|
+
ua_server.raiseEvent("AuditUrlMismatchEventType", {
|
|
648
|
+
endpointUrl: { dataType: DataType.String, value: request.endpointUrl }
|
|
649
|
+
});
|
|
650
|
+
debugLog("Cannot find endpoint in available endpoints with endpointUri", request.endpointUrl);
|
|
651
|
+
if (OPCUAServer.requestExactEndpointUrl) {
|
|
652
|
+
return { errCode: StatusCodes.BadServiceUnsupported };
|
|
653
|
+
} else {
|
|
654
|
+
endpoints = server._get_endpoints(null);
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
// ignore restricted endpoints
|
|
658
|
+
endpoints = endpoints.filter((e: EndpointDescription) => !(e as any).restricted);
|
|
659
|
+
|
|
660
|
+
const endpoints_matching_security_mode = endpoints.filter((e: EndpointDescription) => {
|
|
661
|
+
return e.securityMode === channel.securityMode;
|
|
662
|
+
});
|
|
663
|
+
|
|
664
|
+
if (endpoints_matching_security_mode.length === 0) {
|
|
665
|
+
return { errCode: StatusCodes.BadSecurityModeRejected };
|
|
666
|
+
}
|
|
667
|
+
const endpoints_matching_security_policy = endpoints_matching_security_mode.filter((e: EndpointDescription) => {
|
|
668
|
+
return e.securityPolicyUri === channel.securityHeader!.securityPolicyUri;
|
|
669
|
+
});
|
|
670
|
+
|
|
671
|
+
if (endpoints_matching_security_policy.length === 0) {
|
|
672
|
+
return { errCode: StatusCodes.BadSecurityPolicyRejected };
|
|
673
|
+
}
|
|
674
|
+
if (endpoints_matching_security_policy.length !== 1) {
|
|
675
|
+
debugLog("endpoints_matching_security_policy= ", endpoints_matching_security_policy.length);
|
|
676
|
+
}
|
|
677
|
+
return { errCode: StatusCodes.Good, endpoint: endpoints_matching_security_policy[0] };
|
|
678
|
+
}
|
|
679
|
+
|
|
583
680
|
export enum RegisterServerMethod {
|
|
584
681
|
HIDDEN = 1, // the server doesn't expose itself to the external world
|
|
585
682
|
MDNS = 2, // the server publish itself to the mDNS Multicast network directly
|
|
@@ -797,12 +894,12 @@ export interface OPCUAServer {
|
|
|
797
894
|
userCertificateManager: OPCUACertificateManager;
|
|
798
895
|
}
|
|
799
896
|
|
|
800
|
-
const g_requestExactEndpointUrl
|
|
897
|
+
const g_requestExactEndpointUrl = !!process.env.NODEOPCUA_SERVER_REQUEST_EXACT_ENDPOINT_URL;
|
|
801
898
|
/**
|
|
802
899
|
*
|
|
803
900
|
*/
|
|
804
901
|
export class OPCUAServer extends OPCUABaseServer {
|
|
805
|
-
static defaultShutdownTimeout
|
|
902
|
+
static defaultShutdownTimeout = 100; // 250 ms
|
|
806
903
|
/**
|
|
807
904
|
* if requestExactEndpointUrl is set to true the server will only accept createSession that have a endpointUrl that strictly matches
|
|
808
905
|
* one of the provided endpoint.
|
|
@@ -851,8 +948,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
851
948
|
*/
|
|
852
949
|
public get currentChannelCount(): number {
|
|
853
950
|
// TODO : move to base
|
|
854
|
-
|
|
855
|
-
return self.endpoints.reduce((currentValue: number, endPoint: OPCUAServerEndPoint) => {
|
|
951
|
+
return this.endpoints.reduce((currentValue: number, endPoint: OPCUAServerEndPoint) => {
|
|
856
952
|
return currentValue + endPoint.currentChannelCount;
|
|
857
953
|
}, 0);
|
|
858
954
|
}
|
|
@@ -932,7 +1028,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
932
1028
|
/**
|
|
933
1029
|
* false if anonymous connection are not allowed
|
|
934
1030
|
*/
|
|
935
|
-
public allowAnonymous
|
|
1031
|
+
public allowAnonymous = false;
|
|
936
1032
|
|
|
937
1033
|
/**
|
|
938
1034
|
* the user manager
|
|
@@ -947,6 +1043,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
947
1043
|
constructor(options?: OPCUAServerOptions) {
|
|
948
1044
|
super(options);
|
|
949
1045
|
|
|
1046
|
+
this.allowAnonymous = false;
|
|
950
1047
|
options = options || {};
|
|
951
1048
|
|
|
952
1049
|
this.options = options;
|
|
@@ -1208,7 +1305,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
1208
1305
|
});
|
|
1209
1306
|
}
|
|
1210
1307
|
|
|
1211
|
-
public dispose() {
|
|
1308
|
+
public dispose(): void {
|
|
1212
1309
|
for (const endpoint of this.endpoints) {
|
|
1213
1310
|
endpoint.dispose();
|
|
1214
1311
|
}
|
|
@@ -1228,7 +1325,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
1228
1325
|
}
|
|
1229
1326
|
}
|
|
1230
1327
|
|
|
1231
|
-
public raiseEvent(eventType:
|
|
1328
|
+
public raiseEvent(eventType: EventTypeLike | UAObjectType, options: RaiseEventData): void {
|
|
1232
1329
|
/* istanbul ignore next */
|
|
1233
1330
|
if (!this.engine.addressSpace) {
|
|
1234
1331
|
errorLog("addressSpace missing");
|
|
@@ -1243,16 +1340,16 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
1243
1340
|
return;
|
|
1244
1341
|
}
|
|
1245
1342
|
|
|
1246
|
-
let eventTypeNode = eventType;
|
|
1343
|
+
let eventTypeNode: EventTypeLike | UAObjectType | null = eventType;
|
|
1247
1344
|
if (typeof eventType === "string") {
|
|
1248
1345
|
eventTypeNode = this.engine.addressSpace.findEventType(eventType);
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1346
|
+
if (eventTypeNode) {
|
|
1347
|
+
return server.raiseEvent(eventTypeNode, options);
|
|
1348
|
+
} else {
|
|
1349
|
+
console.warn(" cannot find event type ", eventType);
|
|
1350
|
+
}
|
|
1254
1351
|
} else {
|
|
1255
|
-
|
|
1352
|
+
return server.raiseEvent(eventTypeNode, options);
|
|
1256
1353
|
}
|
|
1257
1354
|
}
|
|
1258
1355
|
|
|
@@ -1260,7 +1357,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
1260
1357
|
* create and register a new session
|
|
1261
1358
|
* @internal
|
|
1262
1359
|
*/
|
|
1263
|
-
protected createSession(options:
|
|
1360
|
+
protected createSession(options: CreateSessionOption): ServerSession {
|
|
1264
1361
|
/* istanbul ignore next */
|
|
1265
1362
|
if (!this.engine) {
|
|
1266
1363
|
throw new Error("Internal Error");
|
|
@@ -1315,11 +1412,11 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
1315
1412
|
protected isValidUserNameIdentityToken(
|
|
1316
1413
|
channel: ServerSecureChannelLayer,
|
|
1317
1414
|
session: ServerSession,
|
|
1318
|
-
userTokenPolicy:
|
|
1415
|
+
userTokenPolicy: UserTokenPolicy,
|
|
1319
1416
|
userIdentityToken: UserNameIdentityToken,
|
|
1320
|
-
userTokenSignature:
|
|
1417
|
+
userTokenSignature: SignatureData,
|
|
1321
1418
|
callback: (err: Error | null, statusCode?: StatusCode) => void
|
|
1322
|
-
) {
|
|
1419
|
+
): void {
|
|
1323
1420
|
assert(userIdentityToken instanceof UserNameIdentityToken);
|
|
1324
1421
|
|
|
1325
1422
|
const securityPolicy = adjustSecurityPolicy(channel, userTokenPolicy.securityPolicyUri);
|
|
@@ -1351,11 +1448,11 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
1351
1448
|
protected isValidX509IdentityToken(
|
|
1352
1449
|
channel: ServerSecureChannelLayer,
|
|
1353
1450
|
session: ServerSession,
|
|
1354
|
-
userTokenPolicy:
|
|
1451
|
+
userTokenPolicy: UserTokenPolicy,
|
|
1355
1452
|
userIdentityToken: X509IdentityToken,
|
|
1356
|
-
userTokenSignature:
|
|
1453
|
+
userTokenSignature: SignatureData,
|
|
1357
1454
|
callback: (err: Error | null, statusCode?: StatusCode) => void
|
|
1358
|
-
) {
|
|
1455
|
+
): void {
|
|
1359
1456
|
assert(userIdentityToken instanceof X509IdentityToken);
|
|
1360
1457
|
assert(callback instanceof Function);
|
|
1361
1458
|
|
|
@@ -1433,7 +1530,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
1433
1530
|
protected userNameIdentityTokenAuthenticateUser(
|
|
1434
1531
|
channel: ServerSecureChannelLayer,
|
|
1435
1532
|
session: ServerSession,
|
|
1436
|
-
userTokenPolicy:
|
|
1533
|
+
userTokenPolicy: UserTokenPolicy,
|
|
1437
1534
|
userIdentityToken: UserNameIdentityToken,
|
|
1438
1535
|
callback: (err: Error | null, isAuthorized?: boolean) => void
|
|
1439
1536
|
): void {
|
|
@@ -1488,7 +1585,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
1488
1585
|
channel: ServerSecureChannelLayer,
|
|
1489
1586
|
session: ServerSession,
|
|
1490
1587
|
userIdentityToken: UserIdentityToken,
|
|
1491
|
-
userTokenSignature:
|
|
1588
|
+
userTokenSignature: SignatureData,
|
|
1492
1589
|
endpointDescription: EndpointDescription,
|
|
1493
1590
|
callback: (err: Error | null, statusCode?: StatusCode) => void
|
|
1494
1591
|
): void {
|
|
@@ -1544,13 +1641,16 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
1544
1641
|
session: ServerSession,
|
|
1545
1642
|
userIdentityToken: UserIdentityToken,
|
|
1546
1643
|
callback: (err: Error | null, isAuthorized?: boolean) => void
|
|
1547
|
-
) {
|
|
1644
|
+
): void {
|
|
1548
1645
|
assert(userIdentityToken);
|
|
1549
1646
|
assert(typeof callback === "function");
|
|
1550
1647
|
|
|
1551
1648
|
const userTokenType = getTokenType(userIdentityToken);
|
|
1552
1649
|
const userTokenPolicy = findUserTokenByPolicy(session.getEndpointDescription(), userTokenType, userIdentityToken.policyId!);
|
|
1553
|
-
|
|
1650
|
+
/** istanbul ignore next */
|
|
1651
|
+
if (!userTokenPolicy) {
|
|
1652
|
+
return callback(null, false);
|
|
1653
|
+
}
|
|
1554
1654
|
// find if a userToken exists
|
|
1555
1655
|
if (userIdentityToken instanceof UserNameIdentityToken) {
|
|
1556
1656
|
return this.userNameIdentityTokenAuthenticateUser(channel, session, userTokenPolicy, userIdentityToken, callback);
|
|
@@ -1563,12 +1663,12 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
1563
1663
|
}
|
|
1564
1664
|
|
|
1565
1665
|
// session services
|
|
1566
|
-
|
|
1567
|
-
|
|
1666
|
+
// eslint-disable-next-line max-statements
|
|
1667
|
+
protected async _on_CreateSessionRequest(message: Message, channel: ServerSecureChannelLayer): Promise<void> {
|
|
1568
1668
|
const request = message.request as CreateSessionRequest;
|
|
1569
1669
|
assert(request instanceof CreateSessionRequest);
|
|
1570
1670
|
|
|
1571
|
-
function rejectConnection(statusCode: StatusCode): void {
|
|
1671
|
+
function rejectConnection(server: OPCUAServer, statusCode: StatusCode): void {
|
|
1572
1672
|
server.engine.incrementSecurityRejectedSessionCount();
|
|
1573
1673
|
|
|
1574
1674
|
const response1 = new CreateSessionResponse({
|
|
@@ -1582,13 +1682,13 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
1582
1682
|
// A Server application should limit the number of Sessions. To protect against misbehaving Clients and denial
|
|
1583
1683
|
// of service attacks, the Server shall close the oldest Session that is not activated before reaching the
|
|
1584
1684
|
// maximum number of supported Sessions
|
|
1585
|
-
if (
|
|
1586
|
-
await _attempt_to_close_some_old_unactivated_session(
|
|
1685
|
+
if (this.currentSessionCount >= this.maxAllowedSessionNumber) {
|
|
1686
|
+
await _attempt_to_close_some_old_unactivated_session(this);
|
|
1587
1687
|
}
|
|
1588
1688
|
|
|
1589
1689
|
// check if session count hasn't reach the maximum allowed sessions
|
|
1590
|
-
if (
|
|
1591
|
-
return rejectConnection(StatusCodes.BadTooManySessions);
|
|
1690
|
+
if (this.currentSessionCount >= this.maxAllowedSessionNumber) {
|
|
1691
|
+
return rejectConnection(this, StatusCodes.BadTooManySessions);
|
|
1592
1692
|
}
|
|
1593
1693
|
|
|
1594
1694
|
// Release 1.03 OPC Unified Architecture, Part 4 page 24 - CreateSession Parameters
|
|
@@ -1626,7 +1726,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
1626
1726
|
request.clientNonce && request.clientNonce.toString("hex")
|
|
1627
1727
|
);
|
|
1628
1728
|
|
|
1629
|
-
return rejectConnection(StatusCodes.BadNonceInvalid);
|
|
1729
|
+
return rejectConnection(this, StatusCodes.BadNonceInvalid);
|
|
1630
1730
|
}
|
|
1631
1731
|
}
|
|
1632
1732
|
if (nonceAlreadyBeenUsed(request.clientNonce)) {
|
|
@@ -1635,93 +1735,21 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
1635
1735
|
request.clientNonce && request.clientNonce.toString("hex")
|
|
1636
1736
|
);
|
|
1637
1737
|
|
|
1638
|
-
return rejectConnection(StatusCodes.BadNonceInvalid);
|
|
1738
|
+
return rejectConnection(this, StatusCodes.BadNonceInvalid);
|
|
1639
1739
|
}
|
|
1640
|
-
|
|
1641
|
-
function validate_applicationUri(applicationUri: string, clientCertificate: Certificate): boolean {
|
|
1642
|
-
// if session is insecure there is no need to check certificate information
|
|
1643
|
-
if (channel.securityMode === MessageSecurityMode.None) {
|
|
1644
|
-
return true; // assume correct
|
|
1645
|
-
}
|
|
1646
|
-
if (!clientCertificate || clientCertificate.length === 0) {
|
|
1647
|
-
return true; // can't check
|
|
1648
|
-
}
|
|
1649
|
-
const e = exploreCertificate(clientCertificate);
|
|
1650
|
-
const applicationUriFromCert = e.tbsCertificate.extensions!.subjectAltName.uniformResourceIdentifier[0];
|
|
1651
|
-
|
|
1652
|
-
/* istanbul ignore next */
|
|
1653
|
-
if (applicationUriFromCert !== applicationUri) {
|
|
1654
|
-
errorLog("BadCertificateUriInvalid!");
|
|
1655
|
-
errorLog("applicationUri = ", applicationUri);
|
|
1656
|
-
errorLog("applicationUriFromCert = ", applicationUriFromCert);
|
|
1657
|
-
}
|
|
1658
|
-
|
|
1659
|
-
return applicationUriFromCert === applicationUri;
|
|
1660
|
-
}
|
|
1661
|
-
|
|
1662
1740
|
// check application spoofing
|
|
1663
1741
|
// check if applicationUri in createSessionRequest matches applicationUri in client Certificate
|
|
1664
|
-
if (!validate_applicationUri(
|
|
1665
|
-
return rejectConnection(StatusCodes.BadCertificateUriInvalid);
|
|
1666
|
-
}
|
|
1667
|
-
|
|
1668
|
-
function validate_security_endpoint(channel1: ServerSecureChannelLayer): {
|
|
1669
|
-
errCode: StatusCode;
|
|
1670
|
-
endpoint?: EndpointDescription;
|
|
1671
|
-
} {
|
|
1672
|
-
debugLog("validate_security_endpoint = ", request.endpointUrl);
|
|
1673
|
-
let endpoints = server._get_endpoints(request.endpointUrl);
|
|
1674
|
-
// endpointUrl String The network address that the Client used to access the Session Endpoint.
|
|
1675
|
-
// The HostName portion of the URL should be one of the HostNames for the application that are
|
|
1676
|
-
// specified in the Server’s ApplicationInstanceCertificate (see 7.2). The Server shall raise an
|
|
1677
|
-
// AuditUrlMismatchEventType event if the URL does not match the Server’s HostNames.
|
|
1678
|
-
// AuditUrlMismatchEventType event type is defined in Part 5.
|
|
1679
|
-
// The Server uses this information for diagnostics and to determine the set of
|
|
1680
|
-
// EndpointDescriptions to return in the response.
|
|
1681
|
-
// ToDo: check endpointUrl validity and emit an AuditUrlMismatchEventType event if not
|
|
1682
|
-
if (endpoints.length === 0) {
|
|
1683
|
-
// we have a UrlMismatch here
|
|
1684
|
-
const ua_server = server.engine.addressSpace!.rootFolder.objects.server;
|
|
1685
|
-
ua_server.raiseEvent("AuditUrlMismatchEventType", {
|
|
1686
|
-
endpointUrl: { dataType: DataType.String, value: request.endpointUrl }
|
|
1687
|
-
});
|
|
1688
|
-
debugLog("Cannot find endpoint in available endpoints with endpointUri", request.endpointUrl);
|
|
1689
|
-
if (OPCUAServer.requestExactEndpointUrl) {
|
|
1690
|
-
return { errCode: StatusCodes.BadServiceUnsupported };
|
|
1691
|
-
} else {
|
|
1692
|
-
endpoints = server._get_endpoints(null);
|
|
1693
|
-
}
|
|
1694
|
-
}
|
|
1695
|
-
// ignore restricted endpoints
|
|
1696
|
-
endpoints = endpoints.filter((e: EndpointDescription) => !(e as any).restricted);
|
|
1697
|
-
|
|
1698
|
-
const endpoints_matching_security_mode = endpoints.filter((e: EndpointDescription) => {
|
|
1699
|
-
return e.securityMode === channel1.securityMode;
|
|
1700
|
-
});
|
|
1701
|
-
|
|
1702
|
-
if (endpoints_matching_security_mode.length === 0) {
|
|
1703
|
-
return { errCode: StatusCodes.BadSecurityModeRejected };
|
|
1704
|
-
}
|
|
1705
|
-
const endpoints_matching_security_policy = endpoints_matching_security_mode.filter((e: EndpointDescription) => {
|
|
1706
|
-
return e.securityPolicyUri === channel1.securityHeader!.securityPolicyUri;
|
|
1707
|
-
});
|
|
1708
|
-
|
|
1709
|
-
if (endpoints_matching_security_policy.length === 0) {
|
|
1710
|
-
return { errCode: StatusCodes.BadSecurityPolicyRejected };
|
|
1711
|
-
}
|
|
1712
|
-
if (endpoints_matching_security_policy.length !== 1) {
|
|
1713
|
-
debugLog("endpoints_matching_security_policy= ", endpoints_matching_security_policy.length);
|
|
1714
|
-
}
|
|
1715
|
-
return { errCode: StatusCodes.Good, endpoint: endpoints_matching_security_policy[0] };
|
|
1742
|
+
if (!validate_applicationUri(channel, request)) {
|
|
1743
|
+
return rejectConnection(this, StatusCodes.BadCertificateUriInvalid);
|
|
1716
1744
|
}
|
|
1717
1745
|
|
|
1718
|
-
const { errCode, endpoint } = validate_security_endpoint(channel);
|
|
1746
|
+
const { errCode, endpoint } = validate_security_endpoint(this, request, channel);
|
|
1719
1747
|
if (errCode !== StatusCodes.Good) {
|
|
1720
|
-
return rejectConnection(errCode);
|
|
1748
|
+
return rejectConnection(this, errCode);
|
|
1721
1749
|
}
|
|
1722
1750
|
|
|
1723
1751
|
// see Release 1.02 27 OPC Unified Architecture, Part 4
|
|
1724
|
-
const session =
|
|
1752
|
+
const session = this.createSession({
|
|
1725
1753
|
clientDescription: request.clientDescription,
|
|
1726
1754
|
sessionTimeout: revisedSessionTimeout
|
|
1727
1755
|
});
|
|
@@ -1747,12 +1775,12 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
1747
1775
|
//
|
|
1748
1776
|
// ( this serverNonce will only be used up to the _on_ActivateSessionRequest
|
|
1749
1777
|
// where a new nonce will be created)
|
|
1750
|
-
session.nonce =
|
|
1778
|
+
session.nonce = this.makeServerNonce();
|
|
1751
1779
|
session.channelId = channel.channelId;
|
|
1752
1780
|
|
|
1753
1781
|
session._attach_channel(channel);
|
|
1754
1782
|
|
|
1755
|
-
const serverCertificateChain =
|
|
1783
|
+
const serverCertificateChain = this.getCertificateChain();
|
|
1756
1784
|
|
|
1757
1785
|
const hasEncryption = true;
|
|
1758
1786
|
// If the securityPolicyUri is None and none of the UserTokenPolicies requires encryption
|
|
@@ -1793,7 +1821,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
1793
1821
|
// securityPolicyUri, userIdentityTokens, transportProfileUri and securityLevel with all
|
|
1794
1822
|
// other parameters set to null. Only the recommended parameters shall be verified by
|
|
1795
1823
|
// the client.
|
|
1796
|
-
serverEndpoints: _serverEndpointsForCreateSessionResponse(
|
|
1824
|
+
serverEndpoints: _serverEndpointsForCreateSessionResponse(this, session.endpoint!.endpointUrl, request.serverUri),
|
|
1797
1825
|
|
|
1798
1826
|
// This parameter is deprecated and the array shall be empty.
|
|
1799
1827
|
serverSoftwareCertificates: null,
|
|
@@ -1804,7 +1832,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
1804
1832
|
// The SignatureAlgorithm shall be the AsymmetricSignatureAlgorithm specified in the
|
|
1805
1833
|
// SecurityPolicy for the Endpoint.
|
|
1806
1834
|
// The SignatureData type is defined in 7.30.
|
|
1807
|
-
serverSignature:
|
|
1835
|
+
serverSignature: this.computeServerSignature(channel, request.clientCertificate, request.clientNonce),
|
|
1808
1836
|
|
|
1809
1837
|
// The maximum message size accepted by the server
|
|
1810
1838
|
// The Client Communication Stack should return a Bad_RequestTooLarge error to the
|
|
@@ -1813,15 +1841,15 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
1813
1841
|
maxRequestMessageSize: 0x4000000
|
|
1814
1842
|
});
|
|
1815
1843
|
|
|
1816
|
-
|
|
1844
|
+
this.emit("create_session", session);
|
|
1817
1845
|
|
|
1818
1846
|
session.on("session_closed", (session1: ServerSession, deleteSubscriptions: boolean, reason: string) => {
|
|
1819
1847
|
assert(typeof reason === "string");
|
|
1820
|
-
if (
|
|
1848
|
+
if (this.isAuditing) {
|
|
1821
1849
|
assert(reason === "Timeout" || reason === "Terminated" || reason === "CloseSession" || reason === "Forcing");
|
|
1822
1850
|
const sourceName = "Session/" + reason;
|
|
1823
1851
|
|
|
1824
|
-
|
|
1852
|
+
this.raiseEvent("AuditSessionEventType", {
|
|
1825
1853
|
/* part 5 - 6.4.3 AuditEventType */
|
|
1826
1854
|
actionTimeStamp: { dataType: "DateTime", value: new Date() },
|
|
1827
1855
|
status: { dataType: "Boolean", value: true },
|
|
@@ -1842,12 +1870,12 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
1842
1870
|
});
|
|
1843
1871
|
}
|
|
1844
1872
|
|
|
1845
|
-
|
|
1873
|
+
this.emit("session_closed", session1, deleteSubscriptions);
|
|
1846
1874
|
});
|
|
1847
1875
|
|
|
1848
|
-
if (
|
|
1876
|
+
if (this.isAuditing) {
|
|
1849
1877
|
// ------------------------------------------------------------------------------------------------------
|
|
1850
|
-
|
|
1878
|
+
this.raiseEvent("AuditCreateSessionEventType", {
|
|
1851
1879
|
/* part 5 - 6.4.3 AuditEventType */
|
|
1852
1880
|
actionTimeStamp: { dataType: "DateTime", value: new Date() },
|
|
1853
1881
|
status: { dataType: "Boolean", value: true },
|
|
@@ -1881,7 +1909,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
1881
1909
|
|
|
1882
1910
|
// clientCertificateThumbprint
|
|
1883
1911
|
clientCertificateThumbprint: {
|
|
1884
|
-
dataType: "
|
|
1912
|
+
dataType: "String",
|
|
1885
1913
|
value: thumbprint(session.channel!.clientCertificate!)
|
|
1886
1914
|
}
|
|
1887
1915
|
});
|
|
@@ -1909,17 +1937,16 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
1909
1937
|
*
|
|
1910
1938
|
*
|
|
1911
1939
|
*/
|
|
1912
|
-
protected _on_ActivateSessionRequest(message: Message, channel: ServerSecureChannelLayer) {
|
|
1913
|
-
const server = this;
|
|
1940
|
+
protected _on_ActivateSessionRequest(message: Message, channel: ServerSecureChannelLayer): void {
|
|
1914
1941
|
const request = message.request as ActivateSessionRequest;
|
|
1915
1942
|
assert(request instanceof ActivateSessionRequest);
|
|
1916
1943
|
|
|
1917
1944
|
// get session from authenticationToken
|
|
1918
1945
|
const authenticationToken = request.requestHeader.authenticationToken;
|
|
1919
1946
|
|
|
1920
|
-
const session =
|
|
1947
|
+
const session = this.getSession(authenticationToken);
|
|
1921
1948
|
|
|
1922
|
-
function rejectConnection(statusCode: StatusCode): void {
|
|
1949
|
+
function rejectConnection(server: OPCUAServer, statusCode: StatusCode): void {
|
|
1923
1950
|
if (statusCode === StatusCodes.BadSessionIdInvalid) {
|
|
1924
1951
|
server.engine.incrementRejectedSessionCount();
|
|
1925
1952
|
} else {
|
|
@@ -1941,7 +1968,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
1941
1968
|
// that the previous session may still be active
|
|
1942
1969
|
debugLog(chalk.yellow.bold(" Bad Session in _on_ActivateSessionRequest"), authenticationToken.toString());
|
|
1943
1970
|
|
|
1944
|
-
return rejectConnection(StatusCodes.BadSessionIdInvalid);
|
|
1971
|
+
return rejectConnection(this, StatusCodes.BadSessionIdInvalid);
|
|
1945
1972
|
}
|
|
1946
1973
|
|
|
1947
1974
|
// tslint:disable-next-line: no-unused-expression
|
|
@@ -1956,7 +1983,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
1956
1983
|
// it looks like session activation is being using a channel that is not the
|
|
1957
1984
|
// one that have been used to create the session
|
|
1958
1985
|
errorLog(" channel.sessionTokens === " + Object.keys(channel.sessionTokens).join(" "));
|
|
1959
|
-
return rejectConnection(StatusCodes.BadSessionNotActivated);
|
|
1986
|
+
return rejectConnection(this, StatusCodes.BadSessionNotActivated);
|
|
1960
1987
|
}
|
|
1961
1988
|
}
|
|
1962
1989
|
|
|
@@ -1983,35 +2010,35 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
1983
2010
|
const new_channel_cert_thumbprint = thumbprint(channel.clientCertificate!);
|
|
1984
2011
|
|
|
1985
2012
|
if (old_channel_cert_thumbprint !== new_channel_cert_thumbprint) {
|
|
1986
|
-
return rejectConnection(StatusCodes.BadNoValidCertificates); // not sure about this code !
|
|
2013
|
+
return rejectConnection(this, StatusCodes.BadNoValidCertificates); // not sure about this code !
|
|
1987
2014
|
}
|
|
1988
2015
|
|
|
1989
2016
|
// ... In addition the Server shall verify that the Client supplied a UserIdentityToken that is
|
|
1990
2017
|
// identical to the token currently associated with the Session reassign session to new channel.
|
|
1991
2018
|
if (!sameIdentityToken(session.userIdentityToken!, request.userIdentityToken as UserIdentityToken)) {
|
|
1992
|
-
return rejectConnection(StatusCodes.BadIdentityChangeNotSupported); // not sure about this code !
|
|
2019
|
+
return rejectConnection(this, StatusCodes.BadIdentityChangeNotSupported); // not sure about this code !
|
|
1993
2020
|
}
|
|
1994
2021
|
}
|
|
1995
2022
|
|
|
1996
2023
|
moveSessionToChannel(session, channel);
|
|
1997
2024
|
} else if (session.status === "screwed") {
|
|
1998
2025
|
// session has been used before being activated => this should be detected and session should be dismissed.
|
|
1999
|
-
return rejectConnection(StatusCodes.BadSessionClosed);
|
|
2026
|
+
return rejectConnection(this, StatusCodes.BadSessionClosed);
|
|
2000
2027
|
} else if (session.status === "closed") {
|
|
2001
2028
|
warningLog(chalk.yellow.bold(" Bad Session Closed in _on_ActivateSessionRequest"), authenticationToken.toString());
|
|
2002
|
-
return rejectConnection(StatusCodes.BadSessionClosed);
|
|
2029
|
+
return rejectConnection(this, StatusCodes.BadSessionClosed);
|
|
2003
2030
|
}
|
|
2004
2031
|
|
|
2005
2032
|
// verify clientSignature provided by the client
|
|
2006
|
-
if (!
|
|
2007
|
-
return rejectConnection(StatusCodes.BadApplicationSignatureInvalid);
|
|
2033
|
+
if (!this.verifyClientSignature(session, channel, request.clientSignature)) {
|
|
2034
|
+
return rejectConnection(this, StatusCodes.BadApplicationSignatureInvalid);
|
|
2008
2035
|
}
|
|
2009
2036
|
|
|
2010
2037
|
// userIdentityToken may be missing , assume anonymous access then
|
|
2011
2038
|
request.userIdentityToken = request.userIdentityToken || createAnonymousIdentityToken(session.endpoint!);
|
|
2012
2039
|
|
|
2013
2040
|
// check request.userIdentityToken is correct ( expected type and correctly formed)
|
|
2014
|
-
|
|
2041
|
+
this.isValidUserIdentityToken(
|
|
2015
2042
|
channel,
|
|
2016
2043
|
session,
|
|
2017
2044
|
request.userIdentityToken as UserIdentityToken,
|
|
@@ -2024,28 +2051,28 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
2024
2051
|
const a = 23;
|
|
2025
2052
|
}
|
|
2026
2053
|
assert(statusCode && statusCode instanceof StatusCode, "expecting statusCode");
|
|
2027
|
-
return rejectConnection(statusCode!);
|
|
2054
|
+
return rejectConnection(this, statusCode!);
|
|
2028
2055
|
}
|
|
2029
2056
|
session.userIdentityToken = request.userIdentityToken as UserIdentityToken;
|
|
2030
2057
|
|
|
2031
2058
|
// check if user access is granted
|
|
2032
|
-
|
|
2059
|
+
this.isUserAuthorized(
|
|
2033
2060
|
channel,
|
|
2034
2061
|
session,
|
|
2035
2062
|
request.userIdentityToken as UserIdentityToken,
|
|
2036
2063
|
(err1: Error | null, authorized?: boolean) => {
|
|
2037
2064
|
/* istanbul ignore next */
|
|
2038
2065
|
if (err1) {
|
|
2039
|
-
return rejectConnection(StatusCodes.BadInternalError);
|
|
2066
|
+
return rejectConnection(this, StatusCodes.BadInternalError);
|
|
2040
2067
|
}
|
|
2041
2068
|
|
|
2042
2069
|
if (!authorized) {
|
|
2043
|
-
return rejectConnection(StatusCodes.BadUserAccessDenied);
|
|
2070
|
+
return rejectConnection(this, StatusCodes.BadUserAccessDenied);
|
|
2044
2071
|
} else {
|
|
2045
2072
|
// extract : OPC UA part 4 - 5.6.3
|
|
2046
2073
|
// Once used, a serverNonce cannot be used again. For that reason, the Server returns a new
|
|
2047
2074
|
// serverNonce each time the ActivateSession Service is called.
|
|
2048
|
-
session.nonce =
|
|
2075
|
+
session.nonce = this.makeServerNonce();
|
|
2049
2076
|
|
|
2050
2077
|
session.status = "active";
|
|
2051
2078
|
|
|
@@ -2067,8 +2094,8 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
2067
2094
|
// xx assert(session.channel.clientCertificate instanceof Buffer);
|
|
2068
2095
|
assert(session.sessionTimeout > 0);
|
|
2069
2096
|
|
|
2070
|
-
if (
|
|
2071
|
-
|
|
2097
|
+
if (this.isAuditing) {
|
|
2098
|
+
this.raiseEvent("AuditActivateSessionEventType", {
|
|
2072
2099
|
/* part 5 - 6.4.3 AuditEventType */
|
|
2073
2100
|
actionTimeStamp: { dataType: "DateTime", value: new Date() },
|
|
2074
2101
|
status: { dataType: "Boolean", value: true },
|
|
@@ -2109,7 +2136,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
2109
2136
|
secureChannelId: { dataType: "String", value: session.channel!.channelId!.toString() }
|
|
2110
2137
|
});
|
|
2111
2138
|
}
|
|
2112
|
-
|
|
2139
|
+
this.emit("session_activated", session, userIdentityTokenPasswordRemoved);
|
|
2113
2140
|
}
|
|
2114
2141
|
}
|
|
2115
2142
|
);
|
|
@@ -2117,13 +2144,12 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
2117
2144
|
);
|
|
2118
2145
|
}
|
|
2119
2146
|
|
|
2120
|
-
protected prepare(message: Message, channel: ServerSecureChannelLayer) {
|
|
2121
|
-
const server = this;
|
|
2147
|
+
protected prepare(message: Message, channel: ServerSecureChannelLayer): void {
|
|
2122
2148
|
const request = message.request;
|
|
2123
2149
|
|
|
2124
2150
|
// --- check that session is correct
|
|
2125
2151
|
const authenticationToken = request.requestHeader.authenticationToken;
|
|
2126
|
-
const session =
|
|
2152
|
+
const session = this.getSession(authenticationToken, /*activeOnly*/ true);
|
|
2127
2153
|
if (!session) {
|
|
2128
2154
|
message.session_statusCode = StatusCodes.BadSessionIdInvalid;
|
|
2129
2155
|
return;
|
|
@@ -2150,27 +2176,27 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
2150
2176
|
* @param ResponseClass the constructor of the response Class
|
|
2151
2177
|
* @param message
|
|
2152
2178
|
* @param channel
|
|
2153
|
-
* @param
|
|
2154
|
-
* @param
|
|
2155
|
-
* @param
|
|
2156
|
-
* @param
|
|
2157
|
-
* @param
|
|
2158
|
-
* @param
|
|
2159
|
-
* @param
|
|
2179
|
+
* @param actionToPerform
|
|
2180
|
+
* @param actionToPerform.session {ServerSession}
|
|
2181
|
+
* @param actionToPerform.sendResponse
|
|
2182
|
+
* @param actionToPerform.sendResponse.response
|
|
2183
|
+
* @param actionToPerform.sendError
|
|
2184
|
+
* @param actionToPerform.sendError.statusCode
|
|
2185
|
+
* @param actionToPerform.sendError.diagnostics
|
|
2160
2186
|
*
|
|
2161
2187
|
* @private
|
|
2162
2188
|
*/
|
|
2163
2189
|
protected async _apply_on_SessionObject(
|
|
2164
|
-
ResponseClass:
|
|
2190
|
+
ResponseClass: ResponseClassType,
|
|
2165
2191
|
message: Message,
|
|
2166
2192
|
channel: ServerSecureChannelLayer,
|
|
2167
|
-
|
|
2193
|
+
actionToPerform: (
|
|
2168
2194
|
session: ServerSession,
|
|
2169
2195
|
sendResponse: (response: Response) => void,
|
|
2170
2196
|
sendError: (statusCode: StatusCode) => void
|
|
2171
2197
|
) => void | Promise<void>
|
|
2172
|
-
) {
|
|
2173
|
-
assert(typeof
|
|
2198
|
+
): Promise<void> {
|
|
2199
|
+
assert(typeof actionToPerform === "function");
|
|
2174
2200
|
|
|
2175
2201
|
function sendResponse(response1: Response) {
|
|
2176
2202
|
try {
|
|
@@ -2247,31 +2273,23 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
2247
2273
|
message.session.keepAlive();
|
|
2248
2274
|
}
|
|
2249
2275
|
message.session.incrementTotalRequestCount();
|
|
2250
|
-
await
|
|
2276
|
+
await actionToPerform(message.session as ServerSession, sendResponse, sendError);
|
|
2251
2277
|
}
|
|
2252
2278
|
|
|
2253
|
-
/**
|
|
2254
|
-
* @method _apply_on_Subscription
|
|
2255
|
-
* @param ResponseClass
|
|
2256
|
-
* @param message
|
|
2257
|
-
* @param channel
|
|
2258
|
-
* @param action_to_perform
|
|
2259
|
-
* @private
|
|
2260
|
-
*/
|
|
2261
2279
|
protected async _apply_on_Subscription(
|
|
2262
|
-
ResponseClass:
|
|
2280
|
+
ResponseClass: ResponseClassType,
|
|
2263
2281
|
message: Message,
|
|
2264
2282
|
channel: ServerSecureChannelLayer,
|
|
2265
|
-
|
|
2283
|
+
actionToPerform: (
|
|
2266
2284
|
session: ServerSession,
|
|
2267
2285
|
subscription: Subscription,
|
|
2268
2286
|
sendResponse: (response: Response) => void,
|
|
2269
2287
|
sendError: (statusCode: StatusCode) => void
|
|
2270
2288
|
) => Promise<void>
|
|
2271
|
-
) {
|
|
2272
|
-
assert(typeof
|
|
2289
|
+
): Promise<void> {
|
|
2290
|
+
assert(typeof actionToPerform === "function");
|
|
2273
2291
|
const request = message.request as unknown as { subscriptionId: number };
|
|
2274
|
-
assert(
|
|
2292
|
+
assert(Object.prototype.hasOwnProperty.call(request, "subscriptionId"));
|
|
2275
2293
|
|
|
2276
2294
|
this._apply_on_SessionObject(
|
|
2277
2295
|
ResponseClass,
|
|
@@ -2287,28 +2305,20 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
2287
2305
|
return sendError(StatusCodes.BadSubscriptionIdInvalid);
|
|
2288
2306
|
}
|
|
2289
2307
|
subscription.resetLifeTimeAndKeepAliveCounters();
|
|
2290
|
-
await
|
|
2308
|
+
await actionToPerform(session, subscription, sendResponse, sendError);
|
|
2291
2309
|
}
|
|
2292
2310
|
);
|
|
2293
2311
|
}
|
|
2294
2312
|
|
|
2295
|
-
/**
|
|
2296
|
-
* @method _apply_on_SubscriptionIds
|
|
2297
|
-
* @param ResponseClass
|
|
2298
|
-
* @param message
|
|
2299
|
-
* @param channel
|
|
2300
|
-
* @param action_to_perform
|
|
2301
|
-
* @private
|
|
2302
|
-
*/
|
|
2303
2313
|
protected _apply_on_SubscriptionIds<T>(
|
|
2304
2314
|
ResponseClass: typeof SetPublishingModeResponse | typeof TransferSubscriptionsResponse | typeof DeleteSubscriptionsResponse,
|
|
2305
2315
|
message: Message,
|
|
2306
2316
|
channel: ServerSecureChannelLayer,
|
|
2307
|
-
|
|
2308
|
-
) {
|
|
2309
|
-
assert(typeof
|
|
2317
|
+
actionToPerform: (session: ServerSession, subscriptionId: number) => Promise<T>
|
|
2318
|
+
): void {
|
|
2319
|
+
assert(typeof actionToPerform === "function");
|
|
2310
2320
|
const request = message.request as unknown as { subscriptionIds: number[] };
|
|
2311
|
-
assert(
|
|
2321
|
+
assert(Object.prototype.hasOwnProperty.call(request, "subscriptionIds"));
|
|
2312
2322
|
|
|
2313
2323
|
this._apply_on_SessionObject(
|
|
2314
2324
|
ResponseClass,
|
|
@@ -2329,7 +2339,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
2329
2339
|
// return sendError(StatusCodes.BadTooManyOperations);
|
|
2330
2340
|
// }
|
|
2331
2341
|
|
|
2332
|
-
const results: any[] = subscriptionIds.map((subscriptionId: number) =>
|
|
2342
|
+
const results: any[] = subscriptionIds.map((subscriptionId: number) => actionToPerform(session, subscriptionId));
|
|
2333
2343
|
|
|
2334
2344
|
// resolve potential pending promises ....
|
|
2335
2345
|
for (let i = 0; i < results.length; i++) {
|
|
@@ -2352,20 +2362,12 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
2352
2362
|
);
|
|
2353
2363
|
}
|
|
2354
2364
|
|
|
2355
|
-
/**
|
|
2356
|
-
* @method _apply_on_Subscriptions
|
|
2357
|
-
* @param ResponseClass
|
|
2358
|
-
* @param message
|
|
2359
|
-
* @param channel
|
|
2360
|
-
* @param action_to_perform
|
|
2361
|
-
* @private
|
|
2362
|
-
*/
|
|
2363
2365
|
protected _apply_on_Subscriptions(
|
|
2364
|
-
ResponseClass: typeof SetPublishingModeResponse,
|
|
2366
|
+
ResponseClass: typeof SetPublishingModeResponse | typeof TransferSubscriptionsResponse | typeof DeleteSubscriptionsResponse,
|
|
2365
2367
|
message: Message,
|
|
2366
2368
|
channel: ServerSecureChannelLayer,
|
|
2367
|
-
|
|
2368
|
-
) {
|
|
2369
|
+
actionToPerform: (session: ServerSession, subscription: Subscription) => Promise<StatusCode>
|
|
2370
|
+
): void {
|
|
2369
2371
|
this._apply_on_SubscriptionIds<StatusCode>(
|
|
2370
2372
|
ResponseClass,
|
|
2371
2373
|
message,
|
|
@@ -2379,15 +2381,12 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
2379
2381
|
if (!subscription) {
|
|
2380
2382
|
return StatusCodes.BadSubscriptionIdInvalid;
|
|
2381
2383
|
}
|
|
2382
|
-
return
|
|
2384
|
+
return actionToPerform(session, subscription);
|
|
2383
2385
|
}
|
|
2384
2386
|
);
|
|
2385
2387
|
}
|
|
2386
2388
|
|
|
2387
|
-
private async _closeSession(authenticationToken: NodeId, deleteSubscriptions: boolean, reason: ClosingReason) {
|
|
2388
|
-
const server = this;
|
|
2389
|
-
|
|
2390
|
-
//
|
|
2389
|
+
private async _closeSession(authenticationToken: NodeId, deleteSubscriptions: boolean, reason: ClosingReason): Promise<void> {
|
|
2391
2390
|
if (deleteSubscriptions && this.options.onDeleteMonitoredItem) {
|
|
2392
2391
|
const session = this.getSession(authenticationToken);
|
|
2393
2392
|
if (session) {
|
|
@@ -2397,7 +2396,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
2397
2396
|
}
|
|
2398
2397
|
}
|
|
2399
2398
|
}
|
|
2400
|
-
await
|
|
2399
|
+
await this.engine.closeSession(authenticationToken, deleteSubscriptions, reason);
|
|
2401
2400
|
}
|
|
2402
2401
|
/**
|
|
2403
2402
|
* @method _on_CloseSessionRequest
|
|
@@ -2405,9 +2404,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
2405
2404
|
* @param channel
|
|
2406
2405
|
* @private
|
|
2407
2406
|
*/
|
|
2408
|
-
protected _on_CloseSessionRequest(message: Message, channel: ServerSecureChannelLayer) {
|
|
2409
|
-
const server = this;
|
|
2410
|
-
|
|
2407
|
+
protected _on_CloseSessionRequest(message: Message, channel: ServerSecureChannelLayer): void {
|
|
2411
2408
|
const request = message.request as CloseSessionRequest;
|
|
2412
2409
|
assert(request instanceof CloseSessionRequest);
|
|
2413
2410
|
|
|
@@ -2454,8 +2451,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
2454
2451
|
* @param channel
|
|
2455
2452
|
* @private
|
|
2456
2453
|
*/
|
|
2457
|
-
protected _on_BrowseRequest(message: Message, channel: ServerSecureChannelLayer) {
|
|
2458
|
-
const server = this;
|
|
2454
|
+
protected _on_BrowseRequest(message: Message, channel: ServerSecureChannelLayer): void {
|
|
2459
2455
|
const request = message.request as BrowseRequest;
|
|
2460
2456
|
assert(request instanceof BrowseRequest);
|
|
2461
2457
|
const diagnostic: any = {};
|
|
@@ -2468,7 +2464,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
2468
2464
|
let response: BrowseResponse;
|
|
2469
2465
|
// test view
|
|
2470
2466
|
if (request.view && !request.view.viewId.isEmpty()) {
|
|
2471
|
-
let theView: UAView | null =
|
|
2467
|
+
let theView: UAView | null = this.engine!.addressSpace!.findNode(request.view.viewId) as UAView;
|
|
2472
2468
|
if (theView && theView.nodeClass !== NodeClass.View) {
|
|
2473
2469
|
// Error: theView is not a View
|
|
2474
2470
|
diagnostic.localizedText = { text: "Expecting a view here" };
|
|
@@ -2483,8 +2479,8 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
2483
2479
|
return sendError(StatusCodes.BadNothingToDo);
|
|
2484
2480
|
}
|
|
2485
2481
|
|
|
2486
|
-
if (
|
|
2487
|
-
if (request.nodesToBrowse.length >
|
|
2482
|
+
if (this.engine.serverCapabilities.operationLimits.maxNodesPerBrowse > 0) {
|
|
2483
|
+
if (request.nodesToBrowse.length > this.engine.serverCapabilities.operationLimits.maxNodesPerBrowse) {
|
|
2488
2484
|
return sendError(StatusCodes.BadTooManyOperations);
|
|
2489
2485
|
}
|
|
2490
2486
|
}
|
|
@@ -2493,9 +2489,9 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
2493
2489
|
const requestedMaxReferencesPerNode = Math.min(9876, request.requestedMaxReferencesPerNode);
|
|
2494
2490
|
assert(request.nodesToBrowse[0].schema.name === "BrowseDescription");
|
|
2495
2491
|
|
|
2496
|
-
const context = new SessionContext({ session, server });
|
|
2492
|
+
const context = new SessionContext({ session, server: this });
|
|
2497
2493
|
|
|
2498
|
-
const f = callbackify(
|
|
2494
|
+
const f = callbackify(this.engine.browseWithAutomaticExpansion).bind(this.engine);
|
|
2499
2495
|
(f as any)(request.nodesToBrowse, context, (err?: Error | null, results?: BrowseResult[]) => {
|
|
2500
2496
|
// istanbul ignore next
|
|
2501
2497
|
if (!results) {
|
|
@@ -2505,7 +2501,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
2505
2501
|
assert(results[0].schema.name === "BrowseResult");
|
|
2506
2502
|
|
|
2507
2503
|
// handle continuation point and requestedMaxReferencesPerNode
|
|
2508
|
-
const maxBrowseContinuationPoints =
|
|
2504
|
+
const maxBrowseContinuationPoints = this.engine.serverCapabilities.maxBrowseContinuationPoints;
|
|
2509
2505
|
results = results.map((result: BrowseResult) => {
|
|
2510
2506
|
assert(!result.continuationPoint);
|
|
2511
2507
|
|
|
@@ -2514,16 +2510,22 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
2514
2510
|
return new BrowseResult({ statusCode: StatusCodes.BadNoContinuationPoints });
|
|
2515
2511
|
}
|
|
2516
2512
|
|
|
2517
|
-
if (session.continuationPointManager.
|
|
2513
|
+
if (session.continuationPointManager.hasReachedMaximum(maxBrowseContinuationPoints)) {
|
|
2518
2514
|
return new BrowseResult({ statusCode: StatusCodes.BadNoContinuationPoints });
|
|
2519
2515
|
}
|
|
2520
|
-
const truncatedResult = session.continuationPointManager.
|
|
2516
|
+
const truncatedResult = session.continuationPointManager.registerReferences(
|
|
2521
2517
|
requestedMaxReferencesPerNode,
|
|
2522
|
-
result.references || []
|
|
2518
|
+
result.references || [],
|
|
2519
|
+
{ continuationPoint: null }
|
|
2523
2520
|
);
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2521
|
+
let { statusCode } = truncatedResult;
|
|
2522
|
+
const { continuationPoint, values } = truncatedResult;
|
|
2523
|
+
statusCode = result.statusCode;
|
|
2524
|
+
return new BrowseResult({
|
|
2525
|
+
statusCode,
|
|
2526
|
+
continuationPoint,
|
|
2527
|
+
references: values
|
|
2528
|
+
});
|
|
2527
2529
|
});
|
|
2528
2530
|
|
|
2529
2531
|
response = new BrowseResponse({
|
|
@@ -2542,7 +2544,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
2542
2544
|
* @param channel
|
|
2543
2545
|
* @private
|
|
2544
2546
|
*/
|
|
2545
|
-
protected _on_BrowseNextRequest(message: Message, channel: ServerSecureChannelLayer) {
|
|
2547
|
+
protected _on_BrowseNextRequest(message: Message, channel: ServerSecureChannelLayer): void {
|
|
2546
2548
|
const request = message.request as BrowseNextRequest;
|
|
2547
2549
|
assert(request instanceof BrowseNextRequest);
|
|
2548
2550
|
this._apply_on_SessionObject(
|
|
@@ -2550,35 +2552,27 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
2550
2552
|
message,
|
|
2551
2553
|
channel,
|
|
2552
2554
|
(session: ServerSession, sendResponse: (response: Response) => void, sendError: (statusCode: StatusCode) => void) => {
|
|
2553
|
-
let response;
|
|
2554
|
-
|
|
2555
2555
|
if (!request.continuationPoints || request.continuationPoints.length === 0) {
|
|
2556
2556
|
return sendError(StatusCodes.BadNothingToDo);
|
|
2557
2557
|
}
|
|
2558
|
+
const results = request.continuationPoints
|
|
2559
|
+
.map((continuationPoint: ContinuationPoint, index: number) =>
|
|
2560
|
+
session.continuationPointManager.getNextReferences(0, {
|
|
2561
|
+
continuationPoint,
|
|
2562
|
+
index,
|
|
2563
|
+
releaseContinuationPoints: request.releaseContinuationPoints
|
|
2564
|
+
})
|
|
2565
|
+
)
|
|
2566
|
+
.map(
|
|
2567
|
+
(r) =>
|
|
2568
|
+
<BrowseResultOptions>{
|
|
2569
|
+
continuationPoint: r.continuationPoint,
|
|
2570
|
+
references: r.values,
|
|
2571
|
+
statusCode: r.statusCode
|
|
2572
|
+
}
|
|
2573
|
+
);
|
|
2558
2574
|
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
let results;
|
|
2562
|
-
if (request.releaseContinuationPoints) {
|
|
2563
|
-
// releaseContinuationPoints = TRUE
|
|
2564
|
-
// passed continuationPoints shall be reset to free resources in
|
|
2565
|
-
// the Server. The continuation points are released and the results
|
|
2566
|
-
// and diagnosticInfos arrays are empty.
|
|
2567
|
-
results = request.continuationPoints.map((continuationPoint: ContinuationPoint) => {
|
|
2568
|
-
return session.continuationPointManager.cancel(continuationPoint);
|
|
2569
|
-
});
|
|
2570
|
-
} else {
|
|
2571
|
-
// let extract data from continuation points
|
|
2572
|
-
|
|
2573
|
-
// releaseContinuationPoints = FALSE
|
|
2574
|
-
// passed continuationPoints shall be used to get the next set of
|
|
2575
|
-
// browse information.
|
|
2576
|
-
results = request.continuationPoints.map((continuationPoint: ContinuationPoint) => {
|
|
2577
|
-
return session.continuationPointManager.getNext(continuationPoint);
|
|
2578
|
-
});
|
|
2579
|
-
}
|
|
2580
|
-
|
|
2581
|
-
response = new BrowseNextResponse({
|
|
2575
|
+
const response = new BrowseNextResponse({
|
|
2582
2576
|
diagnosticInfos: undefined,
|
|
2583
2577
|
results
|
|
2584
2578
|
});
|
|
@@ -2588,8 +2582,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
2588
2582
|
}
|
|
2589
2583
|
|
|
2590
2584
|
// read services
|
|
2591
|
-
protected _on_ReadRequest(message: Message, channel: ServerSecureChannelLayer) {
|
|
2592
|
-
const server = this;
|
|
2585
|
+
protected _on_ReadRequest(message: Message, channel: ServerSecureChannelLayer): void {
|
|
2593
2586
|
const request = message.request as ReadRequest;
|
|
2594
2587
|
assert(request instanceof ReadRequest);
|
|
2595
2588
|
|
|
@@ -2598,7 +2591,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
2598
2591
|
message,
|
|
2599
2592
|
channel,
|
|
2600
2593
|
(session: ServerSession, sendResponse: (response: Response) => void, sendError: (statusCode: StatusCode) => void) => {
|
|
2601
|
-
const context = new SessionContext({ session, server });
|
|
2594
|
+
const context = new SessionContext({ session, server: this });
|
|
2602
2595
|
|
|
2603
2596
|
let response;
|
|
2604
2597
|
|
|
@@ -2623,8 +2616,8 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
2623
2616
|
assert(request.nodesToRead[0].schema.name === "ReadValueId");
|
|
2624
2617
|
|
|
2625
2618
|
// limit size of nodesToRead array to maxNodesPerRead
|
|
2626
|
-
if (
|
|
2627
|
-
if (request.nodesToRead.length >
|
|
2619
|
+
if (this.engine.serverCapabilities.operationLimits.maxNodesPerRead > 0) {
|
|
2620
|
+
if (request.nodesToRead.length > this.engine.serverCapabilities.operationLimits.maxNodesPerRead) {
|
|
2628
2621
|
return sendError(StatusCodes.BadTooManyOperations);
|
|
2629
2622
|
}
|
|
2630
2623
|
}
|
|
@@ -2635,10 +2628,10 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
2635
2628
|
}
|
|
2636
2629
|
|
|
2637
2630
|
// ask for a refresh of asynchronous variables
|
|
2638
|
-
|
|
2631
|
+
this.engine.refreshValues(request.nodesToRead, request.maxAge, (err?: Error | null) => {
|
|
2639
2632
|
assert(!err, " error not handled here , fix me");
|
|
2640
2633
|
|
|
2641
|
-
results =
|
|
2634
|
+
results = this.engine.read(context, request);
|
|
2642
2635
|
|
|
2643
2636
|
assert(results[0].schema.name === "DataValue");
|
|
2644
2637
|
assert(results.length === request.nodesToRead!.length);
|
|
@@ -2657,8 +2650,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
2657
2650
|
}
|
|
2658
2651
|
|
|
2659
2652
|
// read services
|
|
2660
|
-
protected _on_HistoryReadRequest(message: Message, channel: ServerSecureChannelLayer) {
|
|
2661
|
-
const server = this;
|
|
2653
|
+
protected _on_HistoryReadRequest(message: Message, channel: ServerSecureChannelLayer): void {
|
|
2662
2654
|
const request = message.request as HistoryReadRequest;
|
|
2663
2655
|
|
|
2664
2656
|
assert(request instanceof HistoryReadRequest);
|
|
@@ -2685,32 +2677,30 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
2685
2677
|
assert(request.nodesToRead[0].schema.name === "HistoryReadValueId");
|
|
2686
2678
|
|
|
2687
2679
|
// limit size of nodesToRead array to maxNodesPerRead
|
|
2688
|
-
if (
|
|
2689
|
-
if (request.nodesToRead.length >
|
|
2680
|
+
if (this.engine.serverCapabilities.operationLimits.maxNodesPerRead > 0) {
|
|
2681
|
+
if (request.nodesToRead.length > this.engine.serverCapabilities.operationLimits.maxNodesPerRead) {
|
|
2690
2682
|
return sendError(StatusCodes.BadTooManyOperations);
|
|
2691
2683
|
}
|
|
2692
2684
|
}
|
|
2693
2685
|
// todo : handle
|
|
2694
|
-
if (
|
|
2695
|
-
if (request.nodesToRead.length >
|
|
2686
|
+
if (this.engine.serverCapabilities.operationLimits.maxNodesPerHistoryReadData > 0) {
|
|
2687
|
+
if (request.nodesToRead.length > this.engine.serverCapabilities.operationLimits.maxNodesPerHistoryReadData) {
|
|
2696
2688
|
return sendError(StatusCodes.BadTooManyOperations);
|
|
2697
2689
|
}
|
|
2698
2690
|
}
|
|
2699
|
-
if (
|
|
2700
|
-
if (
|
|
2701
|
-
request.nodesToRead.length > server.engine.serverCapabilities.operationLimits.maxNodesPerHistoryReadEvents
|
|
2702
|
-
) {
|
|
2691
|
+
if (this.engine.serverCapabilities.operationLimits.maxNodesPerHistoryReadEvents > 0) {
|
|
2692
|
+
if (request.nodesToRead.length > this.engine.serverCapabilities.operationLimits.maxNodesPerHistoryReadEvents) {
|
|
2703
2693
|
return sendError(StatusCodes.BadTooManyOperations);
|
|
2704
2694
|
}
|
|
2705
2695
|
}
|
|
2706
2696
|
|
|
2707
|
-
const context = new SessionContext({ session, server });
|
|
2697
|
+
const context = new SessionContext({ session, server: this });
|
|
2708
2698
|
|
|
2709
2699
|
// ask for a refresh of asynchronous variables
|
|
2710
|
-
|
|
2700
|
+
this.engine.refreshValues(request.nodesToRead, 0, (err?: Error | null) => {
|
|
2711
2701
|
assert(!err, " error not handled here , fix me"); // TODO
|
|
2712
2702
|
|
|
2713
|
-
|
|
2703
|
+
this.engine.historyRead(context, request, (err1: Error | null, results?: HistoryReadResult[]) => {
|
|
2714
2704
|
if (err1) {
|
|
2715
2705
|
return sendError(StatusCodes.BadHistoryOperationInvalid);
|
|
2716
2706
|
}
|
|
@@ -2748,8 +2738,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
2748
2738
|
// In the cases where the Server is able to verify that it has successfully written to the data source,
|
|
2749
2739
|
// it reports an unconditional success.
|
|
2750
2740
|
*/
|
|
2751
|
-
protected _on_WriteRequest(message: Message, channel: ServerSecureChannelLayer) {
|
|
2752
|
-
const server = this;
|
|
2741
|
+
protected _on_WriteRequest(message: Message, channel: ServerSecureChannelLayer): void {
|
|
2753
2742
|
const request = message.request as WriteRequest;
|
|
2754
2743
|
assert(request instanceof WriteRequest);
|
|
2755
2744
|
assert(!request.nodesToWrite || Array.isArray(request.nodesToWrite));
|
|
@@ -2765,8 +2754,8 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
2765
2754
|
return sendError(StatusCodes.BadNothingToDo);
|
|
2766
2755
|
}
|
|
2767
2756
|
|
|
2768
|
-
if (
|
|
2769
|
-
if (request.nodesToWrite.length >
|
|
2757
|
+
if (this.engine.serverCapabilities.operationLimits.maxNodesPerWrite > 0) {
|
|
2758
|
+
if (request.nodesToWrite.length > this.engine.serverCapabilities.operationLimits.maxNodesPerWrite) {
|
|
2770
2759
|
return sendError(StatusCodes.BadTooManyOperations);
|
|
2771
2760
|
}
|
|
2772
2761
|
}
|
|
@@ -2776,10 +2765,10 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
2776
2765
|
nodeToWrite.nodeId = session.resolveRegisteredNode(nodeToWrite.nodeId);
|
|
2777
2766
|
}
|
|
2778
2767
|
|
|
2779
|
-
const context = new SessionContext({ session, server });
|
|
2768
|
+
const context = new SessionContext({ session, server: this });
|
|
2780
2769
|
|
|
2781
2770
|
assert(request.nodesToWrite[0].schema.name === "WriteValue");
|
|
2782
|
-
|
|
2771
|
+
this.engine.write(context, request.nodesToWrite, (err: Error | null, results?: StatusCode[]) => {
|
|
2783
2772
|
assert(!err);
|
|
2784
2773
|
assert(Array.isArray(results));
|
|
2785
2774
|
assert(results!.length === request.nodesToWrite!.length);
|
|
@@ -2794,9 +2783,8 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
2794
2783
|
}
|
|
2795
2784
|
|
|
2796
2785
|
// subscription services
|
|
2797
|
-
protected _on_CreateSubscriptionRequest(message: Message, channel: ServerSecureChannelLayer) {
|
|
2798
|
-
const
|
|
2799
|
-
const engine = server.engine;
|
|
2786
|
+
protected _on_CreateSubscriptionRequest(message: Message, channel: ServerSecureChannelLayer): void {
|
|
2787
|
+
const engine = this.engine;
|
|
2800
2788
|
const addressSpace = engine.addressSpace!;
|
|
2801
2789
|
|
|
2802
2790
|
const request = message.request as CreateSubscriptionRequest;
|
|
@@ -2807,7 +2795,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
2807
2795
|
message,
|
|
2808
2796
|
channel,
|
|
2809
2797
|
(session: ServerSession, sendResponse: (response: Response) => void, sendError: (statusCode: StatusCode) => void) => {
|
|
2810
|
-
const context = new SessionContext({ session, server });
|
|
2798
|
+
const context = new SessionContext({ session, server: this });
|
|
2811
2799
|
|
|
2812
2800
|
if (session.currentSubscriptionCount >= OPCUAServer.MAX_SUBSCRIPTION) {
|
|
2813
2801
|
return sendError(StatusCodes.BadTooManySubscriptions);
|
|
@@ -2830,8 +2818,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
2830
2818
|
);
|
|
2831
2819
|
}
|
|
2832
2820
|
|
|
2833
|
-
protected _on_DeleteSubscriptionsRequest(message: Message, channel: ServerSecureChannelLayer) {
|
|
2834
|
-
const server = this;
|
|
2821
|
+
protected _on_DeleteSubscriptionsRequest(message: Message, channel: ServerSecureChannelLayer): void {
|
|
2835
2822
|
const request = message.request as DeleteSubscriptionsRequest;
|
|
2836
2823
|
assert(request instanceof DeleteSubscriptionsRequest);
|
|
2837
2824
|
this._apply_on_SubscriptionIds(
|
|
@@ -2839,13 +2826,13 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
2839
2826
|
message,
|
|
2840
2827
|
channel,
|
|
2841
2828
|
async (session: ServerSession, subscriptionId: number) => {
|
|
2842
|
-
let subscription =
|
|
2829
|
+
let subscription = this.engine.findOrphanSubscription(subscriptionId);
|
|
2843
2830
|
// istanbul ignore next
|
|
2844
2831
|
if (subscription) {
|
|
2845
2832
|
warningLog("Deleting an orphan subscription", subscriptionId);
|
|
2846
2833
|
|
|
2847
2834
|
await this._beforeDeleteSubscription(subscription);
|
|
2848
|
-
return
|
|
2835
|
+
return this.engine.deleteOrphanSubscription(subscription);
|
|
2849
2836
|
}
|
|
2850
2837
|
|
|
2851
2838
|
subscription = session.getSubscription(subscriptionId);
|
|
@@ -2858,7 +2845,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
2858
2845
|
);
|
|
2859
2846
|
}
|
|
2860
2847
|
|
|
2861
|
-
protected _on_TransferSubscriptionsRequest(message: Message, channel: ServerSecureChannelLayer) {
|
|
2848
|
+
protected _on_TransferSubscriptionsRequest(message: Message, channel: ServerSecureChannelLayer): void {
|
|
2862
2849
|
//
|
|
2863
2850
|
// sendInitialValue Boolean
|
|
2864
2851
|
// A Boolean parameter with the following values:
|
|
@@ -2870,8 +2857,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
2870
2857
|
// This parameter only applies to MonitoredItems used for monitoring Attribute changes.
|
|
2871
2858
|
//
|
|
2872
2859
|
|
|
2873
|
-
const
|
|
2874
|
-
const engine = server.engine;
|
|
2860
|
+
const engine = this.engine;
|
|
2875
2861
|
|
|
2876
2862
|
const request = message.request as TransferSubscriptionsRequest;
|
|
2877
2863
|
assert(request instanceof TransferSubscriptionsRequest);
|
|
@@ -2884,9 +2870,8 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
2884
2870
|
);
|
|
2885
2871
|
}
|
|
2886
2872
|
|
|
2887
|
-
protected _on_CreateMonitoredItemsRequest(message: Message, channel: ServerSecureChannelLayer) {
|
|
2888
|
-
const
|
|
2889
|
-
const engine = server.engine;
|
|
2873
|
+
protected _on_CreateMonitoredItemsRequest(message: Message, channel: ServerSecureChannelLayer): void {
|
|
2874
|
+
const engine = this.engine;
|
|
2890
2875
|
const addressSpace = engine.addressSpace!;
|
|
2891
2876
|
|
|
2892
2877
|
const request = message.request as CreateMonitoredItemsRequest;
|
|
@@ -2910,8 +2895,8 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
2910
2895
|
if (!request.itemsToCreate || request.itemsToCreate.length === 0) {
|
|
2911
2896
|
return sendError(StatusCodes.BadNothingToDo);
|
|
2912
2897
|
}
|
|
2913
|
-
if (
|
|
2914
|
-
if (request.itemsToCreate.length >
|
|
2898
|
+
if (this.engine.serverCapabilities.operationLimits.maxMonitoredItemsPerCall > 0) {
|
|
2899
|
+
if (request.itemsToCreate.length > this.engine.serverCapabilities.operationLimits.maxMonitoredItemsPerCall) {
|
|
2915
2900
|
return sendError(StatusCodes.BadTooManyOperations);
|
|
2916
2901
|
}
|
|
2917
2902
|
}
|
|
@@ -2955,7 +2940,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
2955
2940
|
);
|
|
2956
2941
|
}
|
|
2957
2942
|
|
|
2958
|
-
protected _on_ModifySubscriptionRequest(message: Message, channel: ServerSecureChannelLayer) {
|
|
2943
|
+
protected _on_ModifySubscriptionRequest(message: Message, channel: ServerSecureChannelLayer): void {
|
|
2959
2944
|
const request = message.request as ModifySubscriptionRequest;
|
|
2960
2945
|
assert(request instanceof ModifySubscriptionRequest);
|
|
2961
2946
|
|
|
@@ -2982,8 +2967,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
2982
2967
|
);
|
|
2983
2968
|
}
|
|
2984
2969
|
|
|
2985
|
-
protected _on_ModifyMonitoredItemsRequest(message: Message, channel: ServerSecureChannelLayer) {
|
|
2986
|
-
const server = this;
|
|
2970
|
+
protected _on_ModifyMonitoredItemsRequest(message: Message, channel: ServerSecureChannelLayer): void {
|
|
2987
2971
|
const request = message.request as ModifyMonitoredItemsRequest;
|
|
2988
2972
|
|
|
2989
2973
|
assert(request instanceof ModifyMonitoredItemsRequest);
|
|
@@ -3007,8 +2991,8 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
3007
2991
|
}
|
|
3008
2992
|
|
|
3009
2993
|
/* istanbul ignore next */
|
|
3010
|
-
if (
|
|
3011
|
-
if (request.itemsToModify.length >
|
|
2994
|
+
if (this.engine.serverCapabilities.operationLimits.maxMonitoredItemsPerCall > 0) {
|
|
2995
|
+
if (request.itemsToModify.length > this.engine.serverCapabilities.operationLimits.maxMonitoredItemsPerCall) {
|
|
3012
2996
|
return sendError(StatusCodes.BadTooManyOperations);
|
|
3013
2997
|
}
|
|
3014
2998
|
}
|
|
@@ -3039,7 +3023,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
3039
3023
|
);
|
|
3040
3024
|
}
|
|
3041
3025
|
|
|
3042
|
-
protected _on_PublishRequest(message: Message, channel: ServerSecureChannelLayer) {
|
|
3026
|
+
protected _on_PublishRequest(message: Message, channel: ServerSecureChannelLayer): void {
|
|
3043
3027
|
const request = message.request as PublishRequest;
|
|
3044
3028
|
assert(request instanceof PublishRequest);
|
|
3045
3029
|
|
|
@@ -3050,14 +3034,14 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
3050
3034
|
(session: ServerSession, sendResponse: (response: Response) => void, sendError: (statusCode: StatusCode) => void) => {
|
|
3051
3035
|
assert(session);
|
|
3052
3036
|
assert(session.publishEngine); // server.publishEngine doesn't exists, OPCUAServer has probably shut down already
|
|
3053
|
-
session.publishEngine._on_PublishRequest(request, (request1:
|
|
3037
|
+
session.publishEngine._on_PublishRequest(request, (request1: PublishRequest, response: PublishResponse) => {
|
|
3054
3038
|
sendResponse(response);
|
|
3055
3039
|
});
|
|
3056
3040
|
}
|
|
3057
3041
|
);
|
|
3058
3042
|
}
|
|
3059
3043
|
|
|
3060
|
-
protected _on_SetPublishingModeRequest(message: Message, channel: ServerSecureChannelLayer) {
|
|
3044
|
+
protected _on_SetPublishingModeRequest(message: Message, channel: ServerSecureChannelLayer): void {
|
|
3061
3045
|
const request = message.request as SetPublishingModeRequest;
|
|
3062
3046
|
assert(request instanceof SetPublishingModeRequest);
|
|
3063
3047
|
const publishingEnabled = request.publishingEnabled;
|
|
@@ -3071,8 +3055,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
3071
3055
|
);
|
|
3072
3056
|
}
|
|
3073
3057
|
|
|
3074
|
-
protected _on_DeleteMonitoredItemsRequest(message: Message, channel: ServerSecureChannelLayer) {
|
|
3075
|
-
const server = this;
|
|
3058
|
+
protected _on_DeleteMonitoredItemsRequest(message: Message, channel: ServerSecureChannelLayer): void {
|
|
3076
3059
|
const request = message.request as DeleteMonitoredItemsRequest;
|
|
3077
3060
|
assert(request instanceof DeleteMonitoredItemsRequest);
|
|
3078
3061
|
|
|
@@ -3092,10 +3075,8 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
3092
3075
|
}
|
|
3093
3076
|
|
|
3094
3077
|
/* istanbul ignore next */
|
|
3095
|
-
if (
|
|
3096
|
-
if (
|
|
3097
|
-
request.monitoredItemIds.length > server.engine.serverCapabilities.operationLimits.maxMonitoredItemsPerCall
|
|
3098
|
-
) {
|
|
3078
|
+
if (this.engine.serverCapabilities.operationLimits.maxMonitoredItemsPerCall > 0) {
|
|
3079
|
+
if (request.monitoredItemIds.length > this.engine.serverCapabilities.operationLimits.maxMonitoredItemsPerCall) {
|
|
3099
3080
|
return sendError(StatusCodes.BadTooManyOperations);
|
|
3100
3081
|
}
|
|
3101
3082
|
}
|
|
@@ -3126,8 +3107,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
3126
3107
|
}
|
|
3127
3108
|
);
|
|
3128
3109
|
}
|
|
3129
|
-
protected _on_SetTriggeringRequest(message: Message, channel: ServerSecureChannelLayer) {
|
|
3130
|
-
const server = this;
|
|
3110
|
+
protected _on_SetTriggeringRequest(message: Message, channel: ServerSecureChannelLayer): void {
|
|
3131
3111
|
const request = message.request as SetTriggeringRequest;
|
|
3132
3112
|
assert(request instanceof SetTriggeringRequest);
|
|
3133
3113
|
|
|
@@ -3152,8 +3132,8 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
3152
3132
|
*
|
|
3153
3133
|
*/
|
|
3154
3134
|
const maxElements = (linksToAdd ? linksToAdd.length : 0) + (linksToRemove ? linksToRemove.length : 0);
|
|
3155
|
-
if (
|
|
3156
|
-
if (maxElements >
|
|
3135
|
+
if (this.engine.serverCapabilities.operationLimits.maxMonitoredItemsPerCall > 0) {
|
|
3136
|
+
if (maxElements > this.engine.serverCapabilities.operationLimits.maxMonitoredItemsPerCall) {
|
|
3157
3137
|
return sendError(StatusCodes.BadTooManyOperations);
|
|
3158
3138
|
}
|
|
3159
3139
|
}
|
|
@@ -3177,13 +3157,13 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
3177
3157
|
);
|
|
3178
3158
|
}
|
|
3179
3159
|
|
|
3180
|
-
protected async _beforeDeleteSubscription(subscription: Subscription) {
|
|
3160
|
+
protected async _beforeDeleteSubscription(subscription: Subscription): Promise<void> {
|
|
3181
3161
|
if (!this.options.onDeleteMonitoredItem) {
|
|
3182
3162
|
return;
|
|
3183
3163
|
}
|
|
3184
3164
|
await subscription.applyOnMonitoredItem(this.options.onDeleteMonitoredItem.bind(null, subscription) as any);
|
|
3185
3165
|
}
|
|
3186
|
-
protected _on_RepublishRequest(message: Message, channel: ServerSecureChannelLayer) {
|
|
3166
|
+
protected _on_RepublishRequest(message: Message, channel: ServerSecureChannelLayer): void {
|
|
3187
3167
|
const request = message.request as RepublishRequest;
|
|
3188
3168
|
assert(request instanceof RepublishRequest);
|
|
3189
3169
|
|
|
@@ -3225,8 +3205,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
3225
3205
|
// Bad_TooManyOperations
|
|
3226
3206
|
// Bad_SubscriptionIdInvalid
|
|
3227
3207
|
// Bad_MonitoringModeInvalid
|
|
3228
|
-
protected _on_SetMonitoringModeRequest(message: Message, channel: ServerSecureChannelLayer) {
|
|
3229
|
-
const server = this;
|
|
3208
|
+
protected _on_SetMonitoringModeRequest(message: Message, channel: ServerSecureChannelLayer): void {
|
|
3230
3209
|
const request = message.request as SetMonitoringModeRequest;
|
|
3231
3210
|
assert(request instanceof SetMonitoringModeRequest);
|
|
3232
3211
|
|
|
@@ -3246,10 +3225,8 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
3246
3225
|
}
|
|
3247
3226
|
|
|
3248
3227
|
/* istanbul ignore next */
|
|
3249
|
-
if (
|
|
3250
|
-
if (
|
|
3251
|
-
request.monitoredItemIds.length > server.engine.serverCapabilities.operationLimits.maxMonitoredItemsPerCall
|
|
3252
|
-
) {
|
|
3228
|
+
if (this.engine.serverCapabilities.operationLimits.maxMonitoredItemsPerCall > 0) {
|
|
3229
|
+
if (request.monitoredItemIds.length > this.engine.serverCapabilities.operationLimits.maxMonitoredItemsPerCall) {
|
|
3253
3230
|
return sendError(StatusCodes.BadTooManyOperations);
|
|
3254
3231
|
}
|
|
3255
3232
|
}
|
|
@@ -3277,10 +3254,9 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
3277
3254
|
}
|
|
3278
3255
|
|
|
3279
3256
|
// _on_TranslateBrowsePathsToNodeIds service
|
|
3280
|
-
protected _on_TranslateBrowsePathsToNodeIdsRequest(message: Message, channel: ServerSecureChannelLayer) {
|
|
3257
|
+
protected _on_TranslateBrowsePathsToNodeIdsRequest(message: Message, channel: ServerSecureChannelLayer): void {
|
|
3281
3258
|
const request = message.request as TranslateBrowsePathsToNodeIdsRequest;
|
|
3282
3259
|
assert(request instanceof TranslateBrowsePathsToNodeIdsRequest);
|
|
3283
|
-
const server = this;
|
|
3284
3260
|
|
|
3285
3261
|
this._apply_on_SessionObject(
|
|
3286
3262
|
TranslateBrowsePathsToNodeIdsResponse,
|
|
@@ -3294,16 +3270,16 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
3294
3270
|
if (!request.browsePaths || request.browsePaths.length === 0) {
|
|
3295
3271
|
return sendError(StatusCodes.BadNothingToDo);
|
|
3296
3272
|
}
|
|
3297
|
-
if (
|
|
3273
|
+
if (this.engine.serverCapabilities.operationLimits.maxNodesPerTranslateBrowsePathsToNodeIds > 0) {
|
|
3298
3274
|
if (
|
|
3299
3275
|
request.browsePaths.length >
|
|
3300
|
-
|
|
3276
|
+
this.engine.serverCapabilities.operationLimits.maxNodesPerTranslateBrowsePathsToNodeIds
|
|
3301
3277
|
) {
|
|
3302
3278
|
return sendError(StatusCodes.BadTooManyOperations);
|
|
3303
3279
|
}
|
|
3304
3280
|
}
|
|
3305
3281
|
|
|
3306
|
-
const browsePathsResults = request.browsePaths.map((browsePath) =>
|
|
3282
|
+
const browsePathsResults = request.browsePaths.map((browsePath) => this.engine.browsePath(browsePath));
|
|
3307
3283
|
|
|
3308
3284
|
const response = new TranslateBrowsePathsToNodeIdsResponse({
|
|
3309
3285
|
diagnosticInfos: null,
|
|
@@ -3320,8 +3296,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
3320
3296
|
// Bad_NothingToDo See Table 165 for the description of this result code.
|
|
3321
3297
|
// Bad_TooManyOperations See Table 165 for the description of this result code.
|
|
3322
3298
|
//
|
|
3323
|
-
protected _on_CallRequest(message: Message, channel: ServerSecureChannelLayer) {
|
|
3324
|
-
const server = this;
|
|
3299
|
+
protected _on_CallRequest(message: Message, channel: ServerSecureChannelLayer): void {
|
|
3325
3300
|
const request = message.request as CallRequest;
|
|
3326
3301
|
assert(request instanceof CallRequest);
|
|
3327
3302
|
|
|
@@ -3338,16 +3313,16 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
3338
3313
|
|
|
3339
3314
|
// the MaxNodesPerMethodCall Property indicates the maximum size of the methodsToCall array when
|
|
3340
3315
|
// a Client calls the Call Service.
|
|
3341
|
-
let maxNodesPerMethodCall =
|
|
3316
|
+
let maxNodesPerMethodCall = this.engine.serverCapabilities.operationLimits.maxNodesPerMethodCall;
|
|
3342
3317
|
maxNodesPerMethodCall = maxNodesPerMethodCall <= 0 ? 1000 : maxNodesPerMethodCall;
|
|
3343
3318
|
if (request.methodsToCall.length > maxNodesPerMethodCall) {
|
|
3344
3319
|
return sendError(StatusCodes.BadTooManyOperations);
|
|
3345
3320
|
}
|
|
3346
3321
|
|
|
3347
3322
|
/* jshint validthis: true */
|
|
3348
|
-
const addressSpace =
|
|
3323
|
+
const addressSpace = this.engine.addressSpace!;
|
|
3349
3324
|
|
|
3350
|
-
const context = new SessionContext({ session, server });
|
|
3325
|
+
const context = new SessionContext({ session, server: this });
|
|
3351
3326
|
|
|
3352
3327
|
async.map(
|
|
3353
3328
|
request.methodsToCall,
|
|
@@ -3368,8 +3343,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
3368
3343
|
);
|
|
3369
3344
|
}
|
|
3370
3345
|
|
|
3371
|
-
protected _on_RegisterNodesRequest(message: Message, channel: ServerSecureChannelLayer) {
|
|
3372
|
-
const server = this;
|
|
3346
|
+
protected _on_RegisterNodesRequest(message: Message, channel: ServerSecureChannelLayer): void {
|
|
3373
3347
|
const request = message.request as RegisterNodesRequest;
|
|
3374
3348
|
assert(request instanceof RegisterNodesRequest);
|
|
3375
3349
|
|
|
@@ -3384,10 +3358,8 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
3384
3358
|
response = new RegisterNodesResponse({ responseHeader: { serviceResult: StatusCodes.BadNothingToDo } });
|
|
3385
3359
|
return sendResponse(response);
|
|
3386
3360
|
}
|
|
3387
|
-
if (
|
|
3388
|
-
if (
|
|
3389
|
-
request.nodesToRegister.length > server.engine.serverCapabilities.operationLimits.maxNodesPerRegisterNodes
|
|
3390
|
-
) {
|
|
3361
|
+
if (this.engine.serverCapabilities.operationLimits.maxNodesPerRegisterNodes > 0) {
|
|
3362
|
+
if (request.nodesToRegister.length > this.engine.serverCapabilities.operationLimits.maxNodesPerRegisterNodes) {
|
|
3391
3363
|
return sendError(StatusCodes.BadTooManyOperations);
|
|
3392
3364
|
}
|
|
3393
3365
|
}
|
|
@@ -3408,8 +3380,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
3408
3380
|
);
|
|
3409
3381
|
}
|
|
3410
3382
|
|
|
3411
|
-
protected _on_UnregisterNodesRequest(message: Message, channel: ServerSecureChannelLayer) {
|
|
3412
|
-
const server = this;
|
|
3383
|
+
protected _on_UnregisterNodesRequest(message: Message, channel: ServerSecureChannelLayer): void {
|
|
3413
3384
|
const request = message.request as UnregisterNodesRequest;
|
|
3414
3385
|
assert(request instanceof UnregisterNodesRequest);
|
|
3415
3386
|
|
|
@@ -3427,9 +3398,9 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
3427
3398
|
return sendResponse(response);
|
|
3428
3399
|
}
|
|
3429
3400
|
|
|
3430
|
-
if (
|
|
3401
|
+
if (this.engine.serverCapabilities.operationLimits.maxNodesPerRegisterNodes > 0) {
|
|
3431
3402
|
if (
|
|
3432
|
-
request.nodesToUnregister.length >
|
|
3403
|
+
request.nodesToUnregister.length > this.engine.serverCapabilities.operationLimits.maxNodesPerRegisterNodes
|
|
3433
3404
|
) {
|
|
3434
3405
|
return sendError(StatusCodes.BadTooManyOperations);
|
|
3435
3406
|
}
|
|
@@ -3444,7 +3415,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
3444
3415
|
}
|
|
3445
3416
|
|
|
3446
3417
|
/* istanbul ignore next */
|
|
3447
|
-
protected _on_Cancel(message: Message, channel: ServerSecureChannelLayer) {
|
|
3418
|
+
protected _on_Cancel(message: Message, channel: ServerSecureChannelLayer): void {
|
|
3448
3419
|
return g_sendError(channel, message, CancelResponse, StatusCodes.BadServiceUnsupported);
|
|
3449
3420
|
}
|
|
3450
3421
|
|
|
@@ -3453,38 +3424,38 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
3453
3424
|
// Nodes continue to exist in the AddressSpace even if the Client that created them disconnects from the Server.
|
|
3454
3425
|
//
|
|
3455
3426
|
/* istanbul ignore next */
|
|
3456
|
-
protected _on_AddNodes(message: Message, channel: ServerSecureChannelLayer) {
|
|
3427
|
+
protected _on_AddNodes(message: Message, channel: ServerSecureChannelLayer): void {
|
|
3457
3428
|
return g_sendError(channel, message, AddNodesResponse, StatusCodes.BadServiceUnsupported);
|
|
3458
3429
|
}
|
|
3459
3430
|
|
|
3460
3431
|
/* istanbul ignore next */
|
|
3461
|
-
protected _on_AddReferences(message: Message, channel: ServerSecureChannelLayer) {
|
|
3432
|
+
protected _on_AddReferences(message: Message, channel: ServerSecureChannelLayer): void {
|
|
3462
3433
|
return g_sendError(channel, message, AddReferencesResponse, StatusCodes.BadServiceUnsupported);
|
|
3463
3434
|
}
|
|
3464
3435
|
|
|
3465
3436
|
/* istanbul ignore next */
|
|
3466
|
-
protected _on_DeleteNodes(message: Message, channel: ServerSecureChannelLayer) {
|
|
3437
|
+
protected _on_DeleteNodes(message: Message, channel: ServerSecureChannelLayer): void {
|
|
3467
3438
|
return g_sendError(channel, message, DeleteNodesResponse, StatusCodes.BadServiceUnsupported);
|
|
3468
3439
|
}
|
|
3469
3440
|
|
|
3470
3441
|
/* istanbul ignore next */
|
|
3471
|
-
protected _on_DeleteReferences(message: Message, channel: ServerSecureChannelLayer) {
|
|
3442
|
+
protected _on_DeleteReferences(message: Message, channel: ServerSecureChannelLayer): void {
|
|
3472
3443
|
return g_sendError(channel, message, DeleteReferencesResponse, StatusCodes.BadServiceUnsupported);
|
|
3473
3444
|
}
|
|
3474
3445
|
|
|
3475
3446
|
// Query Service
|
|
3476
3447
|
/* istanbul ignore next */
|
|
3477
|
-
protected _on_QueryFirst(message: Message, channel: ServerSecureChannelLayer) {
|
|
3448
|
+
protected _on_QueryFirst(message: Message, channel: ServerSecureChannelLayer): void {
|
|
3478
3449
|
return g_sendError(channel, message, QueryFirstResponse, StatusCodes.BadServiceUnsupported);
|
|
3479
3450
|
}
|
|
3480
3451
|
|
|
3481
3452
|
/* istanbul ignore next */
|
|
3482
|
-
protected _on_QueryNext(message: Message, channel: ServerSecureChannelLayer) {
|
|
3453
|
+
protected _on_QueryNext(message: Message, channel: ServerSecureChannelLayer): void {
|
|
3483
3454
|
return g_sendError(channel, message, QueryNextResponse, StatusCodes.BadServiceUnsupported);
|
|
3484
3455
|
}
|
|
3485
3456
|
|
|
3486
3457
|
/* istanbul ignore next */
|
|
3487
|
-
protected _on_HistoryUpdate(message: Message, channel: ServerSecureChannelLayer) {
|
|
3458
|
+
protected _on_HistoryUpdate(message: Message, channel: ServerSecureChannelLayer): void {
|
|
3488
3459
|
return g_sendError(channel, message, HistoryUpdateResponse, StatusCodes.BadServiceUnsupported);
|
|
3489
3460
|
}
|
|
3490
3461
|
|
|
@@ -3522,7 +3493,7 @@ export class OPCUAServer extends OPCUABaseServer {
|
|
|
3522
3493
|
|
|
3523
3494
|
/* istanbul ignore next */
|
|
3524
3495
|
if (
|
|
3525
|
-
!Object.prototype.hasOwnProperty.call(endpointOptions,"port") ||
|
|
3496
|
+
!Object.prototype.hasOwnProperty.call(endpointOptions, "port") ||
|
|
3526
3497
|
!isFinite(endpointOptions.port!) ||
|
|
3527
3498
|
typeof endpointOptions.port !== "number"
|
|
3528
3499
|
) {
|
|
@@ -3606,7 +3577,7 @@ export interface RaiseEventAuditCreateSessionEventData extends RaiseEventAuditSe
|
|
|
3606
3577
|
secureChannelId: PseudoVariantString;
|
|
3607
3578
|
revisedSessionTimeout: PseudoVariantDuration;
|
|
3608
3579
|
clientCertificate: PseudoVariantByteString;
|
|
3609
|
-
clientCertificateThumbprint:
|
|
3580
|
+
clientCertificateThumbprint: PseudoVariantString;
|
|
3610
3581
|
}
|
|
3611
3582
|
|
|
3612
3583
|
export interface RaiseEventAuditActivateSessionEventData extends RaiseEventAuditSessionEventData {
|
|
@@ -3734,8 +3705,6 @@ export interface OPCUAServer extends EventEmitter {
|
|
|
3734
3705
|
on(event: string, eventHandler: (...args: [any?, ...any[]]) => void): this;
|
|
3735
3706
|
}
|
|
3736
3707
|
|
|
3737
|
-
// tslint:disable:no-var-requires
|
|
3738
|
-
const thenify = require("thenify");
|
|
3739
3708
|
const opts = { multiArgs: false };
|
|
3740
3709
|
OPCUAServer.prototype.start = thenify.withCallback(OPCUAServer.prototype.start, opts);
|
|
3741
3710
|
OPCUAServer.prototype.initialize = thenify.withCallback(OPCUAServer.prototype.initialize, opts);
|