node-opcua-server 2.58.0 → 2.62.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.
@@ -21,7 +21,8 @@ import {
21
21
  ServerSecureChannelParent,
22
22
  toURI,
23
23
  AsymmetricAlgorithmSecurityHeader,
24
- IServerSessionBase
24
+ IServerSessionBase,
25
+ Message
25
26
  } from "node-opcua-secure-channel";
26
27
  import { UserTokenType } from "node-opcua-service-endpoints";
27
28
  import { EndpointDescription } from "node-opcua-service-endpoints";
@@ -747,7 +748,7 @@ export class OPCUAServerEndPoint extends EventEmitter implements ServerSecureCha
747
748
  }
748
749
  });
749
750
 
750
- channel.on("message", (message: any) => {
751
+ channel.on("message", (message: Message) => {
751
752
  // forward
752
753
  this.emit("message", message, channel, this);
753
754
  });
@@ -1001,10 +1002,12 @@ function estimateSecurityLevel(securityMode: MessageSecurityMode, securityPolicy
1001
1002
  return 4; // deprecated => low
1002
1003
  case SecurityPolicy.Basic256Rsa15:
1003
1004
  return 4 + offset;
1005
+ case SecurityPolicy.Aes128_Sha256_RsaOaep:
1006
+ return 5 + offset;
1004
1007
  case SecurityPolicy.Basic256Sha256:
1005
1008
  return 6 + offset;
1006
- case SecurityPolicy.Aes128_Sha256_RsaOaep:
1007
- return 1;
1009
+ case SecurityPolicy.Aes256_Sha256_RsaPss:
1010
+ return 7 + offset;
1008
1011
 
1009
1012
  default:
1010
1013
  case SecurityPolicy.None:
@@ -1047,65 +1050,31 @@ function _makeEndpointDescription(options: MakeEndpointDescriptionOptions): Endp
1047
1050
  });
1048
1051
  }
1049
1052
 
1050
- const onlyCertificateLessConnection =
1051
- options.onlyCertificateLessConnection === undefined ? false : options.onlyCertificateLessConnection;
1052
-
1053
- if (!onlyCertificateLessConnection) {
1054
- if (options.securityPolicies.indexOf(SecurityPolicy.Basic256) >= 0) {
1053
+ const a = (tokenType: UserTokenType, securityPolicy: SecurityPolicy, name: string) => {
1054
+ if (options.securityPolicies.indexOf(securityPolicy) >= 0) {
1055
1055
  userIdentityTokens.push({
1056
- policyId: u("username_basic256"),
1057
- tokenType: UserTokenType.UserName,
1058
-
1056
+ policyId: u(name),
1057
+ tokenType,
1059
1058
  issuedTokenType: null,
1060
1059
  issuerEndpointUrl: null,
1061
- securityPolicyUri: SecurityPolicy.Basic256
1060
+ securityPolicyUri: securityPolicy
1062
1061
  });
1063
1062
  }
1063
+ };
1064
+ const onlyCertificateLessConnection =
1065
+ options.onlyCertificateLessConnection === undefined ? false : options.onlyCertificateLessConnection;
1064
1066
 
1065
- if (options.securityPolicies.indexOf(SecurityPolicy.Basic128Rsa15) >= 0) {
1066
- userIdentityTokens.push({
1067
- policyId: u("username_basic128Rsa15"),
1068
- tokenType: UserTokenType.UserName,
1069
-
1070
- issuedTokenType: null,
1071
- issuerEndpointUrl: null,
1072
- securityPolicyUri: SecurityPolicy.Basic128Rsa15
1073
- });
1074
- }
1075
-
1076
- if (options.securityPolicies.indexOf(SecurityPolicy.Basic256Sha256) >= 0) {
1077
- userIdentityTokens.push({
1078
- policyId: u("username_basic256Sha256"),
1079
- tokenType: UserTokenType.UserName,
1080
-
1081
- issuedTokenType: null,
1082
- issuerEndpointUrl: null,
1083
- securityPolicyUri: SecurityPolicy.Basic256Sha256
1084
- });
1085
- }
1067
+ if (!onlyCertificateLessConnection) {
1068
+ a(UserTokenType.UserName, SecurityPolicy.Basic256, "username_basic256");
1069
+ a(UserTokenType.UserName, SecurityPolicy.Basic128Rsa15, "username_basic128Rsa15");
1070
+ a(UserTokenType.UserName, SecurityPolicy.Basic256Sha256, "username_basic256Sha256");
1071
+ a(UserTokenType.UserName, SecurityPolicy.Aes128_Sha256_RsaOaep, "username_aes128Sha256RsaOaep");
1086
1072
 
1087
1073
  // X509
1088
- if (options.securityPolicies.indexOf(SecurityPolicy.Basic256) >= 0) {
1089
- userIdentityTokens.push({
1090
- policyId: u("certificate_basic256"),
1091
- tokenType: UserTokenType.UserName,
1092
-
1093
- issuedTokenType: null,
1094
- issuerEndpointUrl: null,
1095
- securityPolicyUri: SecurityPolicy.Basic256
1096
- });
1097
- }
1098
- // Certificate
1099
- if (options.securityPolicies.indexOf(SecurityPolicy.Basic256Sha256) >= 0) {
1100
- userIdentityTokens.push({
1101
- policyId: u("certificate_basic256Sha256"),
1102
- tokenType: UserTokenType.Certificate,
1103
-
1104
- issuedTokenType: null,
1105
- issuerEndpointUrl: null,
1106
- securityPolicyUri: SecurityPolicy.Basic256Sha256
1107
- });
1108
- }
1074
+ a(UserTokenType.Certificate, SecurityPolicy.Basic256, "certificate_basic256");
1075
+ a(UserTokenType.Certificate, SecurityPolicy.Basic128Rsa15, "certificate_basic128Rsa15");
1076
+ a(UserTokenType.Certificate, SecurityPolicy.Basic256Sha256, "certificate_basic256Sha256");
1077
+ a(UserTokenType.Certificate, SecurityPolicy.Aes128_Sha256_RsaOaep, "certificate_aes128Sha256RsaOaep");
1109
1078
  }
1110
1079
  } else {
1111
1080
  // note:
@@ -1195,5 +1164,7 @@ const defaultSecurityPolicies = [
1195
1164
  SecurityPolicy.Basic128Rsa15,
1196
1165
  SecurityPolicy.Basic256,
1197
1166
  // xx UNUSED!! SecurityPolicy.Basic256Rsa15,
1198
- SecurityPolicy.Basic256Sha256
1167
+ SecurityPolicy.Basic256Sha256,
1168
+ SecurityPolicy.Aes128_Sha256_RsaOaep
1169
+ // NO USED YET SecurityPolicy.Aes256_Sha256_RsaPss
1199
1170
  ];
@@ -11,7 +11,6 @@ import {
11
11
  AddressSpace,
12
12
  BaseNode,
13
13
  bindExtObjArrayNode,
14
- DataValueCallback,
15
14
  ensureDatatypeExtractedWithCallback,
16
15
  ensureObjectIsSecure,
17
16
  MethodFunctor,
@@ -229,8 +228,8 @@ function getMonitoredItemsId(
229
228
  const callMethodResult = new CallMethodResult({
230
229
  statusCode: result.statusCode,
231
230
  outputArguments: [
232
- { dataType: DataType.UInt32, arrayType: VariantArrayType.Array, value: new Uint32Array(result.serverHandles) },
233
- { dataType: DataType.UInt32, arrayType: VariantArrayType.Array, value: new Uint32Array(result.clientHandles) }
231
+ { dataType: DataType.UInt32, arrayType: VariantArrayType.Array, value: result.serverHandles },
232
+ { dataType: DataType.UInt32, arrayType: VariantArrayType.Array, value: result.clientHandles }
234
233
  ]
235
234
  });
236
235
  callback(null, callMethodResult);
@@ -473,8 +472,6 @@ export class ServerEngine extends EventEmitter {
473
472
  this._orphanPublishEngine.shutdown();
474
473
  }
475
474
 
476
- // xx console.log("xxxxxxxxx ServerEngine.shutdown must terminate "+ tokens.length," sessions");
477
-
478
475
  for (const token of tokens) {
479
476
  this.closeSession(token, true, "Terminated");
480
477
  }
@@ -642,7 +639,7 @@ export class ServerEngine extends EventEmitter {
642
639
  public setServerState(serverState: ServerState): void {
643
640
  assert(serverState !== null && serverState !== undefined);
644
641
  this.addressSpace?.rootFolder?.objects?.server?.serverStatus?.state?.setValueFromSource({
645
- dataType: DataType.UInt32,
642
+ dataType: DataType.Int32,
646
643
  value: serverState
647
644
  });
648
645
  }
@@ -817,7 +814,6 @@ export class ServerEngine extends EventEmitter {
817
814
 
818
815
  // TimeZoneDataType
819
816
  const timeZoneDataType = addressSpace.findDataType(resolveNodeId(DataTypeIds.TimeZoneDataType))!;
820
- // xx console.log(timeZoneDataType.toString());
821
817
 
822
818
  const timeZone = new TimeZoneDataType({
823
819
  daylightSavingInOffset: /* boolean*/ false,
@@ -1076,36 +1072,36 @@ export class ServerEngine extends EventEmitter {
1076
1072
  // mainly for compliance
1077
1073
 
1078
1074
  // The version number for the data type description. i=104
1079
- bindStandardScalar(VariableIds.DataTypeDescriptionType_DataTypeVersion, DataType.UInt16, () => {
1080
- return 0.0;
1075
+ bindStandardScalar(VariableIds.DataTypeDescriptionType_DataTypeVersion, DataType.String, () => {
1076
+ return "0";
1081
1077
  });
1082
1078
 
1083
1079
  const namingRuleDataTypeNode = addressSpace.findDataType(resolveNodeId(DataTypeIds.NamingRuleType))! as UADataType;
1084
- // xx console.log(nrt.toString());
1080
+
1085
1081
  if (namingRuleDataTypeNode) {
1086
1082
  const namingRuleType = (namingRuleDataTypeNode as any)._getEnumerationInfo().nameIndex; // getEnumeration("NamingRuleType");
1087
1083
  if (!namingRuleType) {
1088
1084
  throw new Error("Cannot find Enumeration definition for NamingRuleType");
1089
1085
  }
1090
1086
  // i=111
1091
- bindStandardScalar(VariableIds.ModellingRuleType_NamingRule, DataType.UInt16, () => {
1087
+ bindStandardScalar(VariableIds.ModellingRuleType_NamingRule, DataType.Int32, () => {
1092
1088
  return 0;
1093
1089
  });
1094
1090
 
1095
1091
  // i=112
1096
- bindStandardScalar(VariableIds.ModellingRule_Mandatory_NamingRule, DataType.UInt16, () => {
1092
+ bindStandardScalar(VariableIds.ModellingRule_Mandatory_NamingRule, DataType.Int32, () => {
1097
1093
  return namingRuleType.Mandatory ? namingRuleType.Mandatory.value : 0;
1098
1094
  });
1099
1095
 
1100
1096
  // i=113
1101
- bindStandardScalar(VariableIds.ModellingRule_Optional_NamingRule, DataType.UInt16, () => {
1097
+ bindStandardScalar(VariableIds.ModellingRule_Optional_NamingRule, DataType.Int32, () => {
1102
1098
  return namingRuleType.Optional ? namingRuleType.Optional.value : 0;
1103
1099
  });
1104
1100
  // i=114
1105
- bindStandardScalar(VariableIds.ModellingRule_ExposesItsArray_NamingRule, DataType.UInt16, () => {
1101
+ bindStandardScalar(VariableIds.ModellingRule_ExposesItsArray_NamingRule, DataType.Int32, () => {
1106
1102
  return namingRuleType.ExposesItsArray ? namingRuleType.ExposesItsArray.value : 0;
1107
1103
  });
1108
- bindStandardScalar(VariableIds.ModellingRule_MandatoryPlaceholder_NamingRule, DataType.UInt16, () => {
1104
+ bindStandardScalar(VariableIds.ModellingRule_MandatoryPlaceholder_NamingRule, DataType.Int32, () => {
1109
1105
  return namingRuleType.MandatoryPlaceholder ? namingRuleType.MandatoryPlaceholder.value : 0;
1110
1106
  });
1111
1107
  }
@@ -1162,7 +1158,6 @@ export class ServerEngine extends EventEmitter {
1162
1158
  if (samplingIntervalDiagnosticsArray) {
1163
1159
  addressSpace.deleteNode(samplingIntervalDiagnosticsArray);
1164
1160
  const s = serverDiagnosticsNode.getComponents();
1165
- // xx console.log(s.map((x) => x.browseName.toString()).join(" "));
1166
1161
  }
1167
1162
 
1168
1163
  const subscriptionDiagnosticsArrayNode = serverDiagnosticsNode.getComponentByName(
@@ -1233,9 +1228,9 @@ export class ServerEngine extends EventEmitter {
1233
1228
  node.onFirstBrowseAction = undefined;
1234
1229
  } catch (err) {
1235
1230
  if (err instanceof Error) {
1236
- console.log("onFirstBrowseAction method has failed", err.message);
1231
+ errorLog("onFirstBrowseAction method has failed", err.message);
1237
1232
  }
1238
- console.log(err);
1233
+ errorLog(err);
1239
1234
  }
1240
1235
  assert(node.onFirstBrowseAction === undefined, "expansion can only be made once");
1241
1236
  }
@@ -1720,7 +1715,6 @@ export class ServerEngine extends EventEmitter {
1720
1715
  }
1721
1716
  const subscription = session.publishEngine.getSubscriptionById(subscriptionId);
1722
1717
  if (subscription) {
1723
- // xx console.log("foundSubscription ", subscriptionId, " in session", session.sessionName);
1724
1718
  subscriptions.push(subscription);
1725
1719
  }
1726
1720
  });
@@ -1880,7 +1874,7 @@ export class ServerEngine extends EventEmitter {
1880
1874
  const referenceTime = new Date(Date.now() - maxAge);
1881
1875
 
1882
1876
  assert(callback instanceof Function);
1883
- const objectMap: any = {};
1877
+ const objectMap: Record<string, BaseNode> = {};
1884
1878
  for (const nodeToRefresh of nodesToRefresh) {
1885
1879
  // only consider node for which the caller wants to read the Value attribute
1886
1880
  // assuming that Value is requested if attributeId is missing,
@@ -1903,14 +1897,16 @@ export class ServerEngine extends EventEmitter {
1903
1897
 
1904
1898
  objectMap[key] = obj;
1905
1899
  }
1906
- if (Object.keys(objectMap).length === 0) {
1900
+
1901
+ const objectArray = Object.values(objectMap);
1902
+ if (objectArray.length === 0) {
1907
1903
  // nothing to do
1908
1904
  return callback(null, []);
1909
1905
  }
1910
1906
  // perform all asyncRefresh in parallel
1911
1907
  async.map(
1912
- objectMap,
1913
- (obj: BaseNode, inner_callback: DataValueCallback) => {
1908
+ objectArray,
1909
+ (obj: BaseNode, inner_callback: CallbackT<DataValue>) => {
1914
1910
  if (obj.nodeClass !== NodeClass.Variable) {
1915
1911
  inner_callback(
1916
1912
  null,
@@ -1920,7 +1916,18 @@ export class ServerEngine extends EventEmitter {
1920
1916
  );
1921
1917
  return;
1922
1918
  }
1923
- (obj as UAVariable).asyncRefresh(referenceTime, inner_callback);
1919
+ try {
1920
+ (obj as UAVariable).asyncRefresh(referenceTime, (err, dataValue) => {
1921
+ inner_callback(err, dataValue);
1922
+ });
1923
+ } catch (err) {
1924
+ // istanbul ignore next
1925
+ if (!(err instanceof Error)) {
1926
+ throw new Error("internal error");
1927
+ }
1928
+ errorLog("asyncRefresh internal error", err);
1929
+ inner_callback(err);
1930
+ }
1924
1931
  },
1925
1932
  (err?: Error | null, arrResult?: (DataValue | undefined)[]) => {
1926
1933
  callback(err || null, arrResult as DataValue[]);
@@ -2087,7 +2094,7 @@ export class ServerEngine extends EventEmitter {
2087
2094
  "HistoryReadDetails " +
2088
2095
  historyReadDetails.toString();
2089
2096
  if (doDebug) {
2090
- console.log(chalk.cyan("ServerEngine#_historyReadSingleNode "), chalk.white.bold(msg));
2097
+ debugLog(chalk.cyan("ServerEngine#_historyReadSingleNode "), chalk.white.bold(msg));
2091
2098
  }
2092
2099
  const err = new Error(msg);
2093
2100
  // object has no historyRead method
@@ -2132,13 +2139,12 @@ export class ServerEngine extends EventEmitter {
2132
2139
  if (methodNode && methodNode.bindMethod) {
2133
2140
  methodNode.bindMethod(func);
2134
2141
  } else {
2135
- console.log(
2142
+ warningLog(
2136
2143
  chalk.yellow("WARNING: cannot bind a method with id ") +
2137
2144
  chalk.cyan(nodeId.toString()) +
2138
2145
  chalk.yellow(". please check your nodeset.xml file or add this node programmatically")
2139
2146
  );
2140
-
2141
- console.log(traceFromThisProjectOnly());
2147
+ warningLog(traceFromThisProjectOnly());
2142
2148
  }
2143
2149
  }
2144
2150
 
@@ -196,7 +196,7 @@ export class ServerSession extends EventEmitter implements ISubscriber, ISession
196
196
  assert(!this.sessionObject, " sessionObject has not been cleared !");
197
197
 
198
198
  this.parent = null as any as ServerEngine;
199
- this.authenticationToken = NodeId.nullNodeId;
199
+ this.authenticationToken = new NodeId();
200
200
 
201
201
  if (this.publishEngine) {
202
202
  this.publishEngine.dispose();
@@ -407,12 +407,12 @@ export interface GetMonitoredItemsResult {
407
407
  * array of serverHandles for all MonitoredItems of the subscription
408
408
  * identified by subscriptionId.
409
409
  */
410
- serverHandles: number[];
410
+ serverHandles: Uint32Array;
411
411
  /**
412
412
  * array of clientHandles for all MonitoredItems of the subscription
413
413
  * identified by subscriptionId.
414
414
  */
415
- clientHandles: number[];
415
+ clientHandles: Uint32Array;
416
416
  statusCode: StatusCode;
417
417
  }
418
418
 
@@ -790,7 +790,7 @@ export class Subscription extends EventEmitter {
790
790
  this._pending_notifications.clear();
791
791
  this._sent_notification_messages = [];
792
792
 
793
- this.sessionId = NodeId.nullNodeId;
793
+ this.sessionId = new NodeId();
794
794
 
795
795
  this.$session = undefined;
796
796
  this.removeAllListeners();
@@ -1143,19 +1143,23 @@ export class Subscription extends EventEmitter {
1143
1143
  *
1144
1144
  */
1145
1145
  public getMonitoredItems(): GetMonitoredItemsResult {
1146
+ const monitoredItems = Object.keys(this.monitoredItems);
1147
+ const monitoredItemCount = monitoredItems.length;
1146
1148
  const result: GetMonitoredItemsResult = {
1147
- clientHandles: [] as number[],
1148
- serverHandles: [] as number[],
1149
+ clientHandles: new Uint32Array(monitoredItemCount),
1150
+ serverHandles: new Uint32Array(monitoredItemCount),
1149
1151
  statusCode: StatusCodes.Good
1150
1152
  };
1151
- for (const monitoredItemId of Object.keys(this.monitoredItems)) {
1152
- const monitoredItem = this.getMonitoredItem(parseInt(monitoredItemId, 10))!;
1153
- result.clientHandles.push(monitoredItem.clientHandle!);
1153
+ for (let index = 0; index < monitoredItemCount; index++) {
1154
+ const monitoredItemId = monitoredItems[index];
1155
+ const serverHandle = parseInt(monitoredItemId, 10);
1156
+ const monitoredItem = this.getMonitoredItem(serverHandle)!;
1157
+ result.clientHandles[index] = monitoredItem.clientHandle;
1154
1158
  // TODO: serverHandle is defined anywhere in the OPCUA Specification 1.02
1155
1159
  // I am not sure what shall be reported for serverHandle...
1156
1160
  // using monitoredItem.monitoredItemId instead...
1157
1161
  // May be a clarification in the OPCUA Spec is required.
1158
- result.serverHandles.push(parseInt(monitoredItemId, 10));
1162
+ result.serverHandles[index] = serverHandle;
1159
1163
  }
1160
1164
  return result;
1161
1165
  }