@zhafron/opencode-kiro-auth 1.2.8 → 1.3.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/README.md +31 -45
- package/dist/index.d.ts +1 -1
- package/dist/kiro/auth.js +15 -6
- package/dist/plugin/accounts.d.ts +2 -1
- package/dist/plugin/accounts.js +43 -20
- package/dist/plugin/cli.js +1 -1
- package/dist/plugin/config/index.d.ts +2 -2
- package/dist/plugin/config/index.js +2 -2
- package/dist/plugin/config/loader.js +3 -3
- package/dist/plugin/config/schema.d.ts +3 -0
- package/dist/plugin/config/schema.js +2 -0
- package/dist/plugin/request.d.ts +1 -1
- package/dist/plugin/request.js +10 -8
- package/dist/plugin/response.d.ts +1 -1
- package/dist/plugin/server.js +1 -1
- package/dist/plugin/storage/migration.d.ts +1 -0
- package/dist/plugin/storage/migration.js +53 -0
- package/dist/plugin/storage/sqlite.d.ts +16 -0
- package/dist/plugin/storage/sqlite.js +104 -0
- package/dist/plugin/sync/kiro-cli.d.ts +2 -0
- package/dist/plugin/sync/kiro-cli.js +96 -0
- package/dist/plugin/token.js +29 -17
- package/dist/plugin/types.d.ts +1 -27
- package/dist/plugin/usage.d.ts +1 -1
- package/dist/plugin.js +173 -249
- package/package.json +3 -2
- package/dist/plugin/storage.d.ts +0 -7
- package/dist/plugin/storage.js +0 -124
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { Database } from 'bun:sqlite';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { homedir, platform } from 'node:os';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { createDeterministicAccountId } from '../accounts';
|
|
6
|
+
import * as logger from '../logger';
|
|
7
|
+
import { kiroDb } from '../storage/sqlite';
|
|
8
|
+
function getCliDbPath() {
|
|
9
|
+
const p = platform();
|
|
10
|
+
if (p === 'win32')
|
|
11
|
+
return join(process.env.APPDATA || join(homedir(), 'AppData', 'Roaming'), 'kiro-cli', 'data.sqlite3');
|
|
12
|
+
if (p === 'darwin')
|
|
13
|
+
return join(homedir(), 'Library', 'Application Support', 'kiro-cli', 'data.sqlite3');
|
|
14
|
+
return join(homedir(), '.local', 'share', 'kiro-cli', 'data.sqlite3');
|
|
15
|
+
}
|
|
16
|
+
export async function syncFromKiroCli() {
|
|
17
|
+
const dbPath = getCliDbPath();
|
|
18
|
+
if (!existsSync(dbPath))
|
|
19
|
+
return;
|
|
20
|
+
try {
|
|
21
|
+
const cliDb = new Database(dbPath, { readonly: true });
|
|
22
|
+
cliDb.run('PRAGMA busy_timeout = 5000');
|
|
23
|
+
const rows = cliDb.prepare('SELECT key, value FROM auth_kv').all();
|
|
24
|
+
for (const row of rows) {
|
|
25
|
+
if (row.key.includes(':token')) {
|
|
26
|
+
let data;
|
|
27
|
+
try {
|
|
28
|
+
data = JSON.parse(row.value);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
if (!data.access_token)
|
|
34
|
+
continue;
|
|
35
|
+
const email = data.email || 'cli-account@kiro.dev';
|
|
36
|
+
const authMethod = row.key.includes('odic') ? 'idc' : 'desktop';
|
|
37
|
+
const clientId = data.client_id ||
|
|
38
|
+
(authMethod === 'idc'
|
|
39
|
+
? JSON.parse(rows.find((r) => r.key.includes('device-registration'))?.value || '{}')
|
|
40
|
+
.client_id
|
|
41
|
+
: undefined);
|
|
42
|
+
const clientSecret = data.client_secret ||
|
|
43
|
+
(authMethod === 'idc'
|
|
44
|
+
? JSON.parse(rows.find((r) => r.key.includes('device-registration'))?.value || '{}')
|
|
45
|
+
.client_secret
|
|
46
|
+
: undefined);
|
|
47
|
+
const id = createDeterministicAccountId(email, authMethod, clientId, data.profile_arn);
|
|
48
|
+
const existing = kiroDb.getAccounts().find((a) => a.id === id);
|
|
49
|
+
const cliExpiresAt = data.expires_at ? new Date(data.expires_at).getTime() : 0;
|
|
50
|
+
if (existing && existing.expires_at >= cliExpiresAt)
|
|
51
|
+
continue;
|
|
52
|
+
kiroDb.upsertAccount({
|
|
53
|
+
id,
|
|
54
|
+
email,
|
|
55
|
+
realEmail: data.real_email || email,
|
|
56
|
+
authMethod,
|
|
57
|
+
region: data.region || 'us-east-1',
|
|
58
|
+
clientId,
|
|
59
|
+
clientSecret,
|
|
60
|
+
profileArn: data.profile_arn,
|
|
61
|
+
refreshToken: data.refresh_token,
|
|
62
|
+
accessToken: data.access_token,
|
|
63
|
+
expiresAt: cliExpiresAt || Date.now() + 3600000,
|
|
64
|
+
isHealthy: 1
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
cliDb.close();
|
|
69
|
+
}
|
|
70
|
+
catch (e) {
|
|
71
|
+
logger.error('Sync failed', e);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
export async function writeToKiroCli(acc) {
|
|
75
|
+
const dbPath = getCliDbPath();
|
|
76
|
+
if (!existsSync(dbPath))
|
|
77
|
+
return;
|
|
78
|
+
try {
|
|
79
|
+
const cliDb = new Database(dbPath);
|
|
80
|
+
cliDb.exec('PRAGMA busy_timeout = 5000');
|
|
81
|
+
const rows = cliDb.prepare('SELECT key, value FROM auth_kv').all();
|
|
82
|
+
const targetKey = acc.authMethod === 'idc' ? 'kirocli:odic:token' : 'kirocli:social:token';
|
|
83
|
+
const row = rows.find((r) => r.key === targetKey || r.key.endsWith(targetKey));
|
|
84
|
+
if (row) {
|
|
85
|
+
const data = JSON.parse(row.value);
|
|
86
|
+
data.access_token = acc.accessToken;
|
|
87
|
+
data.refresh_token = acc.refreshToken;
|
|
88
|
+
data.expires_at = new Date(acc.expiresAt).toISOString();
|
|
89
|
+
cliDb.prepare('UPDATE auth_kv SET value = ? WHERE key = ?').run(JSON.stringify(data), row.key);
|
|
90
|
+
}
|
|
91
|
+
cliDb.close();
|
|
92
|
+
}
|
|
93
|
+
catch (e) {
|
|
94
|
+
logger.warn('Write back failed', e);
|
|
95
|
+
}
|
|
96
|
+
}
|
package/dist/plugin/token.js
CHANGED
|
@@ -1,17 +1,30 @@
|
|
|
1
|
-
import
|
|
1
|
+
import crypto from 'node:crypto';
|
|
2
2
|
import { decodeRefreshToken, encodeRefreshToken } from '../kiro/auth';
|
|
3
|
+
import { KiroTokenRefreshError } from './errors';
|
|
3
4
|
export async function refreshAccessToken(auth) {
|
|
4
|
-
const url = `https://oidc.${auth.region}.amazonaws.com/token`;
|
|
5
5
|
const p = decodeRefreshToken(auth.refresh);
|
|
6
|
-
|
|
6
|
+
const isIdc = auth.authMethod === 'idc';
|
|
7
|
+
const url = isIdc
|
|
8
|
+
? `https://oidc.${auth.region}.amazonaws.com/token`
|
|
9
|
+
: `https://prod.${auth.region}.auth.desktop.kiro.dev/refreshToken`;
|
|
10
|
+
if (isIdc && (!p.clientId || !p.clientSecret)) {
|
|
7
11
|
throw new KiroTokenRefreshError('Missing creds', 'MISSING_CREDENTIALS');
|
|
8
12
|
}
|
|
9
|
-
const requestBody =
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
const requestBody = isIdc
|
|
14
|
+
? {
|
|
15
|
+
refreshToken: p.refreshToken,
|
|
16
|
+
clientId: p.clientId,
|
|
17
|
+
clientSecret: p.clientSecret,
|
|
18
|
+
grantType: 'refresh_token'
|
|
19
|
+
}
|
|
20
|
+
: {
|
|
21
|
+
refreshToken: p.refreshToken
|
|
22
|
+
};
|
|
23
|
+
const machineId = crypto
|
|
24
|
+
.createHash('sha256')
|
|
25
|
+
.update(auth.profileArn || auth.clientId || 'KIRO_DEFAULT_MACHINE')
|
|
26
|
+
.digest('hex');
|
|
27
|
+
const ua = isIdc ? 'aws-sdk-js/1.0.0' : `KiroIDE-0.7.45-${machineId}`;
|
|
15
28
|
try {
|
|
16
29
|
const res = await fetch(url, {
|
|
17
30
|
method: 'POST',
|
|
@@ -20,6 +33,7 @@ export async function refreshAccessToken(auth) {
|
|
|
20
33
|
Accept: 'application/json',
|
|
21
34
|
'amz-sdk-request': 'attempt=1; max=1',
|
|
22
35
|
'x-amzn-kiro-agent-mode': 'vibe',
|
|
36
|
+
'user-agent': ua,
|
|
23
37
|
Connection: 'close'
|
|
24
38
|
},
|
|
25
39
|
body: JSON.stringify(requestBody)
|
|
@@ -37,30 +51,28 @@ export async function refreshAccessToken(auth) {
|
|
|
37
51
|
}
|
|
38
52
|
const d = await res.json();
|
|
39
53
|
const acc = d.access_token || d.accessToken;
|
|
40
|
-
if (!acc)
|
|
54
|
+
if (!acc)
|
|
41
55
|
throw new KiroTokenRefreshError('No access token', 'INVALID_RESPONSE');
|
|
42
|
-
}
|
|
43
56
|
const upP = {
|
|
44
57
|
refreshToken: d.refresh_token || d.refreshToken || p.refreshToken,
|
|
45
58
|
clientId: p.clientId,
|
|
46
59
|
clientSecret: p.clientSecret,
|
|
47
|
-
authMethod:
|
|
60
|
+
authMethod: auth.authMethod
|
|
48
61
|
};
|
|
49
62
|
return {
|
|
50
63
|
refresh: encodeRefreshToken(upP),
|
|
51
64
|
access: acc,
|
|
52
|
-
expires: Date.now() + (d.expires_in || 3600) * 1000,
|
|
53
|
-
authMethod:
|
|
65
|
+
expires: Date.now() + (d.expires_in || d.expiresIn || 3600) * 1000,
|
|
66
|
+
authMethod: auth.authMethod,
|
|
54
67
|
region: auth.region,
|
|
55
68
|
clientId: auth.clientId,
|
|
56
69
|
clientSecret: auth.clientSecret,
|
|
57
|
-
email: auth.email
|
|
70
|
+
email: auth.email || d.userInfo?.email
|
|
58
71
|
};
|
|
59
72
|
}
|
|
60
73
|
catch (error) {
|
|
61
|
-
if (error instanceof KiroTokenRefreshError)
|
|
74
|
+
if (error instanceof KiroTokenRefreshError)
|
|
62
75
|
throw error;
|
|
63
|
-
}
|
|
64
76
|
throw new KiroTokenRefreshError(`Token refresh failed: ${error instanceof Error ? error.message : 'Unknown error'}`, 'NETWORK_ERROR', error instanceof Error ? error : undefined);
|
|
65
77
|
}
|
|
66
78
|
}
|
package/dist/plugin/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type KiroAuthMethod = 'idc';
|
|
1
|
+
export type KiroAuthMethod = 'idc' | 'desktop';
|
|
2
2
|
export type KiroRegion = 'us-east-1' | 'us-west-2';
|
|
3
3
|
export interface KiroAuthDetails {
|
|
4
4
|
refresh: string;
|
|
@@ -38,38 +38,12 @@ export interface ManagedAccount {
|
|
|
38
38
|
limitCount?: number;
|
|
39
39
|
lastUsed?: number;
|
|
40
40
|
}
|
|
41
|
-
export interface AccountMetadata {
|
|
42
|
-
id: string;
|
|
43
|
-
email: string;
|
|
44
|
-
realEmail?: string;
|
|
45
|
-
authMethod: KiroAuthMethod;
|
|
46
|
-
region: KiroRegion;
|
|
47
|
-
clientId?: string;
|
|
48
|
-
clientSecret?: string;
|
|
49
|
-
profileArn?: string;
|
|
50
|
-
refreshToken: string;
|
|
51
|
-
accessToken: string;
|
|
52
|
-
expiresAt: number;
|
|
53
|
-
rateLimitResetTime: number;
|
|
54
|
-
isHealthy: boolean;
|
|
55
|
-
unhealthyReason?: string;
|
|
56
|
-
recoveryTime?: number;
|
|
57
|
-
}
|
|
58
|
-
export interface AccountStorage {
|
|
59
|
-
version: 1;
|
|
60
|
-
accounts: AccountMetadata[];
|
|
61
|
-
activeIndex: number;
|
|
62
|
-
}
|
|
63
41
|
export interface UsageMetadata {
|
|
64
42
|
usedCount: number;
|
|
65
43
|
limitCount: number;
|
|
66
44
|
realEmail?: string;
|
|
67
45
|
lastSync: number;
|
|
68
46
|
}
|
|
69
|
-
export interface UsageStorage {
|
|
70
|
-
version: 1;
|
|
71
|
-
usage: Record<string, UsageMetadata>;
|
|
72
|
-
}
|
|
73
47
|
export interface CodeWhispererMessage {
|
|
74
48
|
userInputMessage?: {
|
|
75
49
|
content: string;
|
package/dist/plugin/usage.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { KiroAuthDetails, ManagedAccount } from './types';
|
|
2
2
|
export declare function fetchUsageLimits(auth: KiroAuthDetails): Promise<any>;
|
|
3
3
|
export declare function updateAccountQuota(account: ManagedAccount, usage: any, accountManager?: any): void;
|