@be-link/shield-for-tcb-node-sdk 1.0.20 → 1.0.22

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.
@@ -39,6 +39,11 @@ export interface ShieldConfigManagerOptions {
39
39
  enableInfoLog?: boolean;
40
40
  /** 自定义日志函数,默认 console */
41
41
  logger?: Logger;
42
+ /**
43
+ * 是否拉取 V1 全局动态配置(设置 process.env.authorizationTokenInside),默认 true(向后兼容 V1 SDK)。
44
+ * 纯 V2 接入、不需要 authorizationTokenInside 的场景可设为 false 跳过该逻辑。
45
+ */
46
+ enableV1DynamicConfig?: boolean;
42
47
  }
43
48
  export interface Logger {
44
49
  info: (message: string, ...args: any[]) => void;
@@ -71,7 +71,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
71
71
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
72
72
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
73
73
  };
74
- var _ShieldConfigManager_instances, _ShieldConfigManager_serviceName, _ShieldConfigManager_env, _ShieldConfigManager_refreshIntervalMs, _ShieldConfigManager_fetchTimeoutMs, _ShieldConfigManager_enableInfoLog, _ShieldConfigManager_logger, _ShieldConfigManager_config, _ShieldConfigManager_refreshTimer, _ShieldConfigManager_isSetup, _ShieldConfigManager_setupPromise, _ShieldConfigManager_doSetup, _ShieldConfigManager_startRefreshTimer;
74
+ var _ShieldConfigManager_instances, _ShieldConfigManager_serviceName, _ShieldConfigManager_env, _ShieldConfigManager_refreshIntervalMs, _ShieldConfigManager_fetchTimeoutMs, _ShieldConfigManager_enableInfoLog, _ShieldConfigManager_enableV1DynamicConfig, _ShieldConfigManager_logger, _ShieldConfigManager_config, _ShieldConfigManager_refreshTimer, _ShieldConfigManager_isSetup, _ShieldConfigManager_setupPromise, _ShieldConfigManager_doSetup, _ShieldConfigManager_startRefreshTimer;
75
75
  Object.defineProperty(exports, "__esModule", { value: true });
76
76
  exports.ShieldConfigManager = void 0;
77
77
  const serviceV2_1 = require("./serviceV2");
@@ -103,6 +103,7 @@ class ShieldConfigManager {
103
103
  _ShieldConfigManager_refreshIntervalMs.set(this, void 0);
104
104
  _ShieldConfigManager_fetchTimeoutMs.set(this, void 0);
105
105
  _ShieldConfigManager_enableInfoLog.set(this, void 0);
106
+ _ShieldConfigManager_enableV1DynamicConfig.set(this, void 0);
106
107
  _ShieldConfigManager_logger.set(this, void 0);
107
108
  _ShieldConfigManager_config.set(this, null);
108
109
  _ShieldConfigManager_refreshTimer.set(this, null);
@@ -116,6 +117,7 @@ class ShieldConfigManager {
116
117
  __classPrivateFieldSet(this, _ShieldConfigManager_refreshIntervalMs, options.refreshIntervalMs || DEFAULT_REFRESH_INTERVAL_MS, "f");
117
118
  __classPrivateFieldSet(this, _ShieldConfigManager_fetchTimeoutMs, options.fetchTimeoutMs || DEFAULT_FETCH_TIMEOUT_MS, "f");
118
119
  __classPrivateFieldSet(this, _ShieldConfigManager_enableInfoLog, options.enableInfoLog || false, "f");
120
+ __classPrivateFieldSet(this, _ShieldConfigManager_enableV1DynamicConfig, options.enableV1DynamicConfig !== false, "f");
119
121
  const baseLogger = options.logger || defaultLogger;
120
122
  __classPrivateFieldSet(this, _ShieldConfigManager_logger, __classPrivateFieldGet(this, _ShieldConfigManager_enableInfoLog, "f") ? baseLogger : { ...baseLogger, info: () => { } }, "f");
121
123
  }
@@ -165,15 +167,17 @@ class ShieldConfigManager {
165
167
  catch (error) {
166
168
  __classPrivateFieldGet(this, _ShieldConfigManager_logger, "f").error(`ShieldConfigManager refresh error: ${error instanceof Error ? error.message : JSON.stringify(error)}`);
167
169
  }
168
- // 兼容旧的逻辑
169
- try {
170
- const dynamicConfig = await withTimeout(shieldClient.backendConfigService.fetchGlobalDynamicConfig(), __classPrivateFieldGet(this, _ShieldConfigManager_fetchTimeoutMs, "f"));
171
- if (dynamicConfig) {
172
- process.env.authorizationTokenInside = dynamicConfig.tokenKey;
170
+ // 兼容旧的逻辑(V1 全局动态配置),可通过 enableV1DynamicConfig: false 跳过
171
+ if (__classPrivateFieldGet(this, _ShieldConfigManager_enableV1DynamicConfig, "f")) {
172
+ try {
173
+ const dynamicConfig = await withTimeout(shieldClient.backendConfigService.fetchGlobalDynamicConfig(), __classPrivateFieldGet(this, _ShieldConfigManager_fetchTimeoutMs, "f"));
174
+ if (dynamicConfig) {
175
+ process.env.authorizationTokenInside = dynamicConfig.tokenKey;
176
+ }
177
+ }
178
+ catch (error) {
179
+ __classPrivateFieldGet(this, _ShieldConfigManager_logger, "f").error(`fetch dynamic config error: ${error instanceof Error ? error.message : JSON.stringify(error)}`);
173
180
  }
174
- }
175
- catch (error) {
176
- __classPrivateFieldGet(this, _ShieldConfigManager_logger, "f").error(`fetch dynamic config error: ${error instanceof Error ? error.message : JSON.stringify(error)}`);
177
181
  }
178
182
  __classPrivateFieldGet(this, _ShieldConfigManager_logger, "f").info(`ShieldConfigManager config refreshed finally (config: ${JSON.stringify(__classPrivateFieldGet(this, _ShieldConfigManager_config, "f"))})`);
179
183
  }
@@ -281,7 +285,7 @@ class ShieldConfigManager {
281
285
  }
282
286
  }
283
287
  exports.ShieldConfigManager = ShieldConfigManager;
284
- _ShieldConfigManager_serviceName = new WeakMap(), _ShieldConfigManager_env = new WeakMap(), _ShieldConfigManager_refreshIntervalMs = new WeakMap(), _ShieldConfigManager_fetchTimeoutMs = new WeakMap(), _ShieldConfigManager_enableInfoLog = new WeakMap(), _ShieldConfigManager_logger = new WeakMap(), _ShieldConfigManager_config = new WeakMap(), _ShieldConfigManager_refreshTimer = new WeakMap(), _ShieldConfigManager_isSetup = new WeakMap(), _ShieldConfigManager_setupPromise = new WeakMap(), _ShieldConfigManager_instances = new WeakSet(), _ShieldConfigManager_doSetup = async function _ShieldConfigManager_doSetup() {
288
+ _ShieldConfigManager_serviceName = new WeakMap(), _ShieldConfigManager_env = new WeakMap(), _ShieldConfigManager_refreshIntervalMs = new WeakMap(), _ShieldConfigManager_fetchTimeoutMs = new WeakMap(), _ShieldConfigManager_enableInfoLog = new WeakMap(), _ShieldConfigManager_enableV1DynamicConfig = new WeakMap(), _ShieldConfigManager_logger = new WeakMap(), _ShieldConfigManager_config = new WeakMap(), _ShieldConfigManager_refreshTimer = new WeakMap(), _ShieldConfigManager_isSetup = new WeakMap(), _ShieldConfigManager_setupPromise = new WeakMap(), _ShieldConfigManager_instances = new WeakSet(), _ShieldConfigManager_doSetup = async function _ShieldConfigManager_doSetup() {
285
289
  try {
286
290
  await this.refresh();
287
291
  }
@@ -6,6 +6,7 @@ import BaseService from '../BaseService';
6
6
  */
7
7
  export declare class ConfigServiceV2 extends BaseService implements ServiceV2.ConfigController {
8
8
  protected prefixUrl: string;
9
+ private callEncryptedConfig;
9
10
  /**
10
11
  * 获取单个配置
11
12
  * @param req 请求参数
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.backendConfigServiceV2 = exports.ConfigServiceV2 = void 0;
7
7
  const http_1 = require("../../utils/http");
8
8
  const cloudFunctionHttp_1 = require("../../utils/cloudFunctionHttp");
9
+ const encryption_1 = require("../../utils/encryption");
9
10
  const BaseService_1 = __importDefault(require("../BaseService"));
10
11
  /**
11
12
  * V2 配置服务
@@ -16,15 +17,32 @@ class ConfigServiceV2 extends BaseService_1.default {
16
17
  super(...arguments);
17
18
  this.prefixUrl = '/shield/v2/config';
18
19
  }
20
+ async callEncryptedConfig(path, req, fallbackData) {
21
+ const keyId = (0, encryption_1.getKeyId)();
22
+ const enhancedReq = keyId ? { ...req, encryption: { version: 1, keyId } } : req;
23
+ const response = await (0, http_1.callApiFull)(this.getApiUrlV2(path), enhancedReq).catch(() => ({
24
+ success: false,
25
+ data: fallbackData,
26
+ requestId: '',
27
+ message: '',
28
+ errorType: '',
29
+ encryption: undefined,
30
+ }));
31
+ if (response.encryption?.version && typeof response.data === 'string') {
32
+ return (0, encryption_1.decryptPayload)(response.data);
33
+ }
34
+ if ((0, encryption_1.isEncryptionAvailable)()) {
35
+ throw new Error('Encrypted response required but server returned plaintext');
36
+ }
37
+ return response.data;
38
+ }
19
39
  /**
20
40
  * 获取单个配置
21
41
  * @param req 请求参数
22
42
  * @returns 配置数据,如果配置不存在返回 null
23
43
  */
24
44
  fetchConfig(req) {
25
- return (0, http_1.callApi)(this.getApiUrlV2('/fetch'), req, {
26
- skipErrorHandling: true,
27
- }).catch(() => null);
45
+ return this.callEncryptedConfig('/fetch', req, null);
28
46
  }
29
47
  /**
30
48
  * 批量获取配置
@@ -32,7 +50,7 @@ class ConfigServiceV2 extends BaseService_1.default {
32
50
  * @returns 配置数据映射
33
51
  */
34
52
  fetchConfigs(req) {
35
- return (0, http_1.callApi)(this.getApiUrlV2('/fetch-batch'), req).catch(() => ({}));
53
+ return this.callEncryptedConfig('/fetch-batch', req, {});
36
54
  }
37
55
  /**
38
56
  * 云函数单 Key 配置读取
@@ -18,6 +18,10 @@ export declare namespace ServiceV2 {
18
18
  }
19
19
  }
20
20
  namespace Request {
21
+ interface EncryptionRequest {
22
+ version: number;
23
+ keyId: string;
24
+ }
21
25
  /**
22
26
  * 获取单个配置请求参数
23
27
  */
@@ -25,6 +29,7 @@ export declare namespace ServiceV2 {
25
29
  service: string;
26
30
  key: string;
27
31
  env?: string;
32
+ encryption?: EncryptionRequest;
28
33
  }
29
34
  /**
30
35
  * 批量获取配置请求参数
@@ -33,6 +38,7 @@ export declare namespace ServiceV2 {
33
38
  service: string;
34
39
  keys?: string[];
35
40
  env?: string;
41
+ encryption?: EncryptionRequest;
36
42
  }
37
43
  /**
38
44
  * 获取服务列表请求参数
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@be-link/shield-for-tcb-node-sdk",
3
- "version": "1.0.20",
3
+ "version": "1.0.22",
4
4
  "description": "ShieldForTCB Node.js SDK",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -0,0 +1,3 @@
1
+ export declare function isEncryptionAvailable(): boolean;
2
+ export declare function getKeyId(): string | null;
3
+ export declare function decryptPayload(encryptedBase64: string): any;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.isEncryptionAvailable = isEncryptionAvailable;
7
+ exports.getKeyId = getKeyId;
8
+ exports.decryptPayload = decryptPayload;
9
+ const crypto_1 = __importDefault(require("crypto"));
10
+ const ALGORITHM = 'aes-256-gcm';
11
+ const IV_LENGTH = 12;
12
+ const AUTH_TAG_LENGTH = 16;
13
+ function getDecryptionKey() {
14
+ const keyB64 = process.env.SHIELD_ENCRYPTION_KEY;
15
+ if (!keyB64)
16
+ return null;
17
+ return Buffer.from(keyB64, 'base64');
18
+ }
19
+ function isEncryptionAvailable() {
20
+ return !!process.env.SHIELD_ENCRYPTION_KEY;
21
+ }
22
+ function getKeyId() {
23
+ const key = getDecryptionKey();
24
+ if (!key)
25
+ return null;
26
+ return crypto_1.default.createHash('sha256').update(key).digest('hex').slice(0, 8);
27
+ }
28
+ function decryptPayload(encryptedBase64) {
29
+ const key = getDecryptionKey();
30
+ if (!key)
31
+ throw new Error('SHIELD_ENCRYPTION_KEY not configured');
32
+ const data = Buffer.from(encryptedBase64, 'base64');
33
+ const iv = data.subarray(0, IV_LENGTH);
34
+ const authTag = data.subarray(data.length - AUTH_TAG_LENGTH);
35
+ const ciphertext = data.subarray(IV_LENGTH, data.length - AUTH_TAG_LENGTH);
36
+ const decipher = crypto_1.default.createDecipheriv(ALGORITHM, key, iv);
37
+ decipher.setAuthTag(authTag);
38
+ const decrypted = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
39
+ return JSON.parse(decrypted.toString('utf8'));
40
+ }
package/utils/http.d.ts CHANGED
@@ -1,10 +1,22 @@
1
- type CallApiOptions = {
1
+ export type ResponseData = {
2
+ data: any;
3
+ success: boolean;
4
+ requestId: string;
5
+ message: string;
6
+ errorType: string;
7
+ encryption?: {
8
+ version: number;
9
+ keyId: string;
10
+ };
11
+ };
12
+ export type CallApiOptions = {
2
13
  skipErrorHandling?: boolean;
3
14
  };
4
15
  type GetApiOptions = {
5
16
  skipErrorHandling?: boolean;
6
17
  };
7
18
  export declare function callApi<T extends (args: any) => Promise<any>>(url: string, request?: Parameters<T>[0], options?: CallApiOptions): Promise<Awaited<ReturnType<T>>>;
19
+ export declare function callApiFull<TRequest = any>(url: string, request?: TRequest, options?: CallApiOptions): Promise<ResponseData>;
8
20
  /**
9
21
  * GET 请求 API
10
22
  */
package/utils/http.js CHANGED
@@ -37,6 +37,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.callApi = callApi;
40
+ exports.callApiFull = callApiFull;
40
41
  exports.getApi = getApi;
41
42
  const axios_1 = __importDefault(require("axios"));
42
43
  const uuid_1 = require("uuid");
@@ -100,6 +101,32 @@ async function callApi(url, request, options) {
100
101
  throw error;
101
102
  }
102
103
  }
104
+ async function callApiFull(url, request, options) {
105
+ const requestId = (0, uuid_1.v4)();
106
+ try {
107
+ console.info(`准备发起shield-for-tcb请求[${requestId}]: ${url}, 参数: ${JSON.stringify(request)}`);
108
+ const response = await axios_1.default.post(url, request || {}, {
109
+ headers: { 'x-request-id': requestId, 'content-type': 'application/json' },
110
+ });
111
+ return response.data;
112
+ }
113
+ catch (error) {
114
+ if (options && options.skipErrorHandling) {
115
+ throw error;
116
+ }
117
+ const axiosError = error;
118
+ if (axiosError.response) {
119
+ const response = axiosError.response;
120
+ const data = response.data;
121
+ console.error(`shield-for-tcb 异常: ${axiosError.message}, requestId: ${requestId}`);
122
+ console.info('响应信息', data.message);
123
+ console.error('异常堆栈', JSON.stringify(error.stack));
124
+ throw axiosError;
125
+ }
126
+ console.error(`shield-for-tcb 未知异常: ${axiosError.message}`, error.stack);
127
+ throw error;
128
+ }
129
+ }
103
130
  /**
104
131
  * GET 请求 API
105
132
  */