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.
- package/dist/src/alarms_and_conditions/ua_limit_alarm_impl.d.ts +1 -1
- package/dist/src/base_node_impl.d.ts +1 -0
- package/dist/src/base_node_impl.js +30 -3
- package/dist/src/base_node_impl.js.map +1 -1
- package/dist/src/historical_access/address_space_historical_data_node.js +14 -3
- package/dist/src/historical_access/address_space_historical_data_node.js.map +1 -1
- package/dist/src/nodeset_tools/nodeset_to_xml.js +45 -9
- package/dist/src/nodeset_tools/nodeset_to_xml.js.map +1 -1
- package/dist/src/ua_method_impl.d.ts +2 -1
- package/dist/src/ua_method_impl.js +9 -1
- package/dist/src/ua_method_impl.js.map +1 -1
- package/dist/src/ua_variable_impl.d.ts +5 -0
- package/dist/src/ua_variable_impl.js +32 -2
- package/dist/src/ua_variable_impl.js.map +1 -1
- package/package.json +26 -26
- package/src/alarms_and_conditions/ua_limit_alarm_impl.ts +1 -1
- package/src/base_node_impl.ts +34 -3
- package/src/historical_access/address_space_historical_data_node.ts +18 -3
- package/src/nodeset_tools/nodeset_to_xml.ts +57 -13
- package/src/ua_method_impl.ts +9 -3
- package/src/ua_variable_impl.ts +36 -4
- package/test_helpers/test_fixtures/mini.Node.Set2.xml +178 -0
- package/dist/source/helpers/check_event_clause.d.ts +0 -17
- package/dist/source/helpers/check_event_clause.js +0 -53
- package/dist/source/helpers/check_event_clause.js.map +0 -1
- package/dist/src/alarms_and_conditions/check_where_clause.d.ts +0 -4
- package/dist/src/alarms_and_conditions/check_where_clause.js +0 -110
- package/dist/src/alarms_and_conditions/check_where_clause.js.map +0 -1
- package/dist/src/alarms_and_conditions/condition_info.d.ts +0 -27
- package/dist/src/alarms_and_conditions/condition_info.js +0 -55
- package/dist/src/alarms_and_conditions/condition_info.js.map +0 -1
- package/dist/src/alarms_and_conditions/condition_snapshot.d.ts +0 -233
- package/dist/src/alarms_and_conditions/condition_snapshot.js +0 -667
- package/dist/src/alarms_and_conditions/condition_snapshot.js.map +0 -1
- package/dist/src/alarms_and_conditions/extract_event_fields.d.ts +0 -10
- package/dist/src/alarms_and_conditions/extract_event_fields.js +0 -90
- package/dist/src/alarms_and_conditions/extract_event_fields.js.map +0 -1
- package/dist/src/data_access/ua_multistate_value_discrete.d.ts +0 -51
- package/dist/src/data_access/ua_multistate_value_discrete.js +0 -250
- package/dist/src/data_access/ua_multistate_value_discrete.js.map +0 -1
- package/dist/src/data_access/ua_two_state_discrete.d.ts +0 -25
- package/dist/src/data_access/ua_two_state_discrete.js +0 -154
- package/dist/src/data_access/ua_two_state_discrete.js.map +0 -1
- package/dist/src/nodeset_tools/typedictionary_to_xml.d.ts +0 -2
- package/dist/src/nodeset_tools/typedictionary_to_xml.js +0 -155
- 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.
|
|
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.
|
|
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.
|
|
25
|
+
"node-opcua-address-space-base": "2.79.0",
|
|
25
26
|
"node-opcua-assert": "2.77.0",
|
|
26
|
-
"node-opcua-basic-types": "2.
|
|
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.
|
|
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.
|
|
32
|
-
"node-opcua-data-model": "2.
|
|
33
|
-
"node-opcua-data-value": "2.
|
|
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.
|
|
38
|
-
"node-opcua-factory": "2.
|
|
39
|
-
"node-opcua-nodeid": "2.
|
|
40
|
-
"node-opcua-nodeset-ua": "2.
|
|
41
|
-
"node-opcua-numeric-range": "2.
|
|
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.
|
|
44
|
-
"node-opcua-service-browse": "2.
|
|
45
|
-
"node-opcua-service-call": "2.
|
|
46
|
-
"node-opcua-service-history": "2.
|
|
47
|
-
"node-opcua-service-translate-browse-path": "2.
|
|
48
|
-
"node-opcua-service-write": "2.
|
|
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.
|
|
51
|
+
"node-opcua-types": "2.79.0",
|
|
51
52
|
"node-opcua-utils": "2.77.0",
|
|
52
|
-
"node-opcua-variant": "2.
|
|
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.
|
|
66
|
-
"node-opcua-service-filter": "2.
|
|
67
|
-
"node-opcua-test-fixtures": "2.
|
|
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": "
|
|
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";
|
package/src/base_node_impl.ts
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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 ===
|
|
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 ===
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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.
|
|
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) {
|
package/src/ua_method_impl.ts
CHANGED
|
@@ -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.
|
|
116
|
+
options.value = { dataType: DataType.Boolean, value: this.getUserExecutableFlag(context) };
|
|
111
117
|
options.statusCode = StatusCodes.Good;
|
|
112
118
|
break;
|
|
113
119
|
default:
|
package/src/ua_variable_impl.ts
CHANGED
|
@@ -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.
|
|
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 (!(
|
|
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
|
});
|