node-opcua-server 2.51.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.
Files changed (100) hide show
  1. package/.mocharc.yml +10 -0
  2. package/LICENSE +20 -0
  3. package/dist/base_server.d.ts +110 -0
  4. package/dist/base_server.js +476 -0
  5. package/dist/base_server.js.map +1 -0
  6. package/dist/factory.d.ts +10 -0
  7. package/dist/factory.js +24 -0
  8. package/dist/factory.js.map +1 -0
  9. package/dist/history_server_capabilities.d.ts +35 -0
  10. package/dist/history_server_capabilities.js +44 -0
  11. package/dist/history_server_capabilities.js.map +1 -0
  12. package/dist/i_channel_data.d.ts +13 -0
  13. package/dist/i_channel_data.js +3 -0
  14. package/dist/i_channel_data.js.map +1 -0
  15. package/dist/i_register_server_manager.d.ts +16 -0
  16. package/dist/i_register_server_manager.js +3 -0
  17. package/dist/i_register_server_manager.js.map +1 -0
  18. package/dist/i_server_side_publish_engine.d.ts +36 -0
  19. package/dist/i_server_side_publish_engine.js +50 -0
  20. package/dist/i_server_side_publish_engine.js.map +1 -0
  21. package/dist/i_socket_data.d.ts +11 -0
  22. package/dist/i_socket_data.js +3 -0
  23. package/dist/i_socket_data.js.map +1 -0
  24. package/dist/index.d.ts +14 -0
  25. package/dist/index.js +27 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/monitored_item.d.ts +173 -0
  28. package/dist/monitored_item.js +1006 -0
  29. package/dist/monitored_item.js.map +1 -0
  30. package/dist/node_sampler.d.ts +3 -0
  31. package/dist/node_sampler.js +76 -0
  32. package/dist/node_sampler.js.map +1 -0
  33. package/dist/opcua_server.d.ts +668 -0
  34. package/dist/opcua_server.js +2407 -0
  35. package/dist/opcua_server.js.map +1 -0
  36. package/dist/queue.d.ts +11 -0
  37. package/dist/queue.js +71 -0
  38. package/dist/queue.js.map +1 -0
  39. package/dist/register_server_manager.d.ts +92 -0
  40. package/dist/register_server_manager.js +574 -0
  41. package/dist/register_server_manager.js.map +1 -0
  42. package/dist/register_server_manager_hidden.d.ts +17 -0
  43. package/dist/register_server_manager_hidden.js +28 -0
  44. package/dist/register_server_manager_hidden.js.map +1 -0
  45. package/dist/register_server_manager_mdns_only.d.ts +19 -0
  46. package/dist/register_server_manager_mdns_only.js +58 -0
  47. package/dist/register_server_manager_mdns_only.js.map +1 -0
  48. package/dist/server_capabilities.d.ts +61 -0
  49. package/dist/server_capabilities.js +109 -0
  50. package/dist/server_capabilities.js.map +1 -0
  51. package/dist/server_end_point.d.ts +180 -0
  52. package/dist/server_end_point.js +825 -0
  53. package/dist/server_end_point.js.map +1 -0
  54. package/dist/server_engine.d.ts +311 -0
  55. package/dist/server_engine.js +1659 -0
  56. package/dist/server_engine.js.map +1 -0
  57. package/dist/server_publish_engine.d.ts +109 -0
  58. package/dist/server_publish_engine.js +531 -0
  59. package/dist/server_publish_engine.js.map +1 -0
  60. package/dist/server_publish_engine_for_orphan_subscriptions.d.ts +16 -0
  61. package/dist/server_publish_engine_for_orphan_subscriptions.js +50 -0
  62. package/dist/server_publish_engine_for_orphan_subscriptions.js.map +1 -0
  63. package/dist/server_session.d.ts +176 -0
  64. package/dist/server_session.js +734 -0
  65. package/dist/server_session.js.map +1 -0
  66. package/dist/server_subscription.d.ts +393 -0
  67. package/dist/server_subscription.js +1313 -0
  68. package/dist/server_subscription.js.map +1 -0
  69. package/dist/sessions_compatible_for_transfer.d.ts +2 -0
  70. package/dist/sessions_compatible_for_transfer.js +36 -0
  71. package/dist/sessions_compatible_for_transfer.js.map +1 -0
  72. package/dist/validate_filter.d.ts +5 -0
  73. package/dist/validate_filter.js +64 -0
  74. package/dist/validate_filter.js.map +1 -0
  75. package/package.json +88 -0
  76. package/source/base_server.ts +617 -0
  77. package/source/factory.ts +25 -0
  78. package/source/history_server_capabilities.ts +75 -0
  79. package/source/i_channel_data.ts +17 -0
  80. package/source/i_register_server_manager.ts +24 -0
  81. package/source/i_server_side_publish_engine.ts +77 -0
  82. package/source/i_socket_data.ts +11 -0
  83. package/source/index.ts +14 -0
  84. package/source/monitored_item.ts +1303 -0
  85. package/source/node_sampler.ts +82 -0
  86. package/source/opcua_server.ts +3742 -0
  87. package/source/queue.ts +73 -0
  88. package/source/register_server_manager.ts +744 -0
  89. package/source/register_server_manager_hidden.ts +33 -0
  90. package/source/register_server_manager_mdns_only.ts +69 -0
  91. package/source/server_capabilities.ts +177 -0
  92. package/source/server_end_point.ts +1182 -0
  93. package/source/server_engine.ts +2167 -0
  94. package/source/server_publish_engine.ts +657 -0
  95. package/source/server_publish_engine_for_orphan_subscriptions.ts +52 -0
  96. package/source/server_session.ts +931 -0
  97. package/source/server_subscription.ts +1792 -0
  98. package/source/sessions_compatible_for_transfer.ts +33 -0
  99. package/source/validate_filter.ts +86 -0
  100. package/test_helpers/create_certificates.js +1 -0
@@ -0,0 +1,1182 @@
1
+ /**
2
+ * @module node-opcua-server
3
+ */
4
+ // tslint:disable:no-console
5
+ import * as async from "async";
6
+ import * as chalk from "chalk";
7
+ import { EventEmitter } from "events";
8
+ import * as net from "net";
9
+ import { Server, Socket } from "net";
10
+
11
+ import { assert } from "node-opcua-assert";
12
+ import { ICertificateManager, OPCUACertificateManager } from "node-opcua-certificate-manager";
13
+ import { Certificate, convertPEMtoDER, makeSHA1Thumbprint, PrivateKeyPEM, split_der } from "node-opcua-crypto";
14
+ import { checkDebugFlag, make_debugLog, make_errorLog } from "node-opcua-debug";
15
+ import { getFullyQualifiedDomainName, resolveFullyQualifiedDomainName } from "node-opcua-hostname";
16
+ import {
17
+ fromURI,
18
+ MessageSecurityMode,
19
+ SecurityPolicy,
20
+ ServerSecureChannelLayer,
21
+ ServerSecureChannelParent,
22
+ toURI,
23
+ AsymmetricAlgorithmSecurityHeader
24
+ } from "node-opcua-secure-channel";
25
+ import { UserTokenType } from "node-opcua-service-endpoints";
26
+ import { EndpointDescription } from "node-opcua-service-endpoints";
27
+ import { ApplicationDescription } from "node-opcua-service-endpoints";
28
+ import { IChannelData } from "./i_channel_data";
29
+ import { ISocketData } from "./i_socket_data";
30
+
31
+ const debugLog = make_debugLog(__filename);
32
+ const errorLog = make_errorLog(__filename);
33
+ const doDebug = checkDebugFlag(__filename);
34
+
35
+ const default_transportProfileUri = "http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary";
36
+
37
+ function extractSocketData(socket: net.Socket, reason: string): ISocketData {
38
+ const { bytesRead, bytesWritten, remoteAddress, remoteFamily, remotePort, localAddress, localPort } = socket;
39
+ const data: ISocketData = {
40
+ bytesRead,
41
+ bytesWritten,
42
+ localAddress,
43
+ localPort,
44
+ remoteAddress,
45
+ remoteFamily,
46
+ remotePort,
47
+ timestamp: new Date(),
48
+ reason
49
+ };
50
+ return data;
51
+ }
52
+
53
+ function extractChannelData(channel: ServerSecureChannelLayer): IChannelData {
54
+ const {
55
+ channelId,
56
+ clientCertificate,
57
+ clientNonce,
58
+ clientSecurityHeader,
59
+ securityHeader,
60
+ securityMode,
61
+ securityPolicy,
62
+ timeout,
63
+ transactionsCount
64
+ } = channel;
65
+
66
+ const channelData: IChannelData = {
67
+ channelId,
68
+ clientCertificate,
69
+ clientNonce,
70
+ clientSecurityHeader,
71
+ securityHeader,
72
+ securityMode,
73
+ securityPolicy,
74
+ timeout,
75
+ transactionsCount
76
+ };
77
+ return channelData;
78
+ }
79
+
80
+ function dumpChannelInfo(channels: ServerSecureChannelLayer[]): void {
81
+ function dumpChannel(channel: ServerSecureChannelLayer): void {
82
+ console.log("------------------------------------------------------");
83
+ console.log(" channelId = ", channel.channelId);
84
+ console.log(" timeout = ", channel.timeout);
85
+ console.log(" remoteAddress = ", channel.remoteAddress);
86
+ console.log(" remotePort = ", channel.remotePort);
87
+ console.log("");
88
+ console.log(" bytesWritten = ", channel.bytesWritten);
89
+ console.log(" bytesRead = ", channel.bytesRead);
90
+
91
+ const socket = (channel as any).transport?._socket;
92
+ if (!socket) {
93
+ console.log(" SOCKET IS CLOSED");
94
+ }
95
+ }
96
+
97
+ for (const channel of channels) {
98
+ dumpChannel(channel);
99
+ }
100
+ console.log("------------------------------------------------------");
101
+ }
102
+
103
+ const emptyCertificate = Buffer.alloc(0);
104
+ const emptyPrivateKeyPEM = "";
105
+
106
+ let OPCUAServerEndPointCounter = 0;
107
+
108
+ export interface OPCUAServerEndPointOptions {
109
+ /**
110
+ * the tcp port
111
+ */
112
+ port: number;
113
+ /**
114
+ * the DER certificate chain
115
+ */
116
+ certificateChain: Certificate;
117
+
118
+ /**
119
+ * privateKey
120
+ */
121
+ privateKey: PrivateKeyPEM;
122
+
123
+ certificateManager: OPCUACertificateManager;
124
+
125
+ /**
126
+ * the default secureToken lifetime @default=60000
127
+ */
128
+ defaultSecureTokenLifetime?: number;
129
+
130
+ /**
131
+ * the maximum number of connection allowed on the TCP server socket
132
+ * @default 20
133
+ */
134
+ maxConnections?: number;
135
+
136
+ /**
137
+ * the timeout for the TCP HEL/ACK transaction (in ms)
138
+ * @default 30000
139
+ */
140
+ timeout?: number;
141
+
142
+ serverInfo: ApplicationDescription;
143
+
144
+ objectFactory?: any;
145
+ }
146
+
147
+ export interface EndpointDescriptionParams {
148
+ allowAnonymous?: boolean;
149
+ restricted?: boolean;
150
+ allowUnsecurePassword?: boolean;
151
+ resourcePath?: string;
152
+ alternateHostname?: string[];
153
+ hostname: string;
154
+ securityPolicies: SecurityPolicy[];
155
+ }
156
+
157
+ export interface AddStandardEndpointDescriptionsParam {
158
+ securityModes?: MessageSecurityMode[];
159
+ securityPolicies?: SecurityPolicy[];
160
+ disableDiscovery?: boolean;
161
+
162
+ allowAnonymous?: boolean;
163
+ restricted?: boolean;
164
+ hostname?: string;
165
+ alternateHostname?: string[];
166
+ allowUnsecurePassword?: boolean;
167
+ resourcePath?: string;
168
+ }
169
+
170
+ function getUniqueName(name: string, collection: { [key: string]: number }) {
171
+ if (collection[name]) {
172
+ let counter = 0;
173
+ while (collection[name + "_" + counter.toString()]) {
174
+ counter++;
175
+ }
176
+ name = name + "_" + counter.toString();
177
+ collection[name] = 1;
178
+ return name;
179
+ } else {
180
+ collection[name] = 1;
181
+ return name;
182
+ }
183
+ }
184
+ /**
185
+ * OPCUAServerEndPoint a Server EndPoint.
186
+ * A sever end point is listening to one port
187
+ * note:
188
+ * see OPCUA Release 1.03 part 4 page 108 7.1 ApplicationDescription
189
+ */
190
+ export class OPCUAServerEndPoint extends EventEmitter implements ServerSecureChannelParent {
191
+ /**
192
+ * the tcp port
193
+ */
194
+ public port: number;
195
+ public certificateManager: OPCUACertificateManager;
196
+ public defaultSecureTokenLifetime: number;
197
+ public maxConnections: number;
198
+ public timeout: number;
199
+ public bytesWrittenInOldChannels: number;
200
+ public bytesReadInOldChannels: number;
201
+ public transactionsCountOldChannels: number;
202
+ public securityTokenCountOldChannels: number;
203
+ public serverInfo: ApplicationDescription;
204
+ public objectFactory: any;
205
+
206
+ public _on_new_channel?: (channel: ServerSecureChannelLayer) => void;
207
+ public _on_close_channel?: (channel: ServerSecureChannelLayer) => void;
208
+ public _on_connectionRefused?: (socketData: any) => void;
209
+ public _on_openSecureChannelFailure?: (socketData: any, channelData: any) => void;
210
+
211
+ private _certificateChain: Certificate;
212
+ private _privateKey: PrivateKeyPEM;
213
+ private _channels: { [key: string]: ServerSecureChannelLayer };
214
+ private _server?: Server;
215
+ private _endpoints: EndpointDescription[];
216
+ private _listen_callback: any;
217
+ private _started: boolean = false;
218
+ private _counter = OPCUAServerEndPointCounter++;
219
+ private _policy_deduplicator: { [key: string]: number } = {};
220
+ constructor(options: OPCUAServerEndPointOptions) {
221
+ super();
222
+
223
+ assert(!Object.prototype.hasOwnProperty.call(options,"certificate"), "expecting a certificateChain instead");
224
+ assert(Object.prototype.hasOwnProperty.call(options,"certificateChain"), "expecting a certificateChain");
225
+ assert(Object.prototype.hasOwnProperty.call(options,"privateKey"));
226
+
227
+ this.certificateManager = options.certificateManager;
228
+
229
+ options.port = options.port || 0;
230
+
231
+ this.port = parseInt(options.port.toString(), 10);
232
+ assert(typeof this.port === "number");
233
+
234
+ this._certificateChain = options.certificateChain;
235
+ this._privateKey = options.privateKey;
236
+
237
+ this._channels = {};
238
+
239
+ this.defaultSecureTokenLifetime = options.defaultSecureTokenLifetime || 600000;
240
+
241
+ this.maxConnections = options.maxConnections || 20;
242
+
243
+ this.timeout = options.timeout || 30000;
244
+
245
+ this._server = undefined;
246
+
247
+ this._setup_server();
248
+
249
+ this._endpoints = [];
250
+
251
+ this.objectFactory = options.objectFactory;
252
+
253
+ this.bytesWrittenInOldChannels = 0;
254
+ this.bytesReadInOldChannels = 0;
255
+ this.transactionsCountOldChannels = 0;
256
+ this.securityTokenCountOldChannels = 0;
257
+
258
+ this.serverInfo = options.serverInfo;
259
+ assert(this.serverInfo !== null && typeof this.serverInfo === "object");
260
+ }
261
+
262
+ public dispose() {
263
+ this._certificateChain = emptyCertificate;
264
+ this._privateKey = emptyPrivateKeyPEM;
265
+
266
+ assert(Object.keys(this._channels).length === 0, "OPCUAServerEndPoint channels must have been deleted");
267
+ this._channels = {};
268
+ this.serverInfo = new ApplicationDescription({});
269
+
270
+ this._endpoints = [];
271
+ assert(this._endpoints.length === 0, "endpoints must have been deleted");
272
+ this._endpoints = [];
273
+
274
+ this._server = undefined;
275
+ this._listen_callback = null;
276
+
277
+ this.removeAllListeners();
278
+ }
279
+
280
+ public toString(): string {
281
+ const privateKey1 = convertPEMtoDER(this.getPrivateKey());
282
+
283
+ const txt =
284
+ " end point" +
285
+ this._counter +
286
+ " port = " +
287
+ this.port +
288
+ " l = " +
289
+ this._endpoints.length +
290
+ " " +
291
+ makeSHA1Thumbprint(this.getCertificateChain()).toString("hex") +
292
+ " " +
293
+ makeSHA1Thumbprint(privateKey1).toString("hex");
294
+ return txt;
295
+ }
296
+
297
+ public getChannels(): ServerSecureChannelLayer[] {
298
+ return Object.values(this._channels);
299
+ }
300
+
301
+ /**
302
+ * Returns the X509 DER form of the server certificate
303
+ */
304
+ public getCertificate(): Certificate {
305
+ return split_der(this.getCertificateChain())[0];
306
+ }
307
+
308
+ /**
309
+ * Returns the X509 DER form of the server certificate
310
+ */
311
+ public getCertificateChain(): Certificate {
312
+ return this._certificateChain;
313
+ }
314
+
315
+ /**
316
+ * the private key
317
+ */
318
+ public getPrivateKey(): PrivateKeyPEM {
319
+ return this._privateKey;
320
+ }
321
+
322
+ /**
323
+ * The number of active channel on this end point.
324
+ */
325
+ public get currentChannelCount(): number {
326
+ return Object.keys(this._channels).length;
327
+ }
328
+
329
+ /**
330
+ * @method getEndpointDescription
331
+ * @param securityMode
332
+ * @param securityPolicy
333
+ * @return endpoint_description {EndpointDescription|null}
334
+ */
335
+ public getEndpointDescription(
336
+ securityMode: MessageSecurityMode,
337
+ securityPolicy: SecurityPolicy,
338
+ endpointUrl: string | null
339
+ ): EndpointDescription | null {
340
+ const endpoints = this.endpointDescriptions();
341
+ const arr = endpoints.filter(matching_endpoint.bind(this, securityMode, securityPolicy, endpointUrl));
342
+
343
+ if (endpointUrl && endpointUrl.length > 0 && !(arr.length === 0 || arr.length === 1)) {
344
+ errorLog("Several matching endpoints have been found : ");
345
+ for (const a of arr) {
346
+ errorLog(" ", a.endpointUrl, MessageSecurityMode[securityMode], securityPolicy);
347
+ }
348
+ }
349
+ return arr.length === 0 ? null : arr[0];
350
+ }
351
+
352
+ public addEndpointDescription(
353
+ securityMode: MessageSecurityMode,
354
+ securityPolicy: SecurityPolicy,
355
+ options?: EndpointDescriptionParams
356
+ ) {
357
+ if (!options) {
358
+ options = {
359
+ hostname: getFullyQualifiedDomainName(),
360
+ securityPolicies: [SecurityPolicy.Basic256Sha256]
361
+ };
362
+ }
363
+
364
+ options.allowAnonymous = options.allowAnonymous === undefined ? true : options.allowAnonymous;
365
+
366
+ // istanbul ignore next
367
+ if (securityMode === MessageSecurityMode.None && securityPolicy !== SecurityPolicy.None) {
368
+ throw new Error(" invalid security ");
369
+ }
370
+ // istanbul ignore next
371
+ if (securityMode !== MessageSecurityMode.None && securityPolicy === SecurityPolicy.None) {
372
+ throw new Error(" invalid security ");
373
+ }
374
+ //
375
+
376
+ const port = this.port;
377
+
378
+ // resource Path is a string added at the end of the url such as "/UA/Server"
379
+ const resourcePath = (options.resourcePath || "").replace(/\\/g, "/");
380
+
381
+ assert(resourcePath.length === 0 || resourcePath.charAt(0) === "/", "resourcePath should start with /");
382
+
383
+ const hostname = options.hostname || getFullyQualifiedDomainName();
384
+ const endpointUrl = `opc.tcp://${hostname}:${port}${resourcePath}`;
385
+
386
+ const endpoint_desc = this.getEndpointDescription(securityMode, securityPolicy, endpointUrl);
387
+
388
+ // istanbul ignore next
389
+ if (endpoint_desc) {
390
+ throw new Error(" endpoint already exist");
391
+ }
392
+
393
+ // now build endpointUrl
394
+ this._endpoints.push(
395
+ _makeEndpointDescription({
396
+ collection: this._policy_deduplicator,
397
+ endpointUrl,
398
+ hostname,
399
+ port,
400
+
401
+ server: this.serverInfo,
402
+ serverCertificateChain: this.getCertificateChain(),
403
+
404
+ securityMode,
405
+ securityPolicy,
406
+
407
+ allowAnonymous: options.allowAnonymous,
408
+ allowUnsecurePassword: options.allowUnsecurePassword,
409
+ resourcePath: options.resourcePath,
410
+
411
+ restricted: !!options.restricted,
412
+ securityPolicies: options?.securityPolicies || []
413
+ })
414
+ );
415
+ }
416
+
417
+ public addRestrictedEndpointDescription(options: EndpointDescriptionParams) {
418
+ options = { ...options };
419
+ options.restricted = true;
420
+ return this.addEndpointDescription(MessageSecurityMode.None, SecurityPolicy.None, options);
421
+ }
422
+
423
+ public addStandardEndpointDescriptions(options?: AddStandardEndpointDescriptionsParam) {
424
+ options = options || {};
425
+
426
+ options.securityModes = options.securityModes || defaultSecurityModes;
427
+ options.securityPolicies = options.securityPolicies || defaultSecurityPolicies;
428
+
429
+ const defaultHostname = options.hostname || getFullyQualifiedDomainName();
430
+
431
+ let hostnames: string[] = [defaultHostname];
432
+
433
+ options.alternateHostname = options.alternateHostname || [];
434
+ if (typeof options.alternateHostname === "string") {
435
+ options.alternateHostname = [options.alternateHostname];
436
+ }
437
+ // remove duplicates if any (uniq)
438
+ hostnames = [...new Set(hostnames.concat(options.alternateHostname as string[]))];
439
+
440
+ for (const alternateHostname of hostnames) {
441
+ const optionsE = options as EndpointDescriptionParams;
442
+ optionsE.hostname = alternateHostname;
443
+
444
+ if (options.securityModes.indexOf(MessageSecurityMode.None) >= 0) {
445
+ this.addEndpointDescription(MessageSecurityMode.None, SecurityPolicy.None, optionsE);
446
+ } else {
447
+ if (!options.disableDiscovery) {
448
+ this.addRestrictedEndpointDescription(optionsE);
449
+ }
450
+ }
451
+ for (const securityMode of options.securityModes) {
452
+ if (securityMode === MessageSecurityMode.None) {
453
+ continue;
454
+ }
455
+ for (const securityPolicy of options.securityPolicies) {
456
+ if (securityPolicy === SecurityPolicy.None) {
457
+ continue;
458
+ }
459
+ this.addEndpointDescription(securityMode, securityPolicy, optionsE);
460
+ }
461
+ }
462
+ }
463
+ }
464
+
465
+ /**
466
+ * returns the list of end point descriptions.
467
+ */
468
+ public endpointDescriptions(): EndpointDescription[] {
469
+ return this._endpoints;
470
+ }
471
+
472
+ /**
473
+ * @method listen
474
+ * @async
475
+ */
476
+ public listen(callback: (err?: Error) => void) {
477
+ assert(typeof callback === "function");
478
+ assert(!this._started, "OPCUAServerEndPoint is already listening");
479
+
480
+ this._listen_callback = callback;
481
+
482
+ this._server!.on("error", (err: Error) => {
483
+ debugLog(chalk.red.bold(" error") + " port = " + this.port, err);
484
+ this._started = false;
485
+ this._end_listen(err);
486
+ });
487
+ this._server!.on("listening", () => {
488
+ debugLog("server is listening");
489
+ });
490
+ this._server!.listen(
491
+ this.port,
492
+ /*"::",*/ (err?: Error) => {
493
+ // 'listening' listener
494
+ debugLog(chalk.green.bold("LISTENING TO PORT "), this.port, "err ", err);
495
+ assert(!err, " cannot listen to port ");
496
+ this._started = true;
497
+ this._end_listen();
498
+ }
499
+ );
500
+ }
501
+
502
+ public killClientSockets(callback: (err?: Error) => void) {
503
+ for (const channel of this.getChannels()) {
504
+ const hacked_channel = channel as any;
505
+ if (hacked_channel.transport && hacked_channel.transport._socket) {
506
+ // hacked_channel.transport._socket.close();
507
+ hacked_channel.transport._socket.destroy();
508
+ hacked_channel.transport._socket.emit("error", new Error("EPIPE"));
509
+ }
510
+ }
511
+ callback();
512
+ }
513
+
514
+ public suspendConnection(callback: (err?: Error) => void) {
515
+ if (!this._started) {
516
+ return callback(new Error("Connection already suspended !!"));
517
+ }
518
+
519
+ // Stops the server from accepting new connections and keeps existing connections.
520
+ // (note from nodejs doc: This function is asynchronous, the server is finally closed
521
+ // when all connections are ended and the server emits a 'close' event.
522
+ // The optional callback will be called once the 'close' event occurs.
523
+ // Unlike that event, it will be called with an Error as its only argument
524
+ // if the server was not open when it was closed.
525
+ this._server!.close(() => {
526
+ this._started = false;
527
+ debugLog("Connection has been closed !" + this.port);
528
+ });
529
+ this._started = false;
530
+ callback();
531
+ }
532
+
533
+ public restoreConnection(callback: (err?: Error) => void) {
534
+ this.listen(callback);
535
+ }
536
+
537
+ public abruptlyInterruptChannels() {
538
+ for (const channel of Object.values(this._channels)) {
539
+ channel.abruptlyInterrupt();
540
+ }
541
+ }
542
+
543
+ /**
544
+ * @method shutdown
545
+ * @async
546
+ */
547
+ public shutdown(callback: (err?: Error) => void) {
548
+ debugLog("OPCUAServerEndPoint#shutdown ");
549
+
550
+ if (this._started) {
551
+ // make sure we don't accept new connection any more ...
552
+ this.suspendConnection(() => {
553
+ // shutdown all opened channels ...
554
+ const _channels = Object.values(this._channels);
555
+ async.each(
556
+ _channels,
557
+ (channel: ServerSecureChannelLayer, callback1: (err?: Error) => void) => {
558
+ this.shutdown_channel(channel, callback1);
559
+ },
560
+ (err?: Error | null) => {
561
+ /* istanbul ignore next */
562
+ if (!(Object.keys(this._channels).length === 0)) {
563
+ errorLog(" Bad !");
564
+ }
565
+ assert(Object.keys(this._channels).length === 0, "channel must have unregistered themselves");
566
+ callback(err || undefined);
567
+ }
568
+ );
569
+ });
570
+ } else {
571
+ callback();
572
+ }
573
+ }
574
+
575
+ /**
576
+ * @method start
577
+ * @async
578
+ * @param callback
579
+ */
580
+ public start(callback: (err?: Error) => void): void {
581
+ assert(typeof callback === "function");
582
+ this.listen(callback);
583
+ }
584
+
585
+ public get bytesWritten(): number {
586
+ const channels = Object.values(this._channels);
587
+ return (
588
+ this.bytesWrittenInOldChannels +
589
+ channels.reduce((accumulated: number, channel: ServerSecureChannelLayer) => {
590
+ return accumulated + channel.bytesWritten;
591
+ }, 0)
592
+ );
593
+ }
594
+
595
+ public get bytesRead(): number {
596
+ const channels = Object.values(this._channels);
597
+ return (
598
+ this.bytesReadInOldChannels +
599
+ channels.reduce((accumulated: number, channel: ServerSecureChannelLayer) => {
600
+ return accumulated + channel.bytesRead;
601
+ }, 0)
602
+ );
603
+ }
604
+
605
+ public get transactionsCount(): number {
606
+ const channels = Object.values(this._channels);
607
+ return (
608
+ this.transactionsCountOldChannels +
609
+ channels.reduce((accumulated: number, channel: ServerSecureChannelLayer) => {
610
+ return accumulated + channel.transactionsCount;
611
+ }, 0)
612
+ );
613
+ }
614
+
615
+ public get securityTokenCount(): number {
616
+ const channels = Object.values(this._channels);
617
+ return (
618
+ this.securityTokenCountOldChannels +
619
+ channels.reduce((accumulated: number, channel: ServerSecureChannelLayer) => {
620
+ return accumulated + channel.securityTokenCount;
621
+ }, 0)
622
+ );
623
+ }
624
+
625
+ public get activeChannelCount(): number {
626
+ return Object.keys(this._channels).length;
627
+ }
628
+
629
+ private _dump_statistics() {
630
+ const self = this;
631
+
632
+ self._server!.getConnections((err: Error | null, count: number) => {
633
+ debugLog(chalk.cyan("CONCURRENT CONNECTION = "), count);
634
+ });
635
+ debugLog(chalk.cyan("MAX CONNECTIONS = "), self._server!.maxConnections);
636
+ }
637
+
638
+ private _setup_server() {
639
+ assert(!this._server);
640
+ this._server = net.createServer({ pauseOnConnect: true }, this._on_client_connection.bind(this));
641
+
642
+ // xx console.log(" Server with max connections ", self.maxConnections);
643
+ this._server.maxConnections = this.maxConnections + 1; // plus one extra
644
+
645
+ this._listen_callback = null;
646
+ this._server
647
+ .on("connection", (socket: NodeJS.Socket) => {
648
+ // istanbul ignore next
649
+ if (doDebug) {
650
+ this._dump_statistics();
651
+ debugLog("server connected with : " + (socket as any).remoteAddress + ":" + (socket as any).remotePort);
652
+ }
653
+ })
654
+ .on("close", () => {
655
+ debugLog("server closed : all connections have ended");
656
+ })
657
+ .on("error", (err: Error) => {
658
+ // this could be because the port is already in use
659
+ debugLog(chalk.red.bold("server error: "), err.message);
660
+ });
661
+ }
662
+
663
+ private _on_client_connection(socket: Socket) {
664
+ // a client is attempting a connection on the socket
665
+ (socket as any).setNoDelay(true);
666
+
667
+ debugLog("OPCUAServerEndPoint#_on_client_connection", this._started);
668
+ if (!this._started) {
669
+ debugLog(
670
+ chalk.bgWhite.cyan(
671
+ "OPCUAServerEndPoint#_on_client_connection " +
672
+ "SERVER END POINT IS PROBABLY SHUTTING DOWN !!! - Connection is refused"
673
+ )
674
+ );
675
+ socket.end();
676
+ return;
677
+ }
678
+
679
+ const establish_connection = () => {
680
+ const nbConnections = Object.keys(this._channels).length;
681
+ debugLog(
682
+ " nbConnections ",
683
+ nbConnections,
684
+ " self._server.maxConnections",
685
+ this._server!.maxConnections,
686
+ this.maxConnections
687
+ );
688
+ if (nbConnections >= this.maxConnections) {
689
+ console.log(
690
+ chalk.bgWhite.cyan(
691
+ "OPCUAServerEndPoint#_on_client_connection " +
692
+ "The maximum number of connection has been reached - Connection is refused"
693
+ )
694
+ );
695
+ const reason = "maxConnections reached (" + this.maxConnections + ")";
696
+ const socketData = extractSocketData(socket, reason);
697
+ this.emit("connectionRefused", socketData);
698
+
699
+ socket.end();
700
+ (socket as any).destroy();
701
+ return;
702
+ }
703
+
704
+ debugLog("OPCUAServerEndPoint._on_client_connection successful => New Channel");
705
+
706
+ const channel = new ServerSecureChannelLayer({
707
+ defaultSecureTokenLifetime: this.defaultSecureTokenLifetime,
708
+ // objectFactory: this.objectFactory,
709
+ parent: this,
710
+ timeout: this.timeout
711
+ });
712
+
713
+ socket.resume();
714
+
715
+ this._preregisterChannel(channel);
716
+
717
+ channel.init(socket, (err?: Error) => {
718
+ this._un_pre_registerChannel(channel);
719
+ debugLog(chalk.yellow.bold("Channel#init done"), err);
720
+ if (err) {
721
+ const reason = "openSecureChannel has Failed " + err.message;
722
+ const socketData = extractSocketData(socket, reason);
723
+ const channelData = extractChannelData(channel);
724
+ this.emit("openSecureChannelFailure", socketData, channelData);
725
+
726
+ socket.end();
727
+ (socket as any).destroy();
728
+ } else {
729
+ debugLog("server receiving a client connection");
730
+ this._registerChannel(channel);
731
+ }
732
+ });
733
+
734
+ channel.on("message", (message: any) => {
735
+ // forward
736
+ this.emit("message", message, channel, this);
737
+ });
738
+ };
739
+ // Each SecureChannel exists until it is explicitly closed or until the last token has expired and the overlap
740
+ // period has elapsed. A Server application should limit the number of SecureChannels.
741
+ // To protect against misbehaving Clients and denial of service attacks, the Server shall close the oldest
742
+ // SecureChannel that has no Session assigned before reaching the maximum number of supported SecureChannels.
743
+ this._prevent_DDOS_Attack(establish_connection);
744
+ }
745
+
746
+ private _preregisterChannel(channel: ServerSecureChannelLayer) {
747
+ // _preregisterChannel is used to keep track of channel for which
748
+ // that are in early stage of the hand shaking process.
749
+ // e.g HEL/ACK and OpenSecureChannel may not have been received yet
750
+ // as they will need to be interrupted when OPCUAServerEndPoint is closed
751
+ assert(this._started, "OPCUAServerEndPoint must be started");
752
+
753
+ assert(!this._channels.hasOwnProperty(channel.hashKey), " channel already preregistered!");
754
+
755
+ this._channels[channel.hashKey] = channel;
756
+
757
+ (channel as any)._unpreregisterChannelEvent = () => {
758
+ debugLog("Channel received an abort event during the preregistration phase");
759
+ this._un_pre_registerChannel(channel);
760
+ channel.dispose();
761
+ };
762
+ channel.on("abort", (channel as any)._unpreregisterChannelEvent);
763
+ }
764
+
765
+ private _un_pre_registerChannel(channel: ServerSecureChannelLayer) {
766
+ if (!this._channels[channel.hashKey]) {
767
+ debugLog("Already un preregistered ?", channel.hashKey);
768
+ return;
769
+ }
770
+
771
+ delete this._channels[channel.hashKey];
772
+ assert(typeof (channel as any)._unpreregisterChannelEvent === "function");
773
+ channel.removeListener("abort", (channel as any)._unpreregisterChannelEvent);
774
+ (channel as any)._unpreregisterChannelEvent = null;
775
+ }
776
+
777
+ /**
778
+ * @method _registerChannel
779
+ * @param channel
780
+ * @private
781
+ */
782
+ private _registerChannel(channel: ServerSecureChannelLayer) {
783
+ if (this._started) {
784
+ debugLog(chalk.red("_registerChannel = "), "channel.hashKey = ", channel.hashKey);
785
+
786
+ assert(!this._channels[channel.hashKey]);
787
+ this._channels[channel.hashKey] = channel;
788
+
789
+ /**
790
+ * @event newChannel
791
+ * @param channel
792
+ */
793
+ this.emit("newChannel", channel);
794
+
795
+ channel.on("abort", () => {
796
+ this._unregisterChannel(channel);
797
+ });
798
+ } else {
799
+ debugLog("OPCUAServerEndPoint#_registerChannel called when end point is shutdown !");
800
+ debugLog(" -> channel will be forcefully terminated");
801
+ channel.close();
802
+ channel.dispose();
803
+ }
804
+ }
805
+
806
+ /**
807
+ * @method _unregisterChannel
808
+ * @param channel
809
+ * @private
810
+ */
811
+ private _unregisterChannel(channel: ServerSecureChannelLayer): void {
812
+ debugLog("_un-registerChannel channel.hashKey", channel.hashKey);
813
+ if (!this._channels.hasOwnProperty(channel.hashKey)) {
814
+ return;
815
+ }
816
+
817
+ assert(this._channels.hasOwnProperty(channel.hashKey), "channel is not registered");
818
+
819
+ /**
820
+ * @event closeChannel
821
+ * @param channel
822
+ */
823
+ this.emit("closeChannel", channel);
824
+
825
+ // keep trace of statistics data from old channel for our own accumulated stats.
826
+ this.bytesWrittenInOldChannels += channel.bytesWritten;
827
+ this.bytesReadInOldChannels += channel.bytesRead;
828
+ this.transactionsCountOldChannels += channel.transactionsCount;
829
+ delete this._channels[channel.hashKey];
830
+
831
+ // istanbul ignore next
832
+ if (doDebug) {
833
+ this._dump_statistics();
834
+ debugLog("un-registering channel - Count = ", this.currentChannelCount);
835
+ }
836
+
837
+ /// channel.dispose();
838
+ }
839
+
840
+ private _end_listen(err?: Error) {
841
+ assert(typeof this._listen_callback === "function");
842
+ this._listen_callback(err);
843
+ this._listen_callback = null;
844
+ }
845
+
846
+ /**
847
+ * shutdown_channel
848
+ * @param channel
849
+ * @param inner_callback
850
+ */
851
+ private shutdown_channel(channel: ServerSecureChannelLayer, inner_callback: (err?: Error) => void) {
852
+ assert(typeof inner_callback === "function");
853
+ channel.once("close", () => {
854
+ // xx console.log(" ON CLOSED !!!!");
855
+ });
856
+
857
+ channel.close(() => {
858
+ this._unregisterChannel(channel);
859
+ setImmediate(inner_callback);
860
+ });
861
+ }
862
+
863
+ /**
864
+ * @private
865
+ */
866
+ private _prevent_DDOS_Attack(establish_connection: () => void) {
867
+ const nbConnections = this.activeChannelCount;
868
+
869
+ if (nbConnections >= this.maxConnections) {
870
+ // istanbul ignore next
871
+ console.log(chalk.bgRed.white("PREVENTING DDOS ATTACK => Closing unused channels"));
872
+
873
+ const unused_channels: ServerSecureChannelLayer[] = this.getChannels().filter((channel1: ServerSecureChannelLayer) => {
874
+ return !channel1.isOpened && !channel1.hasSession;
875
+ });
876
+ if (unused_channels.length === 0) {
877
+ // all channels are in used , we cannot get any
878
+
879
+ // istanbul ignore next
880
+ console.log(" - all channel are used !!!!");
881
+ dumpChannelInfo(this.getChannels());
882
+ setImmediate(establish_connection);
883
+ return;
884
+ }
885
+ // istanbul ignore next
886
+ if (doDebug) {
887
+ console.log(
888
+ " - Unused channels that can be clobbered",
889
+ unused_channels.map((channel1: ServerSecureChannelLayer) => channel1.hashKey).join(" ")
890
+ );
891
+ }
892
+ const channel = unused_channels[0];
893
+
894
+ channel.close(() => {
895
+ // istanbul ignore next
896
+ if (doDebug) {
897
+ console.log(" _ Unused channel has been closed ", channel.hashKey);
898
+ }
899
+ this._unregisterChannel(channel);
900
+ establish_connection();
901
+ });
902
+ } else {
903
+ setImmediate(establish_connection);
904
+ }
905
+ }
906
+ }
907
+
908
+ interface MakeEndpointDescriptionOptions {
909
+ /**
910
+ * port number s
911
+ */
912
+ port: number;
913
+
914
+ /**
915
+ * @default default hostname (default value will be full qualified domain name)
916
+ */
917
+ hostname: string;
918
+ /**
919
+ *
920
+ */
921
+ endpointUrl: string;
922
+
923
+ serverCertificateChain: Certificate;
924
+ /**
925
+ *
926
+ */
927
+ securityMode: MessageSecurityMode;
928
+ /**
929
+ *
930
+ */
931
+ securityPolicy: SecurityPolicy;
932
+
933
+ securityLevel?: number;
934
+
935
+ server: ApplicationDescription;
936
+ /*
937
+ {
938
+ applicationUri: string;
939
+ applicationName: LocalizedTextOptions;
940
+ applicationType: ApplicationType;
941
+ gatewayServerUri: string;
942
+ discoveryProfileUri: string;
943
+ discoveryUrls: string[];
944
+ };
945
+ */
946
+ resourcePath?: string;
947
+ allowAnonymous?: boolean; // default true
948
+
949
+ // allow un-encrypted password in userNameIdentity
950
+ allowUnsecurePassword?: boolean; // default false
951
+
952
+ /**
953
+ * onlyCertificateLessConnection
954
+ */
955
+ onlyCertificateLessConnection?: boolean;
956
+
957
+ restricted: boolean;
958
+
959
+ collection: { [key: string]: number };
960
+
961
+ securityPolicies: SecurityPolicy[];
962
+ }
963
+
964
+ interface EndpointDescriptionEx extends EndpointDescription {
965
+ restricted: boolean;
966
+ }
967
+
968
+ function estimateSecurityLevel(securityMode: MessageSecurityMode, securityPolicy: SecurityPolicy): number {
969
+ if (securityMode === MessageSecurityMode.None) {
970
+ return 1;
971
+ }
972
+ let offset = 100;
973
+ if (securityMode === MessageSecurityMode.SignAndEncrypt) {
974
+ offset = 200;
975
+ }
976
+ switch (securityPolicy) {
977
+ case SecurityPolicy.Basic128:
978
+ case SecurityPolicy.Basic128Rsa15:
979
+ case SecurityPolicy.Basic192:
980
+ return 2; // deprecated => low
981
+ case SecurityPolicy.Basic192Rsa15:
982
+ return 3; // deprecated => low
983
+ case SecurityPolicy.Basic256:
984
+ return 4; // deprecated => low
985
+ case SecurityPolicy.Basic256Rsa15:
986
+ return 4 + offset;
987
+ case SecurityPolicy.Basic256Sha256:
988
+ return 6 + offset;
989
+ case SecurityPolicy.Aes128_Sha256_RsaOaep:
990
+ return 1;
991
+
992
+ default:
993
+ case SecurityPolicy.None:
994
+ return 1;
995
+ }
996
+ }
997
+ /**
998
+ * @private
999
+ */
1000
+ function _makeEndpointDescription(options: MakeEndpointDescriptionOptions): EndpointDescriptionEx {
1001
+ assert(isFinite(options.port), "expecting a valid port number");
1002
+ assert(Object.prototype.hasOwnProperty.call(options,"serverCertificateChain"));
1003
+ assert(!Object.prototype.hasOwnProperty.call(options,"serverCertificate"));
1004
+ assert(!!options.securityMode); // s.MessageSecurityMode
1005
+ assert(!!options.securityPolicy);
1006
+ assert(options.server !== null && typeof options.server === "object");
1007
+ assert(!!options.hostname && typeof options.hostname === "string");
1008
+ assert(typeof options.restricted === "boolean");
1009
+
1010
+ const u = (n: string) => getUniqueName(n, options.collection);
1011
+ options.securityLevel =
1012
+ options.securityLevel === undefined
1013
+ ? estimateSecurityLevel(options.securityMode, options.securityPolicy)
1014
+ : options.securityLevel;
1015
+ assert(isFinite(options.securityLevel), "expecting a valid securityLevel");
1016
+
1017
+ const securityPolicyUri = toURI(options.securityPolicy);
1018
+
1019
+ const userIdentityTokens = [];
1020
+
1021
+ if (options.securityPolicy === SecurityPolicy.None) {
1022
+ if (options.allowUnsecurePassword) {
1023
+ userIdentityTokens.push({
1024
+ policyId: u("username_unsecure"),
1025
+ tokenType: UserTokenType.UserName,
1026
+
1027
+ issuedTokenType: null,
1028
+ issuerEndpointUrl: null,
1029
+ securityPolicyUri: null
1030
+ });
1031
+ }
1032
+
1033
+ const onlyCertificateLessConnection =
1034
+ options.onlyCertificateLessConnection === undefined ? false : options.onlyCertificateLessConnection;
1035
+
1036
+ if (!onlyCertificateLessConnection) {
1037
+ if (options.securityPolicies.indexOf(SecurityPolicy.Basic256) >= 0) {
1038
+ userIdentityTokens.push({
1039
+ policyId: u("username_basic256"),
1040
+ tokenType: UserTokenType.UserName,
1041
+
1042
+ issuedTokenType: null,
1043
+ issuerEndpointUrl: null,
1044
+ securityPolicyUri: SecurityPolicy.Basic256
1045
+ });
1046
+ }
1047
+
1048
+ if (options.securityPolicies.indexOf(SecurityPolicy.Basic128Rsa15) >= 0) {
1049
+ userIdentityTokens.push({
1050
+ policyId: u("username_basic128Rsa15"),
1051
+ tokenType: UserTokenType.UserName,
1052
+
1053
+ issuedTokenType: null,
1054
+ issuerEndpointUrl: null,
1055
+ securityPolicyUri: SecurityPolicy.Basic128Rsa15
1056
+ });
1057
+ }
1058
+
1059
+ if (options.securityPolicies.indexOf(SecurityPolicy.Basic256Sha256) >= 0) {
1060
+ userIdentityTokens.push({
1061
+ policyId: u("username_basic256Sha256"),
1062
+ tokenType: UserTokenType.UserName,
1063
+
1064
+ issuedTokenType: null,
1065
+ issuerEndpointUrl: null,
1066
+ securityPolicyUri: SecurityPolicy.Basic256Sha256
1067
+ });
1068
+ }
1069
+
1070
+ // X509
1071
+ if (options.securityPolicies.indexOf(SecurityPolicy.Basic256) >= 0) {
1072
+ userIdentityTokens.push({
1073
+ policyId: u("certificate_basic256"),
1074
+ tokenType: UserTokenType.UserName,
1075
+
1076
+ issuedTokenType: null,
1077
+ issuerEndpointUrl: null,
1078
+ securityPolicyUri: SecurityPolicy.Basic256
1079
+ });
1080
+ }
1081
+ // Certificate
1082
+ if (options.securityPolicies.indexOf(SecurityPolicy.Basic256Sha256) >= 0) {
1083
+ userIdentityTokens.push({
1084
+ policyId: u("certificate_basic256Sha256"),
1085
+ tokenType: UserTokenType.Certificate,
1086
+
1087
+ issuedTokenType: null,
1088
+ issuerEndpointUrl: null,
1089
+ securityPolicyUri: SecurityPolicy.Basic256Sha256
1090
+ });
1091
+ }
1092
+ }
1093
+ } else {
1094
+ // note:
1095
+ // when channel session security is not "None",
1096
+ // userIdentityTokens can be left to null.
1097
+ // in this case this mean that secure policy will be the same as connection security policy
1098
+ userIdentityTokens.push({
1099
+ policyId: u("usernamePassword"),
1100
+ tokenType: UserTokenType.UserName,
1101
+
1102
+ issuedTokenType: null,
1103
+ issuerEndpointUrl: null,
1104
+ securityPolicyUri: null
1105
+ });
1106
+
1107
+ userIdentityTokens.push({
1108
+ policyId: u("certificateX509"),
1109
+ tokenType: UserTokenType.Certificate,
1110
+
1111
+ issuedTokenType: null,
1112
+ issuerEndpointUrl: null,
1113
+ securityPolicyUri: null
1114
+ });
1115
+ }
1116
+
1117
+ if (options.allowAnonymous) {
1118
+ userIdentityTokens.push({
1119
+ policyId: u("anonymous"),
1120
+ tokenType: UserTokenType.Anonymous,
1121
+
1122
+ issuedTokenType: null,
1123
+ issuerEndpointUrl: null,
1124
+ securityPolicyUri: null
1125
+ });
1126
+ }
1127
+
1128
+ // return the endpoint object
1129
+ const endpoint = new EndpointDescription({
1130
+ endpointUrl: options.endpointUrl,
1131
+
1132
+ server: undefined, // options.server,
1133
+ serverCertificate: options.serverCertificateChain,
1134
+
1135
+ securityMode: options.securityMode,
1136
+ securityPolicyUri,
1137
+ userIdentityTokens,
1138
+
1139
+ securityLevel: options.securityLevel,
1140
+ transportProfileUri: default_transportProfileUri
1141
+ }) as EndpointDescriptionEx;
1142
+
1143
+ (endpoint as any).__defineGetter__("endpointUrl", () => {
1144
+ return resolveFullyQualifiedDomainName(options.endpointUrl);
1145
+ });
1146
+
1147
+ endpoint.server = options.server;
1148
+
1149
+ endpoint.restricted = options.restricted;
1150
+
1151
+ return endpoint;
1152
+ }
1153
+
1154
+ /**
1155
+ * return true if the end point matches security mode and policy
1156
+ * @param endpoint
1157
+ * @param securityMode
1158
+ * @param securityPolicy
1159
+ * @internal
1160
+ *
1161
+ */
1162
+ function matching_endpoint(
1163
+ securityMode: MessageSecurityMode,
1164
+ securityPolicy: SecurityPolicy,
1165
+ endpointUrl: string | null,
1166
+ endpoint: EndpointDescription
1167
+ ): boolean {
1168
+ assert(endpoint instanceof EndpointDescription);
1169
+ const endpoint_securityPolicy = fromURI(endpoint.securityPolicyUri);
1170
+ if (endpointUrl && endpoint.endpointUrl! !== endpointUrl) {
1171
+ return false;
1172
+ }
1173
+ return endpoint.securityMode === securityMode && endpoint_securityPolicy === securityPolicy;
1174
+ }
1175
+
1176
+ const defaultSecurityModes = [MessageSecurityMode.None, MessageSecurityMode.Sign, MessageSecurityMode.SignAndEncrypt];
1177
+ const defaultSecurityPolicies = [
1178
+ SecurityPolicy.Basic128Rsa15,
1179
+ SecurityPolicy.Basic256,
1180
+ // xx UNUSED!! SecurityPolicy.Basic256Rsa15,
1181
+ SecurityPolicy.Basic256Sha256
1182
+ ];