@cloudbase/manager-node 5.6.0 → 5.6.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.
- package/CHANGELOG.md +7 -0
- package/lib/cloudrun/index.js +20 -5
- package/lib/env/index.js +4 -2
- package/lib/function/index.js +8 -4
- package/lib/integration/crypto.js +102 -0
- package/lib/integration/index.js +194 -12
- package/lib/integration/secretKey.js +88 -0
- package/package.json +1 -1
- package/types/cloudrun/index.d.ts +4 -3
- package/types/cloudrun/type.d.ts +59 -0
- package/types/integration/crypto.d.ts +16 -0
- package/types/integration/index.d.ts +48 -8
- package/types/integration/secretKey.d.ts +13 -0
- package/types/integration/types.d.ts +19 -3
- package/types/interfaces/tcb.interface.d.ts +1 -0
package/CHANGELOG.md
CHANGED
package/lib/cloudrun/index.js
CHANGED
|
@@ -250,7 +250,7 @@ class CloudRunService {
|
|
|
250
250
|
*/
|
|
251
251
|
async deploy(params) {
|
|
252
252
|
var _a;
|
|
253
|
-
const { serverName, targetPath = process.cwd(), serverConfig } = params;
|
|
253
|
+
const { serverName, targetPath = process.cwd(), serverConfig, vpcInfo } = params;
|
|
254
254
|
/**
|
|
255
255
|
* 参数校验和默认值设置
|
|
256
256
|
*/
|
|
@@ -335,7 +335,8 @@ class CloudRunService {
|
|
|
335
335
|
return this._upsertFunction(true, {
|
|
336
336
|
name: serverName,
|
|
337
337
|
deployInfo,
|
|
338
|
-
serverConfig: _serverConfig
|
|
338
|
+
serverConfig: _serverConfig,
|
|
339
|
+
vpcInfo
|
|
339
340
|
});
|
|
340
341
|
}
|
|
341
342
|
}
|
|
@@ -398,15 +399,20 @@ class CloudRunService {
|
|
|
398
399
|
}
|
|
399
400
|
}
|
|
400
401
|
_upsertFunction(isNew, data) {
|
|
401
|
-
const { name, deployInfo, serverConfig } = data;
|
|
402
|
+
const { name, deployInfo, serverConfig, vpcInfo } = data;
|
|
402
403
|
const envConfig = this.environment.lazyEnvironmentConfig;
|
|
403
404
|
const Items = parseObjectToDiffConfigItem(serverConfig);
|
|
404
|
-
|
|
405
|
+
const basePayload = {
|
|
405
406
|
EnvId: envConfig.EnvId,
|
|
406
407
|
ServerName: name,
|
|
407
408
|
DeployInfo: deployInfo,
|
|
408
409
|
Items,
|
|
409
|
-
}
|
|
410
|
+
};
|
|
411
|
+
// CreateCloudRunServer 支持传入 VpcInfo(仅创建时有效)
|
|
412
|
+
if (isNew && vpcInfo) {
|
|
413
|
+
basePayload.VpcInfo = vpcInfo;
|
|
414
|
+
}
|
|
415
|
+
return this.tcbrService.request(isNew ? 'CreateCloudRunServer' : 'UpdateCloudRunServer', basePayload);
|
|
410
416
|
}
|
|
411
417
|
}
|
|
412
418
|
exports.CloudRunService = CloudRunService;
|
|
@@ -550,6 +556,15 @@ function parseObjectToDiffConfigItem(data) {
|
|
|
550
556
|
else if (['TimerScale'].includes(k)) {
|
|
551
557
|
Items.push({ Key, TimerScale: v });
|
|
552
558
|
}
|
|
559
|
+
else if (['VpcConf'].includes(k)) {
|
|
560
|
+
Items.push({ Key, VpcConf: v });
|
|
561
|
+
}
|
|
562
|
+
else if (['VolumesConf'].includes(k)) {
|
|
563
|
+
Items.push({ Key, VolumesConf: v });
|
|
564
|
+
}
|
|
565
|
+
else if (['PublicNetConf'].includes(k)) {
|
|
566
|
+
Items.push({ Key, PublicNetConf: v });
|
|
567
|
+
}
|
|
553
568
|
});
|
|
554
569
|
return Items;
|
|
555
570
|
}
|
package/lib/env/index.js
CHANGED
|
@@ -139,7 +139,7 @@ class EnvService {
|
|
|
139
139
|
* @returns {Promise<IEnvInfoRes>}
|
|
140
140
|
*/
|
|
141
141
|
async getEnvInfo() {
|
|
142
|
-
var _a;
|
|
142
|
+
var _a, _b;
|
|
143
143
|
// 使用 DescribeEnvInfo 进行单环境查询
|
|
144
144
|
const params = {
|
|
145
145
|
EnvId: this.envId
|
|
@@ -147,6 +147,7 @@ class EnvService {
|
|
|
147
147
|
const response = await this.describeEnvInfo(params);
|
|
148
148
|
const envBaseInfo = (_a = response === null || response === void 0 ? void 0 : response.EnvInfo) === null || _a === void 0 ? void 0 : _a.EnvBaseInfo;
|
|
149
149
|
// 将 EnvBaseInfo 完整映射到 EnvInfo 类型,避免新增字段被丢弃
|
|
150
|
+
// UserInfo 位于 response.EnvInfo 顶层(非 EnvBaseInfo),单独映射
|
|
150
151
|
const envInfo = {
|
|
151
152
|
EnvId: envBaseInfo.EnvId,
|
|
152
153
|
Alias: envBaseInfo.Alias,
|
|
@@ -176,7 +177,8 @@ class EnvService {
|
|
|
176
177
|
EnvPreferences: envBaseInfo.EnvPreferences,
|
|
177
178
|
Meta: envBaseInfo.Meta,
|
|
178
179
|
PostgreSQL: envBaseInfo.PostgreSQL,
|
|
179
|
-
EnvStatus: envBaseInfo.EnvStatus
|
|
180
|
+
EnvStatus: envBaseInfo.EnvStatus,
|
|
181
|
+
UserInfo: (_b = response === null || response === void 0 ? void 0 : response.EnvInfo) === null || _b === void 0 ? void 0 : _b.UserInfo
|
|
180
182
|
};
|
|
181
183
|
return {
|
|
182
184
|
EnvInfo: envInfo,
|
package/lib/function/index.js
CHANGED
|
@@ -1506,7 +1506,7 @@ class FunctionService {
|
|
|
1506
1506
|
const { func, functionPath, functionRootPath } = options;
|
|
1507
1507
|
const { env, appId } = this.getFunctionConfig();
|
|
1508
1508
|
if (!appId) {
|
|
1509
|
-
throw new error_1.CloudBaseError('无法获取 AppId
|
|
1509
|
+
throw new error_1.CloudBaseError('无法获取 AppId,请确认环境初始化完成或已开通存储服务');
|
|
1510
1510
|
}
|
|
1511
1511
|
const objectPath = `${appId}/${env}/${func.name}.zip`;
|
|
1512
1512
|
// 1. 生成存放函数包的临时 Cos 目录
|
|
@@ -1742,14 +1742,18 @@ class FunctionService {
|
|
|
1742
1742
|
* @memberof FunctionService
|
|
1743
1743
|
*/
|
|
1744
1744
|
getFunctionConfig() {
|
|
1745
|
-
var _a, _b, _c, _d, _e;
|
|
1745
|
+
var _a, _b, _c, _d, _e, _f;
|
|
1746
1746
|
const envConfig = this.environment.lazyEnvironmentConfig;
|
|
1747
1747
|
// Functions 可能为空
|
|
1748
1748
|
const namespace = ((_b = (_a = envConfig.Functions) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.Namespace) || '';
|
|
1749
|
-
// AppId
|
|
1749
|
+
// AppId 优先从 DescribeEnvInfo 的 UserInfo 获取(账号级标识,不依赖存储服务)
|
|
1750
|
+
// 兜底从 Storages[0] 的 AppId 或 Bucket 名提取
|
|
1750
1751
|
// COS Bucket 格式: {BucketName}-{APPID},APPID 为纯数字
|
|
1751
1752
|
const storage = (_c = envConfig.Storages) === null || _c === void 0 ? void 0 : _c[0];
|
|
1752
|
-
const appId = (
|
|
1753
|
+
const appId = ((_d = envConfig.UserInfo) === null || _d === void 0 ? void 0 : _d.AppId)
|
|
1754
|
+
|| (storage === null || storage === void 0 ? void 0 : storage.AppId)
|
|
1755
|
+
|| ((_f = (_e = storage === null || storage === void 0 ? void 0 : storage.Bucket) === null || _e === void 0 ? void 0 : _e.match(/-(\d+)$/)) === null || _f === void 0 ? void 0 : _f[1])
|
|
1756
|
+
|| '';
|
|
1753
1757
|
const { proxy } = this.environment.cloudBaseContext;
|
|
1754
1758
|
return {
|
|
1755
1759
|
proxy,
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.AESCrypto = void 0;
|
|
37
|
+
exports.aesEncryptWithIv = aesEncryptWithIv;
|
|
38
|
+
/**
|
|
39
|
+
* 集成中心 AES 加解密
|
|
40
|
+
*
|
|
41
|
+
* 与 dev-platform 控制台的 AESCrypto(crypto-js)完全对齐,保证密文可互相解出:
|
|
42
|
+
* - 算法:AES-256-CBC
|
|
43
|
+
* - key:32 字节(按 UTF-8 解析)
|
|
44
|
+
* - IV:每次随机 16 字节
|
|
45
|
+
* - padding:PKCS7
|
|
46
|
+
* - 密文格式:base64(IV) + base64(ciphertext)
|
|
47
|
+
* (IV 固定 16 字节 → base64 长度恒为 24,前 24 字符即 IV)
|
|
48
|
+
*
|
|
49
|
+
* 使用 Node 内置 crypto 复刻,无需引入额外依赖。
|
|
50
|
+
*/
|
|
51
|
+
const crypto = __importStar(require("crypto"));
|
|
52
|
+
const ALGORITHM = 'aes-256-cbc';
|
|
53
|
+
const KEY_BYTE_LENGTH = 32;
|
|
54
|
+
const IV_BYTE_LENGTH = 16;
|
|
55
|
+
/** base64(16 字节) 的固定长度 */
|
|
56
|
+
const IV_BASE64_LENGTH = 24;
|
|
57
|
+
function assertKey(key) {
|
|
58
|
+
if (Buffer.byteLength(key, 'utf8') !== KEY_BYTE_LENGTH) {
|
|
59
|
+
throw new Error('AES key 必须是 32 字节长度');
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* 使用指定 IV 加密(供测试与内部使用,保证可重现)
|
|
64
|
+
*/
|
|
65
|
+
function aesEncryptWithIv(plaintext, key, iv) {
|
|
66
|
+
assertKey(key);
|
|
67
|
+
if (iv.length !== IV_BYTE_LENGTH) {
|
|
68
|
+
throw new Error('IV 必须是 16 字节长度');
|
|
69
|
+
}
|
|
70
|
+
const cipher = crypto.createCipheriv(ALGORITHM, Buffer.from(key, 'utf8'), iv);
|
|
71
|
+
const encrypted = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);
|
|
72
|
+
return iv.toString('base64') + encrypted.toString('base64');
|
|
73
|
+
}
|
|
74
|
+
class AESCryptoImpl {
|
|
75
|
+
/**
|
|
76
|
+
* AES-256-CBC 加密,返回 base64(IV)+base64(密文)
|
|
77
|
+
*/
|
|
78
|
+
encrypt(plaintext, key) {
|
|
79
|
+
assertKey(key);
|
|
80
|
+
const iv = crypto.randomBytes(IV_BYTE_LENGTH);
|
|
81
|
+
return aesEncryptWithIv(plaintext, key, iv);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* 解密 base64(IV)+base64(密文) 格式的密文
|
|
85
|
+
*/
|
|
86
|
+
decrypt(encryptedData, key) {
|
|
87
|
+
assertKey(key);
|
|
88
|
+
const ivBase64 = encryptedData.slice(0, IV_BASE64_LENGTH);
|
|
89
|
+
const ciphertextBase64 = encryptedData.slice(IV_BASE64_LENGTH);
|
|
90
|
+
const iv = Buffer.from(ivBase64, 'base64');
|
|
91
|
+
if (iv.length !== IV_BYTE_LENGTH) {
|
|
92
|
+
throw new Error('密文格式错误:IV 长度非法');
|
|
93
|
+
}
|
|
94
|
+
const decipher = crypto.createDecipheriv(ALGORITHM, Buffer.from(key, 'utf8'), iv);
|
|
95
|
+
const decrypted = Buffer.concat([
|
|
96
|
+
decipher.update(Buffer.from(ciphertextBase64, 'base64')),
|
|
97
|
+
decipher.final()
|
|
98
|
+
]);
|
|
99
|
+
return decrypted.toString('utf8');
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
exports.AESCrypto = new AESCryptoImpl();
|
package/lib/integration/index.js
CHANGED
|
@@ -24,15 +24,18 @@ exports.IntegrationService = void 0;
|
|
|
24
24
|
const error_1 = require("../error");
|
|
25
25
|
const utils_1 = require("../utils");
|
|
26
26
|
const constants_1 = require("./constants");
|
|
27
|
+
const crypto_1 = require("./crypto");
|
|
28
|
+
const secretKey_1 = require("./secretKey");
|
|
27
29
|
__exportStar(require("./types"), exports);
|
|
28
30
|
/**
|
|
29
31
|
* 集成中心(UserKey)服务
|
|
30
32
|
*
|
|
31
33
|
* 复用现有 tcb 云 API(version 2018-06-08),统一携带 Business='integration'。
|
|
32
34
|
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
35
|
+
* 提供两种使用模式:
|
|
36
|
+
* 1. 透传模式:直接传 `ext`(JSON 字符串),SDK 原样传递给云 API(向后兼容)
|
|
37
|
+
* 2. 自动加解密模式:传 `envVariables`(明文键值对),SDK 自动识别模板中的
|
|
38
|
+
* password 字段、拉取七彩石密钥完成加密后拼装 ext
|
|
36
39
|
*/
|
|
37
40
|
class IntegrationService {
|
|
38
41
|
constructor(environment) {
|
|
@@ -66,36 +69,50 @@ class IntegrationService {
|
|
|
66
69
|
Business: (_c = params.business) !== null && _c !== void 0 ? _c : constants_1.USER_KEY_BUSINESS // 默认 integration
|
|
67
70
|
});
|
|
68
71
|
}
|
|
69
|
-
/**
|
|
72
|
+
/**
|
|
73
|
+
* 查询单个集成实例详情。
|
|
74
|
+
*
|
|
75
|
+
* 当 `decryptPwd=true` 时,SDK 自动拉取模板识别 password 字段并从七彩石
|
|
76
|
+
* 获取 AES 密钥解密,Ext 中 password 字段返回明文。解密失败时保留密文原值,
|
|
77
|
+
* 不中断流程。
|
|
78
|
+
*/
|
|
70
79
|
async getUserKey(params) {
|
|
71
|
-
var _a, _b;
|
|
80
|
+
var _a, _b, _c;
|
|
72
81
|
this.validateRequiredParams(params, ['keyId']);
|
|
73
82
|
const { envId } = this.getEnvInfo();
|
|
74
|
-
|
|
83
|
+
const result = await this.tcbService.request('GetOneUserKey', {
|
|
75
84
|
EnvId: envId,
|
|
76
85
|
KeyID: params.keyId,
|
|
77
86
|
NeedPwd: (_a = params.needPwd) !== null && _a !== void 0 ? _a : false,
|
|
78
87
|
Business: (_b = params.business) !== null && _b !== void 0 ? _b : constants_1.USER_KEY_BUSINESS // 默认 integration
|
|
79
88
|
});
|
|
89
|
+
// 自动解密 password 字段
|
|
90
|
+
if (params.decryptPwd && ((_c = result.UserKeyInfo) === null || _c === void 0 ? void 0 : _c.Ext)) {
|
|
91
|
+
result.UserKeyInfo = await this.decryptExtIfNeeded(result.UserKeyInfo, envId);
|
|
92
|
+
}
|
|
93
|
+
return result;
|
|
80
94
|
}
|
|
81
95
|
// =========== 写 API ===========
|
|
82
96
|
/**
|
|
83
97
|
* 创建集成实例。
|
|
84
98
|
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
99
|
+
* 支持两种传参方式:
|
|
100
|
+
* - 传 `ext`:透传模式,原样传递给云 API(向后兼容,调用方自行加密)
|
|
101
|
+
* - 传 `envVariables`:自动加密模式,SDK 识别模板 password 字段并加密后拼装 ext
|
|
102
|
+
* - 两者都传时以 `ext` 优先
|
|
87
103
|
*/
|
|
88
104
|
async createUserKey(params) {
|
|
89
105
|
var _a;
|
|
90
106
|
this.validateRequiredParams(params, ['name', 'authTypeCode']);
|
|
91
107
|
const { envId } = this.getEnvInfo();
|
|
108
|
+
const ext = await this.buildExtFromParams(envId, params.authTypeCode, { ext: params.ext, envVariables: params.envVariables });
|
|
92
109
|
return this.tcbService.request('CreateUserKey', {
|
|
93
110
|
EnvId: envId,
|
|
94
111
|
Name: params.name,
|
|
95
112
|
KeyID: params.keyId,
|
|
96
113
|
AuthTypeCode: params.authTypeCode,
|
|
97
114
|
Description: params.description,
|
|
98
|
-
Ext:
|
|
115
|
+
Ext: ext,
|
|
99
116
|
TicketID: params.ticketId,
|
|
100
117
|
Business: (_a = params.business) !== null && _a !== void 0 ? _a : constants_1.USER_KEY_BUSINESS, // 默认 integration
|
|
101
118
|
DemoCodeFunctionName: params.demoCodeFunctionName,
|
|
@@ -105,20 +122,28 @@ class IntegrationService {
|
|
|
105
122
|
/**
|
|
106
123
|
* 更新集成实例。
|
|
107
124
|
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
125
|
+
* 支持两种传参方式:
|
|
126
|
+
* - 传 `ext`:透传模式,原样传递给云 API(向后兼容)
|
|
127
|
+
* - 传 `envVariables`:自动加密模式,与现有 Ext 合并后加密写入
|
|
128
|
+
* - 两者都传时以 `ext` 优先
|
|
129
|
+
* - 都未传时后端保留原有 Ext 不变
|
|
110
130
|
*/
|
|
111
131
|
async updateUserKey(params) {
|
|
112
132
|
var _a;
|
|
113
133
|
this.validateRequiredParams(params, ['keyId']);
|
|
114
134
|
const { envId } = this.getEnvInfo();
|
|
135
|
+
let ext = params.ext;
|
|
136
|
+
// 传了 envVariables 且未传 ext:需要合并现有 Ext 后加密
|
|
137
|
+
if (params.envVariables && !params.ext) {
|
|
138
|
+
ext = await this.buildMergedExtForUpdate(envId, params.keyId, { authTypeCode: params.authTypeCode, envVariables: params.envVariables });
|
|
139
|
+
}
|
|
115
140
|
return this.tcbService.request('UpdateUserKey', {
|
|
116
141
|
EnvId: envId,
|
|
117
142
|
KeyID: params.keyId,
|
|
118
143
|
Name: params.name,
|
|
119
144
|
AuthTypeCode: params.authTypeCode,
|
|
120
145
|
Description: params.description,
|
|
121
|
-
Ext:
|
|
146
|
+
Ext: ext,
|
|
122
147
|
DemoCodeFunctionName: params.demoCodeFunctionName,
|
|
123
148
|
Business: (_a = params.business) !== null && _a !== void 0 ? _a : constants_1.USER_KEY_BUSINESS, // 默认 integration
|
|
124
149
|
RuntimeConfig: params.runtimeConfig
|
|
@@ -149,6 +174,163 @@ class IntegrationService {
|
|
|
149
174
|
}
|
|
150
175
|
}
|
|
151
176
|
}
|
|
177
|
+
/**
|
|
178
|
+
* 根据 ext / envVariables 参数构造最终的 Ext JSON 字符串。
|
|
179
|
+
* ext 优先;envVariables 由 SDK 自动加密 password 字段。
|
|
180
|
+
*/
|
|
181
|
+
async buildExtFromParams(envId, authTypeCode, opts) {
|
|
182
|
+
// ext 优先(透传模式)
|
|
183
|
+
if (opts.ext !== undefined) {
|
|
184
|
+
return opts.ext;
|
|
185
|
+
}
|
|
186
|
+
// 自动加密模式
|
|
187
|
+
if (opts.envVariables && Object.keys(opts.envVariables).length > 0) {
|
|
188
|
+
return this.encryptAndStringify(envId, authTypeCode, opts.envVariables);
|
|
189
|
+
}
|
|
190
|
+
return undefined;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* 更新场景:将 envVariables 与现有实例的 Ext 合并后加密。
|
|
194
|
+
* 需要先查询现有实例获取当前的 authTypeCode 和 Ext。
|
|
195
|
+
*/
|
|
196
|
+
async buildMergedExtForUpdate(envId, keyId, opts) {
|
|
197
|
+
var _a, _b;
|
|
198
|
+
const { envVariables, authTypeCode } = opts;
|
|
199
|
+
if (!envVariables || Object.keys(envVariables).length === 0) {
|
|
200
|
+
return undefined;
|
|
201
|
+
}
|
|
202
|
+
// 查询现有实例以合并 Ext
|
|
203
|
+
let existingExtObj = {};
|
|
204
|
+
let resolvedAuthTypeCode = authTypeCode;
|
|
205
|
+
try {
|
|
206
|
+
const existing = await this.getUserKey({
|
|
207
|
+
keyId,
|
|
208
|
+
needPwd: true,
|
|
209
|
+
decryptPwd: true, // 解密后方便合并
|
|
210
|
+
business: constants_1.USER_KEY_BUSINESS
|
|
211
|
+
});
|
|
212
|
+
const extObj = this.parseExt((_a = existing.UserKeyInfo) === null || _a === void 0 ? void 0 : _a.Ext);
|
|
213
|
+
existingExtObj = Object.assign({}, extObj);
|
|
214
|
+
resolvedAuthTypeCode = resolvedAuthTypeCode || ((_b = existing.UserKeyInfo) === null || _b === void 0 ? void 0 : _b.AuthTypeCode);
|
|
215
|
+
}
|
|
216
|
+
catch (_c) {
|
|
217
|
+
// 查询失败时仅使用传入的 envVariables
|
|
218
|
+
}
|
|
219
|
+
if (!resolvedAuthTypeCode) {
|
|
220
|
+
// 无法获取 authTypeCode,无法识别 password 字段,直接 JSON 序列化
|
|
221
|
+
return JSON.stringify(Object.assign(Object.assign({}, existingExtObj), envVariables));
|
|
222
|
+
}
|
|
223
|
+
// 合并:现有 Ext 为基础,envVariables 覆盖
|
|
224
|
+
const merged = Object.assign(Object.assign({}, existingExtObj), envVariables);
|
|
225
|
+
return this.encryptAndStringify(envId, resolvedAuthTypeCode, merged);
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* 加密 envVariables 中的 password 字段并返回 JSON 字符串。
|
|
229
|
+
* 无 password 字段时直接 JSON.stringify,不请求七彩石。
|
|
230
|
+
*/
|
|
231
|
+
async encryptAndStringify(envId, authTypeCode, envVariables) {
|
|
232
|
+
// 1. 拉取模板,识别 password 字段
|
|
233
|
+
const passwordFieldNames = await this.getPasswordFieldNames(authTypeCode);
|
|
234
|
+
// 2. 判断是否有 password 字段需要加密
|
|
235
|
+
const hasPasswordValue = passwordFieldNames.some(name => envVariables[name]);
|
|
236
|
+
if (!hasPasswordValue) {
|
|
237
|
+
return JSON.stringify(envVariables);
|
|
238
|
+
}
|
|
239
|
+
// 3. 拉取 AES key 并加密
|
|
240
|
+
try {
|
|
241
|
+
const aesKey = await (0, secretKey_1.getAesKey)({ envId });
|
|
242
|
+
const encrypted = this.encryptPasswordFields(envVariables, passwordFieldNames, aesKey);
|
|
243
|
+
return JSON.stringify(encrypted);
|
|
244
|
+
}
|
|
245
|
+
catch (_a) {
|
|
246
|
+
// 获取密钥失败时以明文写入(与 CLI 行为一致)
|
|
247
|
+
return JSON.stringify(envVariables);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* 解密 Ext 中的 password 字段并返回新的 IUserKeyInfo。
|
|
252
|
+
* 解密失败时保留原值,不中断流程。
|
|
253
|
+
*/
|
|
254
|
+
async decryptExtIfNeeded(userKeyInfo, envId) {
|
|
255
|
+
if (!userKeyInfo.Ext || !userKeyInfo.AuthTypeCode)
|
|
256
|
+
return userKeyInfo;
|
|
257
|
+
try {
|
|
258
|
+
const passwordFieldNames = await this.getPasswordFieldNames(userKeyInfo.AuthTypeCode);
|
|
259
|
+
if (passwordFieldNames.length === 0)
|
|
260
|
+
return userKeyInfo;
|
|
261
|
+
const extObj = this.parseExt(userKeyInfo.Ext);
|
|
262
|
+
if (!Object.keys(extObj).length)
|
|
263
|
+
return userKeyInfo;
|
|
264
|
+
const hasPasswordValue = passwordFieldNames.some(name => extObj[name]);
|
|
265
|
+
if (!hasPasswordValue)
|
|
266
|
+
return userKeyInfo;
|
|
267
|
+
const aesKey = await (0, secretKey_1.getAesKey)({ envId });
|
|
268
|
+
const decrypted = this.decryptPasswordFields(extObj, passwordFieldNames, aesKey);
|
|
269
|
+
return Object.assign(Object.assign({}, userKeyInfo), { Ext: JSON.stringify(decrypted) });
|
|
270
|
+
}
|
|
271
|
+
catch (_a) {
|
|
272
|
+
return userKeyInfo;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
/** 从模板中获取 password 类型字段名列表 */
|
|
276
|
+
async getPasswordFieldNames(authTypeCode) {
|
|
277
|
+
var _a, _b;
|
|
278
|
+
try {
|
|
279
|
+
const res = await this.listTemplates({ authTypeCode, limit: 1 });
|
|
280
|
+
const templateExt = (_b = (_a = res.KeyTemplateList) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.Ext;
|
|
281
|
+
if (!templateExt)
|
|
282
|
+
return [];
|
|
283
|
+
const parsed = JSON.parse(templateExt);
|
|
284
|
+
const fields = Array.isArray(parsed === null || parsed === void 0 ? void 0 : parsed.fields) ? parsed.fields : [];
|
|
285
|
+
return fields
|
|
286
|
+
.filter((f) => f && f.type === 'password' && typeof f.name === 'string')
|
|
287
|
+
.map((f) => f.name);
|
|
288
|
+
}
|
|
289
|
+
catch (_c) {
|
|
290
|
+
return [];
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
/** 解析 Ext JSON 字符串为对象,失败返回空对象 */
|
|
294
|
+
parseExt(ext) {
|
|
295
|
+
if (!ext)
|
|
296
|
+
return {};
|
|
297
|
+
try {
|
|
298
|
+
const parsed = JSON.parse(ext);
|
|
299
|
+
return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : {};
|
|
300
|
+
}
|
|
301
|
+
catch (_a) {
|
|
302
|
+
return {};
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
/** 加密 ext 对象中的 password 字段(仅加密有值的字段),返回新对象 */
|
|
306
|
+
encryptPasswordFields(extObj, passwordFieldNames, aesKey) {
|
|
307
|
+
const result = Object.assign({}, extObj);
|
|
308
|
+
passwordFieldNames.forEach(name => {
|
|
309
|
+
const value = result[name];
|
|
310
|
+
if (name && value) {
|
|
311
|
+
result[name] = crypto_1.AESCrypto.encrypt(value, aesKey);
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
return result;
|
|
315
|
+
}
|
|
316
|
+
/** 解密 ext 对象中的 password 字段,解密失败保留原值,返回新对象 */
|
|
317
|
+
decryptPasswordFields(extObj, passwordFieldNames, aesKey) {
|
|
318
|
+
const result = Object.assign({}, extObj);
|
|
319
|
+
const MIN_CIPHERTEXT_LEN = 24; // base64(16 字节 IV) = 24 字符
|
|
320
|
+
passwordFieldNames.forEach(name => {
|
|
321
|
+
const encrypted = result[name];
|
|
322
|
+
if (typeof encrypted !== 'string' || encrypted.length <= MIN_CIPHERTEXT_LEN) {
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
try {
|
|
326
|
+
result[name] = crypto_1.AESCrypto.decrypt(encrypted, aesKey);
|
|
327
|
+
}
|
|
328
|
+
catch (_a) {
|
|
329
|
+
// 解密失败保留原值,不中断流程
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
return result;
|
|
333
|
+
}
|
|
152
334
|
}
|
|
153
335
|
exports.IntegrationService = IntegrationService;
|
|
154
336
|
__decorate([
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getAesKey = getAesKey;
|
|
4
|
+
exports.__clearAesKeyCache = __clearAesKeyCache;
|
|
5
|
+
/**
|
|
6
|
+
* 集成中心 AES key 获取(七彩石)
|
|
7
|
+
*
|
|
8
|
+
* 通过 QueryRainbowConfig 拉取 group=tcb-config(国内)/
|
|
9
|
+
* frontend.tcb-config(国际)下字段 dev-platform-apis 的值作为 AES-256-CBC 密钥。
|
|
10
|
+
*
|
|
11
|
+
* 安全约束:
|
|
12
|
+
* - key 仅在进程内存使用,按 group 维度缓存;
|
|
13
|
+
* - 绝不写入任何本地文件、绝不打印日志。
|
|
14
|
+
*/
|
|
15
|
+
const http_request_1 = require("../utils/http-request");
|
|
16
|
+
const error_1 = require("../error");
|
|
17
|
+
/** 七彩石配置 */
|
|
18
|
+
const RAINBOW_CONFIG = {
|
|
19
|
+
ENV_TYPE: 'Default',
|
|
20
|
+
GROUP_CN: 'tcb-config',
|
|
21
|
+
GROUP_INTL: 'frontend.tcb-config',
|
|
22
|
+
/** AES key 在 kvs 中的字段名 */
|
|
23
|
+
CRYPTO_KEY_FIELD: 'dev-platform-apis'
|
|
24
|
+
};
|
|
25
|
+
const RAINBOW_HOST_CN = 'wedaapi.tcbautomation.cn';
|
|
26
|
+
const RAINBOW_HOST_INTL = 'gray.decisiontcb.tencentcloud.com';
|
|
27
|
+
/** 无 EnvId 时的占位 Uin */
|
|
28
|
+
const FALLBACK_UIN = '3309033';
|
|
29
|
+
/** 进程内缓存(按 group 维度),key 不落盘、不打印 */
|
|
30
|
+
const keyCache = {};
|
|
31
|
+
/**
|
|
32
|
+
* 获取集成中心 AES key(进程内缓存)
|
|
33
|
+
* @throws CloudBaseError 拉取或解析失败
|
|
34
|
+
*/
|
|
35
|
+
async function getAesKey(params = {}) {
|
|
36
|
+
var _a, _b;
|
|
37
|
+
const { envId, isIntl = false } = params;
|
|
38
|
+
const group = isIntl ? RAINBOW_CONFIG.GROUP_INTL : RAINBOW_CONFIG.GROUP_CN;
|
|
39
|
+
if (keyCache[group]) {
|
|
40
|
+
return keyCache[group];
|
|
41
|
+
}
|
|
42
|
+
const host = isIntl ? RAINBOW_HOST_INTL : RAINBOW_HOST_CN;
|
|
43
|
+
const url = `https://${host}/Graydecision/V1/QueryRainbowConfig?group=${group}`;
|
|
44
|
+
const payload = {
|
|
45
|
+
EnvType: RAINBOW_CONFIG.ENV_TYPE,
|
|
46
|
+
Group: group
|
|
47
|
+
};
|
|
48
|
+
if (envId) {
|
|
49
|
+
payload.EnvId = envId;
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
payload.Uin = FALLBACK_UIN;
|
|
53
|
+
}
|
|
54
|
+
let resJson;
|
|
55
|
+
try {
|
|
56
|
+
resJson = await (0, http_request_1.fetch)(url, {
|
|
57
|
+
method: 'POST',
|
|
58
|
+
headers: { 'content-type': 'application/json' },
|
|
59
|
+
body: JSON.stringify(payload)
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
catch (e) {
|
|
63
|
+
throw new error_1.CloudBaseError('获取集成加解密密钥失败:七彩石配置拉取请求异常');
|
|
64
|
+
}
|
|
65
|
+
const data = (_a = resJson === null || resJson === void 0 ? void 0 : resJson.Response) === null || _a === void 0 ? void 0 : _a.Data;
|
|
66
|
+
if (!data || data.ErrorCode !== '0') {
|
|
67
|
+
throw new error_1.CloudBaseError(`获取集成加解密密钥失败:七彩石返回异常(ErrorCode=${data === null || data === void 0 ? void 0 : data.ErrorCode})`);
|
|
68
|
+
}
|
|
69
|
+
let config;
|
|
70
|
+
try {
|
|
71
|
+
config = JSON.parse(data.ConfigValue)[0];
|
|
72
|
+
}
|
|
73
|
+
catch (e) {
|
|
74
|
+
throw new error_1.CloudBaseError('获取集成加解密密钥失败:七彩石配置内容解析失败');
|
|
75
|
+
}
|
|
76
|
+
const kvs = ((_b = config === null || config === void 0 ? void 0 : config.kvs) === null || _b === void 0 ? void 0 : _b.kvs) || [];
|
|
77
|
+
const target = kvs.find(kv => kv.key === RAINBOW_CONFIG.CRYPTO_KEY_FIELD);
|
|
78
|
+
const key = target === null || target === void 0 ? void 0 : target.value;
|
|
79
|
+
if (!key) {
|
|
80
|
+
throw new error_1.CloudBaseError(`获取集成加解密密钥失败:七彩石配置中缺少 ${RAINBOW_CONFIG.CRYPTO_KEY_FIELD} 字段`);
|
|
81
|
+
}
|
|
82
|
+
keyCache[group] = key;
|
|
83
|
+
return key;
|
|
84
|
+
}
|
|
85
|
+
/** 清空进程内缓存(仅供测试使用) */
|
|
86
|
+
function __clearAesKeyCache() {
|
|
87
|
+
Object.keys(keyCache).forEach(k => delete keyCache[k]);
|
|
88
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Environment } from '../environment';
|
|
2
2
|
import { IResponseInfo } from '../interfaces';
|
|
3
|
-
import { CloudrunServerType, ICloudrunDetailResponse, ICloudrunListResponse, ICloudrunServerBaseConfig,
|
|
3
|
+
import { CloudrunServerType, ICloudrunDetailResponse, ICloudrunListResponse, ICloudrunServerBaseConfig, ICreateVpcInfo, IBuildLogResponse, IProcessLogResponse, IDiffConfigItem, ITemplate, ReleaseTypeEnum, IDescribeCloudRunDeployRecordResponse } from './type';
|
|
4
4
|
/**
|
|
5
5
|
* 云托管服务管理类
|
|
6
6
|
* 提供云托管服务的初始化、下载、列表查询和删除等功能
|
|
@@ -128,7 +128,8 @@ export declare class CloudRunService {
|
|
|
128
128
|
deployInfo: {
|
|
129
129
|
ReleaseType: ReleaseTypeEnum;
|
|
130
130
|
};
|
|
131
|
-
|
|
131
|
+
vpcInfo?: ICreateVpcInfo;
|
|
132
|
+
serverConfig?: Partial<Pick<ICloudrunServerBaseConfig, 'OpenAccessTypes' | 'Cpu' | 'Mem' | 'MinNum' | 'MaxNum' | 'PolicyDetails' | 'CustomLogs' | 'EnvParams' | 'Port' | 'Dockerfile' | 'BuildDir' | 'InternalAccess' | 'InternalDomain' | 'EntryPoint' | 'Cmd' | 'InstallDependency' | 'OperationMode' | 'SessionAffinity' | 'LogType' | 'LogSetId' | 'LogTopicId' | 'LogParseType' | 'Tag' | 'TimerScale' | 'VpcConf' | 'VolumesConf' | 'PublicNetConf'>>;
|
|
132
133
|
}): Promise<IResponseInfo>;
|
|
133
134
|
/**
|
|
134
135
|
* 获取云托管服务模板列表
|
|
@@ -157,4 +158,4 @@ export declare function codeToZip(cwd: string, options?: {
|
|
|
157
158
|
/**
|
|
158
159
|
* 将 object 参数转为 [{key:"Port", IntValue:80}] 的格式,并且剔除空字符串
|
|
159
160
|
*/
|
|
160
|
-
export declare function parseObjectToDiffConfigItem(data: Partial<
|
|
161
|
+
export declare function parseObjectToDiffConfigItem(data: Partial<ICloudrunServerBaseConfig>): IDiffConfigItem[];
|
package/types/cloudrun/type.d.ts
CHANGED
|
@@ -261,6 +261,22 @@ export interface ICloudrunServerBaseConfig {
|
|
|
261
261
|
* 是否在线安装依赖,true 则本地不打包 node_modules,依赖在线装(如Docker)
|
|
262
262
|
*/
|
|
263
263
|
InstallDependency?: boolean;
|
|
264
|
+
/**
|
|
265
|
+
* 会话亲和性 open | close
|
|
266
|
+
*/
|
|
267
|
+
SessionAffinity?: string;
|
|
268
|
+
/**
|
|
269
|
+
* VPC 网络配置
|
|
270
|
+
*/
|
|
271
|
+
VpcConf?: IVpcConf;
|
|
272
|
+
/**
|
|
273
|
+
* 存储挂载配置(COS / CFS)
|
|
274
|
+
*/
|
|
275
|
+
VolumesConf?: IVolumeConf[];
|
|
276
|
+
/**
|
|
277
|
+
* 公网访问配置
|
|
278
|
+
*/
|
|
279
|
+
PublicNetConf?: IPublicNetConf;
|
|
264
280
|
}
|
|
265
281
|
export interface IDiffConfigItem {
|
|
266
282
|
Key: string;
|
|
@@ -271,6 +287,9 @@ export interface IDiffConfigItem {
|
|
|
271
287
|
ArrayValue?: string[];
|
|
272
288
|
PolicyDetails?: ICloudrunHpaPolicy[];
|
|
273
289
|
TimerScale?: ICloudrunTimerScale[];
|
|
290
|
+
VpcConf?: IVpcConf;
|
|
291
|
+
VolumesConf?: IVolumeConf[];
|
|
292
|
+
PublicNetConf?: IPublicNetConf;
|
|
274
293
|
}
|
|
275
294
|
/**
|
|
276
295
|
* 在线版本信息
|
|
@@ -471,3 +490,43 @@ export interface IProcessLogResponse {
|
|
|
471
490
|
/** 请求ID */
|
|
472
491
|
RequestId: string;
|
|
473
492
|
}
|
|
493
|
+
/**
|
|
494
|
+
* VPC 网络配置
|
|
495
|
+
*/
|
|
496
|
+
export interface IVpcConf {
|
|
497
|
+
VpcId?: string;
|
|
498
|
+
VpcCIDR?: string;
|
|
499
|
+
SubnetId?: string;
|
|
500
|
+
SubnetCIDR?: string;
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* 存储挂载配置(COS / CFS)
|
|
504
|
+
*/
|
|
505
|
+
export interface IVolumeConf {
|
|
506
|
+
Type?: string;
|
|
507
|
+
BucketName?: string;
|
|
508
|
+
Endpoint?: string;
|
|
509
|
+
KeyID?: string;
|
|
510
|
+
DstPath?: string;
|
|
511
|
+
SrcPath?: string;
|
|
512
|
+
MountIP?: string;
|
|
513
|
+
ReadOnly?: boolean;
|
|
514
|
+
InstanceId?: string;
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* 公网访问配置
|
|
518
|
+
*/
|
|
519
|
+
export interface IPublicNetConf {
|
|
520
|
+
PublicNetStatus?: string;
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* CreateCloudRunServer VPC 信息(仅创建时使用)
|
|
524
|
+
*/
|
|
525
|
+
export interface ICreateVpcInfo {
|
|
526
|
+
/** vpc id,必填 */
|
|
527
|
+
VpcId: string;
|
|
528
|
+
/** 创建类型:1=新建, 2=指定,必填 */
|
|
529
|
+
CreateType: 1 | 2;
|
|
530
|
+
/** 子网ID列表 */
|
|
531
|
+
SubnetIds?: string[];
|
|
532
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 使用指定 IV 加密(供测试与内部使用,保证可重现)
|
|
3
|
+
*/
|
|
4
|
+
export declare function aesEncryptWithIv(plaintext: string, key: string, iv: Buffer): string;
|
|
5
|
+
declare class AESCryptoImpl {
|
|
6
|
+
/**
|
|
7
|
+
* AES-256-CBC 加密,返回 base64(IV)+base64(密文)
|
|
8
|
+
*/
|
|
9
|
+
encrypt(plaintext: string, key: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* 解密 base64(IV)+base64(密文) 格式的密文
|
|
12
|
+
*/
|
|
13
|
+
decrypt(encryptedData: string, key: string): string;
|
|
14
|
+
}
|
|
15
|
+
export declare const AESCrypto: AESCryptoImpl;
|
|
16
|
+
export {};
|
|
@@ -6,9 +6,10 @@ export * from './types';
|
|
|
6
6
|
*
|
|
7
7
|
* 复用现有 tcb 云 API(version 2018-06-08),统一携带 Business='integration'。
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* 提供两种使用模式:
|
|
10
|
+
* 1. 透传模式:直接传 `ext`(JSON 字符串),SDK 原样传递给云 API(向后兼容)
|
|
11
|
+
* 2. 自动加解密模式:传 `envVariables`(明文键值对),SDK 自动识别模板中的
|
|
12
|
+
* password 字段、拉取七彩石密钥完成加密后拼装 ext
|
|
12
13
|
*/
|
|
13
14
|
export declare class IntegrationService {
|
|
14
15
|
private tcbService;
|
|
@@ -18,20 +19,31 @@ export declare class IntegrationService {
|
|
|
18
19
|
listTemplates(params?: IListTemplatesParams): Promise<IGetUserKeyTemplateListResult>;
|
|
19
20
|
/** 列出集成实例(密钥对列表) */
|
|
20
21
|
listUserKeys(params?: IListUserKeysParams): Promise<IGetUserKeyListResult>;
|
|
21
|
-
/**
|
|
22
|
+
/**
|
|
23
|
+
* 查询单个集成实例详情。
|
|
24
|
+
*
|
|
25
|
+
* 当 `decryptPwd=true` 时,SDK 自动拉取模板识别 password 字段并从七彩石
|
|
26
|
+
* 获取 AES 密钥解密,Ext 中 password 字段返回明文。解密失败时保留密文原值,
|
|
27
|
+
* 不中断流程。
|
|
28
|
+
*/
|
|
22
29
|
getUserKey(params: IGetUserKeyParams): Promise<IGetOneUserKeyResult>;
|
|
23
30
|
/**
|
|
24
31
|
* 创建集成实例。
|
|
25
32
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
33
|
+
* 支持两种传参方式:
|
|
34
|
+
* - 传 `ext`:透传模式,原样传递给云 API(向后兼容,调用方自行加密)
|
|
35
|
+
* - 传 `envVariables`:自动加密模式,SDK 识别模板 password 字段并加密后拼装 ext
|
|
36
|
+
* - 两者都传时以 `ext` 优先
|
|
28
37
|
*/
|
|
29
38
|
createUserKey(params: ICreateUserKeyParams): Promise<ICreateUserKeyResult>;
|
|
30
39
|
/**
|
|
31
40
|
* 更新集成实例。
|
|
32
41
|
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
42
|
+
* 支持两种传参方式:
|
|
43
|
+
* - 传 `ext`:透传模式,原样传递给云 API(向后兼容)
|
|
44
|
+
* - 传 `envVariables`:自动加密模式,与现有 Ext 合并后加密写入
|
|
45
|
+
* - 两者都传时以 `ext` 优先
|
|
46
|
+
* - 都未传时后端保留原有 Ext 不变
|
|
35
47
|
*/
|
|
36
48
|
updateUserKey(params: IUpdateUserKeyParams): Promise<IUpdateUserKeyResult>;
|
|
37
49
|
/** 删除集成实例 */
|
|
@@ -40,4 +52,32 @@ export declare class IntegrationService {
|
|
|
40
52
|
private getEnvInfo;
|
|
41
53
|
/** 校验必填参数 */
|
|
42
54
|
private validateRequiredParams;
|
|
55
|
+
/**
|
|
56
|
+
* 根据 ext / envVariables 参数构造最终的 Ext JSON 字符串。
|
|
57
|
+
* ext 优先;envVariables 由 SDK 自动加密 password 字段。
|
|
58
|
+
*/
|
|
59
|
+
private buildExtFromParams;
|
|
60
|
+
/**
|
|
61
|
+
* 更新场景:将 envVariables 与现有实例的 Ext 合并后加密。
|
|
62
|
+
* 需要先查询现有实例获取当前的 authTypeCode 和 Ext。
|
|
63
|
+
*/
|
|
64
|
+
private buildMergedExtForUpdate;
|
|
65
|
+
/**
|
|
66
|
+
* 加密 envVariables 中的 password 字段并返回 JSON 字符串。
|
|
67
|
+
* 无 password 字段时直接 JSON.stringify,不请求七彩石。
|
|
68
|
+
*/
|
|
69
|
+
private encryptAndStringify;
|
|
70
|
+
/**
|
|
71
|
+
* 解密 Ext 中的 password 字段并返回新的 IUserKeyInfo。
|
|
72
|
+
* 解密失败时保留原值,不中断流程。
|
|
73
|
+
*/
|
|
74
|
+
private decryptExtIfNeeded;
|
|
75
|
+
/** 从模板中获取 password 类型字段名列表 */
|
|
76
|
+
private getPasswordFieldNames;
|
|
77
|
+
/** 解析 Ext JSON 字符串为对象,失败返回空对象 */
|
|
78
|
+
private parseExt;
|
|
79
|
+
/** 加密 ext 对象中的 password 字段(仅加密有值的字段),返回新对象 */
|
|
80
|
+
private encryptPasswordFields;
|
|
81
|
+
/** 解密 ext 对象中的 password 字段,解密失败保留原值,返回新对象 */
|
|
82
|
+
private decryptPasswordFields;
|
|
43
83
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface IGetAesKeyParams {
|
|
2
|
+
/** 环境 Id(用于灰度命中,无则用占位 Uin) */
|
|
3
|
+
envId?: string;
|
|
4
|
+
/** 是否国际站 */
|
|
5
|
+
isIntl?: boolean;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* 获取集成中心 AES key(进程内缓存)
|
|
9
|
+
* @throws CloudBaseError 拉取或解析失败
|
|
10
|
+
*/
|
|
11
|
+
export declare function getAesKey(params?: IGetAesKeyParams): Promise<string>;
|
|
12
|
+
/** 清空进程内缓存(仅供测试使用) */
|
|
13
|
+
export declare function __clearAesKeyCache(): void;
|
|
@@ -111,8 +111,10 @@ export interface IListUserKeysParams {
|
|
|
111
111
|
/** 查询集成实例详情入参 */
|
|
112
112
|
export interface IGetUserKeyParams {
|
|
113
113
|
keyId: string;
|
|
114
|
-
/** 为 true
|
|
114
|
+
/** 为 true 时返回加密字段的密文值(原始密文)/ 解密后的明文值(当 decryptPwd=true 时) */
|
|
115
115
|
needPwd?: boolean;
|
|
116
|
+
/** 为 true 时 SDK 自动解密 Ext 中的 password 字段,返回明文(需同时传 needPwd=true) */
|
|
117
|
+
decryptPwd?: boolean;
|
|
116
118
|
/** 业务类型,integration:从集成中心来的,默认为空,表示是从授权管理中心来的 */
|
|
117
119
|
business?: string;
|
|
118
120
|
}
|
|
@@ -123,9 +125,17 @@ export interface ICreateUserKeyParams {
|
|
|
123
125
|
description?: string;
|
|
124
126
|
/**
|
|
125
127
|
* Ext JSON 字符串(模板动态字段的最终取值,含敏感字段密文)。
|
|
126
|
-
*
|
|
128
|
+
* 与 envVariables 二选一:传入 ext 时直接透传;传入 envVariables 时
|
|
129
|
+
* SDK 自动识别模板中的 password 字段、拉取七彩石密钥完成加密后拼装 ext。
|
|
130
|
+
* 两者都传时以 ext 优先。
|
|
127
131
|
*/
|
|
128
132
|
ext?: string;
|
|
133
|
+
/**
|
|
134
|
+
* 环境变量明文键值对。
|
|
135
|
+
* SDK 自动识别模板中的 password 字段并加密,无需调用方自行处理。
|
|
136
|
+
* ext 和 envVariables 都未传时,不携带 Ext 字段。
|
|
137
|
+
*/
|
|
138
|
+
envVariables?: Record<string, string>;
|
|
129
139
|
keyId?: string;
|
|
130
140
|
ticketId?: string;
|
|
131
141
|
/** 业务类型,integration:从集成中心来的,默认为空,表示是从授权管理中心来的 */
|
|
@@ -143,9 +153,15 @@ export interface IUpdateUserKeyParams {
|
|
|
143
153
|
description?: string;
|
|
144
154
|
/**
|
|
145
155
|
* Ext JSON 字符串(模板动态字段的最终取值,含敏感字段密文)。
|
|
146
|
-
*
|
|
156
|
+
* 与 envVariables 二选一。都未传时后端保留原有 Ext 不变。
|
|
147
157
|
*/
|
|
148
158
|
ext?: string;
|
|
159
|
+
/**
|
|
160
|
+
* 环境变量明文键值对。
|
|
161
|
+
* SDK 自动识别模板中的 password 字段并加密,无需调用方自行处理。
|
|
162
|
+
* 传入时与现有 Ext 合并后再加密写入。
|
|
163
|
+
*/
|
|
164
|
+
envVariables?: Record<string, string>;
|
|
149
165
|
/** 绑定的示例代码云函数名称(bind-resource 使用) */
|
|
150
166
|
demoCodeFunctionName?: string;
|
|
151
167
|
/** 业务类型,integration:从集成中心来的,默认为空,表示是从授权管理中心来的 */
|