@pengzi/kms 1.0.2 → 1.1.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.
Files changed (74) hide show
  1. package/README.md +39 -3
  2. package/dist/cli/cli/kms.js +1050 -0
  3. package/dist/cli/kms.js +1050 -0
  4. package/dist/cli/src/client.js +254 -0
  5. package/dist/cli/src/core/asymmetric-crypto.js +170 -0
  6. package/dist/cli/src/core/crypto.js +99 -0
  7. package/dist/cli/src/core/crypto.service.js +66 -0
  8. package/dist/cli/src/core/key-derivation.js +95 -0
  9. package/dist/cli/src/index.js +50 -0
  10. package/dist/cli/src/models/audit.model.js +82 -0
  11. package/dist/cli/src/models/key.model.js +119 -0
  12. package/dist/cli/src/models/project.model.js +53 -0
  13. package/dist/cli/src/models/user.model.js +140 -0
  14. package/dist/cli/src/repositories/audit.repository.js +115 -0
  15. package/dist/cli/src/repositories/base.repository.js +94 -0
  16. package/dist/cli/src/repositories/key.repository.js +125 -0
  17. package/dist/cli/src/repositories/project.repository.js +81 -0
  18. package/dist/cli/src/repositories/user.repository.js +101 -0
  19. package/dist/cli/src/services/audit.service.js +111 -0
  20. package/dist/cli/src/services/auth.service.js +176 -0
  21. package/dist/cli/src/services/key.service.js +137 -0
  22. package/dist/cli/src/services/permission.service.js +142 -0
  23. package/dist/cli/src/services/project.service.js +102 -0
  24. package/dist/cli/src/types/audit.types.js +54 -0
  25. package/dist/cli/src/types/crypto.types.js +5 -0
  26. package/dist/cli/src/types/index.js +90 -0
  27. package/dist/cli/src/types/key.types.js +27 -0
  28. package/dist/cli/src/types/project.types.js +15 -0
  29. package/dist/cli/src/types/user.types.js +48 -0
  30. package/dist/cli/src/utils/config-loader.js +125 -0
  31. package/dist/cli/src/utils/constants.js +118 -0
  32. package/dist/cli/src/utils/error-handler.js +108 -0
  33. package/dist/client.d.ts.map +1 -1
  34. package/dist/client.js +2 -0
  35. package/dist/client.js.map +1 -1
  36. package/dist/models/key.model.js +1 -1
  37. package/dist/models/key.model.js.map +1 -1
  38. package/dist/services/key.service.d.ts +5 -0
  39. package/dist/services/key.service.d.ts.map +1 -1
  40. package/dist/services/key.service.js +12 -4
  41. package/dist/services/key.service.js.map +1 -1
  42. package/dist/services/permission.service.d.ts.map +1 -1
  43. package/dist/services/permission.service.js +6 -1
  44. package/dist/services/permission.service.js.map +1 -1
  45. package/dist/src/client.js +254 -0
  46. package/dist/src/core/asymmetric-crypto.js +170 -0
  47. package/dist/src/core/crypto.js +99 -0
  48. package/dist/src/core/crypto.service.js +66 -0
  49. package/dist/src/core/key-derivation.js +95 -0
  50. package/dist/src/index.js +50 -0
  51. package/dist/src/models/audit.model.js +82 -0
  52. package/dist/src/models/key.model.js +119 -0
  53. package/dist/src/models/project.model.js +53 -0
  54. package/dist/src/models/user.model.js +140 -0
  55. package/dist/src/repositories/audit.repository.js +115 -0
  56. package/dist/src/repositories/base.repository.js +94 -0
  57. package/dist/src/repositories/key.repository.js +125 -0
  58. package/dist/src/repositories/project.repository.js +81 -0
  59. package/dist/src/repositories/user.repository.js +101 -0
  60. package/dist/src/services/audit.service.js +111 -0
  61. package/dist/src/services/auth.service.js +176 -0
  62. package/dist/src/services/key.service.js +137 -0
  63. package/dist/src/services/permission.service.js +142 -0
  64. package/dist/src/services/project.service.js +102 -0
  65. package/dist/src/types/audit.types.js +54 -0
  66. package/dist/src/types/crypto.types.js +5 -0
  67. package/dist/src/types/index.js +90 -0
  68. package/dist/src/types/key.types.js +27 -0
  69. package/dist/src/types/project.types.js +15 -0
  70. package/dist/src/types/user.types.js +48 -0
  71. package/dist/src/utils/config-loader.js +125 -0
  72. package/dist/src/utils/constants.js +118 -0
  73. package/dist/src/utils/error-handler.js +108 -0
  74. package/package.json +7 -2
@@ -0,0 +1,254 @@
1
+ "use strict";
2
+ /**
3
+ * KMS客户端主类
4
+ * 对外API接口
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.KMSClient = void 0;
8
+ const mongodb_1 = require("mongodb");
9
+ const crypto_service_1 = require("./core/crypto.service");
10
+ const project_repository_1 = require("./repositories/project.repository");
11
+ const key_repository_1 = require("./repositories/key.repository");
12
+ const user_repository_1 = require("./repositories/user.repository");
13
+ const audit_repository_1 = require("./repositories/audit.repository");
14
+ const project_service_1 = require("./services/project.service");
15
+ const key_service_1 = require("./services/key.service");
16
+ const auth_service_1 = require("./services/auth.service");
17
+ const permission_service_1 = require("./services/permission.service");
18
+ const audit_service_1 = require("./services/audit.service");
19
+ const error_handler_1 = require("./utils/error-handler");
20
+ const asymmetric_crypto_1 = require("./core/asymmetric-crypto");
21
+ /**
22
+ * KMS客户端类
23
+ */
24
+ class KMSClient {
25
+ constructor(options) {
26
+ this.options = options;
27
+ this.connected = false;
28
+ this.currentUserId = null;
29
+ const connectionString = this.resolveConnectionString(options);
30
+ this.mongoClient = new mongodb_1.MongoClient(connectionString, {
31
+ connectTimeoutMS: this.options.connectionOptions?.connectTimeoutMS || 10000,
32
+ socketTimeoutMS: this.options.connectionOptions?.socketTimeoutMS || 30000,
33
+ serverSelectionTimeoutMS: this.options.connectionOptions?.serverSelectionTimeoutMS || 10000,
34
+ maxPoolSize: this.options.connectionOptions?.maxPoolSize || 10,
35
+ minPoolSize: this.options.connectionOptions?.minPoolSize || 0,
36
+ });
37
+ }
38
+ /**
39
+ * 解析连接字符串(支持加密配置)
40
+ */
41
+ resolveConnectionString(options) {
42
+ // 如果是加密配置,先解密
43
+ if ('encryptedConnectionString' in options) {
44
+ const encrypted = JSON.parse(options.encryptedConnectionString);
45
+ const privateKey = options.privateKey || process.env.KMS_PRIVATE_KEY;
46
+ if (!privateKey) {
47
+ throw (0, error_handler_1.createKMSError)(error_handler_1.ErrorCode.CONNECTION_FAILED, 'Private key is required for encrypted connection string. Set KMS_PRIVATE_KEY environment variable or pass privateKey option.');
48
+ }
49
+ const passphrase = options.privateKeyPassphrase || process.env.KMS_PRIVATE_KEY_PASSPHRASE;
50
+ return (0, asymmetric_crypto_1.parseEncryptedConnectionStringConfig)({ encryptedConnectionString: options.encryptedConnectionString }, privateKey, passphrase);
51
+ }
52
+ // 普通配置直接返回连接字符串
53
+ return options.connectionString;
54
+ }
55
+ /**
56
+ * 连接到数据库
57
+ */
58
+ async connect() {
59
+ if (this.connected) {
60
+ return;
61
+ }
62
+ try {
63
+ await this.mongoClient.connect();
64
+ this.db = this.mongoClient.db(this.options.databaseName);
65
+ this.connected = true;
66
+ // 初始化服务和仓储
67
+ this.initializeServices();
68
+ // 创建索引
69
+ await this.initializeIndexes();
70
+ }
71
+ catch (error) {
72
+ throw (0, error_handler_1.createKMSError)(error_handler_1.ErrorCode.CONNECTION_FAILED, error instanceof Error ? error.message : 'Failed to connect to database');
73
+ }
74
+ }
75
+ /**
76
+ * 断开数据库连接
77
+ */
78
+ async disconnect() {
79
+ if (this.connected) {
80
+ await this.mongoClient.close();
81
+ this.connected = false;
82
+ }
83
+ }
84
+ /**
85
+ * 初始化服务
86
+ */
87
+ initializeServices() {
88
+ this.cryptoService = new crypto_service_1.CryptoService();
89
+ this.projectRepo = new project_repository_1.ProjectRepository(this.db);
90
+ this.keyRepo = new key_repository_1.KeyRepository(this.db);
91
+ this.userRepo = new user_repository_1.UserRepository(this.db);
92
+ this.auditRepo = new audit_repository_1.AuditRepository(this.db);
93
+ this.auditService = new audit_service_1.AuditService(this.auditRepo);
94
+ this.permissionService = new permission_service_1.PermissionService(this.userRepo, this.auditService);
95
+ this.projectService = new project_service_1.ProjectService(this.projectRepo, this.userRepo, this.auditService, this.cryptoService);
96
+ this.authService = new auth_service_1.AuthService(this.userRepo, this.auditService);
97
+ this.keyService = new key_service_1.KeyService(this.keyRepo, this.auditService, this.permissionService, this.cryptoService);
98
+ // 设置 KeyService 的 ProjectService 引用(避免循环依赖)
99
+ this.keyService.setProjectService(this.projectService);
100
+ }
101
+ /**
102
+ * 初始化数据库索引
103
+ */
104
+ async initializeIndexes() {
105
+ // 索引在Repository的构造函数中自动创建
106
+ }
107
+ /**
108
+ * 设置当前用户(用于权限验证)
109
+ */
110
+ setCurrentUser(userId) {
111
+ this.currentUserId = userId;
112
+ }
113
+ /**
114
+ * 获取当前用户ID
115
+ */
116
+ getCurrentUserId() {
117
+ if (!this.currentUserId) {
118
+ throw (0, error_handler_1.createKMSError)(error_handler_1.ErrorCode.AUTHENTICATION_FAILED, 'No user context set');
119
+ }
120
+ return this.currentUserId;
121
+ }
122
+ // ============ 项目管理 ============
123
+ /**
124
+ * 创建项目
125
+ */
126
+ async createProject(projectName, masterPassword, metadata) {
127
+ await this.ensureConnected();
128
+ const userId = this.getCurrentUserId();
129
+ return await this.projectService.createProject({ projectName, masterPassword, metadata }, userId);
130
+ }
131
+ /**
132
+ * 获取项目
133
+ */
134
+ async getProject(projectId) {
135
+ await this.ensureConnected();
136
+ return await this.projectService.getProject(projectId);
137
+ }
138
+ /**
139
+ * 列出所有项目
140
+ */
141
+ async listProjects() {
142
+ await this.ensureConnected();
143
+ return await this.projectService.listProjects();
144
+ }
145
+ /**
146
+ * 删除项目
147
+ */
148
+ async deleteProject(projectId) {
149
+ await this.ensureConnected();
150
+ const userId = this.getCurrentUserId();
151
+ await this.projectService.deleteProject(projectId, userId);
152
+ }
153
+ // ============ 密钥管理 ============
154
+ /**
155
+ * 创建密钥
156
+ */
157
+ async createKey(projectId, masterPassword, keyData) {
158
+ await this.ensureConnected();
159
+ const userId = this.getCurrentUserId();
160
+ return await this.keyService.createKey(projectId, userId, masterPassword, keyData);
161
+ }
162
+ /**
163
+ * 获取密钥(解密)
164
+ */
165
+ async getKey(projectId, masterPassword, keyId) {
166
+ await this.ensureConnected();
167
+ const userId = this.getCurrentUserId();
168
+ return await this.keyService.getKey(projectId, userId, masterPassword, keyId);
169
+ }
170
+ /**
171
+ * 列出密钥
172
+ */
173
+ async listKeys(projectId, filters, options) {
174
+ await this.ensureConnected();
175
+ const userId = this.getCurrentUserId();
176
+ return await this.keyService.listKeys(projectId, userId, filters, options);
177
+ }
178
+ /**
179
+ * 更新密钥
180
+ */
181
+ async updateKey(projectId, masterPassword, keyId, updates) {
182
+ await this.ensureConnected();
183
+ const userId = this.getCurrentUserId();
184
+ return await this.keyService.updateKey(projectId, userId, masterPassword, keyId, updates);
185
+ }
186
+ /**
187
+ * 删除密钥
188
+ */
189
+ async deleteKey(projectId, keyId) {
190
+ await this.ensureConnected();
191
+ const userId = this.getCurrentUserId();
192
+ await this.keyService.deleteKey(projectId, userId, keyId);
193
+ }
194
+ // ============ 用户管理 ============
195
+ /**
196
+ * 创建用户
197
+ */
198
+ async createUser(projectId, userData) {
199
+ await this.ensureConnected();
200
+ const userId = this.getCurrentUserId();
201
+ return await this.authService.createUser(projectId, userId, userData);
202
+ }
203
+ /**
204
+ * 用户登录
205
+ */
206
+ async login(projectId, username, password) {
207
+ await this.ensureConnected();
208
+ const result = await this.authService.login(projectId, { username, password });
209
+ if (result.success && result.user) {
210
+ this.setCurrentUser(result.user.userId);
211
+ }
212
+ return result.success;
213
+ }
214
+ /**
215
+ * 授予角色
216
+ */
217
+ async grantRole(projectId, userId, role) {
218
+ await this.ensureConnected();
219
+ const currentUserId = this.getCurrentUserId();
220
+ await this.permissionService.grantRole(projectId, currentUserId, userId, role);
221
+ }
222
+ /**
223
+ * 撤销角色
224
+ */
225
+ async revokeRole(projectId, userId, role) {
226
+ await this.ensureConnected();
227
+ const currentUserId = this.getCurrentUserId();
228
+ await this.permissionService.revokeRole(projectId, currentUserId, userId, role);
229
+ }
230
+ // ============ 审计日志 ============
231
+ /**
232
+ * 获取审计日志
233
+ */
234
+ async getAuditLogs(projectId, query) {
235
+ await this.ensureConnected();
236
+ return await this.auditService.getAuditLogs(projectId, query);
237
+ }
238
+ /**
239
+ * 获取最近的审计日志
240
+ */
241
+ async getRecentLogs(projectId, limit = 100) {
242
+ await this.ensureConnected();
243
+ return await this.auditService.getRecentLogs(projectId, limit);
244
+ }
245
+ /**
246
+ * 确保已连接
247
+ */
248
+ async ensureConnected() {
249
+ if (!this.connected) {
250
+ throw (0, error_handler_1.createKMSError)(error_handler_1.ErrorCode.CONNECTION_FAILED, 'Client not connected. Call connect() first.');
251
+ }
252
+ }
253
+ }
254
+ exports.KMSClient = KMSClient;
@@ -0,0 +1,170 @@
1
+ "use strict";
2
+ /**
3
+ * 非对称加密服务
4
+ * 使用 RSA-OAEP 加密敏感数据(如数据库连接字符串)
5
+ * 特点:
6
+ * - 公钥加密,私钥解密
7
+ * - 即使加密数据泄露,没有私钥也无法解密
8
+ * - 私钥可以使用密码保护
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.generateRSAKeyPair = generateRSAKeyPair;
12
+ exports.encryptConnectionString = encryptConnectionString;
13
+ exports.decryptConnectionString = decryptConnectionString;
14
+ exports.getPrivateKeyPassphrase = getPrivateKeyPassphrase;
15
+ exports.isValidPEMKey = isValidPEMKey;
16
+ exports.generateKeyId = generateKeyId;
17
+ exports.createEncryptedConnectionStringConfig = createEncryptedConnectionStringConfig;
18
+ exports.parseEncryptedConnectionStringConfig = parseEncryptedConnectionStringConfig;
19
+ const crypto_1 = require("crypto");
20
+ const types_1 = require("../types");
21
+ /**
22
+ * RSA 加密配置
23
+ */
24
+ const RSA_CONFIG = {
25
+ algorithm: 'rsa',
26
+ modulusLength: 4096, // 4096 位密钥(更安全)
27
+ publicKeyEncoding: {
28
+ type: 'spki',
29
+ format: 'pem'
30
+ },
31
+ privateKeyEncoding: {
32
+ type: 'pkcs8',
33
+ format: 'pem',
34
+ cipher: 'aes-256-cbc', // 私钥加密算法
35
+ passphrase: undefined
36
+ },
37
+ padding: crypto_1.constants.RSA_PKCS1_OAEP_PADDING,
38
+ oaepHash: 'sha256'
39
+ };
40
+ /**
41
+ * 生成 RSA 密钥对
42
+ * @param passphrase 私钥密码(可选,但强烈推荐)
43
+ * @returns RSA 密钥对
44
+ */
45
+ function generateRSAKeyPair(passphrase) {
46
+ try {
47
+ const options = {
48
+ ...RSA_CONFIG,
49
+ privateKeyEncoding: {
50
+ ...RSA_CONFIG.privateKeyEncoding,
51
+ passphrase: passphrase
52
+ }
53
+ };
54
+ const { publicKey, privateKey } = (0, crypto_1.generateKeyPairSync)('rsa', options);
55
+ return {
56
+ publicKey,
57
+ privateKey
58
+ };
59
+ }
60
+ catch (error) {
61
+ throw new types_1.CryptoError(`Failed to generate RSA key pair: ${error instanceof Error ? error.message : 'Unknown error'}`);
62
+ }
63
+ }
64
+ /**
65
+ * 使用公钥加密连接字符串
66
+ * @param connectionString 明文连接字符串
67
+ * @param publicKeyPem PEM 格式公钥
68
+ * @returns 加密后的连接字符串
69
+ */
70
+ function encryptConnectionString(connectionString, publicKeyPem) {
71
+ try {
72
+ // RSA OAEP 加密
73
+ const encrypted = (0, crypto_1.publicEncrypt)({
74
+ key: publicKeyPem,
75
+ padding: RSA_CONFIG.padding,
76
+ oaepHash: RSA_CONFIG.oaepHash
77
+ }, Buffer.from(connectionString, 'utf-8'));
78
+ return {
79
+ encrypted: encrypted.toString('base64'),
80
+ algorithm: 'RSA-OAEP-4096',
81
+ keyId: undefined
82
+ };
83
+ }
84
+ catch (error) {
85
+ throw new types_1.CryptoError(`Failed to encrypt connection string: ${error instanceof Error ? error.message : 'Unknown error'}`);
86
+ }
87
+ }
88
+ /**
89
+ * 使用私钥解密连接字符串
90
+ * @param encryptedData 加密的连接字符串
91
+ * @param privateKeyPem PEM 格式私钥
92
+ * @param passphrase 私钥密码(如果私钥有密码保护)
93
+ * @returns 明文连接字符串
94
+ */
95
+ function decryptConnectionString(encryptedData, privateKeyPem, passphrase) {
96
+ try {
97
+ const encryptedBuffer = Buffer.from(encryptedData.encrypted, 'base64');
98
+ // RSA OAEP 解密
99
+ const decrypted = (0, crypto_1.privateDecrypt)({
100
+ key: privateKeyPem,
101
+ passphrase: passphrase,
102
+ padding: RSA_CONFIG.padding,
103
+ oaepHash: RSA_CONFIG.oaepHash
104
+ }, encryptedBuffer);
105
+ return decrypted.toString('utf-8');
106
+ }
107
+ catch (error) {
108
+ throw new types_1.CryptoError(`Failed to decrypt connection string: ${error instanceof Error ? error.message : 'Invalid password or corrupted data'}`);
109
+ }
110
+ }
111
+ /**
112
+ * 从环境变量安全地获取私钥密码
113
+ * @returns 密码字符串
114
+ */
115
+ function getPrivateKeyPassphrase() {
116
+ const passphrase = process.env.KMS_PRIVATE_KEY_PASSPHRASE;
117
+ return passphrase?.trim() || undefined;
118
+ }
119
+ /**
120
+ * 验证 PEM 格式的密钥
121
+ * @param pem PEM 格式密钥
122
+ * @returns 是否有效
123
+ */
124
+ function isValidPEMKey(pem) {
125
+ try {
126
+ const trimmed = pem.trim();
127
+ return (trimmed.includes('-----BEGIN') &&
128
+ trimmed.includes('-----END') &&
129
+ trimmed.includes('KEY-----'));
130
+ }
131
+ catch {
132
+ return false;
133
+ }
134
+ }
135
+ /**
136
+ * 生成密钥 ID(用于密钥轮换)
137
+ * @returns 密钥 ID
138
+ */
139
+ function generateKeyId() {
140
+ const timestamp = Date.now().toString(36);
141
+ const random = (0, crypto_1.randomBytes)(4).toString('hex');
142
+ return `key_${timestamp}_${random}`;
143
+ }
144
+ /**
145
+ * 创建加密的连接字符串配置对象
146
+ * @param connectionString 明文连接字符串
147
+ * @param publicKeyPem 公钥
148
+ * @param keyId 密钥标识(可选)
149
+ * @returns 加密配置
150
+ */
151
+ function createEncryptedConnectionStringConfig(connectionString, publicKeyPem, keyId) {
152
+ const encrypted = encryptConnectionString(connectionString, publicKeyPem);
153
+ if (keyId) {
154
+ encrypted.keyId = keyId;
155
+ }
156
+ return {
157
+ encryptedConnectionString: JSON.stringify(encrypted)
158
+ };
159
+ }
160
+ /**
161
+ * 从加密配置解析连接字符串
162
+ * @param config 配置对象
163
+ * @param privateKeyPem 私钥
164
+ * @param passphrase 私钥密码
165
+ * @returns 明文连接字符串
166
+ */
167
+ function parseEncryptedConnectionStringConfig(config, privateKeyPem, passphrase) {
168
+ const encrypted = JSON.parse(config.encryptedConnectionString);
169
+ return decryptConnectionString(encrypted, privateKeyPem, passphrase);
170
+ }
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ /**
3
+ * 加密/解密工具函数
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.generateRandomBytes = generateRandomBytes;
7
+ exports.generateIV = generateIV;
8
+ exports.encryptAES256GCM = encryptAES256GCM;
9
+ exports.decryptAES256GCM = decryptAES256GCM;
10
+ exports.timingSafeEqual = timingSafeEqual;
11
+ exports.generateRandomKey = generateRandomKey;
12
+ exports.hexToBuffer = hexToBuffer;
13
+ exports.bufferToHex = bufferToHex;
14
+ const crypto_1 = require("crypto");
15
+ const types_1 = require("../types");
16
+ const constants_1 = require("../utils/constants");
17
+ /**
18
+ * 生成随机字节
19
+ */
20
+ function generateRandomBytes(length) {
21
+ return (0, crypto_1.randomBytes)(length);
22
+ }
23
+ /**
24
+ * 生成随机IV
25
+ */
26
+ function generateIV() {
27
+ return generateRandomBytes(constants_1.SECURITY_CONFIG.ENCRYPTION.IV_LENGTH);
28
+ }
29
+ /**
30
+ * 使用AES-256-GCM加密数据
31
+ */
32
+ function encryptAES256GCM(plaintext, key) {
33
+ try {
34
+ const iv = generateIV();
35
+ const cipher = (0, crypto_1.createCipheriv)(constants_1.SECURITY_CONFIG.ENCRYPTION.ALGORITHM, key, iv);
36
+ let encrypted = cipher.update(plaintext, 'utf8', 'hex');
37
+ encrypted += cipher.final('hex');
38
+ const authTag = cipher.getAuthTag();
39
+ return {
40
+ encrypted,
41
+ iv: iv.toString('hex'),
42
+ authTag: authTag.toString('hex'),
43
+ };
44
+ }
45
+ catch (error) {
46
+ throw new types_1.CryptoError(`Encryption failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
47
+ }
48
+ }
49
+ /**
50
+ * 使用AES-256-GCM解密数据
51
+ */
52
+ function decryptAES256GCM(encryptedData, iv, authTag, key) {
53
+ try {
54
+ const decipher = (0, crypto_1.createDecipheriv)(constants_1.SECURITY_CONFIG.ENCRYPTION.ALGORITHM, key, Buffer.from(iv, 'hex'));
55
+ decipher.setAuthTag(Buffer.from(authTag, 'hex'));
56
+ let decrypted = decipher.update(encryptedData, 'hex', 'utf8');
57
+ decrypted += decipher.final('utf8');
58
+ return decrypted;
59
+ }
60
+ catch (error) {
61
+ throw new types_1.CryptoError(`Decryption failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
62
+ }
63
+ }
64
+ /**
65
+ * 比较两个恒定时间字符串(防止时序攻击)
66
+ */
67
+ function timingSafeEqual(a, b) {
68
+ if (a.length !== b.length) {
69
+ return false;
70
+ }
71
+ const aBuffer = Buffer.from(a);
72
+ const bBuffer = Buffer.from(b);
73
+ if (aBuffer.length !== bBuffer.length) {
74
+ return false;
75
+ }
76
+ let result = 0;
77
+ for (let i = 0; i < aBuffer.length; i++) {
78
+ result |= aBuffer[i] ^ bBuffer[i];
79
+ }
80
+ return result === 0;
81
+ }
82
+ /**
83
+ * 生成随机密钥
84
+ */
85
+ function generateRandomKey() {
86
+ return generateRandomBytes(constants_1.SECURITY_CONFIG.ENCRYPTION.KEY_LENGTH);
87
+ }
88
+ /**
89
+ * 从十六进制字符串转换为Buffer
90
+ */
91
+ function hexToBuffer(hex) {
92
+ return Buffer.from(hex, 'hex');
93
+ }
94
+ /**
95
+ * 将Buffer转换为十六进制字符串
96
+ */
97
+ function bufferToHex(buffer) {
98
+ return buffer.toString('hex');
99
+ }
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ /**
3
+ * 加密服务
4
+ * 负责所有密钥加密和解密操作
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.CryptoService = void 0;
8
+ const crypto_1 = require("./crypto");
9
+ const key_derivation_1 = require("./key-derivation");
10
+ const types_1 = require("../types");
11
+ /**
12
+ * 加密服务类
13
+ */
14
+ class CryptoService {
15
+ /**
16
+ * 加密密钥值
17
+ */
18
+ async encryptKey(plainValue, masterKey) {
19
+ return (0, crypto_1.encryptAES256GCM)(plainValue, masterKey);
20
+ }
21
+ /**
22
+ * 解密密钥值
23
+ */
24
+ async decryptKey(encryptedValue, iv, authTag, masterKey) {
25
+ return (0, crypto_1.decryptAES256GCM)(encryptedValue, iv, authTag, masterKey);
26
+ }
27
+ /**
28
+ * 从主密码派生项目主密钥
29
+ */
30
+ async deriveMasterKey(masterPassword, salt) {
31
+ return (0, key_derivation_1.deriveProjectMasterKey)(masterPassword, salt);
32
+ }
33
+ /**
34
+ * 生成主密钥哈希
35
+ */
36
+ async hashMasterKey(masterKey) {
37
+ return (0, key_derivation_1.hashMasterKey)(masterKey);
38
+ }
39
+ /**
40
+ * 验证主密钥
41
+ */
42
+ async verifyMasterKey(masterKey, storedHash) {
43
+ const derivedHash = await this.hashMasterKey(masterKey);
44
+ return derivedHash === storedHash;
45
+ }
46
+ /**
47
+ * 使用主密码解锁项目主密钥
48
+ */
49
+ async unlockProjectMasterKey(masterPassword, salt, masterKeyHash) {
50
+ const masterKey = await this.deriveMasterKey(masterPassword, salt);
51
+ const isValid = await this.verifyMasterKey(masterKey, masterKeyHash);
52
+ if (!isValid) {
53
+ throw new types_1.CryptoError('Invalid master password');
54
+ }
55
+ return masterKey;
56
+ }
57
+ }
58
+ exports.CryptoService = CryptoService;
59
+ /**
60
+ * 简单的依赖注入装饰器(TypeScript版本)
61
+ */
62
+ function Injectable() {
63
+ return function decorator(target) {
64
+ return target;
65
+ };
66
+ }
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ /**
3
+ * 密钥派生功能
4
+ * 使用PBKDF2从密码派生密钥
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.generateSalt = generateSalt;
41
+ exports.deriveKeyFromPassword = deriveKeyFromPassword;
42
+ exports.deriveProjectMasterKey = deriveProjectMasterKey;
43
+ exports.hashMasterKey = hashMasterKey;
44
+ exports.verifyMasterPassword = verifyMasterPassword;
45
+ const crypto_1 = require("crypto");
46
+ const types_1 = require("../types");
47
+ const constants_1 = require("../utils/constants");
48
+ /**
49
+ * 生成随机盐值
50
+ */
51
+ function generateSalt() {
52
+ return (0, crypto_1.randomBytes)(16).toString('hex');
53
+ }
54
+ /**
55
+ * 使用PBKDF2从密码派生密钥
56
+ */
57
+ async function deriveKeyFromPassword(password, salt, iterations, keyLength) {
58
+ return new Promise((resolve, reject) => {
59
+ const config = constants_1.SECURITY_CONFIG.KEY_DERIVATION;
60
+ (0, crypto_1.pbkdf2)(password, salt, iterations || config.ITERATIONS, keyLength || config.KEY_LENGTH, config.DIGEST, (err, derivedKey) => {
61
+ if (err) {
62
+ reject(new types_1.CryptoError(`Key derivation failed: ${err.message}`));
63
+ }
64
+ else {
65
+ resolve(derivedKey);
66
+ }
67
+ });
68
+ });
69
+ }
70
+ /**
71
+ * 派生项目主密钥
72
+ */
73
+ async function deriveProjectMasterKey(masterPassword, salt) {
74
+ return deriveKeyFromPassword(masterPassword, salt);
75
+ }
76
+ /**
77
+ * 生成主密钥哈希(用于验证密码)
78
+ */
79
+ async function hashMasterKey(masterKey) {
80
+ const { createHash } = await Promise.resolve().then(() => __importStar(require('crypto')));
81
+ return createHash('sha256').update(masterKey).digest('hex');
82
+ }
83
+ /**
84
+ * 验证主密码
85
+ */
86
+ async function verifyMasterPassword(masterPassword, salt, storedHash) {
87
+ try {
88
+ const derivedKey = await deriveProjectMasterKey(masterPassword, salt);
89
+ const derivedHash = await hashMasterKey(derivedKey);
90
+ return derivedHash === storedHash;
91
+ }
92
+ catch (error) {
93
+ return false;
94
+ }
95
+ }