node-server-engine 1.3.2 → 1.3.4

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 (41) hide show
  1. package/.env.example +14 -1
  2. package/dist/entities/Server/Server.d.ts +2 -2
  3. package/dist/entities/Server/Server.js +8 -16
  4. package/dist/entities/Server/Server.js.map +1 -1
  5. package/dist/middleware/userResolver/userResolver.d.ts +4 -0
  6. package/dist/middleware/userResolver/userResolver.js +18 -4
  7. package/dist/middleware/userResolver/userResolver.js.map +1 -1
  8. package/dist/utils/createHttpServer/createHttpServer.d.ts +5 -2
  9. package/dist/utils/createHttpServer/createHttpServer.js +17 -12
  10. package/dist/utils/createHttpServer/createHttpServer.js.map +1 -1
  11. package/dist/utils/index.d.ts +1 -0
  12. package/dist/utils/index.js +11 -0
  13. package/dist/utils/index.js.map +1 -1
  14. package/dist/utils/jwt/jwt.js +5 -5
  15. package/dist/utils/jwt/jwt.js.map +1 -1
  16. package/dist/utils/secretManager/index.d.ts +2 -0
  17. package/dist/utils/secretManager/index.js +28 -0
  18. package/dist/utils/secretManager/index.js.map +1 -0
  19. package/dist/utils/secretManager/secretLoader.d.ts +8 -0
  20. package/dist/utils/secretManager/secretLoader.js +64 -0
  21. package/dist/utils/secretManager/secretLoader.js.map +1 -0
  22. package/dist/utils/secretManager/secretResolver.d.ts +5 -0
  23. package/dist/utils/secretManager/secretResolver.js +42 -0
  24. package/dist/utils/secretManager/secretResolver.js.map +1 -0
  25. package/dist/utils/tlsConfig/httpsAgent.js +8 -4
  26. package/dist/utils/tlsConfig/httpsAgent.js.map +1 -1
  27. package/dist/utils/tlsConfig/tlsConfig.d.ts +1 -1
  28. package/dist/utils/tlsConfig/tlsConfig.js +14 -8
  29. package/dist/utils/tlsConfig/tlsConfig.js.map +1 -1
  30. package/package.json +2 -1
  31. package/src/entities/Server/Server.ts +7 -25
  32. package/src/middleware/userResolver/userResolver.ts +19 -1
  33. package/src/utils/createHttpServer/createHttpServer.ts +18 -13
  34. package/src/utils/index.ts +2 -0
  35. package/src/utils/jwt/jwt.ts +8 -7
  36. package/src/utils/secretManager/index.ts +2 -0
  37. package/src/utils/secretManager/secretLoader.ts +62 -0
  38. package/src/utils/secretManager/secretResolver.ts +36 -0
  39. package/src/utils/tlsConfig/httpsAgent.ts +22 -13
  40. package/src/utils/tlsConfig/tlsConfig.ts +22 -20
  41. package/src/middleware/userResolver/userResolver.test.ts +0 -35
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.secretCache = exports.initializeSecrets = void 0;
7
+ var _secretManager = require("@google-cloud/secret-manager");
8
+ var _EngineError = require("../../entities/EngineError");
9
+ // Cache to store preloaded secrets
10
+ const secretCache = exports.secretCache = {};
11
+ let secretClient;
12
+
13
+ /**
14
+ * Initialize the Secret Manager client and preload secrets.
15
+ * @param secretEnvVars List of env var names that contain secret paths
16
+ */
17
+ const initializeSecrets = async secretEnvVars => {
18
+ if (process.env.NODE_ENV !== 'production') {
19
+ console.log('Development mode → using local files for secrets');
20
+ return; // No need to preload anything
21
+ }
22
+ try {
23
+ // Default creds (for GCP runtime)
24
+ secretClient = new _secretManager.SecretManagerServiceClient();
25
+ const secretNames = secretEnvVars.filter(name => process.env[name]);
26
+ if (secretNames.length === 0) {
27
+ throw new _EngineError.EngineError({
28
+ message: 'No secret names defined in environment variables'
29
+ });
30
+ }
31
+
32
+ // Fetch all secrets from GCP Secret Manager
33
+ for (const name of secretNames) {
34
+ const secretPath = process.env[name];
35
+ if (!secretPath) {
36
+ throw new _EngineError.EngineError({
37
+ message: `Secret path for ${name} is not defined`
38
+ });
39
+ }
40
+ try {
41
+ const [version] = await secretClient.accessSecretVersion({
42
+ name: secretPath
43
+ });
44
+ const payload = version.payload?.data?.toString('utf-8');
45
+ if (!payload) {
46
+ throw new _EngineError.EngineError({
47
+ message: `Secret ${name} not found or empty`
48
+ });
49
+ }
50
+ secretCache[name] = payload;
51
+ } catch (err) {
52
+ throw new _EngineError.EngineError({
53
+ message: `Error accessing secret ${name}: ${err.message}`
54
+ });
55
+ }
56
+ }
57
+ } catch (err) {
58
+ throw new _EngineError.EngineError({
59
+ message: `Failed to initialize secrets: ${err.message}`
60
+ });
61
+ }
62
+ };
63
+ exports.initializeSecrets = initializeSecrets;
64
+ //# sourceMappingURL=secretLoader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secretLoader.js","names":["_secretManager","require","_EngineError","secretCache","exports","secretClient","initializeSecrets","secretEnvVars","process","env","NODE_ENV","console","log","SecretManagerServiceClient","secretNames","filter","name","length","EngineError","message","secretPath","version","accessSecretVersion","payload","data","toString","err"],"sources":["../../../src/utils/secretManager/secretLoader.ts"],"sourcesContent":["import { SecretManagerServiceClient } from '@google-cloud/secret-manager';\nimport { EngineError } from 'entities/EngineError';\n\n// Cache to store preloaded secrets\nexport const secretCache: { [key: string]: string } = {};\nlet secretClient: SecretManagerServiceClient;\n\n/**\n * Initialize the Secret Manager client and preload secrets.\n * @param secretEnvVars List of env var names that contain secret paths\n */\nexport const initializeSecrets = async (\n secretEnvVars: string[]\n): Promise<void> => {\n if (process.env.NODE_ENV !== 'production') {\n console.log('Development mode → using local files for secrets');\n return; // No need to preload anything\n }\n\n try {\n // Default creds (for GCP runtime)\n secretClient = new SecretManagerServiceClient();\n\n const secretNames = secretEnvVars.filter((name) => process.env[name]);\n if (secretNames.length === 0) {\n throw new EngineError({\n message: 'No secret names defined in environment variables'\n });\n }\n\n // Fetch all secrets from GCP Secret Manager\n for (const name of secretNames) {\n const secretPath = process.env[name];\n if (!secretPath) {\n throw new EngineError({\n message: `Secret path for ${name} is not defined`\n });\n }\n\n try {\n const [version] = await secretClient.accessSecretVersion({\n name: secretPath\n });\n const payload = version.payload?.data?.toString('utf-8');\n if (!payload) {\n throw new EngineError({\n message: `Secret ${name} not found or empty`\n });\n }\n secretCache[name] = payload;\n } catch (err) {\n throw new EngineError({\n message: `Error accessing secret ${name}: ${(err as Error).message}`\n });\n }\n }\n } catch (err) {\n throw new EngineError({\n message: `Failed to initialize secrets: ${(err as Error).message}`\n });\n }\n};\n"],"mappings":";;;;;;AAAA,IAAAA,cAAA,GAAAC,OAAA;AACA,IAAAC,YAAA,GAAAD,OAAA;AAEA;AACO,MAAME,WAAsC,GAAAC,OAAA,CAAAD,WAAA,GAAG,CAAC,CAAC;AACxD,IAAIE,YAAwC;;AAE5C;AACA;AACA;AACA;AACO,MAAMC,iBAAiB,GAAG,MAC/BC,aAAuB,IACL;EAClB,IAAIC,OAAO,CAACC,GAAG,CAACC,QAAQ,KAAK,YAAY,EAAE;IACzCC,OAAO,CAACC,GAAG,CAAC,kDAAkD,CAAC;IAC/D,OAAO,CAAC;EACV;EAEA,IAAI;IACF;IACAP,YAAY,GAAG,IAAIQ,yCAA0B,CAAC,CAAC;IAE/C,MAAMC,WAAW,GAAGP,aAAa,CAACQ,MAAM,CAAEC,IAAI,IAAKR,OAAO,CAACC,GAAG,CAACO,IAAI,CAAC,CAAC;IACrE,IAAIF,WAAW,CAACG,MAAM,KAAK,CAAC,EAAE;MAC5B,MAAM,IAAIC,wBAAW,CAAC;QACpBC,OAAO,EAAE;MACX,CAAC,CAAC;IACJ;;IAEA;IACA,KAAK,MAAMH,IAAI,IAAIF,WAAW,EAAE;MAC9B,MAAMM,UAAU,GAAGZ,OAAO,CAACC,GAAG,CAACO,IAAI,CAAC;MACpC,IAAI,CAACI,UAAU,EAAE;QACf,MAAM,IAAIF,wBAAW,CAAC;UACpBC,OAAO,EAAE,mBAAmBH,IAAI;QAClC,CAAC,CAAC;MACJ;MAEA,IAAI;QACF,MAAM,CAACK,OAAO,CAAC,GAAG,MAAMhB,YAAY,CAACiB,mBAAmB,CAAC;UACvDN,IAAI,EAAEI;QACR,CAAC,CAAC;QACF,MAAMG,OAAO,GAAGF,OAAO,CAACE,OAAO,EAAEC,IAAI,EAAEC,QAAQ,CAAC,OAAO,CAAC;QACxD,IAAI,CAACF,OAAO,EAAE;UACZ,MAAM,IAAIL,wBAAW,CAAC;YACpBC,OAAO,EAAE,UAAUH,IAAI;UACzB,CAAC,CAAC;QACJ;QACAb,WAAW,CAACa,IAAI,CAAC,GAAGO,OAAO;MAC7B,CAAC,CAAC,OAAOG,GAAG,EAAE;QACZ,MAAM,IAAIR,wBAAW,CAAC;UACpBC,OAAO,EAAE,0BAA0BH,IAAI,KAAMU,GAAG,CAAWP,OAAO;QACpE,CAAC,CAAC;MACJ;IACF;EACF,CAAC,CAAC,OAAOO,GAAG,EAAE;IACZ,MAAM,IAAIR,wBAAW,CAAC;MACpBC,OAAO,EAAE,iCAAkCO,GAAG,CAAWP,OAAO;IAClE,CAAC,CAAC;EACJ;AACF,CAAC;AAACf,OAAA,CAAAE,iBAAA,GAAAA,iBAAA","ignoreList":[]}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Retrieve a secret value (production) or file content (development).
3
+ * @param name The env var name that contains either the secret path (prod) or local file path (dev)
4
+ */
5
+ export declare const getSecretOrFile: (name: string) => string;
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.getSecretOrFile = void 0;
8
+ var _fs = _interopRequireDefault(require("fs"));
9
+ var _EngineError = require("../../entities/EngineError");
10
+ var _secretLoader = require("./secretLoader");
11
+ /**
12
+ * Retrieve a secret value (production) or file content (development).
13
+ * @param name The env var name that contains either the secret path (prod) or local file path (dev)
14
+ */
15
+ const getSecretOrFile = name => {
16
+ if (process.env.NODE_ENV === 'production') {
17
+ const secretValue = _secretLoader.secretCache[name];
18
+ console.log('SecrrtCj', _secretLoader.secretCache);
19
+ if (!secretValue) {
20
+ throw new _EngineError.EngineError({
21
+ message: `Secret value for ${name} not found in cache`
22
+ });
23
+ }
24
+ return secretValue;
25
+ } else {
26
+ const localPath = process.env[name];
27
+ if (!localPath) {
28
+ throw new _EngineError.EngineError({
29
+ message: `Local path for ${name} is not defined`
30
+ });
31
+ }
32
+ try {
33
+ return _fs.default.readFileSync(localPath, 'utf-8');
34
+ } catch (err) {
35
+ throw new _EngineError.EngineError({
36
+ message: `Error reading local file for ${name}: ${err.message}`
37
+ });
38
+ }
39
+ }
40
+ };
41
+ exports.getSecretOrFile = getSecretOrFile;
42
+ //# sourceMappingURL=secretResolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secretResolver.js","names":["_fs","_interopRequireDefault","require","_EngineError","_secretLoader","getSecretOrFile","name","process","env","NODE_ENV","secretValue","secretCache","console","log","EngineError","message","localPath","fs","readFileSync","err","exports"],"sources":["../../../src/utils/secretManager/secretResolver.ts"],"sourcesContent":["import fs from 'fs';\nimport { EngineError } from 'entities/EngineError';\nimport { secretCache } from './secretLoader';\n\n/**\n * Retrieve a secret value (production) or file content (development).\n * @param name The env var name that contains either the secret path (prod) or local file path (dev)\n */\nexport const getSecretOrFile = (name: string): string => {\n if (process.env.NODE_ENV === 'production') {\n const secretValue = secretCache[name];\n console.log('SecrrtCj', secretCache);\n\n if (!secretValue) {\n throw new EngineError({\n message: `Secret value for ${name} not found in cache`\n });\n }\n return secretValue;\n } else {\n const localPath = process.env[name];\n if (!localPath) {\n throw new EngineError({\n message: `Local path for ${name} is not defined`\n });\n }\n\n try {\n return fs.readFileSync(localPath, 'utf-8');\n } catch (err) {\n throw new EngineError({\n message: `Error reading local file for ${name}: ${(err as Error).message}`\n });\n }\n }\n};\n"],"mappings":";;;;;;;AAAA,IAAAA,GAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,YAAA,GAAAD,OAAA;AACA,IAAAE,aAAA,GAAAF,OAAA;AAEA;AACA;AACA;AACA;AACO,MAAMG,eAAe,GAAIC,IAAY,IAAa;EACvD,IAAIC,OAAO,CAACC,GAAG,CAACC,QAAQ,KAAK,YAAY,EAAE;IACzC,MAAMC,WAAW,GAAGC,yBAAW,CAACL,IAAI,CAAC;IACrCM,OAAO,CAACC,GAAG,CAAC,UAAU,EAAEF,yBAAW,CAAC;IAEpC,IAAI,CAACD,WAAW,EAAE;MAChB,MAAM,IAAII,wBAAW,CAAC;QACpBC,OAAO,EAAE,oBAAoBT,IAAI;MACnC,CAAC,CAAC;IACJ;IACA,OAAOI,WAAW;EACpB,CAAC,MAAM;IACL,MAAMM,SAAS,GAAGT,OAAO,CAACC,GAAG,CAACF,IAAI,CAAC;IACnC,IAAI,CAACU,SAAS,EAAE;MACd,MAAM,IAAIF,wBAAW,CAAC;QACpBC,OAAO,EAAE,kBAAkBT,IAAI;MACjC,CAAC,CAAC;IACJ;IAEA,IAAI;MACF,OAAOW,WAAE,CAACC,YAAY,CAACF,SAAS,EAAE,OAAO,CAAC;IAC5C,CAAC,CAAC,OAAOG,GAAG,EAAE;MACZ,MAAM,IAAIL,wBAAW,CAAC;QACpBC,OAAO,EAAE,gCAAgCT,IAAI,KAAMa,GAAG,CAAWJ,OAAO;MAC1E,CAAC,CAAC;IACJ;EACF;AACF,CAAC;AAACK,OAAA,CAAAf,eAAA,GAAAA,eAAA","ignoreList":[]}
@@ -5,17 +5,21 @@ Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
7
  exports.getHttpsAgent = getHttpsAgent;
8
- var _fs = _interopRequireDefault(require("fs"));
9
8
  var _https = _interopRequireDefault(require("https"));
10
9
  var _tlsConfig = require("./tlsConfig.validate");
11
10
  var _EngineError = require("../../entities/EngineError");
11
+ var _ = require("./..");
12
12
  let httpsAgent;
13
13
  function getHttpsAgent() {
14
14
  if (httpsAgent) return httpsAgent;
15
15
  (0, _tlsConfig.validateTlsConfig)();
16
- const key = _fs.default.readFileSync(process.env.TLS_REQUEST_KEY ?? process.env.TLS_SERVER_KEY, 'utf-8');
17
- const cert = _fs.default.readFileSync(process.env.TLS_REQUEST_CERT ?? process.env.TLS_SERVER_CERT, 'utf-8');
18
- const ca = _fs.default.readFileSync(process.env.TLS_REQUEST_CA ?? process.env.TLS_CA, 'utf-8');
16
+
17
+ // Always pass env var *names*, not their values
18
+ const key = (0, _.getSecretOrFile)(process.env.TLS_REQUEST_KEY ? 'TLS_REQUEST_KEY' : 'TLS_SERVER_KEY');
19
+ const cert = (0, _.getSecretOrFile)(process.env.TLS_REQUEST_CERT ? 'TLS_REQUEST_CERT' : 'TLS_SERVER_CERT');
20
+
21
+ // CA is optional → only load if env var is set
22
+ const ca = process.env.TLS_REQUEST_CA ? (0, _.getSecretOrFile)('TLS_REQUEST_CA') : process.env.TLS_CA ? (0, _.getSecretOrFile)('TLS_CA') : undefined;
19
23
  const passphrase = process.env.TLS_REQUEST_KEY_PASSPHRASE ?? process.env.TLS_SERVER_KEY_PASSPHRASE;
20
24
  if (!key || !cert || !ca || !passphrase) {
21
25
  throw new _EngineError.EngineError({
@@ -1 +1 @@
1
- {"version":3,"file":"httpsAgent.js","names":["_fs","_interopRequireDefault","require","_https","_tlsConfig","_EngineError","httpsAgent","getHttpsAgent","validateTlsConfig","key","fs","readFileSync","process","env","TLS_REQUEST_KEY","TLS_SERVER_KEY","cert","TLS_REQUEST_CERT","TLS_SERVER_CERT","ca","TLS_REQUEST_CA","TLS_CA","passphrase","TLS_REQUEST_KEY_PASSPHRASE","TLS_SERVER_KEY_PASSPHRASE","EngineError","message","https","Agent"],"sources":["../../../src/utils/tlsConfig/httpsAgent.ts"],"sourcesContent":["import fs from 'fs';\nimport https, { Agent } from 'https';\nimport { validateTlsConfig } from './tlsConfig.validate';\nimport { EngineError } from 'entities/EngineError';\n\nlet httpsAgent: Agent | undefined;\n\nexport function getHttpsAgent(): Agent {\n if (httpsAgent) return httpsAgent;\n\n validateTlsConfig();\n\n const key = fs.readFileSync(\n process.env.TLS_REQUEST_KEY ?? process.env.TLS_SERVER_KEY!,\n 'utf-8'\n );\n const cert = fs.readFileSync(\n process.env.TLS_REQUEST_CERT ?? process.env.TLS_SERVER_CERT!,\n 'utf-8'\n );\n const ca = fs.readFileSync(\n process.env.TLS_REQUEST_CA ?? process.env.TLS_CA!,\n 'utf-8'\n );\n const passphrase =\n process.env.TLS_REQUEST_KEY_PASSPHRASE ??\n process.env.TLS_SERVER_KEY_PASSPHRASE;\n\n if (!key || !cert || !ca || !passphrase) {\n throw new EngineError({\n message: 'TLS environment variables are not set correctly'\n });\n }\n\n httpsAgent = new https.Agent({ key, cert, ca, passphrase });\n return httpsAgent;\n}\n"],"mappings":";;;;;;;AAAA,IAAAA,GAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,MAAA,GAAAF,sBAAA,CAAAC,OAAA;AACA,IAAAE,UAAA,GAAAF,OAAA;AACA,IAAAG,YAAA,GAAAH,OAAA;AAEA,IAAII,UAA6B;AAE1B,SAASC,aAAaA,CAAA,EAAU;EACrC,IAAID,UAAU,EAAE,OAAOA,UAAU;EAEjC,IAAAE,4BAAiB,EAAC,CAAC;EAEnB,MAAMC,GAAG,GAAGC,WAAE,CAACC,YAAY,CACzBC,OAAO,CAACC,GAAG,CAACC,eAAe,IAAIF,OAAO,CAACC,GAAG,CAACE,cAAe,EAC1D,OACF,CAAC;EACD,MAAMC,IAAI,GAAGN,WAAE,CAACC,YAAY,CAC1BC,OAAO,CAACC,GAAG,CAACI,gBAAgB,IAAIL,OAAO,CAACC,GAAG,CAACK,eAAgB,EAC5D,OACF,CAAC;EACD,MAAMC,EAAE,GAAGT,WAAE,CAACC,YAAY,CACxBC,OAAO,CAACC,GAAG,CAACO,cAAc,IAAIR,OAAO,CAACC,GAAG,CAACQ,MAAO,EACjD,OACF,CAAC;EACD,MAAMC,UAAU,GACdV,OAAO,CAACC,GAAG,CAACU,0BAA0B,IACtCX,OAAO,CAACC,GAAG,CAACW,yBAAyB;EAEvC,IAAI,CAACf,GAAG,IAAI,CAACO,IAAI,IAAI,CAACG,EAAE,IAAI,CAACG,UAAU,EAAE;IACvC,MAAM,IAAIG,wBAAW,CAAC;MACpBC,OAAO,EAAE;IACX,CAAC,CAAC;EACJ;EAEApB,UAAU,GAAG,IAAIqB,cAAK,CAACC,KAAK,CAAC;IAAEnB,GAAG;IAAEO,IAAI;IAAEG,EAAE;IAAEG;EAAW,CAAC,CAAC;EAC3D,OAAOhB,UAAU;AACnB","ignoreList":[]}
1
+ {"version":3,"file":"httpsAgent.js","names":["_https","_interopRequireDefault","require","_tlsConfig","_EngineError","_","httpsAgent","getHttpsAgent","validateTlsConfig","key","getSecretOrFile","process","env","TLS_REQUEST_KEY","cert","TLS_REQUEST_CERT","ca","TLS_REQUEST_CA","TLS_CA","undefined","passphrase","TLS_REQUEST_KEY_PASSPHRASE","TLS_SERVER_KEY_PASSPHRASE","EngineError","message","https","Agent"],"sources":["../../../src/utils/tlsConfig/httpsAgent.ts"],"sourcesContent":["import https, { Agent } from 'https';\nimport { validateTlsConfig } from './tlsConfig.validate';\nimport { EngineError } from 'entities/EngineError';\nimport { getSecretOrFile } from 'utils';\n\nlet httpsAgent: Agent | undefined;\nexport function getHttpsAgent(): Agent {\n if (httpsAgent) return httpsAgent;\n\n validateTlsConfig();\n\n // Always pass env var *names*, not their values\n const key = getSecretOrFile(\n process.env.TLS_REQUEST_KEY ? 'TLS_REQUEST_KEY' : 'TLS_SERVER_KEY'\n );\n\n const cert = getSecretOrFile(\n process.env.TLS_REQUEST_CERT ? 'TLS_REQUEST_CERT' : 'TLS_SERVER_CERT'\n );\n\n // CA is optional → only load if env var is set\n const ca = process.env.TLS_REQUEST_CA\n ? getSecretOrFile('TLS_REQUEST_CA')\n : process.env.TLS_CA\n ? getSecretOrFile('TLS_CA')\n : undefined;\n\n const passphrase =\n process.env.TLS_REQUEST_KEY_PASSPHRASE ??\n process.env.TLS_SERVER_KEY_PASSPHRASE;\n\n if (!key || !cert || !ca || !passphrase) {\n throw new EngineError({\n message: 'TLS environment variables are not set correctly'\n });\n }\n\n httpsAgent = new https.Agent({\n key,\n cert,\n ca,\n passphrase\n });\n\n return httpsAgent;\n}\n"],"mappings":";;;;;;;AAAA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,UAAA,GAAAD,OAAA;AACA,IAAAE,YAAA,GAAAF,OAAA;AACA,IAAAG,CAAA,GAAAH,OAAA;AAEA,IAAII,UAA6B;AAC1B,SAASC,aAAaA,CAAA,EAAU;EACrC,IAAID,UAAU,EAAE,OAAOA,UAAU;EAEjC,IAAAE,4BAAiB,EAAC,CAAC;;EAEnB;EACA,MAAMC,GAAG,GAAG,IAAAC,iBAAe,EACzBC,OAAO,CAACC,GAAG,CAACC,eAAe,GAAG,iBAAiB,GAAG,gBACpD,CAAC;EAED,MAAMC,IAAI,GAAG,IAAAJ,iBAAe,EAC1BC,OAAO,CAACC,GAAG,CAACG,gBAAgB,GAAG,kBAAkB,GAAG,iBACtD,CAAC;;EAED;EACA,MAAMC,EAAE,GAAGL,OAAO,CAACC,GAAG,CAACK,cAAc,GACjC,IAAAP,iBAAe,EAAC,gBAAgB,CAAC,GACjCC,OAAO,CAACC,GAAG,CAACM,MAAM,GAChB,IAAAR,iBAAe,EAAC,QAAQ,CAAC,GACzBS,SAAS;EAEf,MAAMC,UAAU,GACdT,OAAO,CAACC,GAAG,CAACS,0BAA0B,IACtCV,OAAO,CAACC,GAAG,CAACU,yBAAyB;EAEvC,IAAI,CAACb,GAAG,IAAI,CAACK,IAAI,IAAI,CAACE,EAAE,IAAI,CAACI,UAAU,EAAE;IACvC,MAAM,IAAIG,wBAAW,CAAC;MACpBC,OAAO,EAAE;IACX,CAAC,CAAC;EACJ;EAEAlB,UAAU,GAAG,IAAImB,cAAK,CAACC,KAAK,CAAC;IAC3BjB,GAAG;IACHK,IAAI;IACJE,EAAE;IACFI;EACF,CAAC,CAAC;EAEF,OAAOd,UAAU;AACnB","ignoreList":[]}
@@ -3,6 +3,6 @@ import { TlsConfig } from './tlsConfig.types';
3
3
  export declare let tlsConfig: undefined | TlsConfig;
4
4
  export declare let httpsAgent: undefined | Agent;
5
5
  /**
6
- * Load TLS config by its Environment setting.
6
+ * Load TLS config by its environment setting (local files or GCP secrets)
7
7
  */
8
8
  export declare function loadTlsConfig(): void;
@@ -7,26 +7,32 @@ Object.defineProperty(exports, "__esModule", {
7
7
  exports.httpsAgent = void 0;
8
8
  exports.loadTlsConfig = loadTlsConfig;
9
9
  exports.tlsConfig = void 0;
10
- var _fs = _interopRequireDefault(require("fs"));
11
10
  var _https = _interopRequireDefault(require("https"));
12
11
  var _tlsConfig = require("./tlsConfig.validate");
13
12
  var _EngineError = require("../../entities/EngineError");
13
+ var _ = require("./..");
14
14
  let tlsConfig = exports.tlsConfig = void 0;
15
15
  let httpsAgent = exports.httpsAgent = void 0;
16
16
 
17
17
  /**
18
- * Load TLS config by its Environment setting.
18
+ * Load TLS config by its environment setting (local files or GCP secrets)
19
19
  */
20
20
  function loadTlsConfig() {
21
- // Check that environment variables are correctly set
22
21
  (0, _tlsConfig.validateTlsConfig)();
23
22
  exports.tlsConfig = tlsConfig = undefined;
24
23
  if (process.env.TLS_REQUEST_KEY || process.env.TLS_SERVER_KEY) {
24
+ // Fetch TLS secrets using unified utility
25
+ const key = (0, _.getSecretOrFile)(process.env.TLS_REQUEST_KEY ?? process.env.TLS_SERVER_KEY);
26
+ const cert = (0, _.getSecretOrFile)(process.env.TLS_REQUEST_CERT ?? process.env.TLS_SERVER_CERT);
27
+ const ca = (0, _.getSecretOrFile)(process.env.TLS_REQUEST_CA ?? process.env.TLS_CA);
28
+
29
+ // Passphrase is read directly from env variables
30
+ const passphrase = process.env.TLS_REQUEST_KEY_PASSPHRASE ?? process.env.TLS_SERVER_KEY_PASSPHRASE;
25
31
  exports.tlsConfig = tlsConfig = {
26
- key: _fs.default.readFileSync(process.env.TLS_REQUEST_KEY ?? process.env.TLS_SERVER_KEY, 'utf-8'),
27
- cert: _fs.default.readFileSync(process.env.TLS_REQUEST_CERT ?? process.env.TLS_SERVER_CERT, 'utf-8'),
28
- ca: _fs.default.readFileSync(process.env.TLS_REQUEST_CA ?? process.env.TLS_CA, 'utf-8'),
29
- passphrase: process.env.TLS_REQUEST_KEY_PASSPHRASE ?? process.env.TLS_SERVER_KEY_PASSPHRASE
32
+ key,
33
+ cert,
34
+ ca,
35
+ passphrase
30
36
  };
31
37
  exports.httpsAgent = httpsAgent = new _https.default.Agent({
32
38
  key: tlsConfig.key,
@@ -35,7 +41,7 @@ function loadTlsConfig() {
35
41
  passphrase: tlsConfig.passphrase
36
42
  });
37
43
  }
38
- if (!tlsConfig || !(tlsConfig.ca && tlsConfig.cert && tlsConfig.key)) {
44
+ if (!tlsConfig || !(tlsConfig.key && tlsConfig.cert && tlsConfig.ca)) {
39
45
  throw new _EngineError.EngineError({
40
46
  message: 'TLS environment variables are not set correctly'
41
47
  });
@@ -1 +1 @@
1
- {"version":3,"file":"tlsConfig.js","names":["_fs","_interopRequireDefault","require","_https","_tlsConfig","_EngineError","tlsConfig","exports","httpsAgent","loadTlsConfig","validateTlsConfig","undefined","process","env","TLS_REQUEST_KEY","TLS_SERVER_KEY","key","fs","readFileSync","cert","TLS_REQUEST_CERT","TLS_SERVER_CERT","ca","TLS_REQUEST_CA","TLS_CA","passphrase","TLS_REQUEST_KEY_PASSPHRASE","TLS_SERVER_KEY_PASSPHRASE","https","Agent","EngineError","message"],"sources":["../../../src/utils/tlsConfig/tlsConfig.ts"],"sourcesContent":["import fs from 'fs';\nimport https, { Agent } from 'https';\nimport { TlsConfig } from './tlsConfig.types';\nimport { validateTlsConfig } from './tlsConfig.validate';\nimport { EngineError } from 'entities/EngineError';\n\nexport let tlsConfig: undefined | TlsConfig;\nexport let httpsAgent: undefined | Agent;\n\n/**\n * Load TLS config by its Environment setting.\n */\nexport function loadTlsConfig(): void {\n // Check that environment variables are correctly set\n validateTlsConfig();\n tlsConfig = undefined;\n\n if (process.env.TLS_REQUEST_KEY || process.env.TLS_SERVER_KEY) {\n tlsConfig = {\n key: fs.readFileSync(\n (process.env.TLS_REQUEST_KEY ?? process.env.TLS_SERVER_KEY) as string,\n 'utf-8'\n ),\n cert: fs.readFileSync(\n (process.env.TLS_REQUEST_CERT ?? process.env.TLS_SERVER_CERT) as string,\n 'utf-8'\n ),\n ca: fs.readFileSync(\n (process.env.TLS_REQUEST_CA ?? process.env.TLS_CA) as string,\n 'utf-8'\n ),\n passphrase: (process.env.TLS_REQUEST_KEY_PASSPHRASE ??\n process.env.TLS_SERVER_KEY_PASSPHRASE) as string\n } as TlsConfig;\n httpsAgent = new https.Agent({\n key: tlsConfig.key,\n cert: tlsConfig.cert,\n ca: tlsConfig.ca,\n passphrase: tlsConfig.passphrase\n });\n }\n if (!tlsConfig || !(tlsConfig.ca && tlsConfig.cert && tlsConfig.key)) {\n throw new EngineError({\n message: 'TLS environment variables are not set correctly'\n });\n }\n}\n"],"mappings":";;;;;;;;;AAAA,IAAAA,GAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,MAAA,GAAAF,sBAAA,CAAAC,OAAA;AAEA,IAAAE,UAAA,GAAAF,OAAA;AACA,IAAAG,YAAA,GAAAH,OAAA;AAEO,IAAII,SAAgC,GAAAC,OAAA,CAAAD,SAAA;AACpC,IAAIE,UAA6B,GAAAD,OAAA,CAAAC,UAAA;;AAExC;AACA;AACA;AACO,SAASC,aAAaA,CAAA,EAAS;EACpC;EACA,IAAAC,4BAAiB,EAAC,CAAC;EACnBH,OAAA,CAAAD,SAAA,GAAAA,SAAS,GAAGK,SAAS;EAErB,IAAIC,OAAO,CAACC,GAAG,CAACC,eAAe,IAAIF,OAAO,CAACC,GAAG,CAACE,cAAc,EAAE;IAC7DR,OAAA,CAAAD,SAAA,GAAAA,SAAS,GAAG;MACVU,GAAG,EAAEC,WAAE,CAACC,YAAY,CACjBN,OAAO,CAACC,GAAG,CAACC,eAAe,IAAIF,OAAO,CAACC,GAAG,CAACE,cAAc,EAC1D,OACF,CAAC;MACDI,IAAI,EAAEF,WAAE,CAACC,YAAY,CAClBN,OAAO,CAACC,GAAG,CAACO,gBAAgB,IAAIR,OAAO,CAACC,GAAG,CAACQ,eAAe,EAC5D,OACF,CAAC;MACDC,EAAE,EAAEL,WAAE,CAACC,YAAY,CAChBN,OAAO,CAACC,GAAG,CAACU,cAAc,IAAIX,OAAO,CAACC,GAAG,CAACW,MAAM,EACjD,OACF,CAAC;MACDC,UAAU,EAAGb,OAAO,CAACC,GAAG,CAACa,0BAA0B,IACjDd,OAAO,CAACC,GAAG,CAACc;IAChB,CAAc;IACdpB,OAAA,CAAAC,UAAA,GAAAA,UAAU,GAAG,IAAIoB,cAAK,CAACC,KAAK,CAAC;MAC3Bb,GAAG,EAAEV,SAAS,CAACU,GAAG;MAClBG,IAAI,EAAEb,SAAS,CAACa,IAAI;MACpBG,EAAE,EAAEhB,SAAS,CAACgB,EAAE;MAChBG,UAAU,EAAEnB,SAAS,CAACmB;IACxB,CAAC,CAAC;EACJ;EACA,IAAI,CAACnB,SAAS,IAAI,EAAEA,SAAS,CAACgB,EAAE,IAAIhB,SAAS,CAACa,IAAI,IAAIb,SAAS,CAACU,GAAG,CAAC,EAAE;IACpE,MAAM,IAAIc,wBAAW,CAAC;MACpBC,OAAO,EAAE;IACX,CAAC,CAAC;EACJ;AACF","ignoreList":[]}
1
+ {"version":3,"file":"tlsConfig.js","names":["_https","_interopRequireDefault","require","_tlsConfig","_EngineError","_","tlsConfig","exports","httpsAgent","loadTlsConfig","validateTlsConfig","undefined","process","env","TLS_REQUEST_KEY","TLS_SERVER_KEY","key","getSecretOrFile","cert","TLS_REQUEST_CERT","TLS_SERVER_CERT","ca","TLS_REQUEST_CA","TLS_CA","passphrase","TLS_REQUEST_KEY_PASSPHRASE","TLS_SERVER_KEY_PASSPHRASE","https","Agent","EngineError","message"],"sources":["../../../src/utils/tlsConfig/tlsConfig.ts"],"sourcesContent":["import https, { Agent } from 'https';\nimport { TlsConfig } from './tlsConfig.types';\nimport { validateTlsConfig } from './tlsConfig.validate';\nimport { EngineError } from 'entities/EngineError';\nimport { getSecretOrFile } from 'utils';\n\nexport let tlsConfig: undefined | TlsConfig;\nexport let httpsAgent: undefined | Agent;\n\n/**\n * Load TLS config by its environment setting (local files or GCP secrets)\n */\nexport function loadTlsConfig(): void {\n validateTlsConfig();\n tlsConfig = undefined;\n\n if (process.env.TLS_REQUEST_KEY || process.env.TLS_SERVER_KEY) {\n // Fetch TLS secrets using unified utility\n const key = getSecretOrFile(\n process.env.TLS_REQUEST_KEY ?? process.env.TLS_SERVER_KEY!\n );\n const cert = getSecretOrFile(\n process.env.TLS_REQUEST_CERT ?? process.env.TLS_SERVER_CERT!\n );\n const ca = getSecretOrFile(\n process.env.TLS_REQUEST_CA ?? process.env.TLS_CA!\n );\n\n // Passphrase is read directly from env variables\n const passphrase =\n process.env.TLS_REQUEST_KEY_PASSPHRASE ??\n process.env.TLS_SERVER_KEY_PASSPHRASE;\n\n tlsConfig = { key, cert, ca, passphrase } as TlsConfig;\n\n httpsAgent = new https.Agent({\n key: tlsConfig.key,\n cert: tlsConfig.cert,\n ca: tlsConfig.ca,\n passphrase: tlsConfig.passphrase\n });\n }\n\n if (!tlsConfig || !(tlsConfig.key && tlsConfig.cert && tlsConfig.ca)) {\n throw new EngineError({\n message: 'TLS environment variables are not set correctly'\n });\n }\n}\n"],"mappings":";;;;;;;;;AAAA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AAEA,IAAAC,UAAA,GAAAD,OAAA;AACA,IAAAE,YAAA,GAAAF,OAAA;AACA,IAAAG,CAAA,GAAAH,OAAA;AAEO,IAAII,SAAgC,GAAAC,OAAA,CAAAD,SAAA;AACpC,IAAIE,UAA6B,GAAAD,OAAA,CAAAC,UAAA;;AAExC;AACA;AACA;AACO,SAASC,aAAaA,CAAA,EAAS;EACpC,IAAAC,4BAAiB,EAAC,CAAC;EACnBH,OAAA,CAAAD,SAAA,GAAAA,SAAS,GAAGK,SAAS;EAErB,IAAIC,OAAO,CAACC,GAAG,CAACC,eAAe,IAAIF,OAAO,CAACC,GAAG,CAACE,cAAc,EAAE;IAC7D;IACA,MAAMC,GAAG,GAAG,IAAAC,iBAAe,EACzBL,OAAO,CAACC,GAAG,CAACC,eAAe,IAAIF,OAAO,CAACC,GAAG,CAACE,cAC7C,CAAC;IACD,MAAMG,IAAI,GAAG,IAAAD,iBAAe,EAC1BL,OAAO,CAACC,GAAG,CAACM,gBAAgB,IAAIP,OAAO,CAACC,GAAG,CAACO,eAC9C,CAAC;IACD,MAAMC,EAAE,GAAG,IAAAJ,iBAAe,EACxBL,OAAO,CAACC,GAAG,CAACS,cAAc,IAAIV,OAAO,CAACC,GAAG,CAACU,MAC5C,CAAC;;IAED;IACA,MAAMC,UAAU,GACdZ,OAAO,CAACC,GAAG,CAACY,0BAA0B,IACtCb,OAAO,CAACC,GAAG,CAACa,yBAAyB;IAEvCnB,OAAA,CAAAD,SAAA,GAAAA,SAAS,GAAG;MAAEU,GAAG;MAAEE,IAAI;MAAEG,EAAE;MAAEG;IAAW,CAAc;IAEtDjB,OAAA,CAAAC,UAAA,GAAAA,UAAU,GAAG,IAAImB,cAAK,CAACC,KAAK,CAAC;MAC3BZ,GAAG,EAAEV,SAAS,CAACU,GAAG;MAClBE,IAAI,EAAEZ,SAAS,CAACY,IAAI;MACpBG,EAAE,EAAEf,SAAS,CAACe,EAAE;MAChBG,UAAU,EAAElB,SAAS,CAACkB;IACxB,CAAC,CAAC;EACJ;EAEA,IAAI,CAAClB,SAAS,IAAI,EAAEA,SAAS,CAACU,GAAG,IAAIV,SAAS,CAACY,IAAI,IAAIZ,SAAS,CAACe,EAAE,CAAC,EAAE;IACpE,MAAM,IAAIQ,wBAAW,CAAC;MACpBC,OAAO,EAAE;IACX,CAAC,CAAC;EACJ;AACF","ignoreList":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-server-engine",
3
- "version": "1.3.2",
3
+ "version": "1.3.4",
4
4
  "description": "Framework used to develop backend services. This package ships with a lot of features to standardize the creation of services, letting you focus on the business logic.",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -41,6 +41,7 @@
41
41
  "@babel/runtime": "^7.26.0",
42
42
  "@elastic/elasticsearch": "^8.17.0",
43
43
  "@google-cloud/pubsub": "^4.9.0",
44
+ "@google-cloud/secret-manager": "^6.1.0",
44
45
  "@google-cloud/storage": "^7.14.0",
45
46
  "@google/generative-ai": "^0.21.0",
46
47
  "ajv": "^8.17.1",
@@ -1,8 +1,6 @@
1
- import fs from 'fs';
2
1
  import http from 'http';
3
2
  import https from 'https';
4
3
  import { AddressInfo } from 'net';
5
- import path from 'path';
6
4
  import { setTimeout as setTimeoutPromise } from 'timers/promises';
7
5
  import { ValidatorSpec } from 'envalid';
8
6
  import express, { Application } from 'express';
@@ -203,8 +201,8 @@ export class Server {
203
201
 
204
202
  this.handleSignal();
205
203
 
206
- // Watch TSL config files changing
207
- this.watchTlsCaFileChange();
204
+ // Load TSL config files
205
+ this.loadTls();
208
206
  }
209
207
 
210
208
  /** Graceful shutdown */
@@ -344,27 +342,11 @@ export class Server {
344
342
  );
345
343
  }
346
344
 
347
- /** Watch the TLS certificate change event */
348
- private watchTlsCaFileChange(): void {
349
- [
350
- 'TLS_REQUEST_KEY',
351
- 'TLS_REQUEST_CERT',
352
- 'TLS_REQUEST_CA',
353
- 'TLS_SERVER_KEY',
354
- 'TLS_SERVER_CERT',
355
- 'TLS_CA'
356
- ].forEach((key) => {
357
- const file = process.env[key];
358
- if (file)
359
- fs.watch(path.resolve(file), (event) => {
360
- if (event !== 'change') return;
361
- reportInfo(`Reloading TLS config [${file} changed]`);
362
- loadTlsConfig();
363
- (this.httpServer as https.Server).setSecureContext(
364
- tlsConfig as TlsConfig
365
- );
366
- });
367
- });
345
+ /** Load TLS Config */
346
+ private loadTls(): void {
347
+ reportInfo(`Loading TLS config`);
348
+ loadTlsConfig();
349
+ (this.httpServer as https.Server).setSecureContext(tlsConfig as TlsConfig);
368
350
  }
369
351
 
370
352
  /** Executes a recurring job */
@@ -1,6 +1,7 @@
1
1
  import { Request, Response, NextFunction } from 'express';
2
2
  import { EngineError } from 'entities/EngineError';
3
3
  import { reportDebug } from 'utils';
4
+ import { tlsRequest } from 'utils/tlsRequest';
4
5
 
5
6
  const namespace = 'engine:middleware:userResolver';
6
7
 
@@ -15,7 +16,7 @@ export async function userResolver(
15
16
  throw new EngineError({
16
17
  message: 'Could not resolve user as the request is missing his ID'
17
18
  });
18
- const user = { user: 'ram', id };
19
+ const user = await getUserById(id);
19
20
  if (!user)
20
21
  throw new EngineError({
21
22
  message: 'Could not resolve user as it could not be fetched',
@@ -33,3 +34,20 @@ export async function userResolver(
33
34
 
34
35
  next();
35
36
  }
37
+
38
+ /**
39
+ * Call the GET /user/{id} endpoint using TLS
40
+ */
41
+ export async function getUserById(userId: number): Promise<unknown> {
42
+ const userServiceUrl = process.env.USER_SERVICE_URL;
43
+ if (!userServiceUrl) {
44
+ throw new Error('USER_SERVICE_URL is not defined in environment variables');
45
+ }
46
+
47
+ const response = await tlsRequest<unknown>({
48
+ method: 'GET',
49
+ url: `${userServiceUrl}/${userId}`
50
+ });
51
+
52
+ return response.data;
53
+ }
@@ -1,4 +1,3 @@
1
- import fs from 'fs';
2
1
  import { createServer, RequestListener, Server } from 'http';
3
2
  import {
4
3
  createServer as createSecureServer,
@@ -6,23 +5,29 @@ import {
6
5
  } from 'https';
7
6
  import { Application } from 'express';
8
7
  import { validateHttpEnvironment } from './createHttpServer.validate';
8
+ import { getSecretOrFile } from 'utils';
9
9
 
10
- /** Create and configure an http/https server */
11
- export function createHttpServer(
10
+ /**
11
+ * Create and configure an HTTP/HTTPS server.
12
+ * Supports local files in dev and GCP secrets in prod.
13
+ */
14
+ export const createHttpServer = (
12
15
  handler?: Application | RequestListener
13
- ): Server | SecureServer {
14
- // Validate the environment variables
16
+ ): Server | SecureServer => {
15
17
  validateHttpEnvironment();
16
- // Create a https server if env var are specified
18
+
17
19
  if (process.env.TLS_SERVER_KEY && process.env.TLS_SERVER_CERT) {
20
+ const key = getSecretOrFile('TLS_SERVER_KEY');
21
+ const cert = getSecretOrFile('TLS_SERVER_CERT');
22
+ const ca = process.env.TLS_CA ? getSecretOrFile('TLS_CA') : undefined;
23
+ const passphrase = process.env.TLS_SERVER_KEY_PASSPHRASE;
24
+
18
25
  return createSecureServer(
19
26
  {
20
- key: fs.readFileSync(process.env.TLS_SERVER_KEY),
21
- passphrase: process.env.TLS_SERVER_KEY_PASSPHRASE,
22
- cert: fs.readFileSync(process.env.TLS_SERVER_CERT),
23
- ca: process.env.TLS_CA
24
- ? fs.readFileSync(process.env.TLS_CA)
25
- : undefined,
27
+ key,
28
+ cert,
29
+ ca,
30
+ passphrase,
26
31
  requestCert: true,
27
32
  rejectUnauthorized: false
28
33
  },
@@ -31,4 +36,4 @@ export function createHttpServer(
31
36
  } else {
32
37
  return createServer(handler);
33
38
  }
34
- }
39
+ };
@@ -23,5 +23,7 @@ export * from './sendEmail';
23
23
  // String manipulation
24
24
  export * from './trimPathSlash';
25
25
 
26
+ export * from './secretManager';
27
+
26
28
  // File Upload
27
29
  export * from './geminiFileUpload';
@@ -6,7 +6,6 @@ import {
6
6
  VerifyOptions,
7
7
  sign
8
8
  } from 'jsonwebtoken';
9
- import fs from 'fs';
10
9
  import { UserTokenPayload } from './jwt.types';
11
10
  import { TokenIssuer } from 'const';
12
11
  import { EngineError } from 'entities/EngineError';
@@ -15,6 +14,7 @@ import { WebError } from 'entities/WebError';
15
14
  import { assertEnvironment } from 'utils/checkEnvironment';
16
15
  import { envAssert } from 'utils/envAssert';
17
16
  import { reportDebug } from 'utils/report';
17
+ import { getSecretOrFile } from 'utils';
18
18
 
19
19
  export let keySet: KeySet | undefined;
20
20
 
@@ -125,7 +125,8 @@ export async function jwtVerify(
125
125
  }
126
126
  assertEnvironment({
127
127
  ACCESS_TOKEN_AUDIENCE: envAssert.isString(),
128
- ACCESS_TOKEN_ISSUER: envAssert.isString()
128
+ ACCESS_TOKEN_ISSUER: envAssert.isString(),
129
+ ACCESS_TOKEN_EXPIRATION_TIME: envAssert.isString()
129
130
  });
130
131
  let options: VerifyOptions | undefined;
131
132
 
@@ -165,16 +166,16 @@ export async function jwtVerify(
165
166
  export function generateJwtToken(user: unknown) {
166
167
  const signOptions = {
167
168
  algorithm: 'ES256' as const, // or 'ES256' as Algorithm
168
- expiresIn: '1h',
169
+ expiresIn: process.env.ACCESS_TOKEN_EXPIRATION_TIME
170
+ ? parseInt(process.env.ACCESS_TOKEN_EXPIRATION_TIME, 10)
171
+ : undefined,
169
172
  issuer: process.env.ACCESS_TOKEN_ISSUER,
170
173
  audience: process.env.ACCESS_TOKEN_AUDIENCE,
171
174
  keyid: Object.keys(keySet?.getKeys() ?? {})[0]
172
175
  };
173
176
 
174
- const privateKey = fs.readFileSync(
175
- process.env.PRIVATE_KEY_PATH ?? 'keys/private-key.pem',
176
- 'utf8'
177
- );
177
+ const privateKey = getSecretOrFile('PRIVATE_KEY_PATH');
178
+
178
179
  const token = sign({ user }, privateKey, signOptions);
179
180
 
180
181
  return token;
@@ -0,0 +1,2 @@
1
+ export * from './secretResolver';
2
+ export * from './secretLoader';
@@ -0,0 +1,62 @@
1
+ import { SecretManagerServiceClient } from '@google-cloud/secret-manager';
2
+ import { EngineError } from 'entities/EngineError';
3
+
4
+ // Cache to store preloaded secrets
5
+ export const secretCache: { [key: string]: string } = {};
6
+ let secretClient: SecretManagerServiceClient;
7
+
8
+ /**
9
+ * Initialize the Secret Manager client and preload secrets.
10
+ * @param secretEnvVars List of env var names that contain secret paths
11
+ */
12
+ export const initializeSecrets = async (
13
+ secretEnvVars: string[]
14
+ ): Promise<void> => {
15
+ if (process.env.NODE_ENV !== 'production') {
16
+ console.log('Development mode → using local files for secrets');
17
+ return; // No need to preload anything
18
+ }
19
+
20
+ try {
21
+ // Default creds (for GCP runtime)
22
+ secretClient = new SecretManagerServiceClient();
23
+
24
+ const secretNames = secretEnvVars.filter((name) => process.env[name]);
25
+ if (secretNames.length === 0) {
26
+ throw new EngineError({
27
+ message: 'No secret names defined in environment variables'
28
+ });
29
+ }
30
+
31
+ // Fetch all secrets from GCP Secret Manager
32
+ for (const name of secretNames) {
33
+ const secretPath = process.env[name];
34
+ if (!secretPath) {
35
+ throw new EngineError({
36
+ message: `Secret path for ${name} is not defined`
37
+ });
38
+ }
39
+
40
+ try {
41
+ const [version] = await secretClient.accessSecretVersion({
42
+ name: secretPath
43
+ });
44
+ const payload = version.payload?.data?.toString('utf-8');
45
+ if (!payload) {
46
+ throw new EngineError({
47
+ message: `Secret ${name} not found or empty`
48
+ });
49
+ }
50
+ secretCache[name] = payload;
51
+ } catch (err) {
52
+ throw new EngineError({
53
+ message: `Error accessing secret ${name}: ${(err as Error).message}`
54
+ });
55
+ }
56
+ }
57
+ } catch (err) {
58
+ throw new EngineError({
59
+ message: `Failed to initialize secrets: ${(err as Error).message}`
60
+ });
61
+ }
62
+ };
@@ -0,0 +1,36 @@
1
+ import fs from 'fs';
2
+ import { EngineError } from 'entities/EngineError';
3
+ import { secretCache } from './secretLoader';
4
+
5
+ /**
6
+ * Retrieve a secret value (production) or file content (development).
7
+ * @param name The env var name that contains either the secret path (prod) or local file path (dev)
8
+ */
9
+ export const getSecretOrFile = (name: string): string => {
10
+ if (process.env.NODE_ENV === 'production') {
11
+ const secretValue = secretCache[name];
12
+ console.log('SecrrtCj', secretCache);
13
+
14
+ if (!secretValue) {
15
+ throw new EngineError({
16
+ message: `Secret value for ${name} not found in cache`
17
+ });
18
+ }
19
+ return secretValue;
20
+ } else {
21
+ const localPath = process.env[name];
22
+ if (!localPath) {
23
+ throw new EngineError({
24
+ message: `Local path for ${name} is not defined`
25
+ });
26
+ }
27
+
28
+ try {
29
+ return fs.readFileSync(localPath, 'utf-8');
30
+ } catch (err) {
31
+ throw new EngineError({
32
+ message: `Error reading local file for ${name}: ${(err as Error).message}`
33
+ });
34
+ }
35
+ }
36
+ };
@@ -1,27 +1,30 @@
1
- import fs from 'fs';
2
1
  import https, { Agent } from 'https';
3
2
  import { validateTlsConfig } from './tlsConfig.validate';
4
3
  import { EngineError } from 'entities/EngineError';
4
+ import { getSecretOrFile } from 'utils';
5
5
 
6
6
  let httpsAgent: Agent | undefined;
7
-
8
7
  export function getHttpsAgent(): Agent {
9
8
  if (httpsAgent) return httpsAgent;
10
9
 
11
10
  validateTlsConfig();
12
11
 
13
- const key = fs.readFileSync(
14
- process.env.TLS_REQUEST_KEY ?? process.env.TLS_SERVER_KEY!,
15
- 'utf-8'
16
- );
17
- const cert = fs.readFileSync(
18
- process.env.TLS_REQUEST_CERT ?? process.env.TLS_SERVER_CERT!,
19
- 'utf-8'
12
+ // Always pass env var *names*, not their values
13
+ const key = getSecretOrFile(
14
+ process.env.TLS_REQUEST_KEY ? 'TLS_REQUEST_KEY' : 'TLS_SERVER_KEY'
20
15
  );
21
- const ca = fs.readFileSync(
22
- process.env.TLS_REQUEST_CA ?? process.env.TLS_CA!,
23
- 'utf-8'
16
+
17
+ const cert = getSecretOrFile(
18
+ process.env.TLS_REQUEST_CERT ? 'TLS_REQUEST_CERT' : 'TLS_SERVER_CERT'
24
19
  );
20
+
21
+ // CA is optional → only load if env var is set
22
+ const ca = process.env.TLS_REQUEST_CA
23
+ ? getSecretOrFile('TLS_REQUEST_CA')
24
+ : process.env.TLS_CA
25
+ ? getSecretOrFile('TLS_CA')
26
+ : undefined;
27
+
25
28
  const passphrase =
26
29
  process.env.TLS_REQUEST_KEY_PASSPHRASE ??
27
30
  process.env.TLS_SERVER_KEY_PASSPHRASE;
@@ -32,6 +35,12 @@ export function getHttpsAgent(): Agent {
32
35
  });
33
36
  }
34
37
 
35
- httpsAgent = new https.Agent({ key, cert, ca, passphrase });
38
+ httpsAgent = new https.Agent({
39
+ key,
40
+ cert,
41
+ ca,
42
+ passphrase
43
+ });
44
+
36
45
  return httpsAgent;
37
46
  }