node-opcua-address-space 2.78.0 → 2.79.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 (46) hide show
  1. package/dist/src/alarms_and_conditions/ua_limit_alarm_impl.d.ts +1 -1
  2. package/dist/src/base_node_impl.d.ts +1 -0
  3. package/dist/src/base_node_impl.js +30 -3
  4. package/dist/src/base_node_impl.js.map +1 -1
  5. package/dist/src/historical_access/address_space_historical_data_node.js +14 -3
  6. package/dist/src/historical_access/address_space_historical_data_node.js.map +1 -1
  7. package/dist/src/nodeset_tools/nodeset_to_xml.js +45 -9
  8. package/dist/src/nodeset_tools/nodeset_to_xml.js.map +1 -1
  9. package/dist/src/ua_method_impl.d.ts +2 -1
  10. package/dist/src/ua_method_impl.js +9 -1
  11. package/dist/src/ua_method_impl.js.map +1 -1
  12. package/dist/src/ua_variable_impl.d.ts +5 -0
  13. package/dist/src/ua_variable_impl.js +32 -2
  14. package/dist/src/ua_variable_impl.js.map +1 -1
  15. package/package.json +26 -26
  16. package/src/alarms_and_conditions/ua_limit_alarm_impl.ts +1 -1
  17. package/src/base_node_impl.ts +34 -3
  18. package/src/historical_access/address_space_historical_data_node.ts +18 -3
  19. package/src/nodeset_tools/nodeset_to_xml.ts +57 -13
  20. package/src/ua_method_impl.ts +9 -3
  21. package/src/ua_variable_impl.ts +36 -4
  22. package/test_helpers/test_fixtures/mini.Node.Set2.xml +178 -0
  23. package/dist/source/helpers/check_event_clause.d.ts +0 -17
  24. package/dist/source/helpers/check_event_clause.js +0 -53
  25. package/dist/source/helpers/check_event_clause.js.map +0 -1
  26. package/dist/src/alarms_and_conditions/check_where_clause.d.ts +0 -4
  27. package/dist/src/alarms_and_conditions/check_where_clause.js +0 -110
  28. package/dist/src/alarms_and_conditions/check_where_clause.js.map +0 -1
  29. package/dist/src/alarms_and_conditions/condition_info.d.ts +0 -27
  30. package/dist/src/alarms_and_conditions/condition_info.js +0 -55
  31. package/dist/src/alarms_and_conditions/condition_info.js.map +0 -1
  32. package/dist/src/alarms_and_conditions/condition_snapshot.d.ts +0 -233
  33. package/dist/src/alarms_and_conditions/condition_snapshot.js +0 -667
  34. package/dist/src/alarms_and_conditions/condition_snapshot.js.map +0 -1
  35. package/dist/src/alarms_and_conditions/extract_event_fields.d.ts +0 -10
  36. package/dist/src/alarms_and_conditions/extract_event_fields.js +0 -90
  37. package/dist/src/alarms_and_conditions/extract_event_fields.js.map +0 -1
  38. package/dist/src/data_access/ua_multistate_value_discrete.d.ts +0 -51
  39. package/dist/src/data_access/ua_multistate_value_discrete.js +0 -250
  40. package/dist/src/data_access/ua_multistate_value_discrete.js.map +0 -1
  41. package/dist/src/data_access/ua_two_state_discrete.d.ts +0 -25
  42. package/dist/src/data_access/ua_two_state_discrete.js +0 -154
  43. package/dist/src/data_access/ua_two_state_discrete.js.map +0 -1
  44. package/dist/src/nodeset_tools/typedictionary_to_xml.d.ts +0 -2
  45. package/dist/src/nodeset_tools/typedictionary_to_xml.js +0 -155
  46. package/dist/src/nodeset_tools/typedictionary_to_xml.js.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-opcua-address-space",
3
- "version": "2.78.0",
3
+ "version": "2.79.0",
4
4
  "description": "pure nodejs OPCUA SDK - module -address-space",
5
5
  "main": "./dist/src/index_current.js",
6
6
  "types": "./dist/source/index.d.ts",
@@ -16,40 +16,41 @@
16
16
  "c": "mocha --version"
17
17
  },
18
18
  "dependencies": {
19
- "@types/lodash": "4.14.184",
19
+ "@types/lodash": "4.14.185",
20
+ "@types/semver": "^7.3.12",
20
21
  "async": "^3.2.4",
21
22
  "chalk": "4.1.2",
22
23
  "dequeue": "^1.0.5",
23
24
  "lodash": "4.17.21",
24
- "node-opcua-address-space-base": "2.78.0",
25
+ "node-opcua-address-space-base": "2.79.0",
25
26
  "node-opcua-assert": "2.77.0",
26
- "node-opcua-basic-types": "2.77.0",
27
+ "node-opcua-basic-types": "2.79.0",
27
28
  "node-opcua-binary-stream": "2.77.0",
28
- "node-opcua-client-dynamic-extension-object": "2.78.0",
29
+ "node-opcua-client-dynamic-extension-object": "2.79.0",
29
30
  "node-opcua-constants": "2.77.0",
30
31
  "node-opcua-crypto": "^1.11.0",
31
- "node-opcua-data-access": "2.78.0",
32
- "node-opcua-data-model": "2.78.0",
33
- "node-opcua-data-value": "2.78.0",
32
+ "node-opcua-data-access": "2.79.0",
33
+ "node-opcua-data-model": "2.79.0",
34
+ "node-opcua-data-value": "2.79.0",
34
35
  "node-opcua-date-time": "2.77.0",
35
36
  "node-opcua-debug": "2.77.0",
36
37
  "node-opcua-enum": "2.77.0",
37
- "node-opcua-extension-object": "2.78.0",
38
- "node-opcua-factory": "2.78.0",
39
- "node-opcua-nodeid": "2.77.0",
40
- "node-opcua-nodeset-ua": "2.78.0",
41
- "node-opcua-numeric-range": "2.78.0",
38
+ "node-opcua-extension-object": "2.79.0",
39
+ "node-opcua-factory": "2.79.0",
40
+ "node-opcua-nodeid": "2.79.0",
41
+ "node-opcua-nodeset-ua": "2.79.0",
42
+ "node-opcua-numeric-range": "2.79.0",
42
43
  "node-opcua-object-registry": "2.77.0",
43
- "node-opcua-pseudo-session": "2.78.0",
44
- "node-opcua-service-browse": "2.78.0",
45
- "node-opcua-service-call": "2.78.0",
46
- "node-opcua-service-history": "2.78.0",
47
- "node-opcua-service-translate-browse-path": "2.78.0",
48
- "node-opcua-service-write": "2.78.0",
44
+ "node-opcua-pseudo-session": "2.79.0",
45
+ "node-opcua-service-browse": "2.79.0",
46
+ "node-opcua-service-call": "2.79.0",
47
+ "node-opcua-service-history": "2.79.0",
48
+ "node-opcua-service-translate-browse-path": "2.79.0",
49
+ "node-opcua-service-write": "2.79.0",
49
50
  "node-opcua-status-code": "2.77.0",
50
- "node-opcua-types": "2.78.0",
51
+ "node-opcua-types": "2.79.0",
51
52
  "node-opcua-utils": "2.77.0",
52
- "node-opcua-variant": "2.78.0",
53
+ "node-opcua-variant": "2.79.0",
53
54
  "node-opcua-xml2json": "2.77.0",
54
55
  "semver": "^7.3.7",
55
56
  "set-prototype-of": "^1.0.0",
@@ -57,14 +58,13 @@
57
58
  "xml-writer": "^1.7.0"
58
59
  },
59
60
  "devDependencies": {
60
- "@types/semver": "7.3.12",
61
61
  "mocha": "^10.0.0",
62
62
  "node-opcua-benchmarker": "2.77.0",
63
63
  "node-opcua-leak-detector": "2.77.0",
64
64
  "node-opcua-nodesets": "2.77.0",
65
- "node-opcua-packet-analyzer": "2.78.0",
66
- "node-opcua-service-filter": "2.78.0",
67
- "node-opcua-test-fixtures": "2.78.0",
65
+ "node-opcua-packet-analyzer": "2.79.0",
66
+ "node-opcua-service-filter": "2.79.0",
67
+ "node-opcua-test-fixtures": "2.79.0",
68
68
  "should": "^13.2.3",
69
69
  "sinon": "^14.0.0",
70
70
  "source-map-support": "^0.5.21"
@@ -84,5 +84,5 @@
84
84
  "internet of things"
85
85
  ],
86
86
  "homepage": "http://node-opcua.github.io/",
87
- "gitHead": "31c6eee3c51f52427584364fff2fdb07bbac65be"
87
+ "gitHead": "1a6d41827954dccf2c2cdff9344cc11fc99767f3"
88
88
  }
@@ -10,7 +10,7 @@ import { make_warningLog } from "node-opcua-debug";
10
10
  import { NodeId } from "node-opcua-nodeid";
11
11
  import { StatusCodes } from "node-opcua-status-code";
12
12
  import { DataType, VariantOptions } from "node-opcua-variant";
13
- import { UAShelvedStateMachineEx } from "../../source";
13
+ import { UAShelvedStateMachineEx } from "../../source/interfaces/state_machine/ua_shelved_state_machine_ex";
14
14
  import { InstantiateLimitAlarmOptions } from "../../source/interfaces/alarms_and_conditions/instantiate_limit_alarm_options";
15
15
  import { UALimitAlarmEx } from "../../source/interfaces/alarms_and_conditions/ua_limit_alarm_ex";
16
16
  import { NamespacePrivate } from "../namespace_private";
@@ -677,6 +677,9 @@ export class BaseNodeImpl extends EventEmitter implements BaseNode {
677
677
  ) {
678
678
  return callback(null, StatusCodes.BadAttributeIdInvalid);
679
679
  }
680
+ if (!this.canUserWriteAttribute(context, writeValue.attributeId)) {
681
+ return callback(null, StatusCodes.BadUserAccessDenied);
682
+ }
680
683
  // by default Node is read-only,
681
684
  // this method needs to be overridden to change the behavior
682
685
  callback(null, StatusCodes.BadNotWritable);
@@ -1263,6 +1266,23 @@ export class BaseNodeImpl extends EventEmitter implements BaseNode {
1263
1266
  private _clear_caches() {
1264
1267
  BaseNode_clearCache(this);
1265
1268
  }
1269
+
1270
+ public canUserWriteAttribute(context: ISessionContext | null, attributeId: AttributeIds): boolean {
1271
+ // the Client is allowed to write to Attributes other than the Value,
1272
+ // Historizing or RolePermissions Attribute
1273
+ if (!context) return true;
1274
+ if (attributeId === AttributeIds.Historizing) {
1275
+ return context.checkPermission(this, PermissionType.WriteHistorizing);
1276
+ }
1277
+ if (attributeId === AttributeIds.RolePermissions) {
1278
+ return context.checkPermission(this, PermissionType.WriteRolePermissions);
1279
+ }
1280
+ if (attributeId === AttributeIds.Value) {
1281
+ return context.checkPermission(this, PermissionType.Write);
1282
+ }
1283
+ return context.checkPermission(this, PermissionType.WriteAttribute);
1284
+ }
1285
+
1266
1286
  private _readAccessRestrictions(context: ISessionContext | null): DataValue {
1267
1287
  // https://reference.opcfoundation.org/v104/Core/docs/Part3/8.56/
1268
1288
  if (this.accessRestrictions === undefined) {
@@ -1281,7 +1301,7 @@ export class BaseNodeImpl extends EventEmitter implements BaseNode {
1281
1301
  // https://reference.opcfoundation.org/v104/Core/docs/Part3/4.8.3/
1282
1302
 
1283
1303
  // to do check that current user can read permission
1284
- if (context && !context?.checkPermission(this as any, PermissionType.ReadRolePermissions)) {
1304
+ if (context && !context.checkPermission(this, PermissionType.ReadRolePermissions)) {
1285
1305
  return new DataValue({
1286
1306
  statusCode: StatusCodes.BadSecurityModeInsufficient
1287
1307
  });
@@ -1312,6 +1332,16 @@ export class BaseNodeImpl extends EventEmitter implements BaseNode {
1312
1332
  }
1313
1333
 
1314
1334
  private _readUserRolePermissions(context: ISessionContext | null): DataValue {
1335
+ const allUserCanSeeTheirOwnRolePermissions = true;
1336
+ if (!allUserCanSeeTheirOwnRolePermissions) {
1337
+ // to do check that current user can read permission
1338
+ if (context && !context.checkPermission(this, PermissionType.ReadRolePermissions)) {
1339
+ return new DataValue({
1340
+ statusCode: StatusCodes.BadSecurityModeInsufficient
1341
+ });
1342
+ }
1343
+ }
1344
+
1315
1345
  if (this.rolePermissions === undefined) {
1316
1346
  // to do : If not specified, the value of DefaultUserRolePermissions Property from
1317
1347
  // the Namespace Metadata Object associated with the Node is used instead.
@@ -1320,8 +1350,8 @@ export class BaseNodeImpl extends EventEmitter implements BaseNode {
1320
1350
  });
1321
1351
  }
1322
1352
  const context1: ISessionContext = context === null ? SessionContext.defaultContext : context;
1323
- // for the time being ...
1324
- // get user Permission
1353
+
1354
+ // for the time being get user Permission
1325
1355
  const rolePermissions = this.rolePermissions
1326
1356
  .map(({ roleId, permissions }) => {
1327
1357
  return new RolePermissionType({
@@ -1330,6 +1360,7 @@ export class BaseNodeImpl extends EventEmitter implements BaseNode {
1330
1360
  });
1331
1361
  })
1332
1362
  .filter(({ roleId }) => context1.currentUserHasRole(roleId));
1363
+
1333
1364
  return new DataValue({
1334
1365
  statusCode: StatusCodes.Good,
1335
1366
  value: {
@@ -172,7 +172,7 @@ export class VariableHistorian implements IVariableHistorian {
172
172
  reverseDataValue: boolean,
173
173
  callback: CallbackT<DataValue[]>
174
174
  ): void {
175
- assert(typeof callback === 'function');
175
+ assert(typeof callback === "function");
176
176
 
177
177
  let dataValues = filter_dequeue(this._timeline, historyReadRawModifiedDetails, maxNumberToExtract, isReversed);
178
178
 
@@ -322,7 +322,7 @@ function _historyReadRawAsync(
322
322
  reverseDataValue: boolean,
323
323
  callback: CallbackT<DataValue[]>
324
324
  ) {
325
- assert(typeof callback === 'function');
325
+ assert(typeof callback === "function");
326
326
  this.varHistorian!.extractDataValues(historyReadRawModifiedDetails, maxNumberToExtract, isReversed, reverseDataValue, callback);
327
327
  }
328
328
 
@@ -418,9 +418,17 @@ function _historyReadRaw(
418
418
  // the Bad_TimestampNotSupported StatusCode.
419
419
 
420
420
  const session = context.session;
421
+
422
+ // istanbul ignore next
421
423
  if (!session) {
422
424
  throw new Error("Internal Error: context.session not defined");
423
425
  }
426
+
427
+ // istanbul ignore next
428
+ if (!session.continuationPointManager) {
429
+ throw new Error("Internal Error: context.session.continuationPointManager not defined");
430
+ }
431
+
424
432
  if (continuationData.continuationPoint) {
425
433
  const cnt = session.continuationPointManager.getNextHistoryReadRaw(
426
434
  historyReadRawModifiedDetails.numValuesPerNode,
@@ -546,7 +554,14 @@ function _historyRead(
546
554
  continuationData: ContinuationData,
547
555
  callback: CallbackT<HistoryReadResult>
548
556
  ) {
549
- assert(typeof callback === 'function');
557
+ if (!this.canUserReadHistory(context)) {
558
+ const result = new HistoryReadResult({
559
+ statusCode: StatusCodes.BadUserAccessDenied
560
+ });
561
+ callback(null, result);
562
+ }
563
+
564
+ assert(typeof callback === "function");
550
565
  if (historyReadDetails instanceof ReadRawModifiedDetails) {
551
566
  // note: only ReadRawModifiedDetails supported at this time
552
567
  return this._historyReadRawModify(context, historyReadDetails, indexRange, dataEncoding, continuationData, callback);
@@ -4,7 +4,7 @@
4
4
  */
5
5
  // produce nodeset xml files
6
6
  import { assert } from "node-opcua-assert";
7
- import { ObjectIds } from "node-opcua-constants";
7
+ import { ObjectIds, VariableIds } from "node-opcua-constants";
8
8
  import { make_debugLog, make_errorLog, make_warningLog } from "node-opcua-debug";
9
9
  import { ExtensionObject } from "node-opcua-extension-object";
10
10
  import {
@@ -16,7 +16,7 @@ import {
16
16
  makeAccessLevelFlag,
17
17
  QualifiedName
18
18
  } from "node-opcua-data-model";
19
- import { NodeId, NodeIdType, resolveNodeId } from "node-opcua-nodeid";
19
+ import { ExpandedNodeId, NodeId, NodeIdType, resolveNodeId } from "node-opcua-nodeid";
20
20
  import * as utils from "node-opcua-utils";
21
21
  import { Variant, VariantArrayType, DataType } from "node-opcua-variant";
22
22
  import {
@@ -99,10 +99,8 @@ function b(xw: XmlWriter, browseName: QualifiedName): string {
99
99
  }
100
100
 
101
101
  function _dumpReverseReferences(xw: XmlWriter, node: BaseNode) {
102
-
103
102
  const addressSpace = node.addressSpace;
104
103
  const hasSubtypeReferenceType = addressSpace.findReferenceType("HasSubtype")!;
105
-
106
104
  }
107
105
  function _dumpReferences(xw: XmlWriter, node: BaseNode) {
108
106
  xw.startElement("References");
@@ -217,15 +215,29 @@ function _dumpXmlElement(xw: XmlWriter, v: string) {
217
215
  </uax:ExtensionObject>
218
216
  */
219
217
  type XmlNamespaceUri = string;
218
+ type NamespaceUri = string;
220
219
  type XmlNs = string;
221
220
  interface XmlWriterEx extends XmlWriter {
222
221
  map: Record<XmlNamespaceUri, XmlNs>;
223
222
  stackMap: Record<XmlNamespaceUri, XmlNs>[];
223
+ namespaceArray: NamespaceUri[];
224
224
  }
225
- function initXmlWriterEx(xw: XmlWriter, map: Record<XmlNamespaceUri, XmlNs>): void {
225
+ function initXmlWriterEx(xw: XmlWriter, map: Record<XmlNamespaceUri, XmlNs>, namespaceArray: NamespaceUri[]): void {
226
226
  const xwe = xw as XmlWriterEx;
227
227
  xwe.map = map;
228
228
  xwe.stackMap = [];
229
+ xwe.namespaceArray = namespaceArray;
230
+ }
231
+ function findXsdNamespaceUri(xw: XmlWriter, nodeId: NodeId): string {
232
+ const xwe = xw as XmlWriterEx;
233
+ if (!xwe.namespaceArray) {
234
+ return "";
235
+ }
236
+ const namespace = xwe.namespaceArray[nodeId.namespace];
237
+ if (namespace === "http://opcfoundation.org/UA/") {
238
+ return "http://opcfoundation.org/UA/2008/02/Types.xsd";
239
+ }
240
+ return namespace.replace(/\/$/, "") + "/Types.xsd";
229
241
  }
230
242
 
231
243
  function getPrefix(xw: XmlWriter, namespace: XmlNamespaceUri): XmlNs {
@@ -290,6 +302,9 @@ function _dumpVariantInnerExtensionObject(
290
302
  definition: StructureDefinition,
291
303
  value: ExtensionObject
292
304
  ) {
305
+ const namespaceUri = findXsdNamespaceUri(xw, definition.defaultEncodingId);
306
+ const ns = getPrefix(xw, namespaceUri);
307
+
293
308
  for (const field of definition.fields || []) {
294
309
  const dataTypeNodeId = field.dataType;
295
310
 
@@ -305,8 +320,11 @@ function _dumpVariantInnerExtensionObject(
305
320
  // to do ?? shall we do a extension Object here ?
306
321
  continue; // ns=0;i=0 is reserved
307
322
  }
323
+
308
324
  const { name, definition } = definitionMap.findDefinition(dataTypeNodeId);
309
- xw.startElement(fieldName);
325
+
326
+ startElementEx(xw, ns, fieldName, namespaceUri);
327
+ // xw.startElement(fieldName);
310
328
 
311
329
  let fun: (value: any) => void = (value: any) => {
312
330
  /** */
@@ -339,6 +357,7 @@ function _dumpVariantInnerExtensionObject(
339
357
  console.log(field);
340
358
  // throw err;
341
359
  }
360
+ restoreDefaultNamespace(xw);
342
361
  xw.endElement();
343
362
  }
344
363
  }
@@ -443,10 +462,13 @@ function _dumpVariantExtensionObjectValue_Body(
443
462
  value: any
444
463
  ) {
445
464
  if (value) {
446
- xw.startElement(name);
465
+ const namespaceUri = findXsdNamespaceUri(xw, definition.defaultEncodingId);
466
+ const ns = getPrefix(xw, namespaceUri);
467
+ startElementEx(xw, ns, `${name}`, namespaceUri);
447
468
  if (value) {
448
469
  _dumpVariantInnerExtensionObject(xw, definitionMap, definition, value);
449
470
  }
471
+ restoreDefaultNamespace(xw);
450
472
  xw.endElement();
451
473
  }
452
474
  }
@@ -877,7 +899,7 @@ function _dumpUADataTypeDefinition(xw: XmlWriter, uaDataType: UADataType) {
877
899
 
878
900
  const dataValue = uaDataType.readAttribute(SessionContext.defaultContext, AttributeIds.DataTypeDefinition);
879
901
 
880
- if (dataValue.statusCode === StatusCodes.Good) {
902
+ if (true || dataValue.statusCode === StatusCodes.Good) {
881
903
  const definition = uaDataType.getStructureDefinition();
882
904
  const baseDefinition = uaDataTypeBase ? uaDataTypeBase.getStructureDefinition() : null;
883
905
  xw.startElement("Definition");
@@ -1332,11 +1354,20 @@ UADataTypeImpl.prototype.dumpXML = function (xw: XmlWriter) {
1332
1354
  dumpUADataType(xw, this);
1333
1355
  };
1334
1356
 
1357
+ function makeTypeXsd(namespaceUri: string): string {
1358
+ return namespaceUri.replace(/\/$/, "") + "/Type.xsd";
1359
+ }
1360
+
1335
1361
  // eslint-disable-next-line max-statements
1336
1362
  NamespaceImpl.prototype.toNodeset2XML = function (this: NamespaceImpl) {
1337
1363
  const dependency = constructNamespaceDependency(this);
1338
1364
  const translationTable = constructNamespaceTranslationTable(dependency);
1339
1365
 
1366
+ const namespaceArrayNode = this.addressSpace.findNode(VariableIds.Server_NamespaceArray);
1367
+ const namespaceArray: string[] = namespaceArrayNode
1368
+ ? namespaceArrayNode.readAttribute(null, AttributeIds.Value).value.value
1369
+ : [];
1370
+
1340
1371
  const xw = new XMLWriter(true);
1341
1372
  xw.translationTable = translationTable;
1342
1373
 
@@ -1346,17 +1377,30 @@ NamespaceImpl.prototype.toNodeset2XML = function (this: NamespaceImpl) {
1346
1377
  xw.writeAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
1347
1378
  xw.writeAttribute("xmlns:uax", "http://opcfoundation.org/UA/2008/02/Types.xsd");
1348
1379
  xw.writeAttribute("xmlns", "http://opcfoundation.org/UA/2011/03/UANodeSet.xsd");
1380
+
1381
+ const namespacesMap: Record<string, string> = {
1382
+ "http://opcfoundation.org/UA/2011/03/UANodeSet.xsd": "",
1383
+ "http://opcfoundation.org/UA/2008/02/Types.xsd": "uax",
1384
+ "http://www.w3.org/2001/XMLSchema-instance": "xsi"
1385
+ };
1386
+
1387
+ for (const namespace of dependency) {
1388
+ if (namespace.index === 0) {
1389
+ continue;
1390
+ }
1391
+ const translatedIndex = translationTable[namespace.index];
1392
+
1393
+ const smallName = `ns${translatedIndex}`;
1394
+ xw.writeAttribute(`xmlns:${smallName}`, makeTypeXsd(namespace.namespaceUri));
1395
+ namespacesMap[namespace.namespaceUri] = smallName;
1396
+ }
1349
1397
  // xx xw.writeAttribute("Version", "1.02");
1350
1398
  // xx xw.writeAttribute("LastModified", (new Date()).toISOString());
1351
1399
 
1352
1400
  // ------------- INamespace Uris
1353
1401
  xw.startElement("NamespaceUris");
1354
1402
 
1355
- initXmlWriterEx(xw, {
1356
- "http://opcfoundation.org/UA/2011/03/UANodeSet.xsd": "",
1357
- "http://opcfoundation.org/UA/2008/02/Types.xsd": "uax",
1358
- "http://www.w3.org/2001/XMLSchema-instance": "xsi"
1359
- });
1403
+ initXmlWriterEx(xw, namespacesMap, namespaceArray);
1360
1404
 
1361
1405
  // xx const namespaceArray = namespace.addressSpace.getNamespaceArray();
1362
1406
  for (const depend of dependency) {
@@ -31,7 +31,7 @@ import {
31
31
  defaultCloneFilter,
32
32
  defaultCloneExtraInfo
33
33
  } from "node-opcua-address-space-base";
34
- import { SessionContext } from "../source";
34
+ import { SessionContext } from "../source/session_context";
35
35
  import { _clone } from "./base_node_private";
36
36
  import { _handle_hierarchy_parent } from "./namespace_impl";
37
37
  import { BaseNodeImpl } from "./base_node_impl";
@@ -85,7 +85,13 @@ export class UAMethodImpl extends BaseNodeImpl implements UAMethod {
85
85
  }
86
86
  return true;
87
87
  }
88
-
88
+ public getUserExecutableFlag(context: ISessionContext | null): boolean {
89
+ if (context && !context.checkPermission(this, PermissionType.Call)) {
90
+ return false;
91
+ }
92
+ if (!this.getExecutableFlag(context)) return false;
93
+ return true;
94
+ }
89
95
  /**
90
96
  *
91
97
  * @returns true if the method is bound
@@ -107,7 +113,7 @@ export class UAMethodImpl extends BaseNodeImpl implements UAMethod {
107
113
  options.statusCode = StatusCodes.Good;
108
114
  break;
109
115
  case AttributeIds.UserExecutable:
110
- options.value = { dataType: DataType.Boolean, value: this.getExecutableFlag(context) };
116
+ options.value = { dataType: DataType.Boolean, value: this.getUserExecutableFlag(context) };
111
117
  options.statusCode = StatusCodes.Good;
112
118
  break;
113
119
  default:
@@ -389,6 +389,25 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
389
389
  return this.checkPermissionAndAccessLevelPrivate(context, PermissionType.Write, AccessLevelFlag.CurrentWrite);
390
390
  }
391
391
 
392
+ public canUserReadHistory(context: ISessionContext): boolean {
393
+ return this.checkPermissionAndAccessLevelPrivate(context, PermissionType.ReadHistory, AccessLevelFlag.HistoryRead);
394
+ }
395
+ public canUserWriteHistorizingAttribute(context: ISessionContext): boolean {
396
+ if (context && !context.checkPermission(this, PermissionType.WriteHistorizing)) {
397
+ return false;
398
+ }
399
+ return true;
400
+ }
401
+ public canUserInsertHistory(context: ISessionContext): boolean {
402
+ return this.checkPermissionAndAccessLevelPrivate(context, PermissionType.InsertHistory, AccessLevelFlag.HistoryWrite);
403
+ }
404
+ public canUserModifyHistory(context: ISessionContext): boolean {
405
+ return this.checkPermissionAndAccessLevelPrivate(context, PermissionType.ModifyHistory, AccessLevelFlag.HistoryWrite);
406
+ }
407
+ public canUserDeleteHistory(context: ISessionContext): boolean {
408
+ return this.checkPermissionAndAccessLevelPrivate(context, PermissionType.DeleteHistory, AccessLevelFlag.HistoryWrite);
409
+ }
410
+
392
411
  /**
393
412
  *
394
413
  *
@@ -949,6 +968,10 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
949
968
  if (!callback) {
950
969
  throw new Error("Internal error");
951
970
  }
971
+
972
+ if (!this.canUserWriteAttribute(context, writeValueOptions.attributeId!)) {
973
+ return callback(null, StatusCodes.BadUserAccessDenied);
974
+ }
952
975
  const writeValue: WriteValue =
953
976
  writeValueOptions instanceof WriteValue ? (writeValueOptions as WriteValue) : new WriteValue(writeValueOptions);
954
977
 
@@ -972,18 +995,20 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
972
995
  break;
973
996
  case AttributeIds.Historizing:
974
997
  if (writeValue.value!.value.dataType !== DataType.Boolean) {
975
- return callback(null, StatusCodes.BadNotSupported);
998
+ return callback(null, StatusCodes.BadTypeMismatch);
999
+ }
1000
+ if (!this.canUserWriteHistorizingAttribute(context)) {
1001
+ return callback(null, StatusCodes.BadUserAccessDenied);
976
1002
  }
977
1003
  // if the variable has no historizing in place reject
978
- if (!(this as any)["hA Configuration"]) {
1004
+ if (!this.getChildByName("HA Configuration")) {
979
1005
  return callback(null, StatusCodes.BadNotSupported);
980
1006
  }
981
1007
  // check if user is allowed to do that !
982
1008
  // TODO
983
-
984
1009
  this.historizing = !!writeValue.value!.value.value; // yes ! indeed !
985
-
986
1010
  return callback(null, StatusCodes.Good);
1011
+
987
1012
  default:
988
1013
  super.writeAttribute(context, writeValue, callback);
989
1014
  break;
@@ -1496,6 +1521,7 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
1496
1521
  if (typeof this._historyRead !== "function") {
1497
1522
  return callback!(null, new HistoryReadResult({ statusCode: StatusCodes.BadNotReadable }));
1498
1523
  }
1524
+
1499
1525
  this._historyRead(context, historyReadDetails, indexRange, dataEncoding, continuationData, callback!);
1500
1526
  }
1501
1527
 
@@ -1534,6 +1560,12 @@ export class UAVariableImpl extends BaseNodeImpl implements UAVariable {
1534
1560
  continuationData: ContinuationData,
1535
1561
  callback: CallbackT<HistoryReadResult>
1536
1562
  ): void {
1563
+ if (!this.canUserReadHistory(context)) {
1564
+ const result = new HistoryReadResult({
1565
+ statusCode: StatusCodes.BadUserAccessDenied
1566
+ });
1567
+ callback(null, result);
1568
+ }
1537
1569
  const result = new HistoryReadResult({
1538
1570
  statusCode: StatusCodes.BadHistoryOperationUnsupported
1539
1571
  });