node-opcua-server-configuration 2.70.3 → 2.72.1

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 (29) hide show
  1. package/dist/clientTools/push_certificate_management_client.js +7 -9
  2. package/dist/clientTools/push_certificate_management_client.js.map +1 -1
  3. package/dist/server/install_CertificateAlarm.d.ts +8 -2
  4. package/dist/server/install_CertificateAlarm.js +20 -12
  5. package/dist/server/install_CertificateAlarm.js.map +1 -1
  6. package/dist/server/install_certificate_file_watcher.d.ts +5 -0
  7. package/dist/server/install_certificate_file_watcher.js +24 -0
  8. package/dist/server/install_certificate_file_watcher.js.map +1 -0
  9. package/dist/server/install_push_certitifate_management.d.ts +9 -5
  10. package/dist/server/install_push_certitifate_management.js +1 -2
  11. package/dist/server/install_push_certitifate_management.js.map +1 -1
  12. package/dist/server/push_certificate_manager_helpers.d.ts +2 -5
  13. package/dist/server/push_certificate_manager_helpers.js +119 -16
  14. package/dist/server/push_certificate_manager_helpers.js.map +1 -1
  15. package/dist/server/push_certificate_manager_server_impl.d.ts +1 -1
  16. package/dist/server/push_certificate_manager_server_impl.js +3 -3
  17. package/dist/server/push_certificate_manager_server_impl.js.map +1 -1
  18. package/dist/server/tools.js.map +1 -1
  19. package/dist/server/trust_list_server.js +1 -1
  20. package/dist/server/trust_list_server.js.map +1 -1
  21. package/package.json +26 -24
  22. package/source/clientTools/push_certificate_management_client.ts +16 -37
  23. package/source/server/install_CertificateAlarm.ts +35 -29
  24. package/source/server/install_certificate_file_watcher.ts +25 -0
  25. package/source/server/install_push_certitifate_management.ts +8 -8
  26. package/source/server/push_certificate_manager_helpers.ts +142 -26
  27. package/source/server/push_certificate_manager_server_impl.ts +6 -7
  28. package/source/server/tools.ts +1 -1
  29. package/source/server/trust_list_server.ts +3 -3
@@ -1,35 +1,46 @@
1
1
  /**
2
2
  * @module node-opcua-server-configuration
3
3
  */
4
-
5
- import { callbackify } from "util";
6
-
4
+ import * as path from "path";
5
+ import * as fs from "fs";
7
6
  import {
8
7
  AddressSpace,
9
8
  SessionContext,
10
9
  UAMethod,
11
10
  UATrustList,
12
- UAObject,
13
- UAVariable,
14
11
  UAServerConfiguration,
15
- ISessionContext
12
+ ISessionContext,
13
+ UACertificateGroup,
14
+ UACertificateExpirationAlarmEx,
15
+ UACertificateExpirationAlarmImpl
16
16
  } from "node-opcua-address-space";
17
+ import { UAObject, UAVariable, EventNotifierFlags } from "node-opcua-address-space-base";
18
+
17
19
  import { checkDebugFlag, make_debugLog, make_warningLog } from "node-opcua-debug";
18
20
  import { NodeId, resolveNodeId } from "node-opcua-nodeid";
19
21
  import { StatusCodes } from "node-opcua-status-code";
20
22
  import { CallMethodResultOptions } from "node-opcua-types";
21
23
  import { DataType, Variant, VariantArrayType } from "node-opcua-variant";
22
- import { AccessRestrictionsFlag, NodeClass } from "node-opcua-data-model";
24
+ import {
25
+ AccessLevelFlag,
26
+ AccessRestrictionsFlag,
27
+ BrowseDirection,
28
+ coerceQualifiedName,
29
+ NodeClass,
30
+ QualifiedName
31
+ } from "node-opcua-data-model";
23
32
  import { ByteString, UAString } from "node-opcua-basic-types";
24
- import { ObjectTypeIds } from "node-opcua-constants";
33
+ import { ObjectIds, ObjectTypeIds } from "node-opcua-constants";
34
+ import { CertificateManager } from "node-opcua-certificate-manager";
35
+ import { Certificate, readCertificate } from "node-opcua-crypto";
25
36
 
26
37
  import { CreateSigningRequestResult, PushCertificateManager } from "../push_certificate_manager";
27
38
 
28
- import { installCertificateExpirationAlarm } from "./install_CertificateAlarm";
29
39
  import { PushCertificateManagerServerImpl, PushCertificateManagerServerOptions } from "./push_certificate_manager_server_impl";
30
40
  import { installAccessRestrictionOnTrustList, promoteTrustList } from "./promote_trust_list";
31
41
  import { hasEncryptedChannel, hasExpectedUserAccess } from "./tools";
32
42
  import { rolePermissionAdminOnly, rolePermissionRestricted } from "./roles_and_permissions";
43
+ import { installCertificateFileWatcher } from "./install_certificate_file_watcher";
33
44
 
34
45
  const debugLog = make_debugLog("ServerConfiguration");
35
46
  const doDebug = checkDebugFlag("ServerConfiguration");
@@ -247,38 +258,136 @@ async function _applyChanges(
247
258
  return { statusCode };
248
259
  }
249
260
 
261
+ function getCertificateFilename(certificateManager: CertificateManager): string {
262
+ return path.join(certificateManager.rootDir, "own/certs/certificate.pem"); // to do , find a better way
263
+ }
264
+ async function getCertificate(certificateManager: CertificateManager): Promise<Certificate | null> {
265
+ try {
266
+ const certificateFile = getCertificateFilename(certificateManager);
267
+ if (fs.existsSync(certificateFile)) {
268
+ const certificate = await readCertificate(certificateFile);
269
+ return certificate;
270
+ }
271
+ return null;
272
+ } catch (err) {
273
+ warningLog("getCertificate Error", (err as Error).message);
274
+ return null;
275
+ }
276
+ }
277
+
278
+ function bindCertificateGroup(certificateGroup: UACertificateGroup, certificateManager?: CertificateManager) {
279
+ if (certificateManager) {
280
+ const certificateFile = getCertificateFilename(certificateManager);
281
+ const changeDetector = installCertificateFileWatcher(certificateGroup, certificateFile);
282
+ changeDetector.on("certificateChange", () => {
283
+ debugLog("detecting certificate change", certificateFile);
284
+ updateCertificateAlarm();
285
+ });
286
+ }
287
+
288
+ async function updateCertificateAlarm() {
289
+ try {
290
+ debugLog("updateCertificateAlarm", certificateGroup.browseName.toString());
291
+ const certificateExpired = certificateGroup.getComponentByName("CertificateExpired");
292
+ if (certificateExpired && certificateManager) {
293
+ const certificateExpiredEx = certificateExpired as unknown as UACertificateExpirationAlarmEx;
294
+ const certificate = await getCertificate(certificateManager);
295
+ certificateExpiredEx.setCertificate(certificate);
296
+ }
297
+ } catch (err) {
298
+ warningLog("updateCertificateAlarm Error", (err as Error).message);
299
+ }
300
+ }
301
+
302
+ const addressSpace = certificateGroup.addressSpace;
303
+ if (!certificateManager) {
304
+ return;
305
+ }
306
+ const trustList = certificateGroup.getComponentByName("TrustList");
307
+ if (trustList) {
308
+ (trustList as any).$$certificateManager = certificateManager;
309
+ }
310
+ const certificateExpired = certificateGroup.getComponentByName("CertificateExpired");
311
+ if (certificateExpired) {
312
+ (certificateExpired as any).$$certificateManager = certificateManager;
313
+ // install alarm handling
314
+ const timerId = setInterval(updateCertificateAlarm, 60 * 1000);
315
+ addressSpace.registerShutdownTask(() => clearInterval(timerId));
316
+ updateCertificateAlarm();
317
+ }
318
+ }
319
+
250
320
  function bindCertificateManager(addressSpace: AddressSpace, options: PushCertificateManagerServerOptions) {
251
321
  const serverConfiguration = addressSpace.rootFolder.objects.server.getChildByName(
252
322
  "ServerConfiguration"
253
323
  )! as UAServerConfiguration;
254
324
 
255
- const defaultApplicationGroup = serverConfiguration.certificateGroups.getComponentByName("DefaultApplicationGroup");
325
+ const defaultApplicationGroup = serverConfiguration.certificateGroups.getComponentByName(
326
+ "DefaultApplicationGroup"
327
+ ) as UACertificateGroup | null;
256
328
  if (defaultApplicationGroup) {
257
- const trustList = defaultApplicationGroup.getComponentByName("TrustList");
258
- if (trustList) {
259
- (trustList as any).$$certificateManager = options.applicationGroup;
260
- }
329
+ bindCertificateGroup(defaultApplicationGroup, options.applicationGroup);
261
330
  }
262
- const defaultTokenGroup = serverConfiguration.certificateGroups.getComponentByName("DefaultUserTokenGroup");
331
+ const defaultTokenGroup = serverConfiguration.certificateGroups.getComponentByName(
332
+ "DefaultUserTokenGroup"
333
+ ) as UACertificateGroup | null;
263
334
  if (defaultTokenGroup) {
264
- const trustList = defaultTokenGroup.getComponentByName("TrustList");
265
- if (trustList) {
266
- (trustList as any).$$certificateManager = options.userTokenGroup;
267
- }
335
+ bindCertificateGroup(defaultTokenGroup, options.userTokenGroup);
336
+ }
337
+ }
338
+
339
+ function setNotifierOfChain(childObject: UAObject | null) {
340
+ if (!childObject) {
341
+ return;
342
+ }
343
+ const parentObject: UAObject | null = childObject.parent as UAObject | null;
344
+ if (!parentObject) {
345
+ return;
268
346
  }
347
+ const notifierOf = childObject.findReferencesEx("HasNotifier", BrowseDirection.Inverse);
348
+ if (notifierOf.length === 0) {
349
+ const notifierOfNode = childObject.addReference({
350
+ referenceType: "HasNotifier",
351
+ nodeId: parentObject.nodeId,
352
+ isForward: false
353
+ });
354
+ }
355
+ parentObject.setEventNotifier(parentObject.eventNotifier | EventNotifierFlags.SubscribeToEvents);
356
+ if (parentObject.nodeId.namespace === 0 && parentObject.nodeId.value === ObjectIds.Server) {
357
+ return;
358
+ }
359
+ setNotifierOfChain(parentObject);
269
360
  }
270
361
 
271
- export async function promoteCertificateGroup(certificateGroup: UAObject) {
362
+ export async function promoteCertificateGroup(certificateGroup: UACertificateGroup): Promise<void> {
272
363
  const trustList = certificateGroup.getChildByName("TrustList") as UATrustList;
273
364
  if (trustList) {
274
- promoteTrustList(trustList);
275
- }
365
+ await promoteTrustList(trustList);
366
+ }
367
+ if (!certificateGroup.certificateExpired) {
368
+ const namespace = certificateGroup.addressSpace.getOwnNamespace();
369
+
370
+ // certificateGroup.
371
+ UACertificateExpirationAlarmImpl.instantiate(namespace, "CertificateExpirationAlarmType", {
372
+ browseName: coerceQualifiedName("0:CertificateExpired"),
373
+ componentOf: certificateGroup,
374
+ conditionSource: null,
375
+ conditionOf: certificateGroup,
376
+ inputNode: NodeId.nullNodeId,
377
+ normalState: NodeId.nullNodeId,
378
+ optionals: ["ExpirationLimit"]
379
+ });
380
+ }
381
+ certificateGroup.setEventNotifier(EventNotifierFlags.SubscribeToEvents);
382
+ setNotifierOfChain(certificateGroup);
276
383
  }
277
384
 
278
385
  export async function installPushCertificateManagement(
279
386
  addressSpace: AddressSpace,
280
387
  options: PushCertificateManagerServerOptions
281
388
  ): Promise<void> {
389
+ addressSpace.installAlarmsAndConditionsService();
390
+
282
391
  const serverConfiguration = addressSpace.rootFolder.objects.server.getChildByName(
283
392
  "ServerConfiguration"
284
393
  )! as UAServerConfiguration;
@@ -322,8 +431,8 @@ export async function installPushCertificateManagement(
322
431
  }
323
432
  }
324
433
  for (const group of certificateGroups.getComponents()) {
325
- group?.setRolePermissions(rolePermissionAdminOnly);
326
- group?.setAccessRestrictions(AccessRestrictionsFlag.SigningRequired | AccessRestrictionsFlag.EncryptionRequired);
434
+ group.setRolePermissions(rolePermissionAdminOnly);
435
+ group.setAccessRestrictions(AccessRestrictionsFlag.SigningRequired | AccessRestrictionsFlag.EncryptionRequired);
327
436
  if (group.nodeClass === NodeClass.Object) {
328
437
  installAccessRestrictionOnGroup(group as UAObject);
329
438
  }
@@ -359,7 +468,7 @@ export async function installPushCertificateManagement(
359
468
  serverConfiguration.applyChanges!.bindMethod(_applyChanges);
360
469
  }
361
470
 
362
- installCertificateExpirationAlarm(addressSpace);
471
+ //xx installCertificateExpirationAlarm(addressSpace);
363
472
 
364
473
  const cg = serverConfiguration.certificateGroups.getComponents();
365
474
 
@@ -370,11 +479,18 @@ export async function installPushCertificateManagement(
370
479
  arrayType: VariantArrayType.Array,
371
480
  value: [resolveNodeId(ObjectTypeIds.RsaSha256ApplicationCertificateType)]
372
481
  });
482
+
483
+ const certificateGroupType = addressSpace.findObjectType("CertificateGroupType")!;
484
+
373
485
  for (const certificateGroup of cg) {
374
486
  if (certificateGroup.nodeClass !== NodeClass.Object) {
375
487
  continue;
376
488
  }
377
- await promoteCertificateGroup(certificateGroup as UAObject);
489
+ const o = certificateGroup as UAObject;
490
+ if (!o.typeDefinitionObj.isSupertypeOf(certificateGroupType)) {
491
+ continue;
492
+ }
493
+ await promoteCertificateGroup(certificateGroup as UACertificateGroup);
378
494
  }
379
495
  await bindCertificateManager(addressSpace, options);
380
496
  }
@@ -6,11 +6,7 @@ import * as fs from "fs";
6
6
  import * as path from "path";
7
7
  import { promisify} from "util";
8
8
  import * as rimraf from "rimraf";
9
-
10
-
11
- // node 14 onward : import { readFile, writeFile, readdir } from "fs/promises";
12
- const { readFile, writeFile, readdir } = fs.promises;
13
-
9
+ import { SubjectOptions } from "node-opcua-pki";
14
10
  import { assert } from "node-opcua-assert";
15
11
  import { ByteString, StatusCodes } from "node-opcua-basic-types";
16
12
  import {
@@ -41,7 +37,10 @@ import {
41
37
  PushCertificateManager,
42
38
  UpdateCertificateResult
43
39
  } from "../push_certificate_manager";
44
- import { SubjectOptions } from "node-opcua-pki";
40
+
41
+ // node 14 onward : import { readFile, writeFile, readdir } from "fs/promises";
42
+ const { readFile, writeFile, readdir } = fs.promises;
43
+
45
44
 
46
45
  const debugLog = make_debugLog("ServerConfiguration");
47
46
  const errorLog = make_errorLog("ServerConfiguration");
@@ -284,7 +283,7 @@ export class PushCertificateManagerServerImpl extends EventEmitter implements Pu
284
283
  await fs.promises.mkdir(location);
285
284
  }
286
285
 
287
- let destCertificateManager = certificateManager;
286
+ const destCertificateManager = certificateManager;
288
287
  const keySize = (certificateManager as any).keySize; // because keySize is private !
289
288
  certificateManager = new CertificateManager({
290
289
  keySize,
@@ -1,4 +1,4 @@
1
- import { ISessionContext, SessionContext, WellKnownRoles } from "node-opcua-address-space";
1
+ import { ISessionContext, WellKnownRoles } from "node-opcua-address-space";
2
2
  import { MessageSecurityMode } from "node-opcua-secure-channel";
3
3
 
4
4
  export function hasExpectedUserAccess(context: ISessionContext) {
@@ -1,8 +1,8 @@
1
- import { OPCUACertificateManager } from "node-opcua-certificate-manager";
2
- import { TrustListDataType } from "node-opcua-types";
3
-
4
1
  import *as fs from "fs";
5
2
  import * as path from "path";
3
+
4
+ import { OPCUACertificateManager } from "node-opcua-certificate-manager";
5
+ import { TrustListDataType } from "node-opcua-types";
6
6
  import { AbstractFs } from "node-opcua-file-transfer";
7
7
  import { BinaryStream } from "node-opcua-binary-stream";
8
8
  import { readCertificate, readCertificateRevocationList } from "node-opcua-crypto";