node-opcua-pki 6.7.0 → 6.7.2

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/bin/pki.mjs CHANGED
@@ -364,10 +364,26 @@ import {
364
364
  } from "node-opcua-crypto";
365
365
  function getOrComputeInfo(entry) {
366
366
  if (!entry.info) {
367
- entry.info = exploreCertificate(entry.certificate);
367
+ entry.info = exploreCertificateCached(entry.certificate);
368
368
  }
369
369
  return entry.info;
370
370
  }
371
+ function exploreCertificateCached(certificate) {
372
+ const key = makeSHA1Thumbprint(certificate).toString("hex");
373
+ const cached = _exploreCache.get(key);
374
+ if (cached) {
375
+ _exploreCache.delete(key);
376
+ _exploreCache.set(key, cached);
377
+ return cached;
378
+ }
379
+ const info = exploreCertificate(certificate);
380
+ _exploreCache.set(key, info);
381
+ if (_exploreCache.size > EXPLORE_CACHE_MAX) {
382
+ const oldest = _exploreCache.keys().next().value;
383
+ if (oldest) _exploreCache.delete(oldest);
384
+ }
385
+ return info;
386
+ }
371
387
  function makeFingerprint(certificate) {
372
388
  const chain = split_der(certificate);
373
389
  return makeSHA1Thumbprint(chain[0]).toString("hex");
@@ -378,7 +394,7 @@ function short(stringToShorten) {
378
394
  function buildIdealCertificateName(certificate) {
379
395
  const fingerprint2 = makeFingerprint(certificate);
380
396
  try {
381
- const commonName = exploreCertificate(certificate).tbsCertificate.subject.commonName || "";
397
+ const commonName = exploreCertificateCached(certificate).tbsCertificate.subject.commonName || "";
382
398
  const sanitizedCommonName = commonName.replace(forbiddenChars, "_");
383
399
  return `${sanitizedCommonName}[${fingerprint2}]`;
384
400
  } catch (_err) {
@@ -395,14 +411,14 @@ function isSelfSigned2(info) {
395
411
  return info.tbsCertificate.extensions?.subjectKeyIdentifier === info.tbsCertificate.extensions?.authorityKeyIdentifier?.keyIdentifier;
396
412
  }
397
413
  function isSelfSigned3(certificate) {
398
- const info = exploreCertificate(certificate);
414
+ const info = exploreCertificateCached(certificate);
399
415
  return isSelfSigned2(info);
400
416
  }
401
417
  function findIssuerCertificateInChain(certificate, chain) {
402
418
  if (!certificate) {
403
419
  return null;
404
420
  }
405
- const certInfo = exploreCertificate(certificate);
421
+ const certInfo = exploreCertificateCached(certificate);
406
422
  if (isSelfSigned2(certInfo)) {
407
423
  return certificate;
408
424
  }
@@ -412,7 +428,7 @@ function findIssuerCertificateInChain(certificate, chain) {
412
428
  return null;
413
429
  }
414
430
  const potentialIssuers = chain.filter((c) => {
415
- const info = exploreCertificate(c);
431
+ const info = exploreCertificateCached(c);
416
432
  return info.tbsCertificate.extensions && info.tbsCertificate.extensions.subjectKeyIdentifier === wantedIssuerKey;
417
433
  });
418
434
  if (potentialIssuers.length === 1) {
@@ -424,7 +440,7 @@ function findIssuerCertificateInChain(certificate, chain) {
424
440
  }
425
441
  return null;
426
442
  }
427
- var configurationFileSimpleTemplate, fsWriteFile, forbiddenChars, CertificateManager;
443
+ var configurationFileSimpleTemplate, fsWriteFile, EXPLORE_CACHE_MAX, _exploreCache, forbiddenChars, CertificateManager;
428
444
  var init_certificate_manager = __esm({
429
445
  "packages/node-opcua-pki/lib/pki/certificate_manager.ts"() {
430
446
  "use strict";
@@ -435,6 +451,8 @@ var init_certificate_manager = __esm({
435
451
  init_simple_config_template_cnf();
436
452
  configurationFileSimpleTemplate = simple_config_template_cnf_default;
437
453
  fsWriteFile = fs4.promises.writeFile;
454
+ EXPLORE_CACHE_MAX = 8;
455
+ _exploreCache = /* @__PURE__ */ new Map();
438
456
  forbiddenChars = /[\x00-\x1F<>:"/\\|?*]/g;
439
457
  CertificateManager = class _CertificateManager extends EventEmitter {
440
458
  // ── Global instance registry ─────────────────────────────────
@@ -652,7 +670,7 @@ var init_certificate_manager = __esm({
652
670
  }
653
671
  const chain = split_der(certificate);
654
672
  debugLog("NB CERTIFICATE IN CHAIN = ", chain.length);
655
- const info = exploreCertificate(chain[0]);
673
+ const info = exploreCertificateCached(chain[0]);
656
674
  let hasValidIssuer = false;
657
675
  let hasTrustedIssuer = false;
658
676
  const hasIssuerKey = info.tbsCertificate.extensions?.authorityKeyIdentifier?.keyIdentifier;
@@ -929,7 +947,7 @@ var init_certificate_manager = __esm({
929
947
  await this.#readCertificates();
930
948
  }
931
949
  async withLock2(action) {
932
- const lockFileName = path2.join(this.rootDir, "mutex.lock");
950
+ const lockFileName = path2.join(this.rootDir, "mutex");
933
951
  return withLock({ fileToLock: lockFileName }, async () => {
934
952
  return await action();
935
953
  });
@@ -1140,7 +1158,7 @@ var init_certificate_manager = __esm({
1140
1158
  * @param target - "issuers", "trusted", or "all" (default "all")
1141
1159
  */
1142
1160
  async removeRevocationListsForIssuer(issuerCertificate, target = "all") {
1143
- const issuerInfo = exploreCertificate(issuerCertificate);
1161
+ const issuerInfo = exploreCertificateCached(issuerCertificate);
1144
1162
  const issuerFingerprint = issuerInfo.tbsCertificate.subjectFingerPrint;
1145
1163
  const processIndex = async (index) => {
1146
1164
  const crlData = index.get(issuerFingerprint);
@@ -1186,7 +1204,7 @@ var init_certificate_manager = __esm({
1186
1204
  const certificates = split_der(certificateChain);
1187
1205
  const leafCertificate = certificates[0];
1188
1206
  try {
1189
- exploreCertificate(leafCertificate);
1207
+ exploreCertificateCached(leafCertificate);
1190
1208
  } catch (_err) {
1191
1209
  return "BadCertificateInvalid" /* BadCertificateInvalid */;
1192
1210
  }
@@ -1246,7 +1264,7 @@ var init_certificate_manager = __esm({
1246
1264
  *
1247
1265
  */
1248
1266
  async findIssuerCertificate(certificate) {
1249
- const certInfo = exploreCertificate(certificate);
1267
+ const certInfo = exploreCertificateCached(certificate);
1250
1268
  if (isSelfSigned2(certInfo)) {
1251
1269
  return certificate;
1252
1270
  }
@@ -1327,7 +1345,7 @@ var init_certificate_manager = __esm({
1327
1345
  });
1328
1346
  }
1329
1347
  #findAssociatedCRLs(issuerCertificate) {
1330
- const issuerCertificateInfo = exploreCertificate(issuerCertificate);
1348
+ const issuerCertificateInfo = exploreCertificateCached(issuerCertificate);
1331
1349
  const key = issuerCertificateInfo.tbsCertificate.subjectFingerPrint;
1332
1350
  return this.#thumbs.issuersCrl.get(key) ?? this.#thumbs.crl.get(key) ?? null;
1333
1351
  }
@@ -1361,7 +1379,7 @@ var init_certificate_manager = __esm({
1361
1379
  if (!crls) {
1362
1380
  return "BadCertificateRevocationUnknown" /* BadCertificateRevocationUnknown */;
1363
1381
  }
1364
- const certInfo = exploreCertificate(certificate);
1382
+ const certInfo = exploreCertificateCached(certificate);
1365
1383
  const serialNumber = certInfo.tbsCertificate.serialNumber || certInfo.tbsCertificate.extensions?.authorityKeyIdentifier?.serial || "";
1366
1384
  const key = certInfo.tbsCertificate.extensions?.authorityKeyIdentifier?.authorityCertIssuerFingerPrint || "<unknown>";
1367
1385
  const crl2 = this.#thumbs.crl.get(key) ?? null;
@@ -1428,22 +1446,31 @@ var init_certificate_manager = __esm({
1428
1446
  ...usePolling ? { interval: pollingInterval } : {},
1429
1447
  persistent: false
1430
1448
  };
1431
- const createUnreffedWatcher = (folder) => {
1432
- const capturedHandles = [];
1433
- const origWatch = fs4.watch;
1434
- fs4.watch = ((...args) => {
1435
- const handle = origWatch.apply(fs4, args);
1436
- capturedHandles.push(handle);
1437
- return handle;
1449
+ const allCapturedHandles = [];
1450
+ const origWatch = fs4.watch;
1451
+ let watcherReadyCount = 0;
1452
+ const totalWatchers = 5;
1453
+ fs4.watch = ((...args) => {
1454
+ const handle = origWatch.apply(fs4, args);
1455
+ handle.setMaxListeners(handle.getMaxListeners() + 1);
1456
+ handle.on("error", () => {
1438
1457
  });
1458
+ allCapturedHandles.push(handle);
1459
+ return handle;
1460
+ });
1461
+ const createUnreffedWatcher = (folder) => {
1462
+ const startIdx = allCapturedHandles.length;
1439
1463
  const w = chokidar.watch(folder, chokidarOptions);
1440
1464
  const unreffAll = () => {
1441
- fs4.watch = origWatch;
1442
- for (const h of capturedHandles) {
1443
- h.unref();
1465
+ for (let i = startIdx; i < allCapturedHandles.length; i++) {
1466
+ allCapturedHandles[i].unref();
1467
+ }
1468
+ watcherReadyCount++;
1469
+ if (watcherReadyCount >= totalWatchers) {
1470
+ fs4.watch = origWatch;
1444
1471
  }
1445
1472
  };
1446
- return { w, capturedHandles, unreffAll };
1473
+ return { w, capturedHandles: allCapturedHandles.slice(startIdx), unreffAll };
1447
1474
  };
1448
1475
  await Promise.all([
1449
1476
  this.#scanCertFolder(this.trustedFolder, this.#thumbs.trusted),
@@ -1472,7 +1499,7 @@ var init_certificate_manager = __esm({
1472
1499
  const stat = await fs4.promises.stat(filename);
1473
1500
  if (!stat.isFile()) continue;
1474
1501
  const certificate = await readCertificateAsync(filename);
1475
- const info = exploreCertificate(certificate);
1502
+ const info = exploreCertificateCached(certificate);
1476
1503
  const fingerprint2 = makeFingerprint(certificate);
1477
1504
  index.set(fingerprint2, { certificate, filename, info });
1478
1505
  this.#filenameToHash.set(filename, fingerprint2);
@@ -1505,6 +1532,9 @@ var init_certificate_manager = __esm({
1505
1532
  */
1506
1533
  #startCrlWatcher(folder, index, createUnreffedWatcher, store) {
1507
1534
  const { w, unreffAll } = createUnreffedWatcher(folder);
1535
+ w.on("error", (err) => {
1536
+ debugLog(`chokidar CRL watcher error on ${folder}:`, err);
1537
+ });
1508
1538
  let ready = false;
1509
1539
  w.on("unlink", (filename) => {
1510
1540
  for (const [key, data] of index.entries()) {
@@ -1540,6 +1570,9 @@ var init_certificate_manager = __esm({
1540
1570
  */
1541
1571
  #startWatcher(folder, index, createUnreffedWatcher, store) {
1542
1572
  const { w, unreffAll } = createUnreffedWatcher(folder);
1573
+ w.on("error", (err) => {
1574
+ debugLog(`chokidar cert watcher error on ${folder}:`, err);
1575
+ });
1543
1576
  let ready = false;
1544
1577
  w.on("unlink", (filename) => {
1545
1578
  debugLog(chalk3.cyan(`unlink in folder ${folder}`), filename);
@@ -1553,7 +1586,7 @@ var init_certificate_manager = __esm({
1553
1586
  debugLog(chalk3.cyan(`add in folder ${folder}`), filename);
1554
1587
  try {
1555
1588
  const certificate = readCertificate(filename);
1556
- const info = exploreCertificate(certificate);
1589
+ const info = exploreCertificateCached(certificate);
1557
1590
  const fingerprint2 = makeFingerprint(certificate);
1558
1591
  const isNew = !index.has(fingerprint2);
1559
1592
  index.set(fingerprint2, { certificate, filename, info });
@@ -1581,7 +1614,7 @@ var init_certificate_manager = __esm({
1581
1614
  if (oldHash && oldHash !== newFingerprint) {
1582
1615
  index.delete(oldHash);
1583
1616
  }
1584
- index.set(newFingerprint, { certificate, filename: changedPath, info: exploreCertificate(certificate) });
1617
+ index.set(newFingerprint, { certificate, filename: changedPath, info: exploreCertificateCached(certificate) });
1585
1618
  this.#filenameToHash.set(changedPath, newFingerprint);
1586
1619
  this.emit("certificateChange", { store, certificate, fingerprint: newFingerprint, filename: changedPath });
1587
1620
  } catch (err) {