hop-claude 1.0.0

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 (65) hide show
  1. package/CHANGELOG.md +316 -0
  2. package/README.md +574 -0
  3. package/SECURITY.md +280 -0
  4. package/bin/cli.js +6 -0
  5. package/dist/cli.d.ts +6 -0
  6. package/dist/cli.d.ts.map +1 -0
  7. package/dist/cli.js +147 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/config/config-manager.d.ts +88 -0
  10. package/dist/config/config-manager.d.ts.map +1 -0
  11. package/dist/config/config-manager.js +334 -0
  12. package/dist/config/config-manager.js.map +1 -0
  13. package/dist/config/encryption-v2.d.ts +51 -0
  14. package/dist/config/encryption-v2.d.ts.map +1 -0
  15. package/dist/config/encryption-v2.js +93 -0
  16. package/dist/config/encryption-v2.js.map +1 -0
  17. package/dist/config/encryption.d.ts +36 -0
  18. package/dist/config/encryption.d.ts.map +1 -0
  19. package/dist/config/encryption.js +72 -0
  20. package/dist/config/encryption.js.map +1 -0
  21. package/dist/config/keychain.d.ts +56 -0
  22. package/dist/config/keychain.d.ts.map +1 -0
  23. package/dist/config/keychain.js +112 -0
  24. package/dist/config/keychain.js.map +1 -0
  25. package/dist/config/storage.d.ts +32 -0
  26. package/dist/config/storage.d.ts.map +1 -0
  27. package/dist/config/storage.js +87 -0
  28. package/dist/config/storage.js.map +1 -0
  29. package/dist/config/validator.d.ts +9 -0
  30. package/dist/config/validator.d.ts.map +1 -0
  31. package/dist/config/validator.js +53 -0
  32. package/dist/config/validator.js.map +1 -0
  33. package/dist/index.d.ts +2 -0
  34. package/dist/index.d.ts.map +1 -0
  35. package/dist/index.js +10 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/types/index.d.ts +38 -0
  38. package/dist/types/index.d.ts.map +1 -0
  39. package/dist/types/index.js +2 -0
  40. package/dist/types/index.js.map +1 -0
  41. package/dist/ui/display.d.ts +25 -0
  42. package/dist/ui/display.d.ts.map +1 -0
  43. package/dist/ui/display.js +39 -0
  44. package/dist/ui/display.js.map +1 -0
  45. package/dist/ui/prompts.d.ts +52 -0
  46. package/dist/ui/prompts.d.ts.map +1 -0
  47. package/dist/ui/prompts.js +339 -0
  48. package/dist/ui/prompts.js.map +1 -0
  49. package/dist/utils/backup.d.ts +14 -0
  50. package/dist/utils/backup.d.ts.map +1 -0
  51. package/dist/utils/backup.js +27 -0
  52. package/dist/utils/backup.js.map +1 -0
  53. package/dist/utils/claude-launcher.d.ts +8 -0
  54. package/dist/utils/claude-launcher.d.ts.map +1 -0
  55. package/dist/utils/claude-launcher.js +68 -0
  56. package/dist/utils/claude-launcher.js.map +1 -0
  57. package/dist/utils/migration.d.ts +18 -0
  58. package/dist/utils/migration.d.ts.map +1 -0
  59. package/dist/utils/migration.js +176 -0
  60. package/dist/utils/migration.js.map +1 -0
  61. package/dist/utils/platform.d.ts +19 -0
  62. package/dist/utils/platform.d.ts.map +1 -0
  63. package/dist/utils/platform.js +91 -0
  64. package/dist/utils/platform.js.map +1 -0
  65. package/package.json +54 -0
@@ -0,0 +1,334 @@
1
+ import { ConfigStorage } from './storage.js';
2
+ import { Encryption } from './encryption.js';
3
+ import { PassphraseEncryption } from './encryption-v2.js';
4
+ import { KeychainManager } from './keychain.js';
5
+ /**
6
+ * 配置管理核心类
7
+ * 支持三种加密模式:
8
+ * - legacy: 机器绑定加密(向后兼容)
9
+ * - keychain: OS 密钥链存储(推荐)
10
+ * - passphrase: 用户密码加密(可移植)
11
+ */
12
+ export class ConfigManager {
13
+ storage;
14
+ legacyEncryption;
15
+ passphraseEncryption;
16
+ keychainManager;
17
+ // 用于临时存储用户输入的 passphrase(仅在当前会话有效)
18
+ sessionPassphrase;
19
+ constructor() {
20
+ this.storage = new ConfigStorage();
21
+ this.legacyEncryption = new Encryption();
22
+ this.passphraseEncryption = new PassphraseEncryption();
23
+ this.keychainManager = new KeychainManager();
24
+ }
25
+ /**
26
+ * 设置会话密码(用于 passphrase 模式)
27
+ */
28
+ setSessionPassphrase(passphrase) {
29
+ this.sessionPassphrase = passphrase;
30
+ }
31
+ /**
32
+ * 清除会话密码
33
+ */
34
+ clearSessionPassphrase() {
35
+ this.sessionPassphrase = undefined;
36
+ }
37
+ /**
38
+ * 获取当前加密模式
39
+ */
40
+ async getEncryptionMode() {
41
+ const config = await this.storage.read();
42
+ return config?.encryptionMode || 'legacy'; // 默认 legacy 保持向后兼容
43
+ }
44
+ /**
45
+ * 初始化配置文件
46
+ */
47
+ async initialize() {
48
+ const existing = await this.storage.read();
49
+ if (existing) {
50
+ // 确保有 encryptionMode 字段(向后兼容)
51
+ if (!existing.encryptionMode) {
52
+ existing.encryptionMode = 'legacy';
53
+ }
54
+ return existing;
55
+ }
56
+ const newConfig = {
57
+ version: '1.0.0',
58
+ currentProfile: '',
59
+ profiles: [],
60
+ encryptionSalt: this.legacyEncryption.generateSalt(),
61
+ encryptionMode: 'legacy', // 默认使用 legacy 模式
62
+ };
63
+ await this.storage.write(newConfig);
64
+ return newConfig;
65
+ }
66
+ /**
67
+ * 获取所有配置
68
+ */
69
+ async getConfig() {
70
+ const config = await this.storage.read();
71
+ if (!config)
72
+ return await this.initialize();
73
+ // 向后兼容:添加默认的 encryptionMode
74
+ if (!config.encryptionMode) {
75
+ config.encryptionMode = 'legacy';
76
+ }
77
+ return config;
78
+ }
79
+ /**
80
+ * 添加或更新 profile
81
+ * @param profile 解密后的 profile
82
+ * @param passphrase 密码(仅 passphrase 模式需要)
83
+ */
84
+ async saveProfile(profile, passphrase) {
85
+ const config = await this.getConfig();
86
+ const mode = config.encryptionMode || 'legacy';
87
+ if (!config.encryptionSalt && mode !== 'keychain') {
88
+ config.encryptionSalt = this.legacyEncryption.generateSalt();
89
+ }
90
+ let encryptedApiKey;
91
+ // 根据加密模式处理 API Key
92
+ switch (mode) {
93
+ case 'keychain':
94
+ // Keychain 模式:存储到 OS 密钥链
95
+ await this.keychainManager.setAPIKey(profile.domain, profile.apiKey);
96
+ // config.json 中存储占位符
97
+ encryptedApiKey = '__KEYCHAIN__';
98
+ break;
99
+ case 'passphrase':
100
+ // Passphrase 模式:使用用户密码加密
101
+ const pwd = passphrase || this.sessionPassphrase;
102
+ if (!pwd) {
103
+ throw new Error('Passphrase required for passphrase encryption mode');
104
+ }
105
+ if (!config.encryptionSalt) {
106
+ config.encryptionSalt = this.passphraseEncryption.generateSalt();
107
+ }
108
+ encryptedApiKey = this.passphraseEncryption.encrypt(profile.apiKey, pwd, config.encryptionSalt);
109
+ break;
110
+ case 'legacy':
111
+ default:
112
+ // Legacy 模式:机器绑定加密
113
+ if (!config.encryptionSalt) {
114
+ config.encryptionSalt = this.legacyEncryption.generateSalt();
115
+ }
116
+ encryptedApiKey = this.legacyEncryption.encrypt(profile.apiKey, config.encryptionSalt);
117
+ break;
118
+ }
119
+ const encryptedProfile = {
120
+ ...profile,
121
+ apiKey: encryptedApiKey,
122
+ updatedAt: Date.now(),
123
+ };
124
+ const index = config.profiles.findIndex(p => p.domain === profile.domain);
125
+ if (index >= 0) {
126
+ config.profiles[index] = encryptedProfile;
127
+ }
128
+ else {
129
+ encryptedProfile.createdAt = Date.now();
130
+ config.profiles.push(encryptedProfile);
131
+ }
132
+ await this.storage.write(config);
133
+ }
134
+ /**
135
+ * 获取解密后的 profile
136
+ * @param domain profile 名称
137
+ * @param passphrase 密码(仅 passphrase 模式需要)
138
+ */
139
+ async getProfile(domain, passphrase) {
140
+ const config = await this.getConfig();
141
+ const profile = config.profiles.find(p => p.domain === domain);
142
+ if (!profile)
143
+ return null;
144
+ const mode = config.encryptionMode || 'legacy';
145
+ let decryptedApiKey;
146
+ // 根据加密模式解密 API Key
147
+ switch (mode) {
148
+ case 'keychain':
149
+ // Keychain 模式:从 OS 密钥链读取
150
+ const keychainKey = await this.keychainManager.getAPIKey(domain);
151
+ if (!keychainKey) {
152
+ throw new Error(`API key not found in keychain for profile: ${domain}`);
153
+ }
154
+ decryptedApiKey = keychainKey;
155
+ break;
156
+ case 'passphrase':
157
+ // Passphrase 模式:使用用户密码解密
158
+ const pwd = passphrase || this.sessionPassphrase;
159
+ if (!pwd) {
160
+ throw new Error('Passphrase required to decrypt API key');
161
+ }
162
+ if (!config.encryptionSalt) {
163
+ throw new Error('Encryption salt not found');
164
+ }
165
+ decryptedApiKey = this.passphraseEncryption.decrypt(profile.apiKey, pwd, config.encryptionSalt);
166
+ break;
167
+ case 'legacy':
168
+ default:
169
+ // Legacy 模式:机器绑定解密
170
+ if (!config.encryptionSalt) {
171
+ throw new Error('Encryption salt not found');
172
+ }
173
+ decryptedApiKey = this.legacyEncryption.decrypt(profile.apiKey, config.encryptionSalt);
174
+ break;
175
+ }
176
+ return {
177
+ ...profile,
178
+ apiKey: decryptedApiKey,
179
+ };
180
+ }
181
+ /**
182
+ * 设置当前激活的 profile
183
+ */
184
+ async setCurrentProfile(domain) {
185
+ const config = await this.getConfig();
186
+ config.currentProfile = domain;
187
+ await this.storage.write(config);
188
+ }
189
+ /**
190
+ * 获取当前激活的 profile
191
+ * @param passphrase 密码(仅 passphrase 模式需要)
192
+ */
193
+ async getCurrentProfile(passphrase) {
194
+ const config = await this.getConfig();
195
+ if (!config.currentProfile)
196
+ return null;
197
+ return await this.getProfile(config.currentProfile, passphrase);
198
+ }
199
+ /**
200
+ * 列出所有 profiles(API Key 部分隐藏)
201
+ * @param passphrase 密码(仅 passphrase 模式需要)
202
+ */
203
+ async listProfiles(passphrase) {
204
+ const config = await this.getConfig();
205
+ const mode = config.encryptionMode || 'legacy';
206
+ const results = [];
207
+ for (const p of config.profiles) {
208
+ try {
209
+ let decryptedKey;
210
+ switch (mode) {
211
+ case 'keychain':
212
+ const keychainKey = await this.keychainManager.getAPIKey(p.domain);
213
+ decryptedKey = keychainKey || '';
214
+ break;
215
+ case 'passphrase':
216
+ const pwd = passphrase || this.sessionPassphrase;
217
+ if (!pwd || !config.encryptionSalt) {
218
+ decryptedKey = '';
219
+ break;
220
+ }
221
+ decryptedKey = this.passphraseEncryption.decrypt(p.apiKey, pwd, config.encryptionSalt);
222
+ break;
223
+ case 'legacy':
224
+ default:
225
+ if (!config.encryptionSalt) {
226
+ decryptedKey = '';
227
+ break;
228
+ }
229
+ decryptedKey = this.legacyEncryption.decrypt(p.apiKey, config.encryptionSalt);
230
+ break;
231
+ }
232
+ results.push({
233
+ ...p,
234
+ maskedApiKey: this.legacyEncryption.maskApiKey(decryptedKey),
235
+ });
236
+ }
237
+ catch (error) {
238
+ // 如果解密失败,显示错误标记
239
+ results.push({
240
+ ...p,
241
+ maskedApiKey: '[DECRYPT ERROR]',
242
+ });
243
+ }
244
+ }
245
+ return results;
246
+ }
247
+ /**
248
+ * 删除 profile
249
+ */
250
+ async deleteProfile(domain) {
251
+ const config = await this.getConfig();
252
+ const mode = config.encryptionMode || 'legacy';
253
+ // Keychain 模式下,同时从密钥链中删除
254
+ if (mode === 'keychain') {
255
+ await this.keychainManager.deleteAPIKey(domain);
256
+ }
257
+ config.profiles = config.profiles.filter(p => p.domain !== domain);
258
+ if (config.currentProfile === domain) {
259
+ config.currentProfile = config.profiles[0]?.domain || '';
260
+ }
261
+ await this.storage.write(config);
262
+ }
263
+ /**
264
+ * 导出配置(包含加密的数据)
265
+ * 注意:keychain 模式无法导出实际密钥
266
+ */
267
+ async exportConfig() {
268
+ const config = await this.getConfig();
269
+ // 如果是 keychain 模式,警告用户
270
+ if (config.encryptionMode === 'keychain') {
271
+ console.warn('Warning: Keychain mode cannot export actual API keys. Keys will need to be re-entered after import.');
272
+ }
273
+ return JSON.stringify(config, null, 2);
274
+ }
275
+ /**
276
+ * 导入配置
277
+ */
278
+ async importConfig(data) {
279
+ const config = JSON.parse(data);
280
+ // 验证配置格式
281
+ if (!config.version || !Array.isArray(config.profiles)) {
282
+ throw new Error('Invalid configuration format');
283
+ }
284
+ // 向后兼容:如果没有 encryptionMode,设置为 legacy
285
+ if (!config.encryptionMode) {
286
+ config.encryptionMode = 'legacy';
287
+ }
288
+ await this.storage.write(config);
289
+ }
290
+ /**
291
+ * 切换加密模式(需要提供所有必要的凭据)
292
+ * @param newMode 新的加密模式
293
+ * @param passphrase 密码(切换到 passphrase 模式时需要)
294
+ */
295
+ async switchEncryptionMode(newMode, passphrase) {
296
+ const config = await this.getConfig();
297
+ const oldMode = config.encryptionMode || 'legacy';
298
+ if (oldMode === newMode) {
299
+ return; // 无需切换
300
+ }
301
+ // 读取所有 profiles 的明文 API Keys
302
+ const decryptedProfiles = [];
303
+ for (const p of config.profiles) {
304
+ const decrypted = await this.getProfile(p.domain, passphrase);
305
+ if (decrypted) {
306
+ decryptedProfiles.push(decrypted);
307
+ }
308
+ }
309
+ // 更新加密模式
310
+ config.encryptionMode = newMode;
311
+ // 如果切换到非 legacy/passphrase 模式,可能需要新的 salt
312
+ if (newMode === 'passphrase' && !config.encryptionSalt) {
313
+ config.encryptionSalt = this.passphraseEncryption.generateSalt();
314
+ }
315
+ // 清空旧的 profiles
316
+ config.profiles = [];
317
+ await this.storage.write(config);
318
+ // 使用新模式重新保存所有 profiles
319
+ for (const profile of decryptedProfiles) {
320
+ await this.saveProfile(profile, passphrase);
321
+ }
322
+ // 如果从 keychain 切换出去,清理密钥链
323
+ if (oldMode === 'keychain') {
324
+ await this.keychainManager.clearAll();
325
+ }
326
+ }
327
+ /**
328
+ * 获取配置文件路径
329
+ */
330
+ getConfigPath() {
331
+ return this.storage.getConfigPath();
332
+ }
333
+ }
334
+ //# sourceMappingURL=config-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-manager.js","sourceRoot":"","sources":["../../src/config/config-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * PassphraseEncryption:基于用户密码的加密
3
+ * 用于可移植的配置导出/导入
4
+ * 不依赖机器信息,可以在不同机器间迁移
5
+ */
6
+ export declare class PassphraseEncryption {
7
+ private algorithm;
8
+ private iterations;
9
+ /**
10
+ * 从用户密码派生加密密钥
11
+ * @param passphrase 用户提供的密码
12
+ * @param salt 盐值
13
+ * @returns 派生的密钥
14
+ */
15
+ private deriveKey;
16
+ /**
17
+ * 生成随机 salt
18
+ */
19
+ generateSalt(): string;
20
+ /**
21
+ * 加密明文
22
+ * @param plaintext 要加密的明文
23
+ * @param passphrase 用户密码
24
+ * @param salt 盐值
25
+ * @returns 加密后的密文,格式:iv:authTag:encrypted
26
+ */
27
+ encrypt(plaintext: string, passphrase: string, salt: string): string;
28
+ /**
29
+ * 解密密文
30
+ * @param ciphertext 密文,格式:iv:authTag:encrypted
31
+ * @param passphrase 用户密码
32
+ * @param salt 盐值
33
+ * @returns 解密后的明文
34
+ */
35
+ decrypt(ciphertext: string, passphrase: string, salt: string): string;
36
+ /**
37
+ * 验证密码是否正确
38
+ * @param ciphertext 密文
39
+ * @param passphrase 用户密码
40
+ * @param salt 盐值
41
+ * @returns 密码是否正确
42
+ */
43
+ verifyPassphrase(ciphertext: string, passphrase: string, salt: string): boolean;
44
+ /**
45
+ * 部分隐藏 API Key(用于显示)
46
+ * @param apiKey API Key
47
+ * @returns 部分隐藏的 API Key,如:sk-ant-***xyz
48
+ */
49
+ maskApiKey(apiKey: string): string;
50
+ }
51
+ //# sourceMappingURL=encryption-v2.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encryption-v2.d.ts","sourceRoot":"","sources":["../../src/config/encryption-v2.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,SAAS,CAAiB;IAClC,OAAO,CAAC,UAAU,CAAU;IAE5B;;;;;OAKG;IACH,OAAO,CAAC,SAAS;IAIjB;;OAEG;IACH,YAAY,IAAI,MAAM;IAItB;;;;;;OAMG;IACH,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM;IAcpE;;;;;;OAMG;IACH,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM;IAqBrE;;;;;;OAMG;IACH,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO;IAS/E;;;;OAIG;IACH,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;CAOnC"}
@@ -0,0 +1,93 @@
1
+ import crypto from 'crypto';
2
+ /**
3
+ * PassphraseEncryption:基于用户密码的加密
4
+ * 用于可移植的配置导出/导入
5
+ * 不依赖机器信息,可以在不同机器间迁移
6
+ */
7
+ export class PassphraseEncryption {
8
+ algorithm = 'aes-256-gcm';
9
+ iterations = 100000; // PBKDF2 迭代次数
10
+ /**
11
+ * 从用户密码派生加密密钥
12
+ * @param passphrase 用户提供的密码
13
+ * @param salt 盐值
14
+ * @returns 派生的密钥
15
+ */
16
+ deriveKey(passphrase, salt) {
17
+ return crypto.pbkdf2Sync(passphrase, salt, this.iterations, 32, 'sha512');
18
+ }
19
+ /**
20
+ * 生成随机 salt
21
+ */
22
+ generateSalt() {
23
+ return crypto.randomBytes(32).toString('hex');
24
+ }
25
+ /**
26
+ * 加密明文
27
+ * @param plaintext 要加密的明文
28
+ * @param passphrase 用户密码
29
+ * @param salt 盐值
30
+ * @returns 加密后的密文,格式:iv:authTag:encrypted
31
+ */
32
+ encrypt(plaintext, passphrase, salt) {
33
+ const key = this.deriveKey(passphrase, salt);
34
+ const iv = crypto.randomBytes(16);
35
+ const cipher = crypto.createCipheriv(this.algorithm, key, iv);
36
+ let encrypted = cipher.update(plaintext, 'utf8', 'hex');
37
+ encrypted += cipher.final('hex');
38
+ const authTag = cipher.getAuthTag();
39
+ // 格式: iv:authTag:encrypted
40
+ return `${iv.toString('hex')}:${authTag.toString('hex')}:${encrypted}`;
41
+ }
42
+ /**
43
+ * 解密密文
44
+ * @param ciphertext 密文,格式:iv:authTag:encrypted
45
+ * @param passphrase 用户密码
46
+ * @param salt 盐值
47
+ * @returns 解密后的明文
48
+ */
49
+ decrypt(ciphertext, passphrase, salt) {
50
+ const key = this.deriveKey(passphrase, salt);
51
+ const parts = ciphertext.split(':');
52
+ if (parts.length !== 3) {
53
+ throw new Error('Invalid encrypted data format');
54
+ }
55
+ const [ivHex, authTagHex, encrypted] = parts;
56
+ const iv = Buffer.from(ivHex, 'hex');
57
+ const authTag = Buffer.from(authTagHex, 'hex');
58
+ const decipher = crypto.createDecipheriv(this.algorithm, key, iv);
59
+ decipher.setAuthTag(authTag);
60
+ let decrypted = decipher.update(encrypted, 'hex', 'utf8');
61
+ decrypted += decipher.final('utf8');
62
+ return decrypted;
63
+ }
64
+ /**
65
+ * 验证密码是否正确
66
+ * @param ciphertext 密文
67
+ * @param passphrase 用户密码
68
+ * @param salt 盐值
69
+ * @returns 密码是否正确
70
+ */
71
+ verifyPassphrase(ciphertext, passphrase, salt) {
72
+ try {
73
+ this.decrypt(ciphertext, passphrase, salt);
74
+ return true;
75
+ }
76
+ catch {
77
+ return false;
78
+ }
79
+ }
80
+ /**
81
+ * 部分隐藏 API Key(用于显示)
82
+ * @param apiKey API Key
83
+ * @returns 部分隐藏的 API Key,如:sk-ant-***xyz
84
+ */
85
+ maskApiKey(apiKey) {
86
+ if (!apiKey || apiKey.length < 8)
87
+ return '***';
88
+ const prefix = apiKey.slice(0, 6);
89
+ const suffix = apiKey.slice(-3);
90
+ return `${prefix}***${suffix}`;
91
+ }
92
+ }
93
+ //# sourceMappingURL=encryption-v2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encryption-v2.js","sourceRoot":"","sources":["../../src/config/encryption-v2.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * 加密类:使用 AES-256-GCM 对称加密
3
+ * 密钥派生:基于机器标识(hostname + username)+ 随机盐
4
+ */
5
+ export declare class Encryption {
6
+ private algorithm;
7
+ /**
8
+ * 生成加密密钥(基于机器信息 + salt)
9
+ */
10
+ private deriveKey;
11
+ /**
12
+ * 生成随机 salt
13
+ */
14
+ generateSalt(): string;
15
+ /**
16
+ * 加密明文
17
+ * @param plaintext 要加密的明文
18
+ * @param salt 盐值
19
+ * @returns 加密后的密文,格式:iv:authTag:encrypted
20
+ */
21
+ encrypt(plaintext: string, salt: string): string;
22
+ /**
23
+ * 解密密文
24
+ * @param ciphertext 密文,格式:iv:authTag:encrypted
25
+ * @param salt 盐值
26
+ * @returns 解密后的明文
27
+ */
28
+ decrypt(ciphertext: string, salt: string): string;
29
+ /**
30
+ * 部分隐藏 API Key(用于显示)
31
+ * @param apiKey API Key
32
+ * @returns 部分隐藏的 API Key,如:sk-ant-***xyz
33
+ */
34
+ maskApiKey(apiKey: string): string;
35
+ }
36
+ //# sourceMappingURL=encryption.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encryption.d.ts","sourceRoot":"","sources":["../../src/config/encryption.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,SAAS,CAAiB;IAElC;;OAEG;IACH,OAAO,CAAC,SAAS;IAKjB;;OAEG;IACH,YAAY,IAAI,MAAM;IAItB;;;;;OAKG;IACH,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM;IAchD;;;;;OAKG;IACH,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM;IAqBjD;;;;OAIG;IACH,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;CAOnC"}
@@ -0,0 +1,72 @@
1
+ import crypto from 'crypto';
2
+ import os from 'os';
3
+ /**
4
+ * 加密类:使用 AES-256-GCM 对称加密
5
+ * 密钥派生:基于机器标识(hostname + username)+ 随机盐
6
+ */
7
+ export class Encryption {
8
+ algorithm = 'aes-256-gcm';
9
+ /**
10
+ * 生成加密密钥(基于机器信息 + salt)
11
+ */
12
+ deriveKey(salt) {
13
+ const machineId = `${os.hostname()}-${os.userInfo().username}`;
14
+ return crypto.pbkdf2Sync(machineId, salt, 100000, 32, 'sha512');
15
+ }
16
+ /**
17
+ * 生成随机 salt
18
+ */
19
+ generateSalt() {
20
+ return crypto.randomBytes(32).toString('hex');
21
+ }
22
+ /**
23
+ * 加密明文
24
+ * @param plaintext 要加密的明文
25
+ * @param salt 盐值
26
+ * @returns 加密后的密文,格式:iv:authTag:encrypted
27
+ */
28
+ encrypt(plaintext, salt) {
29
+ const key = this.deriveKey(salt);
30
+ const iv = crypto.randomBytes(16);
31
+ const cipher = crypto.createCipheriv(this.algorithm, key, iv);
32
+ let encrypted = cipher.update(plaintext, 'utf8', 'hex');
33
+ encrypted += cipher.final('hex');
34
+ const authTag = cipher.getAuthTag();
35
+ // 格式: iv:authTag:encrypted
36
+ return `${iv.toString('hex')}:${authTag.toString('hex')}:${encrypted}`;
37
+ }
38
+ /**
39
+ * 解密密文
40
+ * @param ciphertext 密文,格式:iv:authTag:encrypted
41
+ * @param salt 盐值
42
+ * @returns 解密后的明文
43
+ */
44
+ decrypt(ciphertext, salt) {
45
+ const key = this.deriveKey(salt);
46
+ const parts = ciphertext.split(':');
47
+ if (parts.length !== 3) {
48
+ throw new Error('Invalid encrypted data format');
49
+ }
50
+ const [ivHex, authTagHex, encrypted] = parts;
51
+ const iv = Buffer.from(ivHex, 'hex');
52
+ const authTag = Buffer.from(authTagHex, 'hex');
53
+ const decipher = crypto.createDecipheriv(this.algorithm, key, iv);
54
+ decipher.setAuthTag(authTag);
55
+ let decrypted = decipher.update(encrypted, 'hex', 'utf8');
56
+ decrypted += decipher.final('utf8');
57
+ return decrypted;
58
+ }
59
+ /**
60
+ * 部分隐藏 API Key(用于显示)
61
+ * @param apiKey API Key
62
+ * @returns 部分隐藏的 API Key,如:sk-ant-***xyz
63
+ */
64
+ maskApiKey(apiKey) {
65
+ if (!apiKey || apiKey.length < 8)
66
+ return '***';
67
+ const prefix = apiKey.slice(0, 6);
68
+ const suffix = apiKey.slice(-3);
69
+ return `${prefix}***${suffix}`;
70
+ }
71
+ }
72
+ //# sourceMappingURL=encryption.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encryption.js","sourceRoot":"","sources":["../../src/config/encryption.ts"],"names":[],"mappings":"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"}