node-opcua-server 2.163.1 → 2.165.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/addressSpace_accessor.js +7 -5
  2. package/dist/addressSpace_accessor.js.map +1 -1
  3. package/dist/base_server.d.ts +95 -18
  4. package/dist/base_server.js +217 -69
  5. package/dist/base_server.js.map +1 -1
  6. package/dist/monitored_item.js +32 -32
  7. package/dist/monitored_item.js.map +1 -1
  8. package/dist/node_sampler.js +1 -1
  9. package/dist/node_sampler.js.map +1 -1
  10. package/dist/opcua_server.d.ts +171 -123
  11. package/dist/opcua_server.js +466 -223
  12. package/dist/opcua_server.js.map +1 -1
  13. package/dist/register_server_manager.d.ts +2 -2
  14. package/dist/register_server_manager.js +12 -6
  15. package/dist/register_server_manager.js.map +1 -1
  16. package/dist/register_server_manager_mdns_only.js +1 -1
  17. package/dist/register_server_manager_mdns_only.js.map +1 -1
  18. package/dist/server_end_point.d.ts +108 -12
  19. package/dist/server_end_point.js +157 -57
  20. package/dist/server_end_point.js.map +1 -1
  21. package/dist/server_engine.d.ts +32 -14
  22. package/dist/server_engine.js +160 -59
  23. package/dist/server_engine.js.map +1 -1
  24. package/dist/server_publish_engine.js +5 -5
  25. package/dist/server_publish_engine.js.map +1 -1
  26. package/dist/server_session.js +4 -4
  27. package/dist/server_session.js.map +1 -1
  28. package/dist/server_subscription.js +18 -18
  29. package/dist/server_subscription.js.map +1 -1
  30. package/dist/sessions_compatible_for_transfer.js +1 -1
  31. package/dist/sessions_compatible_for_transfer.js.map +1 -1
  32. package/package.json +47 -47
  33. package/source/addressSpace_accessor.ts +6 -3
  34. package/source/base_server.ts +252 -90
  35. package/source/monitored_item.ts +32 -32
  36. package/source/node_sampler.ts +1 -1
  37. package/source/opcua_server.ts +674 -489
  38. package/source/register_server_manager.ts +11 -5
  39. package/source/register_server_manager_mdns_only.ts +1 -1
  40. package/source/server_end_point.ts +278 -94
  41. package/source/server_engine.ts +246 -135
  42. package/source/server_publish_engine.ts +5 -5
  43. package/source/server_session.ts +4 -4
  44. package/source/server_subscription.ts +18 -18
  45. package/source/sessions_compatible_for_transfer.ts +4 -2
@@ -2,76 +2,74 @@
2
2
  /**
3
3
  * @module node-opcua-server
4
4
  */
5
- import { randomBytes } from "crypto";
6
- import { EventEmitter } from "events";
7
- import { callbackify, types } from "util";
5
+ import { randomBytes } from "node:crypto";
6
+ import { callbackify, types } from "node:util";
8
7
 
9
- import async from "async";
10
8
  import chalk from "chalk";
11
-
12
- import { extractFullyQualifiedDomainName, getFullyQualifiedDomainName } from "node-opcua-hostname";
13
-
14
- import { assert } from "node-opcua-assert";
15
- import { isNullOrUndefined } from "node-opcua-utils";
16
-
17
9
  import {
18
- AddressSpace,
19
- PseudoVariantBoolean,
20
- PseudoVariantByteString,
21
- PseudoVariantDateTime,
22
- PseudoVariantDuration,
23
- PseudoVariantExtensionObject,
24
- PseudoVariantExtensionObjectArray,
25
- PseudoVariantLocalizedText,
26
- PseudoVariantNodeId,
27
- PseudoVariantString,
28
- RaiseEventData,
29
- SessionContext,
30
- UAObject,
31
- UAVariable,
32
- ISessionContext,
33
- UAView,
34
- EventTypeLike,
35
- UAObjectType,
36
- PseudoVariantStringPredefined,
10
+ type AddressSpace,
11
+ type EventTypeLike,
12
+ type IRolePolicyOverride,
13
+ type IServerBase,
14
+ type ISessionContext,
37
15
  innerBrowse,
38
16
  innerBrowseNext,
39
- UAEventType
17
+ type PseudoVariant,
18
+ type PseudoVariantBoolean,
19
+ type PseudoVariantByteString,
20
+ type PseudoVariantDateTime,
21
+ type PseudoVariantDuration,
22
+ type PseudoVariantExtensionObject,
23
+ type PseudoVariantExtensionObjectArray,
24
+ type PseudoVariantLocalizedText,
25
+ type PseudoVariantNodeId,
26
+ type PseudoVariantString,
27
+ type PseudoVariantStringPredefined,
28
+ type RaiseEventData,
29
+ SessionContext,
30
+ type UAEventType,
31
+ type UAObject,
32
+ type UAObjectType,
33
+ type UAVariable,
34
+ type UAView
40
35
  } from "node-opcua-address-space";
41
- import { getDefaultCertificateManager, OPCUACertificateManager } from "node-opcua-certificate-manager";
36
+ import { assert } from "node-opcua-assert";
37
+ import type { ByteString, UAString } from "node-opcua-basic-types";
38
+ import { getDefaultCertificateManager, type OPCUACertificateManager } from "node-opcua-certificate-manager";
42
39
  import { ServerState } from "node-opcua-common";
43
- import { Certificate, exploreCertificate, Nonce } from "node-opcua-crypto/web";
40
+ import { type Certificate, exploreCertificate, type Nonce } from "node-opcua-crypto/web";
44
41
  import {
45
42
  AttributeIds,
46
43
  filterDiagnosticOperationLevel,
47
44
  filterDiagnosticServiceLevel,
45
+ LocalizedText,
48
46
  NodeClass,
49
47
  RESPONSE_DIAGNOSTICS_MASK_ALL
50
48
  } from "node-opcua-data-model";
51
49
  import { DataValue } from "node-opcua-data-value";
52
50
  import { dump, make_debugLog, make_errorLog, make_warningLog } from "node-opcua-debug";
53
- import { NodeId } from "node-opcua-nodeid";
51
+ import { extractFullyQualifiedDomainName, getFullyQualifiedDomainName, isIPAddress } from "node-opcua-hostname";
52
+ import type { NodeId } from "node-opcua-nodeid";
54
53
  import { ObjectRegistry } from "node-opcua-object-registry";
55
54
  import {
56
- AsymmetricAlgorithmSecurityHeader,
57
55
  coerceSecurityPolicy,
58
56
  computeSignature,
59
57
  fromURI,
60
58
  getCryptoFactory,
61
- Message,
59
+ type Message,
62
60
  MessageSecurityMode,
63
61
  nonceAlreadyBeenUsed,
64
- Request,
65
- Response,
62
+ type Request,
63
+ type Response,
66
64
  SecurityPolicy,
67
- ServerSecureChannelLayer,
68
- SignatureData,
65
+ type ServerSecureChannelLayer,
66
+ type SignatureData,
69
67
  verifySignature
70
68
  } from "node-opcua-secure-channel";
71
69
  import { BrowseNextRequest, BrowseNextResponse, BrowseRequest, BrowseResponse } from "node-opcua-service-browse";
72
70
  import { CallRequest, CallResponse } from "node-opcua-service-call";
73
71
  import { ApplicationType, UserTokenType } from "node-opcua-service-endpoints";
74
- import { HistoryReadRequest, HistoryReadResponse, HistoryReadResult, HistoryUpdateResponse } from "node-opcua-service-history";
72
+ import { HistoryReadRequest, HistoryReadResponse, type HistoryReadResult, HistoryUpdateResponse } from "node-opcua-service-history";
75
73
  import {
76
74
  AddNodesResponse,
77
75
  AddReferencesResponse,
@@ -129,57 +127,48 @@ import {
129
127
  TranslateBrowsePathsToNodeIdsResponse
130
128
  } from "node-opcua-service-translate-browse-path";
131
129
  import { WriteRequest, WriteResponse } from "node-opcua-service-write";
132
- import { CallbackT, ErrorCallback, StatusCode, StatusCodes } from "node-opcua-status-code";
130
+ import { type CallbackT, StatusCode, StatusCodes } from "node-opcua-status-code";
133
131
  import {
134
- ApplicationDescriptionOptions,
135
- BrowseResult,
136
- BuildInfo,
137
- CallMethodResultOptions,
132
+ type ApplicationDescriptionOptions,
133
+ type BrowseDescriptionOptions,
134
+ type BrowseResult,
135
+ type BuildInfo,
136
+ type BuildInfoOptions,
138
137
  CancelResponse,
139
138
  EndpointDescription,
140
- MonitoredItemModifyRequest,
141
- MonitoringMode,
142
- UserIdentityToken,
143
- UserTokenPolicy,
144
- BuildInfoOptions,
145
- MonitoredItemCreateResult,
146
139
  IssuedIdentityToken,
147
- BrowseResultOptions,
140
+ type MonitoredItemCreateResult,
141
+ type MonitoredItemModifyRequest,
142
+ MonitoringMode,
148
143
  ServiceFault,
149
- ServerDiagnosticsSummaryDataType,
150
- BrowseDescriptionOptions
144
+ type UserIdentityToken,
145
+ type UserTokenPolicy
151
146
  } from "node-opcua-types";
152
- import { DataType } from "node-opcua-variant";
153
- import { VariantArrayType } from "node-opcua-variant";
154
- import { matchUri } from "node-opcua-utils";
147
+ import { isNullOrUndefined, matchUri } from "node-opcua-utils";
148
+ import { DataType, type Variant, VariantArrayType } from "node-opcua-variant";
149
+ import { withCallback } from "thenify-ex";
155
150
 
156
- import { UAString } from "node-opcua-basic-types";
157
- import { ObjectIds, ObjectTypeIds } from "node-opcua-constants";
158
- import { OPCUABaseServer, OPCUABaseServerOptions } from "./base_server";
151
+ import { OPCUABaseServer, type OPCUABaseServerOptions } from "./base_server";
159
152
  import { Factory } from "./factory";
160
- import { IRegisterServerManager } from "./i_register_server_manager";
153
+ import type { IChannelData } from "./i_channel_data";
154
+ import type { IRegisterServerManager } from "./i_register_server_manager";
155
+ import type { ISocketData } from "./i_socket_data";
161
156
  import { MonitoredItem } from "./monitored_item";
162
157
  import { RegisterServerManager } from "./register_server_manager";
163
158
  import { RegisterServerManagerHidden } from "./register_server_manager_hidden";
164
159
  import { RegisterServerManagerMDNSONLY } from "./register_server_manager_mdns_only";
165
- import { ServerCapabilitiesOptions } from "./server_capabilities";
166
- import { EndpointDescriptionEx, IServerTransportSettings, OPCUAServerEndPoint } from "./server_end_point";
167
- import { ClosingReason, CreateSessionOption, ServerEngine } from "./server_engine";
168
- import { ServerSession } from "./server_session";
169
- import { CreateMonitoredItemHook, DeleteMonitoredItemHook, Subscription } from "./server_subscription";
170
- import { ISocketData } from "./i_socket_data";
171
- import { IChannelData } from "./i_channel_data";
172
- import { UAUserManagerBase, makeUserManager, UserManagerOptions } from "./user_manager";
160
+ import type { SamplingFunc } from "./sampling_func";
161
+ import type { ServerCapabilitiesOptions } from "./server_capabilities";
162
+ import { type AdvertisedEndpoint, type EndpointDescriptionEx, type IServerTransportSettings, OPCUAServerEndPoint, normalizeAdvertisedEndpoints, parseOpcTcpUrl } from "./server_end_point";
163
+ import { type ClosingReason, type CreateSessionOption, ServerEngine } from "./server_engine";
164
+ import type { ServerSession } from "./server_session";
165
+ import type { CreateMonitoredItemHook, DeleteMonitoredItemHook, Subscription } from "./server_subscription";
166
+ import { makeUserManager, type UAUserManagerBase, type UserManagerOptions } from "./user_manager";
173
167
  import { bindRoleSet } from "./user_manager_ua";
174
- import { SamplingFunc } from "./sampling_func";
175
168
 
176
169
  function isSubscriptionIdInvalid(subscriptionId: number): boolean {
177
170
  return subscriptionId < 0 || subscriptionId >= 0xffffffff;
178
171
  }
179
-
180
- // tslint:disable-next-line:no-var-requires
181
- import { withCallback } from "thenify-ex";
182
- // tslint:disable-next-line:no-var-requires
183
172
  const package_info = require("../package.json");
184
173
  const debugLog = make_debugLog(__filename);
185
174
  const errorLog = make_errorLog(__filename);
@@ -187,11 +176,16 @@ const warningLog = make_warningLog(__filename);
187
176
 
188
177
  const default_maxConnectionsPerEndpoint = 10;
189
178
 
190
- function g_sendError(channel: ServerSecureChannelLayer, message: Message, ResponseClass: any, statusCode: StatusCode): void {
179
+ function g_sendError(
180
+ channel: ServerSecureChannelLayer,
181
+ message: Message,
182
+ _ResponseClass: ResponseClassType,
183
+ statusCode: StatusCode
184
+ ): void {
191
185
  const response = new ServiceFault({
192
186
  responseHeader: { serviceResult: statusCode }
193
187
  });
194
- return channel.send_response("MSG", response, message);
188
+ channel.send_response("MSG", response, message);
195
189
  }
196
190
 
197
191
  const default_build_info: BuildInfoOptions = {
@@ -238,7 +232,7 @@ function _adjust_session_timeout(sessionTimeout: number) {
238
232
 
239
233
  function channel_has_session(channel: ServerSecureChannelLayer, session: ServerSession): boolean {
240
234
  if (session.channel === channel) {
241
- assert(Object.prototype.hasOwnProperty.call(channel.sessionTokens, session.authenticationToken.toString()));
235
+ assert(Object.hasOwn(channel.sessionTokens, session.authenticationToken.toString()));
242
236
  return true;
243
237
  }
244
238
  return false;
@@ -253,13 +247,13 @@ function moveSessionToChannel(session: ServerSession, channel: ServerSecureChann
253
247
  session._detach_channel();
254
248
  session._attach_channel(channel);
255
249
 
256
- assert(session.channel!.channelId === channel.channelId);
250
+ assert(session.channel?.channelId === channel.channelId);
257
251
  }
258
252
 
259
253
  async function _attempt_to_close_some_old_unactivated_session(server: OPCUAServer) {
260
- const session = server.engine!.getOldestInactiveSession();
254
+ const session = server.engine?.getOldestInactiveSession();
261
255
  if (session) {
262
- await server.engine!.closeSession(session.authenticationToken, false, "Forcing");
256
+ await server.engine?.closeSession(session.authenticationToken, false, "Forcing");
263
257
  }
264
258
  }
265
259
 
@@ -282,12 +276,12 @@ function getRequiredEndpointInfo(endpoint: EndpointDescription) {
282
276
  userIdentityTokens: endpoint.userIdentityTokens
283
277
  });
284
278
  // reduce even further by explicitly setting unwanted members to null
285
- e.server.applicationName = null as any;
279
+ e.server.applicationName = new LocalizedText({ text: "" });
286
280
  // xx e.server.applicationType = null as any;
287
281
  e.server.gatewayServerUri = null;
288
282
  e.server.discoveryProfileUri = null;
289
283
  e.server.discoveryUrls = null;
290
- e.serverCertificate = null as any;
284
+ e.serverCertificate = null as unknown as Buffer;
291
285
  return e;
292
286
  }
293
287
 
@@ -301,8 +295,8 @@ function _serverEndpointsForCreateSessionResponse(server: OPCUAServer, endpointU
301
295
  // https://reference.opcfoundation.org/v104/Core/docs/Part4/5.6.2/
302
296
  // https://reference.opcfoundation.org/v105/Core/docs/Part4/5.6.2/
303
297
  return server
304
- ._get_endpoints(endpointUrl)
305
- .filter((e) => !(e as any).restricted) // remove restricted endpoints
298
+ .findMatchingEndpoints(endpointUrl)
299
+ .filter((e) => !(e as unknown as { restricted: boolean }).restricted) // remove restricted endpoints
306
300
  .filter((e) => matchUri(e.endpointUrl, endpointUrl))
307
301
  .map(getRequiredEndpointInfo);
308
302
  }
@@ -325,7 +319,10 @@ function findUserTokenByPolicy(
325
319
  policyId: SecurityPolicy | string | null
326
320
  ): UserTokenPolicy | null {
327
321
  assert(endpoint_description instanceof EndpointDescription);
328
- const r = endpoint_description.userIdentityTokens!.filter(
322
+ if (!endpoint_description.userIdentityTokens) {
323
+ return null;
324
+ }
325
+ const r = endpoint_description.userIdentityTokens.filter(
329
326
  (userIdentity: UserTokenPolicy) =>
330
327
  userIdentity.tokenType === userTokenType && (!policyId || userIdentity.policyId === policyId)
331
328
  );
@@ -334,7 +331,10 @@ function findUserTokenByPolicy(
334
331
 
335
332
  function findUserTokenPolicy(endpoint_description: EndpointDescription, userTokenType: UserTokenType): UserTokenPolicy | null {
336
333
  assert(endpoint_description instanceof EndpointDescription);
337
- const r = endpoint_description.userIdentityTokens!.filter((userIdentity: UserTokenPolicy) => {
334
+ if (!endpoint_description.userIdentityTokens) {
335
+ return null;
336
+ }
337
+ const r = endpoint_description.userIdentityTokens.filter((userIdentity: UserTokenPolicy) => {
338
338
  assert(userIdentity.tokenType !== undefined);
339
339
  return userIdentity.tokenType === userTokenType;
340
340
  });
@@ -350,7 +350,13 @@ function createAnonymousIdentityToken(endpoint_desc: EndpointDescription) {
350
350
  return new AnonymousIdentityToken({ policyId: userTokenPolicy.policyId });
351
351
  }
352
352
 
353
- function sameIdentityToken(token1: UserIdentityToken, token2: UserIdentityToken): boolean {
353
+ function sameIdentityToken(token1?: UserIdentityToken, token2?: UserIdentityToken): boolean {
354
+ if (!token1 && !token2) {
355
+ return true;
356
+ }
357
+ if (!token1 || !token2) {
358
+ return false;
359
+ }
354
360
  if (token1 instanceof UserNameIdentityToken) {
355
361
  if (!(token2 instanceof UserNameIdentityToken)) {
356
362
  return false;
@@ -388,7 +394,7 @@ function getTokenType(userIdentityToken: UserIdentityToken): UserTokenType {
388
394
  }
389
395
  return UserTokenType.Invalid;
390
396
  }
391
- function thumbprint(certificate?: Certificate): string {
397
+ function thumbprint(certificate?: Certificate | null): string {
392
398
  return certificate ? certificate.toString("base64") : "";
393
399
  }
394
400
 
@@ -408,7 +414,7 @@ function monitoredItem_read_and_record_value(
408
414
  context: ISessionContext,
409
415
  oldValue: DataValue,
410
416
  node: UAVariable,
411
- itemToMonitor: any,
417
+ itemToMonitor: ReadValueId,
412
418
  callback: (err: Error | null, dataValue?: DataValue) => void
413
419
  ) {
414
420
  assert(self instanceof MonitoredItem);
@@ -429,7 +435,7 @@ function monitoredItem_read_and_record_value_async(
429
435
  context: ISessionContext,
430
436
  oldValue: DataValue,
431
437
  node: UAVariable,
432
- itemToMonitor: any,
438
+ itemToMonitor: ReadValueId,
433
439
  callback: (err: Error | null, dataValue?: DataValue) => void
434
440
  ) {
435
441
  assert(context instanceof SessionContext);
@@ -444,12 +450,12 @@ function monitoredItem_read_and_record_value_async(
444
450
  });
445
451
  }
446
452
 
447
- function build_scanning_node_function(addressSpace: AddressSpace, itemToMonitor: any): SamplingFunc {
453
+ function build_scanning_node_function(addressSpace: AddressSpace, itemToMonitor: ReadValueId): SamplingFunc {
448
454
  assert(itemToMonitor instanceof ReadValueId);
449
455
 
450
456
  const node = addressSpace.findNode(itemToMonitor.nodeId) as UAVariable;
451
457
 
452
- /* istanbul ignore next */
458
+ /* c8 ignore next */
453
459
  if (!node) {
454
460
  errorLog(" INVALID NODE ID , ", itemToMonitor.nodeId.toString());
455
461
  dump(itemToMonitor);
@@ -508,7 +514,7 @@ function build_scanning_node_function(addressSpace: AddressSpace, itemToMonitor:
508
514
  }
509
515
  }
510
516
 
511
- function prepareMonitoredItem(context: ISessionContext, addressSpace: AddressSpace, monitoredItem: MonitoredItem) {
517
+ function prepareMonitoredItem(_context: ISessionContext, addressSpace: AddressSpace, monitoredItem: MonitoredItem) {
512
518
  const itemToMonitor = monitoredItem.itemToMonitor;
513
519
  const readNodeFunc = build_scanning_node_function(addressSpace, itemToMonitor);
514
520
  monitoredItem.samplingFunc = readNodeFunc;
@@ -523,7 +529,7 @@ function _installRegisterServerManager(self: OPCUAServer) {
523
529
  assert(self instanceof OPCUAServer);
524
530
  assert(!self.registerServerManager);
525
531
 
526
- /* istanbul ignore next */
532
+ /* c8 ignore next */
527
533
  if (!self.registerServerMethod) {
528
534
  throw new Error("Internal Error");
529
535
  }
@@ -545,7 +551,7 @@ function _installRegisterServerManager(self: OPCUAServer) {
545
551
  server: self
546
552
  });
547
553
  break;
548
- /* istanbul ignore next */
554
+ /* c8 ignore next */
549
555
  default:
550
556
  throw new Error("Invalid switch");
551
557
  }
@@ -590,7 +596,7 @@ function _installRegisterServerManager(self: OPCUAServer) {
590
596
  }
591
597
 
592
598
  function validate_applicationUri(channel: ServerSecureChannelLayer, request: CreateSessionRequest): boolean {
593
- const applicationUri = request.clientDescription.applicationUri!;
599
+ const applicationUri = request.clientDescription.applicationUri || "";
594
600
  const clientCertificate = request.clientCertificate;
595
601
  // if session is insecure there is no need to check certificate information
596
602
  if (channel.securityMode === MessageSecurityMode.None) {
@@ -600,11 +606,11 @@ function validate_applicationUri(channel: ServerSecureChannelLayer, request: Cre
600
606
  return true; // can't check
601
607
  }
602
608
  const e = exploreCertificate(clientCertificate);
603
- const uniformResourceIdentifier = e.tbsCertificate.extensions!.subjectAltName?.uniformResourceIdentifier ?? null;
609
+ const uniformResourceIdentifier = e.tbsCertificate.extensions?.subjectAltName?.uniformResourceIdentifier ?? null;
604
610
  const applicationUriFromCert =
605
611
  uniformResourceIdentifier && uniformResourceIdentifier.length > 0 ? uniformResourceIdentifier[0] : null;
606
612
 
607
- /* istanbul ignore next */
613
+ /* c8 ignore next */
608
614
  if (applicationUriFromCert !== applicationUri) {
609
615
  errorLog("BadCertificateUriInvalid!");
610
616
  errorLog("applicationUri = ", applicationUri);
@@ -623,7 +629,7 @@ function validate_security_endpoint(
623
629
  endpoint?: EndpointDescription;
624
630
  } {
625
631
  debugLog("validate_security_endpoint = ", request.endpointUrl);
626
- let endpoints = server._get_endpoints(request.endpointUrl);
632
+ let endpoints = server.findMatchingEndpoints(request.endpointUrl);
627
633
  // endpointUrl String The network address that the Client used to access the Session Endpoint.
628
634
  // The HostName portion of the URL should be one of the HostNames for the application that are
629
635
  // specified in the Server’s ApplicationInstanceCertificate (see 7.2). The Server shall raise an
@@ -636,22 +642,22 @@ function validate_security_endpoint(
636
642
  // sometime endpoints have a extra leading "/" that can be ignored
637
643
  // don't be too harsh.
638
644
  if (endpoints.length === 0 && request.endpointUrl?.endsWith("/")) {
639
- endpoints = server._get_endpoints(request.endpointUrl.slice(0, -1));
645
+ endpoints = server.findMatchingEndpoints(request.endpointUrl.slice(0, -1));
640
646
  }
641
647
 
642
648
  if (endpoints.length === 0) {
643
649
  // we have a UrlMismatch here
644
- const ua_server = server.engine.addressSpace!.rootFolder.objects.server;
650
+ const ua_server = server.engine.addressSpace?.rootFolder.objects.server;
645
651
  if (!request.endpointUrl?.match(/localhost/i) || OPCUAServer.requestExactEndpointUrl) {
646
652
  warningLog("Cannot find suitable endpoints in available endpoints. endpointUri =", request.endpointUrl);
647
653
  }
648
- ua_server.raiseEvent("AuditUrlMismatchEventType", {
654
+ ua_server?.raiseEvent("AuditUrlMismatchEventType", {
649
655
  endpointUrl: { dataType: DataType.String, value: request.endpointUrl }
650
656
  });
651
657
  if (OPCUAServer.requestExactEndpointUrl) {
652
658
  return { errCode: StatusCodes.BadServiceUnsupported };
653
659
  } else {
654
- endpoints = server._get_endpoints(null);
660
+ endpoints = server.findMatchingEndpoints(null);
655
661
  }
656
662
  }
657
663
  // ignore restricted endpoints
@@ -665,7 +671,7 @@ function validate_security_endpoint(
665
671
  return { errCode: StatusCodes.BadSecurityModeRejected };
666
672
  }
667
673
  const endpoints_matching_security_policy = endpoints_matching_security_mode.filter((e: EndpointDescription) => {
668
- return e.securityPolicyUri === channel!.securityPolicy;
674
+ return e.securityPolicyUri === channel?.securityPolicy;
669
675
  });
670
676
 
671
677
  if (endpoints_matching_security_policy.length === 0) {
@@ -674,7 +680,10 @@ function validate_security_endpoint(
674
680
  if (endpoints_matching_security_policy.length !== 1) {
675
681
  debugLog("endpoints_matching_security_policy= ", endpoints_matching_security_policy.length);
676
682
  }
677
- return { errCode: StatusCodes.Good, endpoint: endpoints_matching_security_policy[0] };
683
+ return {
684
+ errCode: StatusCodes.Good,
685
+ endpoint: endpoints_matching_security_policy[0]
686
+ };
678
687
  }
679
688
 
680
689
  export function filterDiagnosticInfo(returnDiagnostics: number, response: CallResponse): void {
@@ -748,6 +757,21 @@ export interface OPCUAServerEndpointOptions {
748
757
  /** alternate hostname or IP to use */
749
758
  alternateHostname?: string | string[];
750
759
 
760
+ /**
761
+ * Additional endpoint URL(s) to advertise.
762
+ *
763
+ * Use when the server is behind Docker port-mapping, a reverse proxy,
764
+ * or a NAT gateway. Each URL is parsed to extract hostname and port.
765
+ * Each entry can be a plain URL string (inherits all security
766
+ * settings from the main endpoint) or an
767
+ * `AdvertisedEndpointConfig` object with per-URL overrides.
768
+ * The server still listens on `port`.
769
+ *
770
+ * @example "opc.tcp://localhost:48481"
771
+ * @example ["opc.tcp://localhost:48481", { url: "opc.tcp://public:4840", securityModes: [MessageSecurityMode.SignAndEncrypt] }]
772
+ */
773
+ advertisedEndpoints?: AdvertisedEndpoint | AdvertisedEndpoint[];
774
+
751
775
  /**
752
776
  * true, if discovery service on secure channel shall be disabled
753
777
  */
@@ -925,39 +949,18 @@ export interface OPCUAServerOptions extends OPCUABaseServerOptions, OPCUAServerE
925
949
  transportSettings?: IServerTransportSettings;
926
950
  }
927
951
 
928
- // eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging
929
- export interface OPCUAServer {
930
- /**
931
- *
932
- */
933
- engine: ServerEngine;
934
- /**
935
- *
936
- */
937
- registerServerMethod: RegisterServerMethod;
938
- /**
939
- *
940
- */
941
- discoveryServerEndpointUrl: string;
942
- /**
943
- *
944
- */
945
- registerServerManager?: IRegisterServerManager;
946
- /**
947
- *
948
- */
949
- capabilitiesForMDNS: string[];
950
- /**
951
- *
952
- */
953
- userCertificateManager: OPCUACertificateManager;
954
- }
955
-
956
952
  const g_requestExactEndpointUrl = !!process.env.NODEOPCUA_SERVER_REQUEST_EXACT_ENDPOINT_URL;
957
953
  /**
958
954
  *
959
955
  */
960
956
  export class OPCUAServer extends OPCUABaseServer {
957
+ public engine!: ServerEngine;
958
+ public registerServerMethod: RegisterServerMethod;
959
+ public discoveryServerEndpointUrl!: string;
960
+ public registerServerManager?: IRegisterServerManager;
961
+ public capabilitiesForMDNS: string[];
962
+ public userCertificateManager: OPCUACertificateManager;
963
+
961
964
  static defaultShutdownTimeout = 100; // 250 ms
962
965
  /**
963
966
  * if requestExactEndpointUrl is set to true the server will only accept createSession that have a endpointUrl that strictly matches
@@ -1069,6 +1072,126 @@ export class OPCUAServer extends OPCUABaseServer {
1069
1072
  return this.engine ? this.engine.isAuditing : false;
1070
1073
  }
1071
1074
 
1075
+ /**
1076
+ * Set the current server state.
1077
+ *
1078
+ * Updates both the internal state and the
1079
+ * `Server.ServerStatus.State` variable in the
1080
+ * address space so that OPC UA reads reflect the
1081
+ * new state immediately.
1082
+ */
1083
+ public setServerState(serverState: ServerState): void {
1084
+ this.engine.setServerState(serverState);
1085
+ }
1086
+
1087
+ /**
1088
+ * Read the current `ServerState` from the
1089
+ * internal server status.
1090
+ */
1091
+ public getServerState(): ServerState {
1092
+ return this.engine.getServerState();
1093
+ }
1094
+
1095
+ /**
1096
+ * Set or clear a temporary role-policy override.
1097
+ *
1098
+ * When set, the override's `getUserRoles(username)`
1099
+ * is called **before** the default `userManager`.
1100
+ * Returning a `NodeId[]` overrides the roles;
1101
+ * returning `null` falls through to the default.
1102
+ *
1103
+ * Call with `null` to remove the override and
1104
+ * restore default behavior.
1105
+ */
1106
+ public setRolePolicyOverride(override: IRolePolicyOverride | null): void {
1107
+ (this as unknown as IServerBase).rolePolicyOverride = override;
1108
+ }
1109
+
1110
+ /**
1111
+ * Set `ServerConfiguration.InApplicationSetup` in
1112
+ * the address space.
1113
+ *
1114
+ * Indicates whether the server is in its initial
1115
+ * application setup phase (e.g. awaiting GDS
1116
+ * provisioning).
1117
+ */
1118
+ public setInApplicationSetup(value: boolean): void {
1119
+ this.engine.setInApplicationSetup(value);
1120
+ }
1121
+
1122
+ /**
1123
+ * Read the current value of
1124
+ * `ServerConfiguration.InApplicationSetup`.
1125
+ */
1126
+ public getInApplicationSetup(): boolean {
1127
+ return this.engine.getInApplicationSetup();
1128
+ }
1129
+
1130
+ /**
1131
+ * Collect additional hostnames for the self-signed certificate SAN.
1132
+ *
1133
+ * Merges hostnames from `alternateHostname` and parsed
1134
+ * `advertisedEndpoints` URLs so the certificate covers all
1135
+ * configured addresses.
1136
+ *
1137
+ * IP literals (v4/v6) are **excluded** — they are handled by
1138
+ * `getConfiguredIPs()` and placed in the SAN `iPAddress` entries.
1139
+ *
1140
+ * @internal
1141
+ */
1142
+ protected override getConfiguredHostnames(): string[] {
1143
+ return this._collectAlternateValues().hostnames;
1144
+ }
1145
+
1146
+ /**
1147
+ * Collect additional IP addresses for the self-signed certificate SAN.
1148
+ *
1149
+ * Merges IP literals from `alternateHostname` and parsed
1150
+ * `advertisedEndpoints` URLs so the certificate covers all
1151
+ * configured IP addresses.
1152
+ *
1153
+ * @internal
1154
+ */
1155
+ protected override getConfiguredIPs(): string[] {
1156
+ return this._collectAlternateValues().ips;
1157
+ }
1158
+
1159
+ /**
1160
+ * Classify all values from `alternateHostname` and
1161
+ * `advertisedEndpoints` into hostnames vs IP addresses using
1162
+ * `isIPAddress()` (wraps `net.isIP()`).
1163
+ */
1164
+ private _collectAlternateValues(): { hostnames: string[]; ips: string[] } {
1165
+ const hostnames: string[] = [];
1166
+ const ips: string[] = [];
1167
+
1168
+ // alternateHostname
1169
+ const alt = this.options.alternateHostname;
1170
+ if (alt) {
1171
+ const altArray = Array.isArray(alt) ? alt : [alt];
1172
+ for (const value of altArray) {
1173
+ if (isIPAddress(value)) {
1174
+ ips.push(value);
1175
+ } else {
1176
+ hostnames.push(value);
1177
+ }
1178
+ }
1179
+ }
1180
+
1181
+ // advertisedEndpoints — normalize to AdvertisedEndpointConfig[]
1182
+ const advList = normalizeAdvertisedEndpoints(this.options.advertisedEndpoints);
1183
+ for (const config of advList) {
1184
+ const { hostname } = parseOpcTcpUrl(config.url);
1185
+ if (isIPAddress(hostname)) {
1186
+ ips.push(hostname);
1187
+ } else {
1188
+ hostnames.push(hostname);
1189
+ }
1190
+ }
1191
+
1192
+ return { hostnames, ips };
1193
+ }
1194
+
1072
1195
  public static registry = new ObjectRegistry();
1073
1196
  public static fallbackSessionName = "Client didn't provide a meaningful sessionName ...";
1074
1197
  /**
@@ -1167,7 +1290,7 @@ export class OPCUAServer extends OPCUABaseServer {
1167
1290
  // note: we need to delay initialization of endpoint as certain resources
1168
1291
  // such as %FQDN% might not be ready yet at this stage
1169
1292
  this._delayInit = async () => {
1170
- /* istanbul ignore next */
1293
+ /* c8 ignore next */
1171
1294
  if (!options) {
1172
1295
  throw new Error("Internal Error");
1173
1296
  }
@@ -1175,7 +1298,7 @@ export class OPCUAServer extends OPCUABaseServer {
1175
1298
 
1176
1299
  // note: applicationUri is handled in a special way
1177
1300
  this.engine = new ServerEngine({
1178
- applicationUri: () => this.serverInfo.applicationUri!,
1301
+ applicationUri: () => this.serverInfo.applicationUri || "",
1179
1302
  buildInfo,
1180
1303
  isAuditing: options.isAuditing,
1181
1304
  serverCapabilities: options.serverCapabilities,
@@ -1213,6 +1336,7 @@ export class OPCUAServer extends OPCUABaseServer {
1213
1336
  host: options.host,
1214
1337
  allowAnonymous: options.allowAnonymous,
1215
1338
  alternateHostname: options.alternateHostname,
1339
+ advertisedEndpoints: options.advertisedEndpoints,
1216
1340
  disableDiscovery: options.disableDiscovery,
1217
1341
  securityModes: options.securityModes,
1218
1342
  securityPolicies: options.securityPolicies
@@ -1220,7 +1344,7 @@ export class OPCUAServer extends OPCUABaseServer {
1220
1344
  }
1221
1345
  // todo should self.serverInfo.productUri match self.engine.buildInfo.productUri ?
1222
1346
  for (const endpointOptions of endpointDefinitions) {
1223
- const endPoint = this.createEndpointDescriptions(options!, endpointOptions);
1347
+ const endPoint = this.createEndpointDescriptions(options, endpointOptions);
1224
1348
  this.endpoints.push(endPoint);
1225
1349
  endPoint.on("message", (message: Message, channel: ServerSecureChannelLayer) => {
1226
1350
  this.on_request(message, channel);
@@ -1262,12 +1386,12 @@ export class OPCUAServer extends OPCUABaseServer {
1262
1386
  */
1263
1387
  public initialize(): Promise<void>;
1264
1388
  public initialize(done: () => void): void;
1265
- public initialize(...args: [any?, ...any[]]): any {
1389
+ public initialize(...args: [((err?: Error) => void)?]): Promise<void> | void {
1266
1390
  const done = args[0] as (err?: Error) => void;
1267
1391
  assert(!this.initialized, "server is already initialized"); // already initialized ?
1268
1392
 
1269
1393
  this._preInitTask.push(async () => {
1270
- /* istanbul ignore else */
1394
+ /* c8 ignore next */
1271
1395
  if (this._delayInit) {
1272
1396
  await this._delayInit();
1273
1397
  this._delayInit = undefined;
@@ -1278,7 +1402,11 @@ export class OPCUAServer extends OPCUABaseServer {
1278
1402
  .then(() => {
1279
1403
  OPCUAServer.registry.register(this);
1280
1404
  this.engine.initialize(this.options, () => {
1281
- bindRoleSet(this.userManager, this.engine.addressSpace!);
1405
+ if (!this.engine.addressSpace) {
1406
+ done(new Error("no addressSpace"));
1407
+ return;
1408
+ }
1409
+ bindRoleSet(this.userManager, this.engine.addressSpace);
1282
1410
  setImmediate(() => {
1283
1411
  this.emit("post_initialize");
1284
1412
  done();
@@ -1295,38 +1423,36 @@ export class OPCUAServer extends OPCUABaseServer {
1295
1423
  */
1296
1424
  public start(): Promise<void>;
1297
1425
  public start(done: () => void): void;
1298
- public start(...args: [any?, ...any[]]): any {
1299
- const done = args[0] as () => void;
1300
- const tasks: any[] = [];
1301
-
1302
- tasks.push(callbackify(extractFullyQualifiedDomainName));
1426
+ public start(...args: [((err?: Error) => void)?]): Promise<void> | void {
1427
+ const callback = args[0];
1428
+ if (callback) {
1429
+ return super.start(callback);
1430
+ }
1431
+ return super.start();
1432
+ }
1433
+ /**
1434
+ * Initiate the server by starting all its endpoints
1435
+ * @private
1436
+ */
1437
+ public async startAsync(): Promise<void> {
1438
+ await extractFullyQualifiedDomainName();
1303
1439
 
1304
1440
  if (!this.initialized) {
1305
- tasks.push((callback: ErrorCallback) => {
1306
- this.initialize(callback);
1307
- });
1441
+ await this.initialize();
1308
1442
  }
1309
- tasks.push((callback: ErrorCallback) => {
1310
- super.start((err?: Error | null) => {
1311
- if (err) {
1312
- this.shutdown((/*err2*/ err2?: Error) => {
1313
- callback(err);
1314
- });
1315
- } else {
1316
- // we start the registration process asynchronously
1317
- // as we want to make server immediately available
1318
- this.registerServerManager!.start().then(() => {
1319
- /* empty */
1320
- }).catch((err) => {
1321
- /* empty */
1322
- });
1323
1443
 
1324
- setImmediate(callback);
1325
- }
1326
- });
1327
- });
1444
+ try {
1445
+ await super.startAsync();
1446
+ } catch (err) {
1447
+ await this.shutdown();
1448
+ throw err;
1449
+ }
1328
1450
 
1329
- async.series(tasks, done);
1451
+ // we start the registration process asynchronously
1452
+ // as we want to make server immediately available
1453
+ this.registerServerManager?.start().catch(() => {
1454
+ /* empty */
1455
+ });
1330
1456
  }
1331
1457
 
1332
1458
  /**
@@ -1356,13 +1482,13 @@ export class OPCUAServer extends OPCUABaseServer {
1356
1482
  public shutdown(timeout?: number): Promise<void>;
1357
1483
  public shutdown(callback: (err?: Error) => void): void;
1358
1484
  public shutdown(timeout: number, callback: (err?: Error) => void): void;
1359
- public shutdown(...args: [any?, ...any[]]): any {
1485
+ public shutdown(...args: [number | ((err?: Error) => void) | undefined, ...((err?: Error) => void)[]]): Promise<void> | void {
1360
1486
  const timeout = args.length === 1 ? OPCUAServer.defaultShutdownTimeout : (args[0] as number);
1361
1487
  const callback = (args.length === 1 ? args[0] : args[1]) as (err?: Error) => void;
1362
1488
  assert(typeof callback === "function");
1363
1489
  debugLog("OPCUAServer#shutdown (timeout = ", timeout, ")");
1364
1490
 
1365
- /* istanbul ignore next */
1491
+ /* c8 ignore next */
1366
1492
  if (!this.engine) {
1367
1493
  return callback();
1368
1494
  }
@@ -1380,28 +1506,31 @@ export class OPCUAServer extends OPCUABaseServer {
1380
1506
  const shutdownTime = new Date(Date.now() + timeout);
1381
1507
  this.engine.setShutdownTime(shutdownTime);
1382
1508
 
1383
- debugLog("OPCUAServer is now un-registering itself from the discovery server " + this.buildInfo);
1384
- this.registerServerManager!.stop()
1509
+ debugLog("OPCUAServer is now un-registering itself from the discovery server ", this.buildInfo);
1510
+ if (!this.registerServerManager) {
1511
+ callback(new Error("invalid register server manager"));
1512
+ return;
1513
+ }
1514
+ this.registerServerManager
1515
+ .stop()
1385
1516
  .then(() => {
1386
1517
  debugLog("OPCUAServer unregistered from discovery server successfully");
1387
-
1388
1518
  })
1389
1519
  .catch((err) => {
1390
1520
  debugLog("OPCUAServer unregistered from discovery server with err: ", err.message);
1391
- }).finally(() => {
1392
-
1521
+ })
1522
+ .finally(() => {
1393
1523
  setTimeout(async () => {
1394
1524
  await this.engine.shutdown();
1395
1525
 
1396
1526
  debugLog("OPCUAServer#shutdown: started");
1397
- OPCUABaseServer.prototype.shutdown.call(this, (err1?: Error) => {
1527
+ OPCUABaseServer.prototype.shutdown.call(this, (err1?: Error | null) => {
1398
1528
  debugLog("OPCUAServer#shutdown: completed");
1399
1529
 
1400
1530
  this.dispose();
1401
- callback(err1);
1531
+ callback(err1 || undefined);
1402
1532
  });
1403
1533
  }, timeout);
1404
-
1405
1534
  });
1406
1535
  }
1407
1536
 
@@ -1419,7 +1548,7 @@ export class OPCUAServer extends OPCUABaseServer {
1419
1548
  }
1420
1549
  OPCUAServer.registry.unregister(this);
1421
1550
 
1422
- /* istanbul ignore next */
1551
+ /* c8 ignore next */
1423
1552
  if (this.engine) {
1424
1553
  this.engine.dispose();
1425
1554
  }
@@ -1439,7 +1568,7 @@ export class OPCUAServer extends OPCUABaseServer {
1439
1568
  public raiseEvent(eventType: "AuditCertificateMismatchEventType", options: RaiseAuditCertificateMismatchEventData): void;
1440
1569
 
1441
1570
  public raiseEvent(eventType: EventTypeLike | UAObjectType, options: RaiseEventData): void {
1442
- /* istanbul ignore next */
1571
+ /* c8 ignore next */
1443
1572
  if (!this.engine.addressSpace) {
1444
1573
  errorLog("addressSpace missing");
1445
1574
  return;
@@ -1447,7 +1576,7 @@ export class OPCUAServer extends OPCUABaseServer {
1447
1576
 
1448
1577
  const server = this.engine.addressSpace.findNode("Server") as UAObject;
1449
1578
 
1450
- /* istanbul ignore next */
1579
+ /* c8 ignore next */
1451
1580
  if (!server) {
1452
1581
  // xx throw new Error("OPCUAServer#raiseEvent : cannot find Server object");
1453
1582
  return;
@@ -1457,12 +1586,12 @@ export class OPCUAServer extends OPCUABaseServer {
1457
1586
  if (typeof eventType === "string") {
1458
1587
  eventTypeNode = this.engine.addressSpace.findEventType(eventType);
1459
1588
  if (eventTypeNode) {
1460
- return server.raiseEvent(eventTypeNode, options);
1589
+ server.raiseEvent(eventTypeNode, options);
1461
1590
  } else {
1462
1591
  console.warn(" cannot find event type ", eventType);
1463
1592
  }
1464
1593
  } else {
1465
- return server.raiseEvent(eventTypeNode, options);
1594
+ server.raiseEvent(eventTypeNode, options);
1466
1595
  }
1467
1596
  }
1468
1597
 
@@ -1471,7 +1600,7 @@ export class OPCUAServer extends OPCUABaseServer {
1471
1600
  * @private
1472
1601
  */
1473
1602
  protected createSession(options: CreateSessionOption): ServerSession {
1474
- /* istanbul ignore next */
1603
+ /* c8 ignore next */
1475
1604
  if (!this.engine) {
1476
1605
  throw new Error("Internal Error");
1477
1606
  }
@@ -1512,47 +1641,51 @@ export class OPCUAServer extends OPCUABaseServer {
1512
1641
  channel: ServerSecureChannelLayer,
1513
1642
  clientSignature: SignatureData
1514
1643
  ): boolean {
1515
- const clientCertificate = channel.clientCertificate!;
1644
+ const clientCertificate = channel.clientCertificate;
1516
1645
  const securityPolicy = channel.securityPolicy;
1517
1646
  const serverCertificate = this.getCertificate();
1518
- const result = verifySignature(serverCertificate, session.nonce!, clientSignature, clientCertificate, securityPolicy);
1647
+ const result = verifySignature(serverCertificate, session.nonce, clientSignature, clientCertificate, securityPolicy);
1519
1648
  return result;
1520
1649
  }
1521
1650
 
1522
1651
  protected isValidUserNameIdentityToken(
1523
1652
  channel: ServerSecureChannelLayer,
1524
- session: ServerSession,
1653
+ _session: ServerSession,
1525
1654
  userTokenPolicy: UserTokenPolicy,
1526
1655
  userIdentityToken: UserNameIdentityToken,
1527
- userTokenSignature: SignatureData,
1656
+ _userTokenSignature: SignatureData,
1528
1657
  callback: (err: Error | null, statusCode?: StatusCode) => void
1529
1658
  ): void {
1530
1659
  assert(userIdentityToken instanceof UserNameIdentityToken);
1531
1660
 
1532
1661
  const securityPolicy = adjustSecurityPolicy(channel, userTokenPolicy.securityPolicyUri);
1533
1662
  if (securityPolicy === SecurityPolicy.None) {
1534
- return callback(null, StatusCodes.Good);
1663
+ callback(null, StatusCodes.Good);
1664
+ return;
1535
1665
  }
1536
1666
  const cryptoFactory = getCryptoFactory(securityPolicy);
1537
1667
 
1538
- /* istanbul ignore next */
1668
+ /* c8 ignore next */
1539
1669
  if (!cryptoFactory) {
1540
- return callback(null, StatusCodes.BadSecurityPolicyRejected);
1670
+ callback(null, StatusCodes.BadSecurityPolicyRejected);
1671
+ return;
1541
1672
  }
1542
1673
 
1543
- /* istanbul ignore next */
1674
+ /* c8 ignore next */
1544
1675
  if (userIdentityToken.encryptionAlgorithm !== cryptoFactory.asymmetricEncryptionAlgorithm) {
1545
1676
  errorLog("invalid encryptionAlgorithm");
1546
1677
  errorLog("userTokenPolicy", userTokenPolicy.toString());
1547
1678
  errorLog("userTokenPolicy", userIdentityToken.toString());
1548
- return callback(null, StatusCodes.BadIdentityTokenInvalid);
1679
+ callback(null, StatusCodes.BadIdentityTokenInvalid);
1680
+ return;
1549
1681
  }
1550
1682
  const userName = userIdentityToken.userName;
1551
1683
  const password = userIdentityToken.password;
1552
1684
  if (!userName || !password) {
1553
- return callback(null, StatusCodes.BadIdentityTokenInvalid);
1685
+ callback(null, StatusCodes.BadIdentityTokenInvalid);
1686
+ return;
1554
1687
  }
1555
- return callback(null, StatusCodes.Good);
1688
+ callback(null, StatusCodes.Good);
1556
1689
  }
1557
1690
 
1558
1691
  protected isValidX509IdentityToken(
@@ -1569,40 +1702,43 @@ export class OPCUAServer extends OPCUABaseServer {
1569
1702
  const securityPolicy = adjustSecurityPolicy(channel, userTokenPolicy.securityPolicyUri);
1570
1703
 
1571
1704
  const cryptoFactory = getCryptoFactory(securityPolicy);
1572
- /* istanbul ignore next */
1705
+ /* c8 ignore next */
1573
1706
  if (!cryptoFactory) {
1574
- return callback(null, StatusCodes.BadSecurityPolicyRejected);
1707
+ callback(null, StatusCodes.BadSecurityPolicyRejected);
1708
+ return;
1575
1709
  }
1576
1710
 
1577
1711
  if (!userTokenSignature || !userTokenSignature.signature) {
1578
1712
  this.raiseEvent("AuditCreateSessionEventType", {});
1579
-
1580
- return callback(null, StatusCodes.BadUserSignatureInvalid);
1713
+ callback(null, StatusCodes.BadUserSignatureInvalid);
1714
+ return;
1581
1715
  }
1582
1716
 
1583
1717
  if (userIdentityToken.policyId !== userTokenPolicy.policyId) {
1584
1718
  errorLog("invalid encryptionAlgorithm");
1585
1719
  errorLog("userTokenPolicy", userTokenPolicy.toString());
1586
1720
  errorLog("userTokenPolicy", userIdentityToken.toString());
1587
- return callback(null, StatusCodes.BadSecurityPolicyRejected);
1721
+ callback(null, StatusCodes.BadSecurityPolicyRejected);
1722
+ return;
1588
1723
  }
1589
1724
  const certificate = userIdentityToken.certificateData; /* as Certificate*/
1590
- const nonce = session.nonce!;
1725
+ const nonce = session.nonce;
1726
+ if (!nonce || nonce.length === 0) {
1727
+ callback(null, StatusCodes.BadNonceInvalid);
1728
+ return;
1729
+ }
1591
1730
  const serverCertificate = this.getCertificate();
1592
-
1593
- assert(serverCertificate instanceof Buffer);
1594
- assert(certificate instanceof Buffer, "expecting certificate to be a Buffer");
1595
- assert(nonce instanceof Buffer, "expecting nonce to be a Buffer");
1596
1731
  assert(userTokenSignature.signature instanceof Buffer, "expecting userTokenSignature to be a Buffer");
1597
1732
 
1598
1733
  // verify proof of possession by checking certificate signature & server nonce correctness
1599
1734
  if (!verifySignature(serverCertificate, nonce, userTokenSignature, certificate, securityPolicy)) {
1600
- return callback(null, StatusCodes.BadUserSignatureInvalid);
1735
+ callback(null, StatusCodes.BadUserSignatureInvalid);
1736
+ return;
1601
1737
  }
1602
1738
 
1603
1739
  // verify if certificate is Valid
1604
- this.userCertificateManager!.checkCertificate(certificate, (err, certificateStatus) => {
1605
- /* istanbul ignore next */
1740
+ this.userCertificateManager.checkCertificate(certificate, (err, certificateStatus) => {
1741
+ /* c8 ignore next */
1606
1742
  if (err) {
1607
1743
  return callback(err);
1608
1744
  }
@@ -1612,31 +1748,55 @@ export class OPCUAServer extends OPCUABaseServer {
1612
1748
  break;
1613
1749
  case StatusCodes.BadCertificateUntrusted:
1614
1750
  this.raiseEvent("AuditCertificateUntrustedEventType", {
1615
- certificate: { dataType: DataType.ByteString, value: certificate },
1616
- sourceName: { dataType: DataType.String, value: "Security/Certificate" }
1751
+ certificate: {
1752
+ dataType: DataType.ByteString,
1753
+ value: certificate
1754
+ },
1755
+ sourceName: {
1756
+ dataType: DataType.String,
1757
+ value: "Security/Certificate"
1758
+ }
1617
1759
  });
1618
1760
  break;
1619
1761
  case StatusCodes.BadCertificateTimeInvalid:
1620
1762
  case StatusCodes.BadCertificateIssuerTimeInvalid:
1621
1763
  this.raiseEvent("AuditCertificateExpiredEventType", {
1622
- certificate: { dataType: DataType.ByteString, value: certificate },
1623
- sourceName: { dataType: DataType.String, value: "Security/Certificate" }
1764
+ certificate: {
1765
+ dataType: DataType.ByteString,
1766
+ value: certificate
1767
+ },
1768
+ sourceName: {
1769
+ dataType: DataType.String,
1770
+ value: "Security/Certificate"
1771
+ }
1624
1772
  });
1625
1773
  break;
1626
1774
  case StatusCodes.BadCertificateRevoked:
1627
1775
  case StatusCodes.BadCertificateRevocationUnknown:
1628
1776
  case StatusCodes.BadCertificateIssuerRevocationUnknown:
1629
1777
  this.raiseEvent("AuditCertificateRevokedEventType", {
1630
- certificate: { dataType: DataType.ByteString, value: certificate },
1631
- sourceName: { dataType: DataType.String, value: "Security/Certificate" }
1778
+ certificate: {
1779
+ dataType: DataType.ByteString,
1780
+ value: certificate
1781
+ },
1782
+ sourceName: {
1783
+ dataType: DataType.String,
1784
+ value: "Security/Certificate"
1785
+ }
1632
1786
  });
1633
1787
  break;
1634
1788
  case StatusCodes.BadCertificateIssuerUseNotAllowed:
1635
1789
  case StatusCodes.BadCertificateUseNotAllowed:
1636
1790
  case StatusCodes.BadSecurityChecksFailed:
1637
1791
  this.raiseEvent("AuditCertificateMismatchEventType", {
1638
- certificate: { dataType: DataType.ByteString, value: certificate },
1639
- sourceName: { dataType: DataType.String, value: "Security/Certificate" }
1792
+ certificate: {
1793
+ dataType: DataType.ByteString,
1794
+ value: certificate
1795
+ },
1796
+ sourceName: {
1797
+ dataType: DataType.String,
1798
+ value: "Security/Certificate"
1799
+ }
1640
1800
  });
1641
1801
  break;
1642
1802
  }
@@ -1688,8 +1848,12 @@ export class OPCUAServer extends OPCUABaseServer {
1688
1848
 
1689
1849
  const securityPolicy = adjustSecurityPolicy(channel, userTokenPolicy.securityPolicyUri);
1690
1850
 
1691
- const userName = userIdentityToken.userName!;
1692
- let password: any = userIdentityToken.password;
1851
+ const userName = userIdentityToken.userName;
1852
+ if (!userName) {
1853
+ callback(new Error(" expecting a no null username"));
1854
+ return;
1855
+ }
1856
+ let password: ByteString | string = userIdentityToken.password;
1693
1857
 
1694
1858
  // decrypt password if necessary
1695
1859
  if (securityPolicy === SecurityPolicy.None) {
@@ -1698,20 +1862,24 @@ export class OPCUAServer extends OPCUABaseServer {
1698
1862
  } else {
1699
1863
  const serverPrivateKey = this.getPrivateKey();
1700
1864
 
1701
- const serverNonce = session.nonce!;
1702
- assert(serverNonce instanceof Buffer);
1865
+ const serverNonce = session.nonce;
1866
+ if (!serverNonce) {
1867
+ callback(new Error(" expecting a no null nonce"));
1868
+ return;
1869
+ }
1703
1870
 
1704
1871
  const cryptoFactory = getCryptoFactory(securityPolicy);
1705
- /* istanbul ignore next */
1872
+ /* c8 ignore next */
1706
1873
  if (!cryptoFactory) {
1707
- return callback(new Error(" Unsupported security Policy"));
1874
+ callback(new Error(" Unsupported security Policy"));
1875
+ return;
1708
1876
  }
1709
1877
 
1710
1878
  const buff = cryptoFactory.asymmetricDecrypt(password, serverPrivateKey);
1711
1879
 
1712
1880
  // server certificate may be invalid and asymmetricDecrypt may fail
1713
1881
  if (!buff || buff.length < 4) {
1714
- async.setImmediate(() => callback(null, false));
1882
+ setImmediate(() => callback(null, false));
1715
1883
  return;
1716
1884
  }
1717
1885
 
@@ -1737,41 +1905,30 @@ export class OPCUAServer extends OPCUABaseServer {
1737
1905
  callback: (err: Error | null, statusCode?: StatusCode) => void
1738
1906
  ): void {
1739
1907
  assert(typeof callback === "function");
1740
- /* istanbul ignore next */
1908
+ /* c8 ignore next */
1741
1909
  if (!userIdentityToken) {
1742
1910
  throw new Error("Invalid token");
1743
1911
  }
1744
1912
 
1745
1913
  const userTokenType = getTokenType(userIdentityToken);
1746
1914
 
1747
- const userTokenPolicy = findUserTokenByPolicy(endpointDescription, userTokenType, userIdentityToken.policyId!);
1915
+ const userTokenPolicy = findUserTokenByPolicy(endpointDescription, userTokenType, userIdentityToken.policyId);
1748
1916
  if (!userTokenPolicy) {
1749
1917
  // cannot find token with this policyId
1750
- return callback(null, StatusCodes.BadIdentityTokenInvalid);
1918
+ callback(null, StatusCodes.BadIdentityTokenInvalid);
1919
+ return;
1751
1920
  }
1752
1921
  //
1753
1922
  if (userIdentityToken instanceof UserNameIdentityToken) {
1754
- return this.isValidUserNameIdentityToken(
1755
- channel,
1756
- session,
1757
- userTokenPolicy,
1758
- userIdentityToken,
1759
- userTokenSignature,
1760
- callback
1761
- );
1923
+ this.isValidUserNameIdentityToken(channel, session, userTokenPolicy, userIdentityToken, userTokenSignature, callback);
1924
+ return;
1762
1925
  }
1763
1926
  if (userIdentityToken instanceof X509IdentityToken) {
1764
- return this.isValidX509IdentityToken(
1765
- channel,
1766
- session,
1767
- userTokenPolicy,
1768
- userIdentityToken,
1769
- userTokenSignature,
1770
- callback
1771
- );
1927
+ this.isValidX509IdentityToken(channel, session, userTokenPolicy, userIdentityToken, userTokenSignature, callback);
1928
+ return;
1772
1929
  }
1773
1930
 
1774
- return callback(null, StatusCodes.Good);
1931
+ callback(null, StatusCodes.Good);
1775
1932
  }
1776
1933
 
1777
1934
  /**
@@ -1793,16 +1950,18 @@ export class OPCUAServer extends OPCUABaseServer {
1793
1950
  assert(typeof callback === "function");
1794
1951
 
1795
1952
  const userTokenType = getTokenType(userIdentityToken);
1796
- const userTokenPolicy = findUserTokenByPolicy(session.getEndpointDescription(), userTokenType, userIdentityToken.policyId!);
1797
- /** istanbul ignore next */
1953
+ const userTokenPolicy = findUserTokenByPolicy(session.getEndpointDescription(), userTokenType, userIdentityToken.policyId);
1954
+ /** c8 ignore next */
1798
1955
  if (!userTokenPolicy) {
1799
- return callback(null, false);
1956
+ callback(null, false);
1957
+ return;
1800
1958
  }
1801
1959
  // find if a userToken exists
1802
1960
  if (userIdentityToken instanceof UserNameIdentityToken) {
1803
- return this.userNameIdentityTokenAuthenticateUser(channel, session, userTokenPolicy, userIdentityToken, callback);
1961
+ this.userNameIdentityTokenAuthenticateUser(channel, session, userTokenPolicy, userIdentityToken, callback);
1962
+ return;
1804
1963
  }
1805
- async.setImmediate(callback.bind(null, null, true));
1964
+ setImmediate(callback.bind(null, null, true));
1806
1965
  }
1807
1966
 
1808
1967
  protected makeServerNonce(): Nonce {
@@ -1870,17 +2029,14 @@ export class OPCUAServer extends OPCUABaseServer {
1870
2029
  if (channel.securityMode !== MessageSecurityMode.None) {
1871
2030
  errorLog(
1872
2031
  chalk.red("SERVER with secure connection: Missing or invalid client Nonce "),
1873
- request.clientNonce && request.clientNonce.toString("hex")
2032
+ request.clientNonce?.toString("hex")
1874
2033
  );
1875
2034
 
1876
2035
  return rejectConnection(this, StatusCodes.BadNonceInvalid);
1877
2036
  }
1878
2037
  }
1879
2038
  if (nonceAlreadyBeenUsed(request.clientNonce)) {
1880
- errorLog(
1881
- chalk.red("SERVER with secure connection: Nonce has already been used"),
1882
- request.clientNonce && request.clientNonce.toString("hex")
1883
- );
2039
+ errorLog(chalk.red("SERVER with secure connection: Nonce has already been used"), request.clientNonce?.toString("hex"));
1884
2040
 
1885
2041
  return rejectConnection(this, StatusCodes.BadNonceInvalid);
1886
2042
  }
@@ -1932,7 +2088,7 @@ export class OPCUAServer extends OPCUABaseServer {
1932
2088
 
1933
2089
  const hasEncryption = true;
1934
2090
  // If the securityPolicyUri is None and none of the UserTokenPolicies requires encryption
1935
- if (session.channel!.securityMode === MessageSecurityMode.None) {
2091
+ if (session.channel?.securityMode === MessageSecurityMode.None) {
1936
2092
  // ToDo: Check that none of our insecure endpoint has a a UserTokenPolicy that require encryption
1937
2093
  // and set hasEncryption = false under this condition
1938
2094
  }
@@ -1969,7 +2125,7 @@ export class OPCUAServer extends OPCUABaseServer {
1969
2125
  // securityPolicyUri, userIdentityTokens, transportProfileUri and securityLevel with all
1970
2126
  // other parameters set to null. Only the recommended parameters shall be verified by
1971
2127
  // the client.
1972
- serverEndpoints: _serverEndpointsForCreateSessionResponse(this, session.endpoint!.endpointUrl, request.serverUri),
2128
+ serverEndpoints: _serverEndpointsForCreateSessionResponse(this, session.endpoint?.endpointUrl || "", request.serverUri),
1973
2129
 
1974
2130
  // This parameter is deprecated and the array shall be empty.
1975
2131
  serverSoftwareCertificates: null,
@@ -1995,7 +2151,7 @@ export class OPCUAServer extends OPCUABaseServer {
1995
2151
  assert(typeof reason === "string");
1996
2152
  if (this.isAuditing) {
1997
2153
  assert(reason === "Timeout" || reason === "Terminated" || reason === "CloseSession" || reason === "Forcing");
1998
- const sourceName = "Session/" + reason;
2154
+ const sourceName = `Session/${reason}`;
1999
2155
 
2000
2156
  this.raiseEvent("AuditSessionEventType", {
2001
2157
  /* part 5 - 6.4.3 AuditEventType */
@@ -2047,18 +2203,27 @@ export class OPCUAServer extends OPCUABaseServer {
2047
2203
  // identifier in all AuditEvents related to the Session Service Set (AuditCreateSessionEventType,
2048
2204
  // AuditActivateSessionEventType and their subtypes) and the SecureChannel Service Set
2049
2205
  // (AuditChannelEventType and its subtypes
2050
- secureChannelId: { dataType: "String", value: session.channel!.channelId!.toString() },
2206
+ secureChannelId: {
2207
+ dataType: "String",
2208
+ value: session.channel?.channelId?.toString() ?? ""
2209
+ },
2051
2210
 
2052
2211
  // Duration
2053
- revisedSessionTimeout: { dataType: "Duration", value: session.sessionTimeout },
2212
+ revisedSessionTimeout: {
2213
+ dataType: "Duration",
2214
+ value: session.sessionTimeout
2215
+ },
2054
2216
 
2055
2217
  // clientCertificate
2056
- clientCertificate: { dataType: "ByteString", value: session.channel!.clientCertificate },
2218
+ clientCertificate: {
2219
+ dataType: "ByteString",
2220
+ value: session.channel?.clientCertificate ?? null
2221
+ },
2057
2222
 
2058
2223
  // clientCertificateThumbprint
2059
2224
  clientCertificateThumbprint: {
2060
2225
  dataType: "String",
2061
- value: thumbprint(session.channel!.clientCertificate!)
2226
+ value: thumbprint(session.channel?.clientCertificate)
2062
2227
  }
2063
2228
  });
2064
2229
  }
@@ -2101,20 +2266,21 @@ export class OPCUAServer extends OPCUABaseServer {
2101
2266
  server.engine.incrementSecurityRejectedSessionCount();
2102
2267
  }
2103
2268
 
2104
- const response1 = new ActivateSessionResponse({ responseHeader: { serviceResult: statusCode } });
2269
+ const response1 = new ActivateSessionResponse({
2270
+ responseHeader: { serviceResult: statusCode }
2271
+ });
2105
2272
 
2106
2273
  channel.send_response("MSG", response1, message);
2107
2274
  }
2108
2275
 
2109
- let response;
2110
-
2111
- /* istanbul ignore next */
2276
+ /* c8 ignore next */
2112
2277
  if (!session) {
2113
2278
  // this may happen when the server has been restarted and a client tries to reconnect, thinking
2114
2279
  // that the previous session may still be active
2115
2280
  debugLog(chalk.yellow.bold(" Bad Session in _on_ActivateSessionRequest"), authenticationToken.toString());
2116
2281
 
2117
- return rejectConnection(this, StatusCodes.BadSessionIdInvalid);
2282
+ rejectConnection(this, StatusCodes.BadSessionIdInvalid);
2283
+ return;
2118
2284
  }
2119
2285
 
2120
2286
  // tslint:disable-next-line: no-unused-expression
@@ -2128,8 +2294,9 @@ export class OPCUAServer extends OPCUABaseServer {
2128
2294
  if (!channel_has_session(channel, session)) {
2129
2295
  // it looks like session activation is being using a channel that is not the
2130
2296
  // one that have been used to create the session
2131
- errorLog(" channel.sessionTokens === " + Object.keys(channel.sessionTokens).join(" "));
2132
- return rejectConnection(this, StatusCodes.BadSessionNotActivated);
2297
+ errorLog(` channel.sessionTokens === ${Object.keys(channel.sessionTokens).join(" ")}`);
2298
+ rejectConnection(this, StatusCodes.BadSessionNotActivated);
2299
+ return;
2133
2300
  }
2134
2301
  }
2135
2302
 
@@ -2139,47 +2306,58 @@ export class OPCUAServer extends OPCUABaseServer {
2139
2306
  // SecureChannel is the same as the Certificate used to create the original SecureChannel.
2140
2307
 
2141
2308
  if (session.status === "active") {
2142
- if (session.channel!.channelId !== channel.channelId) {
2309
+ if (session.channel?.channelId !== channel.channelId) {
2143
2310
  warningLog(
2144
2311
  " Session ",
2145
2312
  session.sessionName,
2146
2313
  " is being transferred from channel",
2147
- chalk.cyan(session.channel!.channelId!.toString()),
2314
+ chalk.cyan(session.channel?.channelId?.toString()),
2148
2315
  " to channel ",
2149
- chalk.cyan(channel.channelId!.toString())
2316
+ chalk.cyan(channel.channelId?.toString())
2150
2317
  );
2151
2318
 
2152
2319
  // session is being reassigned to a new Channel,
2153
2320
  // we shall verify that the certificate used to create the Session is the same as the current
2154
2321
  // channel certificate.
2155
- const old_channel_cert_thumbprint = thumbprint(session.channel!.clientCertificate!);
2156
- const new_channel_cert_thumbprint = thumbprint(channel.clientCertificate!);
2322
+ const old_channel_cert_thumbprint = thumbprint(session.channel?.clientCertificate);
2323
+ const new_channel_cert_thumbprint = thumbprint(channel.clientCertificate);
2157
2324
 
2158
2325
  if (old_channel_cert_thumbprint !== new_channel_cert_thumbprint) {
2159
- return rejectConnection(this, StatusCodes.BadNoValidCertificates); // not sure about this code !
2326
+ rejectConnection(this, StatusCodes.BadNoValidCertificates); // not sure about this code !
2327
+ return;
2160
2328
  }
2161
2329
 
2162
2330
  // ... In addition the Server shall verify that the Client supplied a UserIdentityToken that is
2163
2331
  // identical to the token currently associated with the Session reassign session to new channel.
2164
- if (!sameIdentityToken(session.userIdentityToken!, request.userIdentityToken as UserIdentityToken)) {
2165
- return rejectConnection(this, StatusCodes.BadIdentityChangeNotSupported); // not sure about this code !
2332
+ if (!sameIdentityToken(session.userIdentityToken, request.userIdentityToken as UserIdentityToken)) {
2333
+ rejectConnection(this, StatusCodes.BadIdentityChangeNotSupported); // not sure about this code !
2334
+ return;
2166
2335
  }
2167
2336
  }
2168
2337
  } else if (session.status === "screwed") {
2169
2338
  // session has been used before being activated => this should be detected and session should be dismissed.
2170
- return rejectConnection(this, StatusCodes.BadSessionClosed);
2339
+ rejectConnection(this, StatusCodes.BadSessionClosed);
2340
+ return;
2171
2341
  } else if (session.status === "closed") {
2172
2342
  warningLog(chalk.yellow.bold(" Bad Session Closed in _on_ActivateSessionRequest"), authenticationToken.toString());
2173
- return rejectConnection(this, StatusCodes.BadSessionClosed);
2343
+ rejectConnection(this, StatusCodes.BadSessionClosed);
2344
+ return;
2174
2345
  }
2175
2346
 
2176
2347
  // verify clientSignature provided by the client
2177
2348
  if (!this.verifyClientSignature(session, channel, request.clientSignature)) {
2178
- return rejectConnection(this, StatusCodes.BadApplicationSignatureInvalid);
2349
+ rejectConnection(this, StatusCodes.BadApplicationSignatureInvalid);
2350
+ return;
2351
+ }
2352
+
2353
+ const endpoint = session.endpoint;
2354
+ if (!endpoint) {
2355
+ rejectConnection(this, StatusCodes.BadSessionIdInvalid);
2356
+ return;
2179
2357
  }
2180
2358
 
2181
2359
  // userIdentityToken may be missing , assume anonymous access then
2182
- request.userIdentityToken = request.userIdentityToken || createAnonymousIdentityToken(session.endpoint!);
2360
+ request.userIdentityToken = request.userIdentityToken || createAnonymousIdentityToken(endpoint);
2183
2361
 
2184
2362
  // check request.userIdentityToken is correct ( expected type and correctly formed)
2185
2363
  this.isValidUserIdentityToken(
@@ -2187,10 +2365,10 @@ export class OPCUAServer extends OPCUABaseServer {
2187
2365
  session,
2188
2366
  request.userIdentityToken as UserIdentityToken,
2189
2367
  request.userTokenSignature,
2190
- session.endpoint!,
2191
- (err: Error | null, statusCode?: StatusCode) => {
2368
+ endpoint,
2369
+ (_err: Error | null, statusCode?: StatusCode) => {
2192
2370
  if (!statusCode || statusCode.isNotGood()) {
2193
- /* istanbul ignore next */
2371
+ /* c8 ignore next */
2194
2372
  if (!(statusCode && statusCode instanceof StatusCode)) {
2195
2373
  return rejectConnection(this, StatusCodes.BadCertificateInvalid);
2196
2374
  }
@@ -2203,7 +2381,7 @@ export class OPCUAServer extends OPCUABaseServer {
2203
2381
  session,
2204
2382
  request.userIdentityToken as UserIdentityToken,
2205
2383
  (err1: Error | null, authorized?: boolean) => {
2206
- /* istanbul ignore next */
2384
+ /* c8 ignore next */
2207
2385
  if (err1) {
2208
2386
  return rejectConnection(this, StatusCodes.BadInternalError);
2209
2387
  }
@@ -2223,7 +2401,9 @@ export class OPCUAServer extends OPCUABaseServer {
2223
2401
 
2224
2402
  session.status = "active";
2225
2403
 
2226
- response = new ActivateSessionResponse({ serverNonce: session.nonce });
2404
+ const response = new ActivateSessionResponse({
2405
+ serverNonce: session.nonce
2406
+ });
2227
2407
  channel.send_response("MSG", response, message);
2228
2408
 
2229
2409
  // send OPCUA Event Notification
@@ -2261,13 +2441,18 @@ export class OPCUAServer extends OPCUABaseServer {
2261
2441
  // --- check that provided session matches session attached to channel
2262
2442
  if (channel.channelId !== session.channelId) {
2263
2443
  if (!(request instanceof ActivateSessionRequest)) {
2264
- errorLog(
2265
- chalk.red.bgWhite(
2266
- "ERROR: channel.channelId !== session.channelId on processing request " + request.constructor.name
2267
- ),
2268
- channel.channelId,
2269
- session.channelId
2270
- );
2444
+ // Note: PublishRequests arriving on the new channel before
2445
+ // ActivateSession completes the session transfer are expected
2446
+ // transient occurrences, not errors worth logging.
2447
+ if (request.constructor.name !== "PublishRequest") {
2448
+ errorLog(
2449
+ chalk.red.bgWhite(
2450
+ `ERROR: channel.channelId !== session.channelId on processing request ${request.constructor.name}`
2451
+ ),
2452
+ channel.channelId,
2453
+ session.channelId
2454
+ );
2455
+ }
2271
2456
  }
2272
2457
  message.session_statusCode = StatusCodes.BadSecureChannelIdInvalid;
2273
2458
  } else if (channel_has_session(channel, session)) {
@@ -2315,9 +2500,9 @@ export class OPCUAServer extends OPCUABaseServer {
2315
2500
  return channel.send_response("MSG", response1, message);
2316
2501
  } catch (err) {
2317
2502
  warningLog(err);
2318
- // istanbul ignore next
2503
+ // c8 ignore next
2319
2504
  if (types.isNativeError(err)) {
2320
- // istanbul ignore next
2505
+ // c8 ignore next
2321
2506
  errorLog(
2322
2507
  "Internal error in issuing response\nplease contact support@sterfive.com",
2323
2508
  message.request.toString(),
@@ -2325,7 +2510,7 @@ export class OPCUAServer extends OPCUABaseServer {
2325
2510
  response1.toString()
2326
2511
  );
2327
2512
  }
2328
- // istanbul ignore next
2513
+ // c8 ignore next
2329
2514
  throw err;
2330
2515
  }
2331
2516
  }
@@ -2337,12 +2522,14 @@ export class OPCUAServer extends OPCUABaseServer {
2337
2522
  return g_sendError(channel, message, ResponseClass, statusCode);
2338
2523
  }
2339
2524
 
2340
- let response: any;
2341
- /* istanbul ignore next */
2525
+ /* c8 ignore next */
2342
2526
  if (!message.session || message.session_statusCode !== StatusCodes.Good) {
2343
- const errMessage = "=>" + message.session_statusCode?.toString();
2344
- response = new ServiceFault({ responseHeader: { serviceResult: message.session_statusCode } });
2345
- debugLog(chalk.red.bold(errMessage), chalk.yellow(message.session_statusCode!.toString()), response.constructor.name);
2527
+ const sessionStatusCode = message.session_statusCode ?? StatusCodes.BadInternalError;
2528
+ const errMessage = `=>${sessionStatusCode.toString()}`;
2529
+ const response = new ServiceFault({
2530
+ responseHeader: { serviceResult: sessionStatusCode }
2531
+ });
2532
+ debugLog(chalk.red.bold(errMessage), chalk.yellow(sessionStatusCode.toString()), response.constructor.name);
2346
2533
  return sendResponse(response);
2347
2534
  }
2348
2535
 
@@ -2398,7 +2585,7 @@ export class OPCUAServer extends OPCUABaseServer {
2398
2585
  ): Promise<void> {
2399
2586
  assert(typeof actionToPerform === "function");
2400
2587
  const request = message.request as unknown as { subscriptionId: number };
2401
- assert(Object.prototype.hasOwnProperty.call(request, "subscriptionId"));
2588
+ assert(Object.hasOwn(request, "subscriptionId"));
2402
2589
 
2403
2590
  this._apply_on_SessionObject(
2404
2591
  ResponseClass,
@@ -2427,7 +2614,7 @@ export class OPCUAServer extends OPCUABaseServer {
2427
2614
  ): void {
2428
2615
  assert(typeof actionToPerform === "function");
2429
2616
  const request = message.request as unknown as { subscriptionIds: number[] };
2430
- assert(Object.prototype.hasOwnProperty.call(request, "subscriptionIds"));
2617
+ assert(Object.hasOwn(request, "subscriptionIds"));
2431
2618
 
2432
2619
  this._apply_on_SessionObject(
2433
2620
  ResponseClass,
@@ -2465,7 +2652,7 @@ export class OPCUAServer extends OPCUABaseServer {
2465
2652
  responseHeader: {
2466
2653
  serviceResult
2467
2654
  },
2468
- results: results as any
2655
+ results: results as unknown as StatusCode[]
2469
2656
  });
2470
2657
  sendResponse(response);
2471
2658
  }
@@ -2483,7 +2670,7 @@ export class OPCUAServer extends OPCUABaseServer {
2483
2670
  message,
2484
2671
  channel,
2485
2672
  async (session: ServerSession, subscriptionId: number) => {
2486
- /* istanbul ignore next */
2673
+ /* c8 ignore next */
2487
2674
  if (isSubscriptionIdInvalid(subscriptionId)) {
2488
2675
  return StatusCodes.BadSubscriptionIdInvalid;
2489
2676
  }
@@ -2502,7 +2689,10 @@ export class OPCUAServer extends OPCUABaseServer {
2502
2689
  if (session) {
2503
2690
  const subscriptions = session.publishEngine.subscriptions;
2504
2691
  for (const subscription of subscriptions) {
2505
- await subscription.applyOnMonitoredItem(this.options.onDeleteMonitoredItem.bind(null, subscription) as any);
2692
+ const onDeleteFn = this.options.onDeleteMonitoredItem;
2693
+ await subscription.applyOnMonitoredItem(async (monitoredItem: MonitoredItem) => {
2694
+ await onDeleteFn(subscription, monitoredItem);
2695
+ });
2506
2696
  }
2507
2697
  }
2508
2698
  }
@@ -2517,8 +2707,6 @@ export class OPCUAServer extends OPCUABaseServer {
2517
2707
  const request = message.request as CloseSessionRequest;
2518
2708
  assert(request instanceof CloseSessionRequest);
2519
2709
 
2520
- let response;
2521
-
2522
2710
  message.session_statusCode = StatusCodes.Good;
2523
2711
 
2524
2712
  function sendError(statusCode: StatusCode) {
@@ -2535,11 +2723,12 @@ export class OPCUAServer extends OPCUABaseServer {
2535
2723
 
2536
2724
  const session = message.session;
2537
2725
  if (!session) {
2538
- return sendError(StatusCodes.BadSessionIdInvalid);
2726
+ sendError(StatusCodes.BadSessionIdInvalid);
2727
+ return;
2539
2728
  }
2540
2729
 
2541
2730
  // session has been created but not activated !
2542
- const wasNotActivated = session.status === "new";
2731
+ const _wasNotActivated = session.status === "new";
2543
2732
 
2544
2733
  (async () => {
2545
2734
  try {
@@ -2549,9 +2738,9 @@ export class OPCUAServer extends OPCUABaseServer {
2549
2738
  // return sendError(StatusCodes.BadSessionNotActivated);
2550
2739
  // }
2551
2740
 
2552
- response = new CloseSessionResponse({});
2741
+ const response = new CloseSessionResponse({});
2553
2742
  sendResponse(response);
2554
- } catch (err) {
2743
+ } catch (_err) {
2555
2744
  sendError(StatusCodes.BadInternalError);
2556
2745
  }
2557
2746
  })();
@@ -2566,7 +2755,7 @@ export class OPCUAServer extends OPCUABaseServer {
2566
2755
  protected _on_BrowseRequest(message: Message, channel: ServerSecureChannelLayer): void {
2567
2756
  const request = message.request as BrowseRequest;
2568
2757
  assert(request instanceof BrowseRequest);
2569
- const diagnostic: any = {};
2758
+ const diagnostic: Record<string, unknown> = {};
2570
2759
 
2571
2760
  this._apply_on_SessionObject(
2572
2761
  BrowseResponse,
@@ -2576,7 +2765,11 @@ export class OPCUAServer extends OPCUABaseServer {
2576
2765
  let response: BrowseResponse;
2577
2766
  // test view
2578
2767
  if (request.view && !request.view.viewId.isEmpty()) {
2579
- let theView: UAView | null = this.engine!.addressSpace!.findNode(request.view.viewId) as UAView;
2768
+ const addressSpace = this.engine.addressSpace;
2769
+ if (!addressSpace) {
2770
+ return sendError(StatusCodes.BadInternalError);
2771
+ }
2772
+ let theView: UAView | null = addressSpace.findNode(request.view.viewId) as UAView;
2580
2773
  if (theView && theView.nodeClass !== NodeClass.View) {
2581
2774
  // Error: theView is not a View
2582
2775
  diagnostic.localizedText = { text: "Expecting a view here" };
@@ -2602,9 +2795,9 @@ export class OPCUAServer extends OPCUABaseServer {
2602
2795
  assert(request.nodesToBrowse[0].schema.name === "BrowseDescription");
2603
2796
 
2604
2797
  const context = session.sessionContext;
2605
- const browseAll = (nodesToBrowse: BrowseDescriptionOptions[], callack: CallbackT<BrowseResult[]>) => {
2798
+ const browseAll = (_nodesToBrowse: BrowseDescriptionOptions[], callack: CallbackT<BrowseResult[]>) => {
2606
2799
  const f = callbackify(this.engine.browseWithAutomaticExpansion).bind(this.engine);
2607
- (f as any)(request.nodesToBrowse, context, callack);
2800
+ f(request.nodesToBrowse ?? [], context, callack);
2608
2801
  };
2609
2802
  // handle continuation point and requestedMaxReferencesPerNode
2610
2803
  const maxBrowseContinuationPoints = this.engine.serverCapabilities.maxBrowseContinuationPoints;
@@ -2618,7 +2811,7 @@ export class OPCUAServer extends OPCUABaseServer {
2618
2811
  maxBrowseContinuationPoints
2619
2812
  },
2620
2813
  request.nodesToBrowse,
2621
- (err, results) => {
2814
+ (_err, results) => {
2622
2815
  if (!results) {
2623
2816
  return sendError(StatusCodes.BadInternalError);
2624
2817
  }
@@ -2711,10 +2904,10 @@ export class OPCUAServer extends OPCUABaseServer {
2711
2904
  }
2712
2905
 
2713
2906
  // ask for a refresh of asynchronous variables
2714
- this.engine.refreshValues(request.nodesToRead, request.maxAge, (err?: Error | null) => {
2907
+ this.engine.refreshValues(request.nodesToRead, request.maxAge, (_err?: Error | null) => {
2715
2908
  this.engine.read(context, request).then((results) => {
2716
2909
  assert(results[0].schema.name === "DataValue");
2717
- assert(results.length === request.nodesToRead!.length);
2910
+ assert(results.length === request.nodesToRead?.length);
2718
2911
 
2719
2912
  const response = new ReadResponse({
2720
2913
  diagnosticInfos: undefined,
@@ -2722,7 +2915,7 @@ export class OPCUAServer extends OPCUABaseServer {
2722
2915
  });
2723
2916
  // set it here for performance
2724
2917
  response.results = results;
2725
- assert(response.diagnosticInfos!.length === 0);
2918
+ assert(response.diagnosticInfos?.length === 0);
2726
2919
  sendResponse(response);
2727
2920
  });
2728
2921
  });
@@ -2741,8 +2934,6 @@ export class OPCUAServer extends OPCUABaseServer {
2741
2934
  message,
2742
2935
  channel,
2743
2936
  (session: ServerSession, sendResponse: (response: Response) => void, sendError: (statsCode: StatusCode) => void) => {
2744
- let response;
2745
-
2746
2937
  const timestampsToReturn = request.timestampsToReturn;
2747
2938
 
2748
2939
  if (timestampsToReturn === TimestampsToReturn.Invalid) {
@@ -2785,17 +2976,17 @@ export class OPCUAServer extends OPCUABaseServer {
2785
2976
  .historyRead(context, request)
2786
2977
  .then((results: HistoryReadResult[]) => {
2787
2978
  assert(results[0].schema.name === "HistoryReadResult");
2788
- assert(results.length === request.nodesToRead!.length);
2979
+ assert(results.length === request.nodesToRead?.length);
2789
2980
 
2790
- response = new HistoryReadResponse({
2981
+ const response = new HistoryReadResponse({
2791
2982
  diagnosticInfos: undefined,
2792
2983
  results
2793
2984
  });
2794
2985
 
2795
- assert(response.diagnosticInfos!.length === 0);
2986
+ assert(response.diagnosticInfos?.length === 0);
2796
2987
  sendResponse(response);
2797
2988
  })
2798
- .catch((err) => {
2989
+ .catch((_err) => {
2799
2990
  return sendError(StatusCodes.BadHistoryOperationInvalid);
2800
2991
  });
2801
2992
  });
@@ -2827,8 +3018,6 @@ export class OPCUAServer extends OPCUABaseServer {
2827
3018
  message,
2828
3019
  channel,
2829
3020
  (session: ServerSession, sendResponse: (response: Response) => void, sendError: (statusCode: StatusCode) => void) => {
2830
- let response;
2831
-
2832
3021
  if (!request.nodesToWrite || request.nodesToWrite.length === 0) {
2833
3022
  return sendError(StatusCodes.BadNothingToDo);
2834
3023
  }
@@ -2851,8 +3040,8 @@ export class OPCUAServer extends OPCUABaseServer {
2851
3040
  this.engine
2852
3041
  .write(context, request.nodesToWrite)
2853
3042
  .then((results: StatusCode[]) => {
2854
- assert(results!.length === request.nodesToWrite!.length);
2855
- response = new WriteResponse({
3043
+ assert(results?.length === request.nodesToWrite?.length);
3044
+ const response = new WriteResponse({
2856
3045
  diagnosticInfos: undefined,
2857
3046
  results
2858
3047
  });
@@ -2869,8 +3058,11 @@ export class OPCUAServer extends OPCUABaseServer {
2869
3058
  // subscription services
2870
3059
  protected _on_CreateSubscriptionRequest(message: Message, channel: ServerSecureChannelLayer): void {
2871
3060
  const engine = this.engine;
2872
- const addressSpace = engine.addressSpace!;
2873
-
3061
+ const addressSpace = engine.addressSpace;
3062
+ if (!addressSpace) {
3063
+ g_sendError(channel, message, CreateSubscriptionResponse, StatusCodes.BadSessionClosed);
3064
+ return;
3065
+ }
2874
3066
  const request = message.request as CreateSubscriptionRequest;
2875
3067
  assert(request instanceof CreateSubscriptionRequest);
2876
3068
 
@@ -2915,7 +3107,7 @@ export class OPCUAServer extends OPCUABaseServer {
2915
3107
  channel,
2916
3108
  async (session: ServerSession, subscriptionId: number) => {
2917
3109
  let subscription = this.engine.findOrphanSubscription(subscriptionId);
2918
- // istanbul ignore next
3110
+ // c8 ignore next
2919
3111
  if (subscription) {
2920
3112
  warningLog("Deleting an orphan subscription", subscriptionId);
2921
3113
 
@@ -2960,7 +3152,11 @@ export class OPCUAServer extends OPCUABaseServer {
2960
3152
 
2961
3153
  protected _on_CreateMonitoredItemsRequest(message: Message, channel: ServerSecureChannelLayer): void {
2962
3154
  const engine = this.engine;
2963
- const addressSpace = engine.addressSpace!;
3155
+ const addressSpace = engine.addressSpace;
3156
+ if (!addressSpace) {
3157
+ g_sendError(channel, message, CreateMonitoredItemsResponse, StatusCodes.BadSessionClosed);
3158
+ return;
3159
+ }
2964
3160
 
2965
3161
  const request = message.request as CreateMonitoredItemsRequest;
2966
3162
  assert(request instanceof CreateMonitoredItemsRequest);
@@ -2970,7 +3166,7 @@ export class OPCUAServer extends OPCUABaseServer {
2970
3166
  message,
2971
3167
  channel,
2972
3168
  async (
2973
- session: ServerSession,
3169
+ _session: ServerSession,
2974
3170
  subscription: Subscription,
2975
3171
  sendResponse: (response: Response) => void,
2976
3172
  sendError: (statusCode: StatusCode) => void
@@ -2999,7 +3195,9 @@ export class OPCUAServer extends OPCUABaseServer {
2999
3195
  monitoredItemCreateRequest
3000
3196
  );
3001
3197
  if (monitoredItem) {
3002
- await options.onCreateMonitoredItem!(subscription, monitoredItem);
3198
+ if (options.onCreateMonitoredItem) {
3199
+ await options.onCreateMonitoredItem(subscription, monitoredItem);
3200
+ }
3003
3201
  subscription.postCreateMonitoredItem(monitoredItem, monitoredItemCreateRequest, createResult);
3004
3202
  }
3005
3203
  return createResult;
@@ -3037,10 +3235,10 @@ export class OPCUAServer extends OPCUABaseServer {
3037
3235
  message,
3038
3236
  channel,
3039
3237
  async (
3040
- session: ServerSession,
3238
+ _session: ServerSession,
3041
3239
  subscription: Subscription,
3042
3240
  sendResponse: (response: ModifySubscriptionResponse) => void,
3043
- sendError: (statusCode: StatusCode) => void
3241
+ _sendError: (statusCode: StatusCode) => void
3044
3242
  ) => {
3045
3243
  subscription.modify(request);
3046
3244
 
@@ -3064,7 +3262,7 @@ export class OPCUAServer extends OPCUABaseServer {
3064
3262
  message,
3065
3263
  channel,
3066
3264
  async (
3067
- session: ServerSession,
3265
+ _session: ServerSession,
3068
3266
  subscription: Subscription,
3069
3267
  sendResponse: (response: ModifyMonitoredItemsResponse) => void,
3070
3268
  sendError: (statusCode: StatusCode) => void
@@ -3078,7 +3276,7 @@ export class OPCUAServer extends OPCUABaseServer {
3078
3276
  return sendError(StatusCodes.BadNothingToDo);
3079
3277
  }
3080
3278
 
3081
- /* istanbul ignore next */
3279
+ /* c8 ignore next */
3082
3280
  if (this.engine.serverCapabilities.operationLimits.maxMonitoredItemsPerCall > 0) {
3083
3281
  if (request.itemsToModify.length > this.engine.serverCapabilities.operationLimits.maxMonitoredItemsPerCall) {
3084
3282
  return sendError(StatusCodes.BadTooManyOperations);
@@ -3091,7 +3289,9 @@ export class OPCUAServer extends OPCUABaseServer {
3091
3289
  const monitoredItemId = item.monitoredItemId;
3092
3290
  const monitoredItem = subscription.getMonitoredItem(monitoredItemId);
3093
3291
  if (!monitoredItem) {
3094
- return new MonitoredItemModifyResult({ statusCode: StatusCodes.BadMonitoredItemIdInvalid });
3292
+ return new MonitoredItemModifyResult({
3293
+ statusCode: StatusCodes.BadMonitoredItemIdInvalid
3294
+ });
3095
3295
  }
3096
3296
 
3097
3297
  // adjust samplingInterval if === -1
@@ -3119,7 +3319,7 @@ export class OPCUAServer extends OPCUABaseServer {
3119
3319
  PublishResponse,
3120
3320
  message,
3121
3321
  channel,
3122
- (session: ServerSession, sendResponse: (response: Response) => void, sendError: (statusCode: StatusCode) => void) => {
3322
+ (session: ServerSession, sendResponse: (response: Response) => void, _sendError: (statusCode: StatusCode) => void) => {
3123
3323
  assert(session);
3124
3324
  assert(session.publishEngine); // server.publishEngine doesn't exists, OPCUAServer has probably shut down already
3125
3325
  session.publishEngine._on_PublishRequest(request, (_request1, response) => {
@@ -3137,7 +3337,7 @@ export class OPCUAServer extends OPCUABaseServer {
3137
3337
  SetPublishingModeResponse,
3138
3338
  message,
3139
3339
  channel,
3140
- async (session: ServerSession, subscription: Subscription) => {
3340
+ async (_session: ServerSession, subscription: Subscription) => {
3141
3341
  return subscription.setPublishingMode(publishingEnabled);
3142
3342
  }
3143
3343
  );
@@ -3152,17 +3352,17 @@ export class OPCUAServer extends OPCUABaseServer {
3152
3352
  message,
3153
3353
  channel,
3154
3354
  async (
3155
- session: ServerSession,
3355
+ _session: ServerSession,
3156
3356
  subscription: Subscription,
3157
3357
  sendResponse: (response: Response) => void,
3158
3358
  sendError: (statusCode: StatusCode) => void
3159
3359
  ) => {
3160
- /* istanbul ignore next */
3360
+ /* c8 ignore next */
3161
3361
  if (!request.monitoredItemIds || request.monitoredItemIds.length === 0) {
3162
3362
  return sendError(StatusCodes.BadNothingToDo);
3163
3363
  }
3164
3364
 
3165
- /* istanbul ignore next */
3365
+ /* c8 ignore next */
3166
3366
  if (this.engine.serverCapabilities.operationLimits.maxMonitoredItemsPerCall > 0) {
3167
3367
  if (request.monitoredItemIds.length > this.engine.serverCapabilities.operationLimits.maxMonitoredItemsPerCall) {
3168
3368
  return sendError(StatusCodes.BadTooManyOperations);
@@ -3204,7 +3404,7 @@ export class OPCUAServer extends OPCUABaseServer {
3204
3404
  message,
3205
3405
  channel,
3206
3406
  async (
3207
- session: ServerSession,
3407
+ _session: ServerSession,
3208
3408
  subscription: Subscription,
3209
3409
  sendResponse: (response: Response) => void,
3210
3410
  sendError: (statusCode: StatusCode) => void
@@ -3232,7 +3432,9 @@ export class OPCUAServer extends OPCUABaseServer {
3232
3432
  linksToRemove
3233
3433
  );
3234
3434
  if (statusCode.isNotGood()) {
3235
- const response = new ServiceFault({ responseHeader: { serviceResult: statusCode } });
3435
+ const response = new ServiceFault({
3436
+ responseHeader: { serviceResult: statusCode }
3437
+ });
3236
3438
  sendResponse(response);
3237
3439
  } else {
3238
3440
  const response = new SetTriggeringResponse({
@@ -3253,7 +3455,11 @@ export class OPCUAServer extends OPCUABaseServer {
3253
3455
  if (!this.options.onDeleteMonitoredItem) {
3254
3456
  return;
3255
3457
  }
3256
- await subscription.applyOnMonitoredItem(this.options.onDeleteMonitoredItem.bind(null, subscription) as any);
3458
+ const t = this.options.onDeleteMonitoredItem.bind(null, subscription);
3459
+ const functor = async (monitoredItem: MonitoredItem) => {
3460
+ await t(monitoredItem);
3461
+ };
3462
+ await subscription.applyOnMonitoredItem(functor);
3257
3463
  }
3258
3464
  protected _on_RepublishRequest(message: Message, channel: ServerSecureChannelLayer): void {
3259
3465
  const request = message.request as RepublishRequest;
@@ -3264,7 +3470,7 @@ export class OPCUAServer extends OPCUABaseServer {
3264
3470
  message,
3265
3471
  channel,
3266
3472
  async (
3267
- session: ServerSession,
3473
+ _session: ServerSession,
3268
3474
  subscription: Subscription,
3269
3475
  sendResponse: (response: Response) => void,
3270
3476
  sendError: (statusCode: StatusCode) => void
@@ -3306,17 +3512,17 @@ export class OPCUAServer extends OPCUABaseServer {
3306
3512
  message,
3307
3513
  channel,
3308
3514
  async (
3309
- session: ServerSession,
3515
+ _session: ServerSession,
3310
3516
  subscription: Subscription,
3311
3517
  sendResponse: (response: Response) => void,
3312
3518
  sendError: (statusCode: StatusCode) => void
3313
3519
  ) => {
3314
- /* istanbul ignore next */
3520
+ /* c8 ignore next */
3315
3521
  if (!request.monitoredItemIds || request.monitoredItemIds.length === 0) {
3316
3522
  return sendError(StatusCodes.BadNothingToDo);
3317
3523
  }
3318
3524
 
3319
- /* istanbul ignore next */
3525
+ /* c8 ignore next */
3320
3526
  if (this.engine.serverCapabilities.operationLimits.maxMonitoredItemsPerCall > 0) {
3321
3527
  if (request.monitoredItemIds.length > this.engine.serverCapabilities.operationLimits.maxMonitoredItemsPerCall) {
3322
3528
  return sendError(StatusCodes.BadTooManyOperations);
@@ -3355,7 +3561,7 @@ export class OPCUAServer extends OPCUABaseServer {
3355
3561
  message,
3356
3562
  channel,
3357
3563
  async (
3358
- session: ServerSession,
3564
+ _session: ServerSession,
3359
3565
  sendResponse: (response: Response) => void,
3360
3566
  sendError: (statusCode: StatusCode) => void
3361
3567
  ) => {
@@ -3380,7 +3586,7 @@ export class OPCUAServer extends OPCUABaseServer {
3380
3586
  });
3381
3587
  sendResponse(response);
3382
3588
  })
3383
- .catch((err) => {
3589
+ .catch((_err) => {
3384
3590
  sendError(StatusCodes.BadInternalError);
3385
3591
  });
3386
3592
  }
@@ -3401,8 +3607,6 @@ export class OPCUAServer extends OPCUABaseServer {
3401
3607
  message,
3402
3608
  channel,
3403
3609
  (session: ServerSession, sendResponse: (response: Response) => void, sendError: (statusCode: StatusCode) => void) => {
3404
- let response;
3405
-
3406
3610
  if (!request.methodsToCall || request.methodsToCall.length === 0) {
3407
3611
  return sendError(StatusCodes.BadNothingToDo);
3408
3612
  }
@@ -3423,7 +3627,7 @@ export class OPCUAServer extends OPCUABaseServer {
3423
3627
  filterDiagnosticInfo(request.requestHeader.returnDiagnostics, response);
3424
3628
  sendResponse(response);
3425
3629
  })
3426
- .catch((err) => {
3630
+ .catch((_err) => {
3427
3631
  sendError(StatusCodes.BadInternalError);
3428
3632
  });
3429
3633
  }
@@ -3495,49 +3699,49 @@ export class OPCUAServer extends OPCUABaseServer {
3495
3699
  );
3496
3700
  }
3497
3701
 
3498
- /* istanbul ignore next */
3702
+ /* c8 ignore next */
3499
3703
  protected _on_Cancel(message: Message, channel: ServerSecureChannelLayer): void {
3500
- return g_sendError(channel, message, CancelResponse, StatusCodes.BadServiceUnsupported);
3704
+ g_sendError(channel, message, CancelResponse, StatusCodes.BadServiceUnsupported);
3501
3705
  }
3502
3706
 
3503
3707
  // NodeManagement Service Set Overview
3504
3708
  // This Service Set defines Services to add and delete AddressSpace Nodes and References between them. All added
3505
3709
  // Nodes continue to exist in the AddressSpace even if the Client that created them disconnects from the Server.
3506
3710
  //
3507
- /* istanbul ignore next */
3711
+ /* c8 ignore next */
3508
3712
  protected _on_AddNodes(message: Message, channel: ServerSecureChannelLayer): void {
3509
- return g_sendError(channel, message, AddNodesResponse, StatusCodes.BadServiceUnsupported);
3713
+ g_sendError(channel, message, AddNodesResponse, StatusCodes.BadServiceUnsupported);
3510
3714
  }
3511
3715
 
3512
- /* istanbul ignore next */
3716
+ /* c8 ignore next */
3513
3717
  protected _on_AddReferences(message: Message, channel: ServerSecureChannelLayer): void {
3514
- return g_sendError(channel, message, AddReferencesResponse, StatusCodes.BadServiceUnsupported);
3718
+ g_sendError(channel, message, AddReferencesResponse, StatusCodes.BadServiceUnsupported);
3515
3719
  }
3516
3720
 
3517
- /* istanbul ignore next */
3721
+ /* c8 ignore next */
3518
3722
  protected _on_DeleteNodes(message: Message, channel: ServerSecureChannelLayer): void {
3519
- return g_sendError(channel, message, DeleteNodesResponse, StatusCodes.BadServiceUnsupported);
3723
+ g_sendError(channel, message, DeleteNodesResponse, StatusCodes.BadServiceUnsupported);
3520
3724
  }
3521
3725
 
3522
- /* istanbul ignore next */
3726
+ /* c8 ignore next */
3523
3727
  protected _on_DeleteReferences(message: Message, channel: ServerSecureChannelLayer): void {
3524
- return g_sendError(channel, message, DeleteReferencesResponse, StatusCodes.BadServiceUnsupported);
3728
+ g_sendError(channel, message, DeleteReferencesResponse, StatusCodes.BadServiceUnsupported);
3525
3729
  }
3526
3730
 
3527
3731
  // Query Service
3528
- /* istanbul ignore next */
3732
+ /* c8 ignore next */
3529
3733
  protected _on_QueryFirst(message: Message, channel: ServerSecureChannelLayer): void {
3530
- return g_sendError(channel, message, QueryFirstResponse, StatusCodes.BadServiceUnsupported);
3734
+ g_sendError(channel, message, QueryFirstResponse, StatusCodes.BadServiceUnsupported);
3531
3735
  }
3532
3736
 
3533
- /* istanbul ignore next */
3737
+ /* c8 ignore next */
3534
3738
  protected _on_QueryNext(message: Message, channel: ServerSecureChannelLayer): void {
3535
- return g_sendError(channel, message, QueryNextResponse, StatusCodes.BadServiceUnsupported);
3739
+ g_sendError(channel, message, QueryNextResponse, StatusCodes.BadServiceUnsupported);
3536
3740
  }
3537
3741
 
3538
- /* istanbul ignore next */
3742
+ /* c8 ignore next */
3539
3743
  protected _on_HistoryUpdate(message: Message, channel: ServerSecureChannelLayer): void {
3540
- return g_sendError(channel, message, HistoryUpdateResponse, StatusCodes.BadServiceUnsupported);
3744
+ g_sendError(channel, message, HistoryUpdateResponse, StatusCodes.BadServiceUnsupported);
3541
3745
  }
3542
3746
 
3543
3747
  private createEndpoint(
@@ -3573,7 +3777,7 @@ export class OPCUAServer extends OPCUABaseServer {
3573
3777
  serverOption: OPCUAServerOptions,
3574
3778
  endpointOptions: OPCUAServerEndpointOptions
3575
3779
  ): OPCUAServerEndPoint {
3576
- /* istanbul ignore next */
3780
+ /* c8 ignore next */
3577
3781
  if (!endpointOptions) {
3578
3782
  throw new Error("internal error");
3579
3783
  }
@@ -3581,10 +3785,10 @@ export class OPCUAServer extends OPCUABaseServer {
3581
3785
  endpointOptions.hostname = endpointOptions.hostname || hostname;
3582
3786
  endpointOptions.port = endpointOptions.port === undefined ? 26543 : endpointOptions.port;
3583
3787
 
3584
- /* istanbul ignore next */
3788
+ /* c8 ignore next */
3585
3789
  if (
3586
- !Object.prototype.hasOwnProperty.call(endpointOptions, "port") ||
3587
- !isFinite(endpointOptions.port!) ||
3790
+ !Object.hasOwn(endpointOptions, "port") ||
3791
+ !Number.isFinite(endpointOptions.port) ||
3588
3792
  typeof endpointOptions.port !== "number"
3589
3793
  ) {
3590
3794
  throw new Error(
@@ -3597,10 +3801,9 @@ export class OPCUAServer extends OPCUABaseServer {
3597
3801
  const endPoint = this.createEndpoint(port, serverOption);
3598
3802
 
3599
3803
  endpointOptions.alternateHostname = endpointOptions.alternateHostname || [];
3600
- const alternateHostname =
3601
- endpointOptions.alternateHostname instanceof Array
3602
- ? endpointOptions.alternateHostname
3603
- : [endpointOptions.alternateHostname];
3804
+ const alternateHostname = Array.isArray(endpointOptions.alternateHostname)
3805
+ ? endpointOptions.alternateHostname
3806
+ : [endpointOptions.alternateHostname];
3604
3807
  const allowAnonymous = endpointOptions.allowAnonymous === undefined ? true : !!endpointOptions.allowAnonymous;
3605
3808
 
3606
3809
  endPoint.addStandardEndpointDescriptions({
@@ -3614,7 +3817,9 @@ export class OPCUAServer extends OPCUABaseServer {
3614
3817
 
3615
3818
  disableDiscovery: !!endpointOptions.disableDiscovery,
3616
3819
  // xx hostname,
3617
- resourcePath: serverOption.resourcePath || ""
3820
+ resourcePath: serverOption.resourcePath || "",
3821
+
3822
+ advertisedEndpoints: endpointOptions.advertisedEndpoints,
3618
3823
 
3619
3824
  // TODO userTokenTypes: endpointOptions.userTokenTypes || undefined,
3620
3825
 
@@ -3627,6 +3832,90 @@ export class OPCUAServer extends OPCUABaseServer {
3627
3832
  await super.initializeCM();
3628
3833
  await this.userCertificateManager.initialize();
3629
3834
  }
3835
+
3836
+ public on(event: "create_session", eventHandler: (session: ServerSession) => void): this;
3837
+
3838
+ public on(event: "session_activated", eventHandler: (session: ServerSession) => void): this;
3839
+
3840
+ public on(event: "session_closed", eventHandler: (session: ServerSession, reason: string) => void): this;
3841
+
3842
+ public on(event: "post_initialize", eventHandler: () => void): this;
3843
+
3844
+ /**
3845
+ * emitted when the server is trying to registered the LDS
3846
+ * but when the connection to the lds has failed
3847
+ * serverRegistrationPending is sent when the backoff signal of the
3848
+ * connection process is raised
3849
+ * @event serverRegistrationPending
3850
+ */
3851
+ public on(event: "serverRegistrationPending", eventHandler: () => void): this;
3852
+
3853
+ /**
3854
+ * event raised when server has been successfully registered on the local discovery server
3855
+ * @event serverRegistered
3856
+ */
3857
+ public on(event: "serverRegistered", eventHandler: () => void): this;
3858
+
3859
+ /**
3860
+ * event raised when server registration has been successfully renewed on the local discovery server
3861
+ * @event serverRegistered
3862
+ */
3863
+ public on(event: "serverRegistrationRenewed", eventHandler: () => void): this;
3864
+
3865
+ /**
3866
+ * event raised when server has been successfully unregistered from the local discovery server
3867
+ * @event serverUnregistered
3868
+ */
3869
+ public on(event: "serverUnregistered", eventHandler: () => void): this;
3870
+
3871
+ /**
3872
+ * event raised after the server has raised an OPCUA event toward a client
3873
+ */
3874
+ public on(event: "event", eventHandler: (eventData: unknown) => void): this;
3875
+
3876
+ /**
3877
+ * event raised when the server received a request from one of its connected client.
3878
+ * useful for trace purpose.
3879
+ */
3880
+ public on(event: "request", eventHandler: (request: Request, channel: ServerSecureChannelLayer) => void): this;
3881
+
3882
+ /**
3883
+ * event raised when the server send an response to a request to one of its connected client.
3884
+ * useful for trace purpose.
3885
+ */
3886
+ public on(event: "response", eventHandler: (request: Response, channel: ServerSecureChannelLayer) => void): this;
3887
+
3888
+ /**
3889
+ * event raised when a new secure channel is opened
3890
+ */
3891
+ public on(event: "newChannel", eventHandler: (channel: ServerSecureChannelLayer, endpoint: OPCUAServerEndPoint) => void): this;
3892
+
3893
+ /**
3894
+ * event raised when a new secure channel is closed
3895
+ */
3896
+ public on(
3897
+ event: "closeChannel",
3898
+ eventHandler: (channel: ServerSecureChannelLayer, endpoint: OPCUAServerEndPoint) => void
3899
+ ): this;
3900
+
3901
+ /**
3902
+ * event raised when the server refused a tcp connection from a client. ( for instance because too any connections)
3903
+ */
3904
+ public on(event: "connectionRefused", eventHandler: (socketData: ISocketData, endpoint: OPCUAServerEndPoint) => void): this;
3905
+
3906
+ /**
3907
+ * event raised when a OpenSecureChannel has failed, it could be a invalid certificate or malformed message
3908
+ */
3909
+ public on(
3910
+ event: "openSecureChannelFailure",
3911
+ eventHandler: (socketData: ISocketData, channelData: IChannelData, endpoint: OPCUAServerEndPoint) => void
3912
+ ): this;
3913
+
3914
+ public on(event: string, eventHandler: (...args: unknown[]) => void): this;
3915
+ // biome-ignore lint/suspicious/noExplicitAny: must match EventEmitter.on() signature
3916
+ public on(event: string, eventHandler: (...args: any[]) => void): this {
3917
+ return super.on(event, eventHandler);
3918
+ }
3630
3919
  }
3631
3920
 
3632
3921
  const userIdentityTokenPasswordRemoved = (userIdentityToken?: UserIdentityToken): UserIdentityToken => {
@@ -3683,7 +3972,10 @@ function raiseAuditActivateSessionEventType(this: OPCUAServer, session: ServerSe
3683
3972
  // use the same identifier in all AuditEvents related to the Session Service Set
3684
3973
  // (AuditCreateSessionEventType, AuditActivateSessionEventType and their subtypes) and
3685
3974
  // the SecureChannel Service Set (AuditChannelEventType and its subtypes).
3686
- secureChannelId: { dataType: "String", value: session.channel!.channelId!.toString() }
3975
+ secureChannelId: {
3976
+ dataType: "String",
3977
+ value: session.channel?.channelId?.toString() ?? ""
3978
+ }
3687
3979
  });
3688
3980
  }
3689
3981
  }
@@ -3706,7 +3998,7 @@ export interface RaiseEventAuditEventData extends RaiseEventData {
3706
3998
 
3707
3999
  export interface RaiseEventAuditUpdateMethodEventData extends RaiseEventAuditEventData {
3708
4000
  methodId: PseudoVariantNodeId;
3709
- inputArguments: any;
4001
+ inputArguments: PseudoVariant | Variant | UAEventType | undefined;
3710
4002
  }
3711
4003
 
3712
4004
  export interface RaiseEventAuditConditionCommentEventData extends RaiseEventAuditUpdateMethodEventData {
@@ -3722,6 +4014,7 @@ export interface RaiseEventAuditSessionEventData extends RaiseEventAuditEventDat
3722
4014
  }
3723
4015
 
3724
4016
  export interface RaiseEventAuditCreateSessionEventData extends RaiseEventAuditSessionEventData {
4017
+ sessionId: PseudoVariantNodeId;
3725
4018
  /**
3726
4019
  * part 5 - 6.4.8 AuditCreateSessionEventType
3727
4020
  * SecureChannelId shall uniquely identify the SecureChannel.
@@ -3841,115 +4134,7 @@ export interface RaiseAuditCertificateRevokedEventData extends RaiseAuditCertifi
3841
4134
  * There are no additional Properties defined for this EventType
3842
4135
  */
3843
4136
  export interface RaiseAuditCertificateMismatchEventData extends RaiseAuditCertificateEventData { }
3844
- export interface OPCUAServer {
3845
- /**
3846
- * @internal
3847
- * @param eventType
3848
- * @param options
3849
- */
3850
- raiseEvent(eventType: "AuditSessionEventType", options: RaiseEventAuditSessionEventData): void;
3851
-
3852
- raiseEvent(eventType: "AuditCreateSessionEventType", options: RaiseEventAuditCreateSessionEventData): void;
3853
-
3854
- raiseEvent(eventType: "AuditActivateSessionEventType", options: RaiseEventAuditActivateSessionEventData): void;
3855
-
3856
- raiseEvent(eventType: "AuditCreateSessionEventType", options: RaiseEventData): void;
3857
-
3858
- raiseEvent(eventType: "AuditConditionCommentEventType", options: RaiseEventAuditConditionCommentEventData): void;
3859
-
3860
- raiseEvent(eventType: "AuditUrlMismatchEventType", options: RaiseEventAuditUrlMismatchEventTypeData): void;
3861
-
3862
- raiseEvent(eventType: "TransitionEventType", options: RaiseEventTransitionEventData): void;
3863
-
3864
- raiseEvent(eventType: "AuditCertificateInvalidEventType", options: RaiseAuditCertificateInvalidEventData): void;
3865
- raiseEvent(eventType: "AuditCertificateExpiredEventType", options: RaiseAuditCertificateExpiredEventData): void;
3866
- raiseEvent(eventType: "AuditCertificateUntrustedEventType", options: RaiseAuditCertificateUntrustedEventData): void;
3867
- raiseEvent(eventType: "AuditCertificateRevokedEventType", options: RaiseAuditCertificateRevokedEventData): void;
3868
- raiseEvent(eventType: "AuditCertificateMismatchEventType", options: RaiseAuditCertificateMismatchEventData): void;
3869
- raiseEvent(eventType: UAEventType, options: RaiseEventData): void;
3870
- }
3871
-
3872
- // eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging
3873
- export interface OPCUAServer extends EventEmitter {
3874
- on(event: "create_session", eventHandler: (session: ServerSession) => void): this;
3875
-
3876
- on(event: "session_activated", eventHandler: (session: ServerSession) => void): this;
3877
-
3878
- on(event: "session_closed", eventHandler: (session: ServerSession, reason: string) => void): this;
3879
-
3880
- on(event: "post_initialize", eventHandler: () => void): this;
3881
-
3882
- /**
3883
- * emitted when the server is trying to registered the LDS
3884
- * but when the connection to the lds has failed
3885
- * serverRegistrationPending is sent when the backoff signal of the
3886
- * connection process is raised
3887
- * @event serverRegistrationPending
3888
- */
3889
- on(event: "serverRegistrationPending", eventHandler: () => void): this;
3890
-
3891
- /**
3892
- * event raised when server has been successfully registered on the local discovery server
3893
- * @event serverRegistered
3894
- */
3895
- on(event: "serverRegistered", eventHandler: () => void): this;
3896
-
3897
- /**
3898
- * event raised when server registration has been successfully renewed on the local discovery server
3899
- * @event serverRegistered
3900
- */
3901
- on(event: "serverRegistrationRenewed", eventHandler: () => void): this;
3902
-
3903
- /**
3904
- * event raised when server has been successfully unregistered from the local discovery server
3905
- * @event serverUnregistered
3906
- */
3907
- on(event: "serverUnregistered", eventHandler: () => void): this;
3908
-
3909
- /**
3910
- * event raised after the server has raised an OPCUA event toward a client
3911
- */
3912
- on(event: "event", eventHandler: (eventData: any) => void): this;
3913
-
3914
- /**
3915
- * event raised when the server received a request from one of its connected client.
3916
- * useful for trace purpose.
3917
- */
3918
- on(event: "request", eventHandler: (request: Request, channel: ServerSecureChannelLayer) => void): this;
3919
-
3920
- /**
3921
- * event raised when the server send an response to a request to one of its connected client.
3922
- * useful for trace purpose.
3923
- */
3924
- on(event: "response", eventHandler: (request: Response, channel: ServerSecureChannelLayer) => void): this;
3925
-
3926
- /**
3927
- * event raised when a new secure channel is opened
3928
- */
3929
- on(event: "newChannel", eventHandler: (channel: ServerSecureChannelLayer, endpoint: OPCUAServerEndPoint) => void): this;
3930
-
3931
- /**
3932
- * event raised when a new secure channel is closed
3933
- */
3934
- on(event: "closeChannel", eventHandler: (channel: ServerSecureChannelLayer, endpoint: OPCUAServerEndPoint) => void): this;
3935
-
3936
- /**
3937
- * event raised when the server refused a tcp connection from a client. ( for instance because too any connections)
3938
- */
3939
- on(event: "connectionRefused", eventHandler: (socketData: ISocketData, endpoint: OPCUAServerEndPoint) => void): this;
3940
-
3941
- /**
3942
- * event raised when a OpenSecureChannel has failed, it could be a invalid certificate or malformed message
3943
- */
3944
- on(
3945
- event: "openSecureChannelFailure",
3946
- eventHandler: (socketData: ISocketData, channelData: IChannelData, endpoint: OPCUAServerEndPoint) => void
3947
- ): this;
3948
-
3949
- on(event: string, eventHandler: (...args: [any?, ...any[]]) => void): this;
3950
- }
3951
4137
 
3952
4138
  const opts = { multiArgs: false };
3953
- OPCUAServer.prototype.start = withCallback(OPCUAServer.prototype.start, opts);
3954
4139
  OPCUAServer.prototype.initialize = withCallback(OPCUAServer.prototype.initialize, opts);
3955
4140
  OPCUAServer.prototype.shutdown = withCallback(OPCUAServer.prototype.shutdown, opts);