@lightharu/krouter 1.8.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.
- package/LICENSE +679 -0
- package/README.md +238 -0
- package/dist-web/assets/index-CM4-0adf.css +1 -0
- package/dist-web/assets/index-DCslvfUR.js +139 -0
- package/dist-web/favicon.svg +9 -0
- package/dist-web/icon.svg +9 -0
- package/dist-web/index.html +19 -0
- package/out-server/main/kiroAuthSync.js +249 -0
- package/out-server/main/kproxy/certManager.js +262 -0
- package/out-server/main/kproxy/index.js +254 -0
- package/out-server/main/kproxy/mitmProxy.js +475 -0
- package/out-server/main/kproxy/types.js +23 -0
- package/out-server/main/proxy/accountPool.js +543 -0
- package/out-server/main/proxy/clientConfig.js +596 -0
- package/out-server/main/proxy/index.js +25 -0
- package/out-server/main/proxy/kiroApi.js +1996 -0
- package/out-server/main/proxy/logger.js +407 -0
- package/out-server/main/proxy/modelCatalog.js +75 -0
- package/out-server/main/proxy/promptCacheTracker.js +301 -0
- package/out-server/main/proxy/proxyServer.js +3543 -0
- package/out-server/main/proxy/selfSignedCert.js +179 -0
- package/out-server/main/proxy/systemProxy.js +250 -0
- package/out-server/main/proxy/tokenCounter.js +164 -0
- package/out-server/main/proxy/toolNameRegistry.js +57 -0
- package/out-server/main/proxy/translator.js +1084 -0
- package/out-server/main/proxy/types.js +3 -0
- package/out-server/main/registration/browser-identity.js +184 -0
- package/out-server/main/registration/chainProxy.js +349 -0
- package/out-server/main/registration/config.js +58 -0
- package/out-server/main/registration/email-service.js +801 -0
- package/out-server/main/registration/fingerprint.js +352 -0
- package/out-server/main/registration/http-utils.js +148 -0
- package/out-server/main/registration/jwe.js +74 -0
- package/out-server/main/registration/names.js +142 -0
- package/out-server/main/registration/proton-mail-window.js +339 -0
- package/out-server/main/registration/registrar.js +1715 -0
- package/out-server/main/registration/tlsClientPool.js +70 -0
- package/out-server/main/registration/xxtea.js +161 -0
- package/out-server/main/runtimePaths.js +19 -0
- package/out-server/main/utils/redact.js +95 -0
- package/out-server/server/index.js +1272 -0
- package/out-server/server/services/accountExtras.js +105 -0
- package/out-server/server/services/accountProfileHydration.js +95 -0
- package/out-server/server/services/authFlows.js +509 -0
- package/out-server/server/services/dashboardTunnel.js +315 -0
- package/out-server/server/services/diagnostics.js +326 -0
- package/out-server/server/services/kiroAccounts.js +431 -0
- package/out-server/server/services/kiroSettings.js +260 -0
- package/out-server/server/services/kproxyRuntime.js +264 -0
- package/out-server/server/services/localKiroCredentials.js +320 -0
- package/out-server/server/services/machineIdRuntime.js +327 -0
- package/out-server/server/services/protonBrowserRuntime.js +724 -0
- package/out-server/server/services/proxyRuntime.js +523 -0
- package/out-server/server/services/registrationRuntime.js +106 -0
- package/out-server/server/store.js +266 -0
- package/package.json +113 -0
- package/resources/tls-client-xgo-1.14.0-windows-amd64.dll +0 -0
- package/scripts/kiro-manager-cli.cjs +3 -0
- package/scripts/krouter-cli.cjs +509 -0
- package/src/renderer/src/assets/krouter-logo.svg +11 -0
- package/src/renderer/src/assets/krouter-mark.svg +9 -0
|
@@ -0,0 +1,264 @@
|
|
|
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.KProxyRuntime = void 0;
|
|
7
|
+
exports.getKProxyRuntime = getKProxyRuntime;
|
|
8
|
+
const child_process_1 = require("child_process");
|
|
9
|
+
const fs_1 = require("fs");
|
|
10
|
+
const path_1 = __importDefault(require("path"));
|
|
11
|
+
const kproxy_1 = require("../../main/kproxy");
|
|
12
|
+
const runtimePaths_1 = require("../../main/runtimePaths");
|
|
13
|
+
function serializeCaInfo(caInfo) {
|
|
14
|
+
if (!caInfo)
|
|
15
|
+
return null;
|
|
16
|
+
return {
|
|
17
|
+
certPath: caInfo.certPath,
|
|
18
|
+
keyPath: caInfo.keyPath,
|
|
19
|
+
fingerprint: caInfo.fingerprint,
|
|
20
|
+
validFrom: caInfo.validFrom instanceof Date ? caInfo.validFrom.toISOString() : caInfo.validFrom,
|
|
21
|
+
validTo: caInfo.validTo instanceof Date ? caInfo.validTo.toISOString() : caInfo.validTo
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
class KProxyRuntime {
|
|
25
|
+
store;
|
|
26
|
+
userId;
|
|
27
|
+
emit;
|
|
28
|
+
service = null;
|
|
29
|
+
constructor(store, userId, emit) {
|
|
30
|
+
this.store = store;
|
|
31
|
+
this.userId = userId;
|
|
32
|
+
this.emit = emit;
|
|
33
|
+
}
|
|
34
|
+
get savedConfig() {
|
|
35
|
+
return this.store.getUserSetting(this.userId, 'kproxyConfig', {});
|
|
36
|
+
}
|
|
37
|
+
get mappings() {
|
|
38
|
+
return this.store.getUserSetting(this.userId, 'kproxyDeviceMappings', []);
|
|
39
|
+
}
|
|
40
|
+
async persistConfig() {
|
|
41
|
+
if (this.service)
|
|
42
|
+
await this.store.setUserSetting(this.userId, 'kproxyConfig', this.service.getConfig());
|
|
43
|
+
}
|
|
44
|
+
async persistMappings() {
|
|
45
|
+
if (this.service)
|
|
46
|
+
await this.store.setUserSetting(this.userId, 'kproxyDeviceMappings', this.service.getAllDeviceIdMappings());
|
|
47
|
+
}
|
|
48
|
+
getOrCreateService(config) {
|
|
49
|
+
if (!this.service) {
|
|
50
|
+
this.service = (0, kproxy_1.initKProxyService)({ ...this.savedConfig, ...config }, {
|
|
51
|
+
onRequest: (info) => this.emit('kproxy-request', info),
|
|
52
|
+
onResponse: (info) => this.emit('kproxy-response', info),
|
|
53
|
+
onError: (error) => this.emit('kproxy-error', error.message),
|
|
54
|
+
onStatusChange: (running, port) => this.emit('kproxy-status-change', { running, port }),
|
|
55
|
+
onMitmIntercept: (host, modified) => this.emit('kproxy-mitm', { host, modified })
|
|
56
|
+
});
|
|
57
|
+
for (const mapping of this.mappings)
|
|
58
|
+
this.service.addDeviceIdMapping(mapping);
|
|
59
|
+
}
|
|
60
|
+
else if (config) {
|
|
61
|
+
this.service.updateConfig(config);
|
|
62
|
+
}
|
|
63
|
+
return this.service;
|
|
64
|
+
}
|
|
65
|
+
async init() {
|
|
66
|
+
try {
|
|
67
|
+
const service = this.getOrCreateService();
|
|
68
|
+
const caInfo = await service.initialize();
|
|
69
|
+
await this.persistConfig();
|
|
70
|
+
return { success: true, caInfo: serializeCaInfo(caInfo) };
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
return { success: false, error: error instanceof Error ? error.message : 'Failed to initialize K-Proxy' };
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
async start(config) {
|
|
77
|
+
try {
|
|
78
|
+
const service = this.getOrCreateService(config);
|
|
79
|
+
await service.start();
|
|
80
|
+
await this.persistConfig();
|
|
81
|
+
return { success: true, port: service.getConfig().port };
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
return { success: false, error: error instanceof Error ? error.message : 'Failed to start K-Proxy' };
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
async stop() {
|
|
88
|
+
try {
|
|
89
|
+
if (this.service)
|
|
90
|
+
await this.service.stop();
|
|
91
|
+
await this.persistConfig();
|
|
92
|
+
return { success: true };
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
return { success: false, error: error instanceof Error ? error.message : 'Failed to stop K-Proxy' };
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
getStatus() {
|
|
99
|
+
const service = this.getOrCreateService();
|
|
100
|
+
return {
|
|
101
|
+
running: service.isRunning(),
|
|
102
|
+
config: service.getConfig(),
|
|
103
|
+
stats: service.getStats(),
|
|
104
|
+
caInfo: serializeCaInfo(service.getCACertInfo())
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
async updateConfig(config) {
|
|
108
|
+
try {
|
|
109
|
+
const service = this.getOrCreateService(config);
|
|
110
|
+
await this.persistConfig();
|
|
111
|
+
return { success: true, config: service.getConfig() };
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
return { success: false, error: error instanceof Error ? error.message : 'Failed to update K-Proxy config' };
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
async setDeviceId(deviceId) {
|
|
118
|
+
try {
|
|
119
|
+
this.getOrCreateService().setDeviceId(deviceId);
|
|
120
|
+
await this.persistConfig();
|
|
121
|
+
return { success: true };
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
return { success: false, error: error instanceof Error ? error.message : 'Failed to set device ID' };
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
generateDeviceId() {
|
|
128
|
+
return { success: true, deviceId: (0, kproxy_1.generateDeviceId)() };
|
|
129
|
+
}
|
|
130
|
+
async addDeviceMapping(mapping) {
|
|
131
|
+
try {
|
|
132
|
+
this.getOrCreateService().addDeviceIdMapping(mapping);
|
|
133
|
+
await this.persistMappings();
|
|
134
|
+
return { success: true };
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
return { success: false, error: error instanceof Error ? error.message : 'Failed to add device mapping' };
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
getDeviceMappings() {
|
|
141
|
+
return { success: true, mappings: this.getOrCreateService().getAllDeviceIdMappings() };
|
|
142
|
+
}
|
|
143
|
+
async switchToAccount(accountId) {
|
|
144
|
+
const service = this.getOrCreateService();
|
|
145
|
+
const success = service.switchToAccount(accountId);
|
|
146
|
+
await this.persistConfig();
|
|
147
|
+
await this.persistMappings();
|
|
148
|
+
return { success, error: success ? undefined : 'No device ID mapping for account' };
|
|
149
|
+
}
|
|
150
|
+
async getCaCert() {
|
|
151
|
+
const initResult = await this.init();
|
|
152
|
+
if (!initResult.success)
|
|
153
|
+
return { success: false, error: initResult.error };
|
|
154
|
+
const service = this.getOrCreateService();
|
|
155
|
+
const certPem = service.getCACertPem();
|
|
156
|
+
const caInfo = service.getCACertInfo();
|
|
157
|
+
if (!certPem || !caInfo)
|
|
158
|
+
return { success: false, error: 'CA certificate not available' };
|
|
159
|
+
return { success: true, certPem, certPath: caInfo.certPath, fingerprint: caInfo.fingerprint };
|
|
160
|
+
}
|
|
161
|
+
async exportCaCert(exportPath) {
|
|
162
|
+
const cert = await this.getCaCert();
|
|
163
|
+
if (!cert.success || !cert.certPem)
|
|
164
|
+
return { success: false, error: cert.error || 'CA certificate not available' };
|
|
165
|
+
const targetPath = exportPath || path_1.default.join((0, runtimePaths_1.getRuntimeUserDataPath)(), 'kproxy-ca.crt');
|
|
166
|
+
await fs_1.promises.mkdir(path_1.default.dirname(targetPath), { recursive: true });
|
|
167
|
+
await fs_1.promises.writeFile(targetPath, cert.certPem, 'utf8');
|
|
168
|
+
return { success: true, path: targetPath };
|
|
169
|
+
}
|
|
170
|
+
async checkCaCertInstalled() {
|
|
171
|
+
try {
|
|
172
|
+
const cert = await this.getCaCert();
|
|
173
|
+
if (!cert.success)
|
|
174
|
+
return { success: false, installed: false, error: cert.error };
|
|
175
|
+
if (process.platform === 'win32') {
|
|
176
|
+
try {
|
|
177
|
+
const output = (0, child_process_1.execSync)('certutil -store -user Root "K-Proxy CA"', { encoding: 'utf8' });
|
|
178
|
+
return { success: true, installed: output.includes('K-Proxy CA') };
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
return { success: true, installed: false };
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
if (process.platform === 'darwin') {
|
|
185
|
+
try {
|
|
186
|
+
(0, child_process_1.execSync)('security find-certificate -c "K-Proxy CA" ~/Library/Keychains/login.keychain-db', { encoding: 'utf8' });
|
|
187
|
+
return { success: true, installed: true };
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
return { success: true, installed: false };
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
const linuxPath = '/usr/local/share/ca-certificates/kproxy-ca.crt';
|
|
194
|
+
try {
|
|
195
|
+
await fs_1.promises.access(linuxPath);
|
|
196
|
+
return { success: true, installed: true };
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
return { success: true, installed: false };
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
catch (error) {
|
|
203
|
+
return { success: false, installed: false, error: error instanceof Error ? error.message : 'Failed to check CA certificate' };
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
async installCaCert() {
|
|
207
|
+
try {
|
|
208
|
+
const cert = await this.getCaCert();
|
|
209
|
+
if (!cert.success || !cert.certPath)
|
|
210
|
+
return { success: false, error: cert.error || 'CA certificate not available' };
|
|
211
|
+
if (process.platform === 'win32') {
|
|
212
|
+
(0, child_process_1.execSync)(`certutil -addstore -user Root "${cert.certPath}"`, { encoding: 'utf8' });
|
|
213
|
+
return { success: true, message: 'CA certificate installed to Windows certificate store' };
|
|
214
|
+
}
|
|
215
|
+
if (process.platform === 'darwin') {
|
|
216
|
+
(0, child_process_1.execSync)(`security add-trusted-cert -r trustRoot -k ~/Library/Keychains/login.keychain-db "${cert.certPath}"`);
|
|
217
|
+
return { success: true, message: 'CA certificate installed to macOS Keychain' };
|
|
218
|
+
}
|
|
219
|
+
const linuxPath = '/usr/local/share/ca-certificates/kproxy-ca.crt';
|
|
220
|
+
await fs_1.promises.copyFile(cert.certPath, linuxPath);
|
|
221
|
+
(0, child_process_1.execSync)('update-ca-certificates');
|
|
222
|
+
return { success: true, message: 'CA certificate installed to Linux CA store' };
|
|
223
|
+
}
|
|
224
|
+
catch (error) {
|
|
225
|
+
return { success: false, error: error instanceof Error ? error.message : 'Failed to install CA certificate' };
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
async uninstallCaCert() {
|
|
229
|
+
try {
|
|
230
|
+
if (process.platform === 'win32') {
|
|
231
|
+
(0, child_process_1.execSync)('certutil -delstore -user Root "K-Proxy CA"', { encoding: 'utf8' });
|
|
232
|
+
return { success: true, message: 'CA certificate removed from Windows certificate store' };
|
|
233
|
+
}
|
|
234
|
+
if (process.platform === 'darwin') {
|
|
235
|
+
(0, child_process_1.execSync)('security delete-certificate -c "K-Proxy CA" ~/Library/Keychains/login.keychain-db');
|
|
236
|
+
return { success: true, message: 'CA certificate removed from macOS Keychain' };
|
|
237
|
+
}
|
|
238
|
+
const linuxPath = '/usr/local/share/ca-certificates/kproxy-ca.crt';
|
|
239
|
+
try {
|
|
240
|
+
await fs_1.promises.unlink(linuxPath);
|
|
241
|
+
}
|
|
242
|
+
catch { /* not installed */ }
|
|
243
|
+
(0, child_process_1.execSync)('update-ca-certificates --fresh');
|
|
244
|
+
return { success: true, message: 'CA certificate removed from Linux CA store' };
|
|
245
|
+
}
|
|
246
|
+
catch (error) {
|
|
247
|
+
return { success: false, error: error instanceof Error ? error.message : 'Failed to uninstall CA certificate' };
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
resetStats() {
|
|
251
|
+
this.getOrCreateService().resetStats();
|
|
252
|
+
return { success: true };
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
exports.KProxyRuntime = KProxyRuntime;
|
|
256
|
+
const runtimes = new Map();
|
|
257
|
+
function getKProxyRuntime(store, userId, emit) {
|
|
258
|
+
const existing = runtimes.get(userId);
|
|
259
|
+
if (existing)
|
|
260
|
+
return existing;
|
|
261
|
+
const runtime = new KProxyRuntime(store, userId, emit);
|
|
262
|
+
runtimes.set(userId, runtime);
|
|
263
|
+
return runtime;
|
|
264
|
+
}
|
|
@@ -0,0 +1,320 @@
|
|
|
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.getLocalActiveAccount = getLocalActiveAccount;
|
|
7
|
+
exports.loadKiroCredentials = loadKiroCredentials;
|
|
8
|
+
exports.switchAccount = switchAccount;
|
|
9
|
+
exports.switchAccountCli = switchAccountCli;
|
|
10
|
+
exports.logoutAccount = logoutAccount;
|
|
11
|
+
const child_process_1 = require("child_process");
|
|
12
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
13
|
+
const fs_1 = require("fs");
|
|
14
|
+
const os_1 = __importDefault(require("os"));
|
|
15
|
+
const path_1 = __importDefault(require("path"));
|
|
16
|
+
const kiroAccounts_1 = require("./kiroAccounts");
|
|
17
|
+
const SOCIAL_PROFILE_ARN = 'arn:aws:codewhisperer:us-east-1:699475941385:profile/EHGA3GRVQMUK';
|
|
18
|
+
const LEGACY_BUILDER_ID_PROFILE_ARN = 'arn:aws:codewhisperer:us-east-1:638616132270:profile/AAAACCCCXXXX';
|
|
19
|
+
function ssoCacheDir() {
|
|
20
|
+
return path_1.default.resolve(process.env.KIRO_SSO_CACHE_DIR || path_1.default.join(os_1.default.homedir(), '.aws', 'sso', 'cache'));
|
|
21
|
+
}
|
|
22
|
+
function tokenPath() {
|
|
23
|
+
return path_1.default.join(ssoCacheDir(), 'kiro-auth-token.json');
|
|
24
|
+
}
|
|
25
|
+
function clientIdHashForStartUrl(startUrl = 'https://view.awsapps.com/start') {
|
|
26
|
+
return crypto_1.default.createHash('sha1').update(JSON.stringify({ startUrl })).digest('hex');
|
|
27
|
+
}
|
|
28
|
+
function cliDataDir() {
|
|
29
|
+
if (process.env.KIRO_CLI_DATA_DIR)
|
|
30
|
+
return path_1.default.resolve(process.env.KIRO_CLI_DATA_DIR);
|
|
31
|
+
return process.platform === 'win32'
|
|
32
|
+
? path_1.default.join(os_1.default.homedir(), 'AppData', 'Local', 'kiro-cli')
|
|
33
|
+
: path_1.default.join(os_1.default.homedir(), '.local', 'share', 'kiro-cli');
|
|
34
|
+
}
|
|
35
|
+
function cliDbPath() {
|
|
36
|
+
return process.env.KIRO_CLI_DB_PATH
|
|
37
|
+
? path_1.default.resolve(process.env.KIRO_CLI_DB_PATH)
|
|
38
|
+
: path_1.default.join(cliDataDir(), 'data.sqlite3');
|
|
39
|
+
}
|
|
40
|
+
function sqlEscape(value) {
|
|
41
|
+
return JSON.stringify(value).replace(/'/g, "''");
|
|
42
|
+
}
|
|
43
|
+
function runSqlite(dbPath, sql) {
|
|
44
|
+
try {
|
|
45
|
+
(0, child_process_1.execFileSync)(process.platform === 'win32' ? 'sqlite3.exe' : 'sqlite3', [dbPath], { input: sql, encoding: 'utf8', timeout: 10000 });
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
catch (cliError) {
|
|
49
|
+
try {
|
|
50
|
+
const sqlite = require('node:sqlite');
|
|
51
|
+
const database = new sqlite.DatabaseSync(dbPath);
|
|
52
|
+
try {
|
|
53
|
+
database.exec(sql);
|
|
54
|
+
}
|
|
55
|
+
finally {
|
|
56
|
+
database.close();
|
|
57
|
+
}
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
catch (nodeError) {
|
|
61
|
+
throw new Error(`sqlite3 command or Node node:sqlite is required for CLI switching on this VPS. sqlite3: ${cliError instanceof Error ? cliError.message : String(cliError)}; node:sqlite: ${nodeError instanceof Error ? nodeError.message : String(nodeError)}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function isSocialCredential(credentials) {
|
|
66
|
+
const authMethod = String(credentials.authMethod || '').toLowerCase();
|
|
67
|
+
const provider = String(credentials.provider || '').toLowerCase();
|
|
68
|
+
return authMethod === 'social' || provider === 'google' || provider === 'github';
|
|
69
|
+
}
|
|
70
|
+
function normalizeProfileArn(profileArn) {
|
|
71
|
+
let value = profileArn?.trim();
|
|
72
|
+
if (!value || value === LEGACY_BUILDER_ID_PROFILE_ARN)
|
|
73
|
+
return undefined;
|
|
74
|
+
if (!value.startsWith('arn:') && value.includes(':codewhisperer:'))
|
|
75
|
+
value = `arn:${value}`;
|
|
76
|
+
return value;
|
|
77
|
+
}
|
|
78
|
+
function resolveCredentialProfileArn(credentials) {
|
|
79
|
+
const explicit = normalizeProfileArn(credentials.profileArn);
|
|
80
|
+
if (explicit)
|
|
81
|
+
return explicit;
|
|
82
|
+
if (isSocialCredential(credentials))
|
|
83
|
+
return SOCIAL_PROFILE_ARN;
|
|
84
|
+
const authMethod = String(credentials.authMethod || '').toLowerCase();
|
|
85
|
+
const provider = String(credentials.provider || '').toLowerCase();
|
|
86
|
+
return provider === 'builderid' || (!provider && (authMethod === 'idc' || authMethod === 'oidc'))
|
|
87
|
+
? LEGACY_BUILDER_ID_PROFILE_ARN
|
|
88
|
+
: undefined;
|
|
89
|
+
}
|
|
90
|
+
function kiroUserDataDirs() {
|
|
91
|
+
const dirs = new Set();
|
|
92
|
+
if (process.env.KIRO_USER_DATA_DIR)
|
|
93
|
+
dirs.add(path_1.default.resolve(process.env.KIRO_USER_DATA_DIR));
|
|
94
|
+
if (process.env.KIRO_IDE_USER_DATA_DIR)
|
|
95
|
+
dirs.add(path_1.default.resolve(process.env.KIRO_IDE_USER_DATA_DIR));
|
|
96
|
+
if (process.platform === 'win32') {
|
|
97
|
+
const appData = process.env.APPDATA || path_1.default.join(os_1.default.homedir(), 'AppData', 'Roaming');
|
|
98
|
+
dirs.add(path_1.default.join(appData, 'Kiro'));
|
|
99
|
+
}
|
|
100
|
+
else if (process.platform === 'darwin') {
|
|
101
|
+
dirs.add(path_1.default.join(os_1.default.homedir(), 'Library', 'Application Support', 'Kiro'));
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
dirs.add(path_1.default.join(os_1.default.homedir(), '.config', 'Kiro'));
|
|
105
|
+
}
|
|
106
|
+
return Array.from(dirs);
|
|
107
|
+
}
|
|
108
|
+
function kiroProfilePaths() {
|
|
109
|
+
const paths = new Set();
|
|
110
|
+
if (process.env.KIRO_IDE_PROFILE_PATH)
|
|
111
|
+
paths.add(path_1.default.resolve(process.env.KIRO_IDE_PROFILE_PATH));
|
|
112
|
+
for (const userDataDir of kiroUserDataDirs()) {
|
|
113
|
+
for (const extensionId of ['kiro.kiroagent', 'kiro.kiro-agent']) {
|
|
114
|
+
paths.add(path_1.default.join(userDataDir, 'User', 'globalStorage', extensionId, 'profile.json'));
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return Array.from(paths);
|
|
118
|
+
}
|
|
119
|
+
async function readKiroIdeProfile() {
|
|
120
|
+
for (const profilePath of kiroProfilePaths()) {
|
|
121
|
+
try {
|
|
122
|
+
const data = JSON.parse(await fs_1.promises.readFile(profilePath, 'utf8'));
|
|
123
|
+
const profileArn = normalizeProfileArn(data.profileArn || data.profile_arn || data.arn);
|
|
124
|
+
if (profileArn)
|
|
125
|
+
return { profileArn, name: data.name, path: profilePath };
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
// Try the next known Kiro profile location.
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
async function findClientRegistration(clientIdHash) {
|
|
134
|
+
if (clientIdHash) {
|
|
135
|
+
try {
|
|
136
|
+
return JSON.parse(await fs_1.promises.readFile(path_1.default.join(ssoCacheDir(), `${clientIdHash}.json`), 'utf8'));
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
// Search below.
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
try {
|
|
143
|
+
for (const file of await fs_1.promises.readdir(ssoCacheDir())) {
|
|
144
|
+
if (!file.endsWith('.json') || file === 'kiro-auth-token.json')
|
|
145
|
+
continue;
|
|
146
|
+
try {
|
|
147
|
+
const data = JSON.parse(await fs_1.promises.readFile(path_1.default.join(ssoCacheDir(), file), 'utf8'));
|
|
148
|
+
if (data.clientId && data.clientSecret)
|
|
149
|
+
return data;
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
// Ignore unrelated cache files.
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
// Cache directory does not exist.
|
|
158
|
+
}
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
async function getLocalActiveAccount() {
|
|
162
|
+
try {
|
|
163
|
+
const tokenData = JSON.parse(await fs_1.promises.readFile(tokenPath(), 'utf8'));
|
|
164
|
+
if (!tokenData.refreshToken)
|
|
165
|
+
return { success: false, error: 'No refreshToken found in VPS SSO cache' };
|
|
166
|
+
return {
|
|
167
|
+
success: true,
|
|
168
|
+
data: {
|
|
169
|
+
refreshToken: tokenData.refreshToken,
|
|
170
|
+
accessToken: tokenData.accessToken,
|
|
171
|
+
authMethod: tokenData.authMethod,
|
|
172
|
+
provider: tokenData.provider
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
return { success: false, error: error instanceof Error ? error.message : 'Unable to read VPS SSO cache' };
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
async function loadKiroCredentials() {
|
|
181
|
+
try {
|
|
182
|
+
const tokenData = JSON.parse(await fs_1.promises.readFile(tokenPath(), 'utf8'));
|
|
183
|
+
if (!tokenData.refreshToken)
|
|
184
|
+
return { success: false, error: 'kiro-auth-token.json is missing refreshToken' };
|
|
185
|
+
const clientIdHash = tokenData.clientIdHash || clientIdHashForStartUrl();
|
|
186
|
+
const clientData = await findClientRegistration(clientIdHash);
|
|
187
|
+
const isSocial = tokenData.authMethod === 'social';
|
|
188
|
+
if (!isSocial && (!clientData?.clientId || !clientData.clientSecret)) {
|
|
189
|
+
return { success: false, error: 'Client registration file was not found in VPS SSO cache' };
|
|
190
|
+
}
|
|
191
|
+
const ideProfile = await readKiroIdeProfile();
|
|
192
|
+
const profileArn = resolveCredentialProfileArn({
|
|
193
|
+
authMethod: tokenData.authMethod,
|
|
194
|
+
provider: tokenData.provider,
|
|
195
|
+
profileArn: tokenData.profileArn || tokenData.profile_arn || ideProfile?.profileArn
|
|
196
|
+
});
|
|
197
|
+
return {
|
|
198
|
+
success: true,
|
|
199
|
+
data: {
|
|
200
|
+
accessToken: tokenData.accessToken || '',
|
|
201
|
+
refreshToken: tokenData.refreshToken,
|
|
202
|
+
clientId: clientData?.clientId || '',
|
|
203
|
+
clientSecret: clientData?.clientSecret || '',
|
|
204
|
+
region: tokenData.region || 'us-east-1',
|
|
205
|
+
authMethod: tokenData.authMethod || 'IdC',
|
|
206
|
+
provider: tokenData.provider || 'BuilderId',
|
|
207
|
+
profileArn,
|
|
208
|
+
startUrl: tokenData.startUrl || tokenData.start_url,
|
|
209
|
+
machineId: tokenData.machineId || tokenData.machine_id
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
catch (error) {
|
|
214
|
+
return { success: false, error: error instanceof Error ? error.message : 'Unable to load VPS Kiro credentials' };
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
async function switchAccount(credentials) {
|
|
218
|
+
try {
|
|
219
|
+
const region = credentials.region || 'us-east-1';
|
|
220
|
+
const authMethod = isSocialCredential(credentials) ? 'social' : 'IdC';
|
|
221
|
+
const provider = credentials.provider || 'BuilderId';
|
|
222
|
+
let accessToken = credentials.accessToken;
|
|
223
|
+
if (credentials.refreshToken) {
|
|
224
|
+
const refreshed = await (0, kiroAccounts_1.refreshTokenByMethod)({
|
|
225
|
+
refreshToken: credentials.refreshToken,
|
|
226
|
+
clientId: credentials.clientId,
|
|
227
|
+
clientSecret: credentials.clientSecret,
|
|
228
|
+
region,
|
|
229
|
+
authMethod
|
|
230
|
+
});
|
|
231
|
+
if (refreshed.success && refreshed.accessToken)
|
|
232
|
+
accessToken = refreshed.accessToken;
|
|
233
|
+
}
|
|
234
|
+
const startUrl = credentials.startUrl || 'https://view.awsapps.com/start';
|
|
235
|
+
const clientIdHash = clientIdHashForStartUrl(startUrl);
|
|
236
|
+
const profileArn = resolveCredentialProfileArn({ ...credentials, authMethod, provider });
|
|
237
|
+
await fs_1.promises.mkdir(ssoCacheDir(), { recursive: true });
|
|
238
|
+
const tokenData = authMethod === 'social'
|
|
239
|
+
? { accessToken, refreshToken: credentials.refreshToken, profileArn, expiresAt: new Date(Date.now() + 3600000).toISOString(), authMethod, provider }
|
|
240
|
+
: { accessToken, refreshToken: credentials.refreshToken, expiresAt: new Date(Date.now() + 3600000).toISOString(), clientIdHash, authMethod, provider, region, profileArn };
|
|
241
|
+
await fs_1.promises.writeFile(tokenPath(), JSON.stringify(tokenData, null, 2), 'utf8');
|
|
242
|
+
if (authMethod !== 'social' && credentials.clientId && credentials.clientSecret) {
|
|
243
|
+
await fs_1.promises.writeFile(path_1.default.join(ssoCacheDir(), `${clientIdHash}.json`), JSON.stringify({
|
|
244
|
+
clientId: credentials.clientId,
|
|
245
|
+
clientSecret: credentials.clientSecret,
|
|
246
|
+
expiresAt: new Date(Date.now() + 90 * 86400000).toISOString().replace('Z', ''),
|
|
247
|
+
scopes: [
|
|
248
|
+
'codewhisperer:completions',
|
|
249
|
+
'codewhisperer:analysis',
|
|
250
|
+
'codewhisperer:conversations',
|
|
251
|
+
'codewhisperer:transformations',
|
|
252
|
+
'codewhisperer:taskassist'
|
|
253
|
+
]
|
|
254
|
+
}, null, 2), 'utf8');
|
|
255
|
+
}
|
|
256
|
+
return { success: true };
|
|
257
|
+
}
|
|
258
|
+
catch (error) {
|
|
259
|
+
return { success: false, error: error instanceof Error ? error.message : 'Failed to switch VPS Kiro account' };
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
async function switchAccountCli(credentials) {
|
|
263
|
+
try {
|
|
264
|
+
const region = credentials.region || 'us-east-1';
|
|
265
|
+
const isSocial = isSocialCredential(credentials);
|
|
266
|
+
let accessToken = credentials.accessToken;
|
|
267
|
+
if (credentials.refreshToken) {
|
|
268
|
+
const refreshed = await (0, kiroAccounts_1.refreshTokenByMethod)({
|
|
269
|
+
refreshToken: credentials.refreshToken,
|
|
270
|
+
clientId: credentials.clientId,
|
|
271
|
+
clientSecret: credentials.clientSecret,
|
|
272
|
+
region,
|
|
273
|
+
authMethod: isSocial ? 'social' : undefined
|
|
274
|
+
});
|
|
275
|
+
if (refreshed.success && refreshed.accessToken)
|
|
276
|
+
accessToken = refreshed.accessToken;
|
|
277
|
+
}
|
|
278
|
+
const dbPath = cliDbPath();
|
|
279
|
+
await fs_1.promises.mkdir(path_1.default.dirname(dbPath), { recursive: true });
|
|
280
|
+
const tokenKey = isSocial ? 'kirocli:social:token' : 'kirocli:odic:token';
|
|
281
|
+
const profileArn = resolveCredentialProfileArn(credentials);
|
|
282
|
+
const tokenData = {
|
|
283
|
+
access_token: accessToken,
|
|
284
|
+
refresh_token: credentials.refreshToken,
|
|
285
|
+
expires_at: new Date(Date.now() + 3600000).toISOString(),
|
|
286
|
+
region,
|
|
287
|
+
profile_arn: profileArn
|
|
288
|
+
};
|
|
289
|
+
if (credentials.scopes)
|
|
290
|
+
tokenData.scopes = credentials.scopes;
|
|
291
|
+
const sql = [
|
|
292
|
+
'CREATE TABLE IF NOT EXISTS auth_kv (key TEXT PRIMARY KEY, value TEXT);',
|
|
293
|
+
`INSERT OR REPLACE INTO auth_kv (key, value) VALUES ('${tokenKey}', '${sqlEscape(tokenData)}');`,
|
|
294
|
+
...(credentials.clientId && credentials.clientSecret && !isSocial
|
|
295
|
+
? [`INSERT OR REPLACE INTO auth_kv (key, value) VALUES ('kirocli:odic:device-registration', '${sqlEscape({ client_id: credentials.clientId, client_secret: credentials.clientSecret, region })}');`]
|
|
296
|
+
: []),
|
|
297
|
+
...['kirocli:social:token', 'kirocli:odic:token', 'codewhisperer:odic:token']
|
|
298
|
+
.filter((key) => key !== tokenKey)
|
|
299
|
+
.map((key) => `DELETE FROM auth_kv WHERE key = '${key}';`)
|
|
300
|
+
].join('\n');
|
|
301
|
+
runSqlite(dbPath, sql);
|
|
302
|
+
return { success: true, dbPath };
|
|
303
|
+
}
|
|
304
|
+
catch (error) {
|
|
305
|
+
return { success: false, error: error instanceof Error ? error.message : 'Failed to switch VPS Kiro CLI account' };
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
async function logoutAccount() {
|
|
309
|
+
try {
|
|
310
|
+
const files = await fs_1.promises.readdir(ssoCacheDir()).catch(() => []);
|
|
311
|
+
let deletedCount = 0;
|
|
312
|
+
for (const file of files) {
|
|
313
|
+
await fs_1.promises.unlink(path_1.default.join(ssoCacheDir(), file)).then(() => { deletedCount++; }).catch(() => undefined);
|
|
314
|
+
}
|
|
315
|
+
return { success: true, deletedCount };
|
|
316
|
+
}
|
|
317
|
+
catch (error) {
|
|
318
|
+
return { success: false, error: error instanceof Error ? error.message : 'Failed to clear VPS SSO cache' };
|
|
319
|
+
}
|
|
320
|
+
}
|