@7365admin1/core 3.51.1-staging.228 → 3.51.1-staging.229

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.
@@ -0,0 +1,9 @@
1
+ ---
2
+ "@7365admin1/core": patch
3
+ ---
4
+
5
+ HID Amico: stop silently deriving the credential encryption key from
6
+ ACCESS_TOKEN_SECRET. Reading still accepts the legacy key so existing credentials
7
+ keep working (and now logs an error saying so), but writing a new credential
8
+ refuses with a message naming HID_AMICO_SECRET, so a later rotation of the JWT
9
+ signing secret cannot orphan credentials that were written after this.
package/dist/index.js CHANGED
@@ -536,13 +536,13 @@ var require_logger = __commonJS({
536
536
  "use strict";
537
537
  exports.__esModule = true;
538
538
  var _utils = require_utils();
539
- var logger219 = {
539
+ var logger220 = {
540
540
  methodMap: ["debug", "info", "warn", "error"],
541
541
  level: "info",
542
542
  // Maps a given level value to the `methodMap` indexes above.
543
543
  lookupLevel: function lookupLevel(level) {
544
544
  if (typeof level === "string") {
545
- var levelMap = _utils.indexOf(logger219.methodMap, level.toLowerCase());
545
+ var levelMap = _utils.indexOf(logger220.methodMap, level.toLowerCase());
546
546
  if (levelMap >= 0) {
547
547
  level = levelMap;
548
548
  } else {
@@ -553,9 +553,9 @@ var require_logger = __commonJS({
553
553
  },
554
554
  // Can be overridden in the host environment
555
555
  log: function log(level) {
556
- level = logger219.lookupLevel(level);
557
- if (typeof console !== "undefined" && logger219.lookupLevel(logger219.level) <= level) {
558
- var method = logger219.methodMap[level];
556
+ level = logger220.lookupLevel(level);
557
+ if (typeof console !== "undefined" && logger220.lookupLevel(logger220.level) <= level) {
558
+ var method = logger220.methodMap[level];
559
559
  if (!console[method]) {
560
560
  method = "log";
561
561
  }
@@ -566,7 +566,7 @@ var require_logger = __commonJS({
566
566
  }
567
567
  }
568
568
  };
569
- exports["default"] = logger219;
569
+ exports["default"] = logger220;
570
570
  module2.exports = exports["default"];
571
571
  }
572
572
  });
@@ -43973,7 +43973,7 @@ var VALID_STATUSES = /* @__PURE__ */ new Set([
43973
43973
  ]);
43974
43974
 
43975
43975
  // src/services/hid-amico.service.ts
43976
- var import_crypto2 = __toESM(require("crypto"));
43976
+ var import_crypto3 = __toESM(require("crypto"));
43977
43977
  var import_axios = __toESM(require("axios"));
43978
43978
  var import_node_server_utils133 = require("@7365admin1/node-server-utils");
43979
43979
 
@@ -45927,6 +45927,31 @@ function stringifyHidJson(value) {
45927
45927
  );
45928
45928
  }
45929
45929
 
45930
+ // src/utils/hid-secret.util.ts
45931
+ var import_crypto2 = __toESM(require("crypto"));
45932
+ var HID_SECRET_ENV = "HID_AMICO_SECRET";
45933
+ var HID_LEGACY_SECRET_ENV = "ACCESS_TOKEN_SECRET";
45934
+ var HID_SECRET_MISSING_FOR_WRITE = `${HID_SECRET_ENV} is not configured, so a new HID credential cannot be encrypted. Set ${HID_SECRET_ENV} on this service and try again. It is deliberately NOT falling back to ${HID_LEGACY_SECRET_ENV}: that key is rotated independently, and anything encrypted with it becomes permanently unreadable the moment it is.`;
45935
+ var HID_SECRET_MISSING_ENTIRELY = `Neither ${HID_SECRET_ENV} nor ${HID_LEGACY_SECRET_ENV} is configured, so stored HID credentials cannot be decrypted. Set ${HID_SECRET_ENV} on this service.`;
45936
+ var HID_SECRET_LEGACY_FALLBACK_IN_USE = `${HID_SECRET_ENV} is not configured. Stored HID credentials are being decrypted with ${HID_LEGACY_SECRET_ENV}, which is rotated independently \u2014 when it is rotated they become permanently unreadable. Set ${HID_SECRET_ENV} and re-save the affected HID readers and SIP accounts.`;
45937
+ function resolveHidSecretKey(purpose, env2 = process.env) {
45938
+ const dedicated = env2[HID_SECRET_ENV];
45939
+ if (dedicated) {
45940
+ return { key: deriveKey(dedicated), usedLegacyFallback: false };
45941
+ }
45942
+ if (purpose === "encrypt") {
45943
+ throw new Error(HID_SECRET_MISSING_FOR_WRITE);
45944
+ }
45945
+ const legacy = env2[HID_LEGACY_SECRET_ENV];
45946
+ if (!legacy) {
45947
+ throw new Error(HID_SECRET_MISSING_ENTIRELY);
45948
+ }
45949
+ return { key: deriveKey(legacy), usedLegacyFallback: true };
45950
+ }
45951
+ function deriveKey(secret) {
45952
+ return import_crypto2.default.createHash("sha256").update(secret).digest();
45953
+ }
45954
+
45930
45955
  // src/services/hid-amico.service.ts
45931
45956
  var PASSWORD_PREFIX = "v1";
45932
45957
  var HID_READER_NOT_FOUND = "HID Amico reader not found.";
@@ -46047,14 +46072,22 @@ function sanitizeHidObjectPayload(object, value) {
46047
46072
  };
46048
46073
  return redactValue(sanitized);
46049
46074
  }
46050
- function getSecretKey() {
46051
- const secret = process.env.HID_AMICO_SECRET || process.env.ACCESS_TOKEN_SECRET;
46052
- if (!secret) {
46053
- throw new import_node_server_utils133.InternalServerError(
46054
- "HID_AMICO_SECRET or ACCESS_TOKEN_SECRET must be configured before HID credentials can be used."
46055
- );
46075
+ var reportedLegacyHidSecret = false;
46076
+ function getSecretKey(purpose) {
46077
+ try {
46078
+ const { key, usedLegacyFallback } = resolveHidSecretKey(purpose);
46079
+ if (usedLegacyFallback && !reportedLegacyHidSecret) {
46080
+ reportedLegacyHidSecret = true;
46081
+ import_node_server_utils133.logger.error({
46082
+ operation: "hid-amico:getSecretKey",
46083
+ message: HID_SECRET_LEGACY_FALLBACK_IN_USE
46084
+ });
46085
+ }
46086
+ return key;
46087
+ } catch (error) {
46088
+ import_node_server_utils133.logger.error({ operation: "hid-amico:getSecretKey", purpose, message: error.message });
46089
+ throw new import_node_server_utils133.InternalServerError(error.message);
46056
46090
  }
46057
- return import_crypto2.default.createHash("sha256").update(secret).digest();
46058
46091
  }
46059
46092
  function getReaderCapabilities(readerModel, firmwareVersion) {
46060
46093
  const isAmicoBiometricReader2 = readerModel === "VL35LF" || readerModel === "VL70LF";
@@ -46120,8 +46153,8 @@ function getPublicMonitorConfiguration(monitor, callbackToken) {
46120
46153
  };
46121
46154
  }
46122
46155
  function encryptSecret(value) {
46123
- const iv = import_crypto2.default.randomBytes(12);
46124
- const cipher = import_crypto2.default.createCipheriv("aes-256-gcm", getSecretKey(), iv);
46156
+ const iv = import_crypto3.default.randomBytes(12);
46157
+ const cipher = import_crypto3.default.createCipheriv("aes-256-gcm", getSecretKey("encrypt"), iv);
46125
46158
  const encrypted = Buffer.concat([cipher.update(value, "utf8"), cipher.final()]);
46126
46159
  const tag = cipher.getAuthTag();
46127
46160
  return [PASSWORD_PREFIX, iv.toString("hex"), tag.toString("hex"), encrypted.toString("hex")].join(":");
@@ -46130,9 +46163,10 @@ function decryptSecret(value) {
46130
46163
  if (!value?.startsWith(`${PASSWORD_PREFIX}:`)) {
46131
46164
  return value;
46132
46165
  }
46166
+ const key = getSecretKey("decrypt");
46133
46167
  try {
46134
46168
  const [, ivHex, tagHex, encryptedHex] = value.split(":");
46135
- const decipher = import_crypto2.default.createDecipheriv("aes-256-gcm", getSecretKey(), Buffer.from(ivHex, "hex"));
46169
+ const decipher = import_crypto3.default.createDecipheriv("aes-256-gcm", key, Buffer.from(ivHex, "hex"));
46136
46170
  decipher.setAuthTag(Buffer.from(tagHex, "hex"));
46137
46171
  return Buffer.concat([
46138
46172
  decipher.update(Buffer.from(encryptedHex, "hex")),
@@ -46172,7 +46206,7 @@ function normalizeHidReaderBaseUrl(value) {
46172
46206
  return endpoint.origin;
46173
46207
  }
46174
46208
  function createStableHidId(seed) {
46175
- const bytes = import_crypto2.default.createHash("sha256").update(seed).digest().subarray(0, 6);
46209
+ const bytes = import_crypto3.default.createHash("sha256").update(seed).digest().subarray(0, 6);
46176
46210
  return Number.parseInt(bytes.toString("hex"), 16) || 1;
46177
46211
  }
46178
46212
  function isUnknownRecord2(value) {
@@ -46247,7 +46281,7 @@ function resolveProfileIdentityType(memberType, userType) {
46247
46281
  var VISITOR_QR_FORMAT = "0";
46248
46282
  function createVisitorQrCredential(visitorId, readerId, qrValue) {
46249
46283
  const credentialId = createStableHidId(`visitor-qr:${readerId}:${visitorId}`);
46250
- const token = qrValue || `VIS${import_crypto2.default.randomBytes(12).toString("hex").toUpperCase()}`;
46284
+ const token = qrValue || `VIS${import_crypto3.default.randomBytes(12).toString("hex").toUpperCase()}`;
46251
46285
  return { credentialId, object: "qrcodes", value: token, qrValue: token };
46252
46286
  }
46253
46287
  async function configureVisitorQrReader(client) {
@@ -46751,7 +46785,7 @@ function getSipProvisioningConfig() {
46751
46785
  return { provisionerUrl, provisionerToken, websocketUrl, domain };
46752
46786
  }
46753
46787
  function createSipPassword() {
46754
- return import_crypto2.default.randomBytes(12).toString("base64url");
46788
+ return import_crypto3.default.randomBytes(12).toString("base64url");
46755
46789
  }
46756
46790
  function sipAccountResponse(account) {
46757
46791
  const { websocketUrl, domain } = getSipProvisioningConfig();
@@ -49431,7 +49465,7 @@ function useHidAmicoService() {
49431
49465
  assertReaderCardProfile(reader, cardType);
49432
49466
  const hidUserId = Number(hidUserIdValue);
49433
49467
  const client = new HidAmicoClient(reader);
49434
- const lockOwner = import_crypto2.default.randomUUID();
49468
+ const lockOwner = import_crypto3.default.randomUUID();
49435
49469
  const acquired = await repo.acquireEnrollmentLock(readerId, lockOwner, timeoutSeconds + 30);
49436
49470
  if (!acquired) {
49437
49471
  throw new import_node_server_utils133.BadRequestError("Another physical HID card enrollment is already running on this reader.");
@@ -51445,17 +51479,17 @@ var import_fs5 = __toESM(require("fs"));
51445
51479
  var import_path2 = __toESM(require("path"));
51446
51480
  var import_axios2 = __toESM(require("axios"));
51447
51481
  var import_xml2js = require("xml2js");
51448
- var import_crypto3 = __toESM(require("crypto"));
51482
+ var import_crypto4 = __toESM(require("crypto"));
51449
51483
  var ALGORITHM = "aes-256-gcm";
51450
- var SECRET_KEY = import_crypto3.default.createSecretKey(
51451
- new Uint8Array(import_crypto3.default.createHash("sha256").update("acm-secret-key").digest())
51484
+ var SECRET_KEY = import_crypto4.default.createSecretKey(
51485
+ new Uint8Array(import_crypto4.default.createHash("sha256").update("acm-secret-key").digest())
51452
51486
  );
51453
51487
  function decryptAcmUrl(encryptedText) {
51454
51488
  const [ivB64, authTagB64, encryptedB64] = encryptedText.split(":");
51455
51489
  const iv = Buffer.from(ivB64, "base64");
51456
51490
  const authTag = Buffer.from(authTagB64, "base64");
51457
51491
  const encrypted = Buffer.from(encryptedB64, "base64");
51458
- const decipher = import_crypto3.default.createDecipheriv(
51492
+ const decipher = import_crypto4.default.createDecipheriv(
51459
51493
  ALGORITHM,
51460
51494
  SECRET_KEY,
51461
51495
  new Uint8Array(iv)
@@ -51598,10 +51632,10 @@ async function getTransactions(index, url) {
51598
51632
  }
51599
51633
  function encryptPayload(payloadHex) {
51600
51634
  const buffer = Buffer.from(payloadHex, "ascii");
51601
- const encrypted = import_crypto3.default.publicEncrypt(
51635
+ const encrypted = import_crypto4.default.publicEncrypt(
51602
51636
  {
51603
51637
  key: "testing",
51604
- padding: import_crypto3.default.constants.RSA_PKCS1_PADDING
51638
+ padding: import_crypto4.default.constants.RSA_PKCS1_PADDING
51605
51639
  },
51606
51640
  buffer
51607
51641
  );
@@ -51611,7 +51645,7 @@ function toHex(num, length) {
51611
51645
  return num.toString(16).padStart(length * 2, "0");
51612
51646
  }
51613
51647
  function buildPayload(cardNumber, validityMinutes) {
51614
- const randomHex = import_crypto3.default.randomBytes(2).toString("hex");
51648
+ const randomHex = import_crypto4.default.randomBytes(2).toString("hex");
51615
51649
  const cardHex = toHex(cardNumber, 4);
51616
51650
  const epochHex = toHex(Math.floor(Date.now() / 1e3), 4);
51617
51651
  const validityHex = toHex(validityMinutes, 2);
@@ -51626,7 +51660,7 @@ function generateQrCodeData(cardNumber, validityMinutes) {
51626
51660
  var import_xml2js2 = require("xml2js");
51627
51661
 
51628
51662
  // src/utils/rsa-encryption.ts
51629
- var crypto6 = __toESM(require("crypto"));
51663
+ var crypto7 = __toESM(require("crypto"));
51630
51664
  var import_fs6 = __toESM(require("fs"));
51631
51665
  var import_path3 = __toESM(require("path"));
51632
51666
  var pub = import_path3.default.resolve(process.cwd(), "./src/public/rsa-keys/new_rsa_512_pub.pem");
@@ -51656,7 +51690,7 @@ var EntrypassRSAEncryption = class extends EncryptionCredentials {
51656
51690
  static constructQrcode(params) {
51657
51691
  const { virtualCardNo, validityMinutes } = params;
51658
51692
  const virtualCardNoHex = this.cardNumberToHex(virtualCardNo);
51659
- const randomHex = crypto6.randomBytes(2).toString("hex").toUpperCase();
51693
+ const randomHex = crypto7.randomBytes(2).toString("hex").toUpperCase();
51660
51694
  const epochHex = Math.floor(Date.now() / 1e3).toString(16).toUpperCase();
51661
51695
  const validityHex = validityMinutes.toString(16).padStart(4, "0").toUpperCase();
51662
51696
  const plainHex = randomHex + virtualCardNoHex.toUpperCase() + epochHex + validityHex;
@@ -51667,10 +51701,10 @@ var EntrypassRSAEncryption = class extends EncryptionCredentials {
51667
51701
  const bufferValue = this.constructQrcode(params);
51668
51702
  const plainTextPayload = bufferValue;
51669
51703
  console.log("Payload to be encrypted:", plainTextPayload);
51670
- const encryptedBuffer = crypto6.publicEncrypt(
51704
+ const encryptedBuffer = crypto7.publicEncrypt(
51671
51705
  {
51672
51706
  key: this.RAW_PUBLIC_KEY,
51673
- padding: crypto6.constants.RSA_PKCS1_PADDING
51707
+ padding: crypto7.constants.RSA_PKCS1_PADDING
51674
51708
  },
51675
51709
  Buffer.from(plainTextPayload, "utf8")
51676
51710
  );
@@ -51681,10 +51715,10 @@ var EntrypassRSAEncryption = class extends EncryptionCredentials {
51681
51715
  static decryptQRCode(base64Cipher) {
51682
51716
  try {
51683
51717
  const buffer = Buffer.from(base64Cipher, "base64");
51684
- const decryptedBuffer = crypto6.privateDecrypt(
51718
+ const decryptedBuffer = crypto7.privateDecrypt(
51685
51719
  {
51686
51720
  key: this.RAW_PRIVATE_KEY,
51687
- padding: crypto6.constants.RSA_PKCS1_PADDING
51721
+ padding: crypto7.constants.RSA_PKCS1_PADDING
51688
51722
  },
51689
51723
  buffer
51690
51724
  );
@@ -81718,12 +81752,12 @@ async function manpowerEvents(io) {
81718
81752
  var import_axios4 = __toESM(require("axios"));
81719
81753
 
81720
81754
  // src/utils/payment-signature.util.ts
81721
- var crypto7 = __toESM(require("crypto"));
81755
+ var crypto8 = __toESM(require("crypto"));
81722
81756
  function hasOwn(obj, key) {
81723
81757
  return Object.prototype.hasOwnProperty.call(obj, key);
81724
81758
  }
81725
81759
  function sha512(input) {
81726
- return crypto7.createHash("sha512").update(input).digest("hex");
81760
+ return crypto8.createHash("sha512").update(input).digest("hex");
81727
81761
  }
81728
81762
  function assertSecret(secretKey) {
81729
81763
  if (!secretKey) {
@@ -82595,7 +82629,7 @@ function useRedDotPaymentController() {
82595
82629
 
82596
82630
  // src/services/verification-v2.service.ts
82597
82631
  var import_node_server_utils262 = require("@7365admin1/node-server-utils");
82598
- var import_crypto4 = __toESM(require("crypto"));
82632
+ var import_crypto5 = __toESM(require("crypto"));
82599
82633
  var import_joi138 = __toESM(require("joi"));
82600
82634
  var import_mongodb160 = require("mongodb");
82601
82635
  function useVerificationServiceV2() {
@@ -82657,7 +82691,7 @@ function useVerificationServiceV2() {
82657
82691
  }
82658
82692
  function generateVerificationCode(length = 8) {
82659
82693
  const chars = "0123456789";
82660
- const bytes = import_crypto4.default.randomBytes(length);
82694
+ const bytes = import_crypto5.default.randomBytes(length);
82661
82695
  let result = "";
82662
82696
  for (let i = 0; i < length; i++) {
82663
82697
  result += chars[bytes[i] % chars.length];