diff --git a/src/auth/kiro-oauth.js b/src/auth/kiro-oauth.js index 4c9e388..ecf2168 100644 --- a/src/auth/kiro-oauth.js +++ b/src/auth/kiro-oauth.js @@ -16,7 +16,7 @@ const KIRO_OAUTH_CONFIG = { authServiceEndpoint: 'https://prod.us-east-1.auth.desktop.kiro.dev', // AWS SSO OIDC 端点 (用于 Builder ID) - ssoOIDCEndpoint: 'https://oidc.us-east-1.amazonaws.com', + ssoOIDCEndpoint: 'https://oidc.{{region}}.amazonaws.com', // AWS Builder ID 起始 URL builderIDStartURL: 'https://view.awsapps.com/start', @@ -34,8 +34,8 @@ const KIRO_OAUTH_CONFIG = { 'codewhisperer:completions', 'codewhisperer:analysis', 'codewhisperer:conversations', - 'codewhisperer:transformations', - 'codewhisperer:taskassist' + // 'codewhisperer:transformations', + // 'codewhisperer:taskassist' ], // 凭据存储(符合现有规范) @@ -252,7 +252,10 @@ async function handleKiroBuilderIDDeviceCode(currentConfig, options = {}) { console.log(`${KIRO_OAUTH_CONFIG.logPrefix} Using Builder ID Start URL: ${builderIDStartURL}`); // 1. 注册 OIDC 客户端 - const regResponse = await fetchWithProxy(`${KIRO_OAUTH_CONFIG.ssoOIDCEndpoint}/client/register`, { + const region = options.region || 'us-east-1'; + const ssoOIDCEndpoint = KIRO_OAUTH_CONFIG.ssoOIDCEndpoint.replace('{{region}}', region); + + const regResponse = await fetchWithProxy(`${ssoOIDCEndpoint}/client/register`, { method: 'POST', headers: { 'Content-Type': 'application/json', @@ -262,7 +265,7 @@ async function handleKiroBuilderIDDeviceCode(currentConfig, options = {}) { clientName: 'Kiro IDE', clientType: 'public', scopes: KIRO_OAUTH_CONFIG.scopes, - grantTypes: ['urn:ietf:params:oauth:grant-type:device_code', 'refresh_token'] + // grantTypes: ['urn:ietf:params:oauth:grant-type:device_code', 'refresh_token'] }) }, 'claude-kiro-oauth'); @@ -273,11 +276,10 @@ async function handleKiroBuilderIDDeviceCode(currentConfig, options = {}) { const regData = await regResponse.json(); // 2. 启动设备授权 - const authResponse = await fetchWithProxy(`${KIRO_OAUTH_CONFIG.ssoOIDCEndpoint}/device_authorization`, { + const authResponse = await fetchWithProxy(`${ssoOIDCEndpoint}/device_authorization`, { method: 'POST', headers: { - 'Content-Type': 'application/json', - 'User-Agent': 'KiroIDE' + 'Content-Type': 'application/json' }, body: JSON.stringify({ clientId: regData.clientId, @@ -304,7 +306,7 @@ async function handleKiroBuilderIDDeviceCode(currentConfig, options = {}) { 5, 300, taskId, - options + { ...options, region } ).catch(error => { console.error(`${KIRO_OAUTH_CONFIG.logPrefix} 轮询失败 [${taskId}]:`, error); broadcastEvent('oauth_error', { @@ -356,7 +358,9 @@ async function pollKiroBuilderIDToken(clientId, clientSecret, deviceCode, interv attempts++; try { - const response = await fetchWithProxy(`${KIRO_OAUTH_CONFIG.ssoOIDCEndpoint}/token`, { + const region = options.region || 'us-east-1'; + const ssoOIDCEndpoint = KIRO_OAUTH_CONFIG.ssoOIDCEndpoint.replace('{{region}}', region); + const response = await fetchWithProxy(`${ssoOIDCEndpoint}/token`, { method: 'POST', headers: { 'Content-Type': 'application/json', @@ -391,7 +395,7 @@ async function pollKiroBuilderIDToken(clientId, clientSecret, deviceCode, interv authMethod: 'builder-id', clientId, clientSecret, - region: 'us-east-1' + idcRegion: options.region || 'us-east-1' }; await fs.promises.mkdir(path.dirname(credPath), { recursive: true }); @@ -634,7 +638,8 @@ const KIRO_REFRESH_CONSTANTS = { AUTH_METHOD_SOCIAL: 'social', DEFAULT_PROVIDER: 'Google', REQUEST_TIMEOUT: 30000, - DEFAULT_REGION: 'us-east-1' + DEFAULT_REGION: 'us-east-1', + IDC_REGION: 'us-east-1' // 用于 REFRESH_IDC_URL 的区域配置 }; /** @@ -1024,7 +1029,8 @@ export async function importAwsCredentials(credentials, skipDuplicateCheck = fal accessToken: credentials.accessToken, refreshToken: credentials.refreshToken, authMethod: credentials.authMethod || 'builder-id', - region: credentials.region || KIRO_REFRESH_CONSTANTS.DEFAULT_REGION + // region: credentials.region || KIRO_REFRESH_CONSTANTS.DEFAULT_REGION, + idcRegion: credentials.idcRegion || KIRO_REFRESH_CONSTANTS.IDC_REGION }; // 可选字段 @@ -1042,8 +1048,8 @@ export async function importAwsCredentials(credentials, skipDuplicateCheck = fal try { console.log(`${KIRO_OAUTH_CONFIG.logPrefix} Attempting to refresh token with provided credentials...`); - const region = credentials.region || KIRO_REFRESH_CONSTANTS.DEFAULT_REGION; - const refreshUrl = KIRO_REFRESH_CONSTANTS.REFRESH_IDC_URL.replace('{{region}}', region); + const refreshRegion = credentials.idcRegion || KIRO_REFRESH_CONSTANTS.IDC_REGION; + const refreshUrl = KIRO_REFRESH_CONSTANTS.REFRESH_IDC_URL.replace('{{region}}', refreshRegion); const refreshResponse = await fetchWithProxy(refreshUrl, { method: 'POST', diff --git a/src/providers/claude/claude-kiro.js b/src/providers/claude/claude-kiro.js index 2c9996c..e77ce82 100644 --- a/src/providers/claude/claude-kiro.js +++ b/src/providers/claude/claude-kiro.js @@ -25,9 +25,7 @@ const KIRO_CONSTANTS = { REFRESH_URL: 'https://prod.{{region}}.auth.desktop.kiro.dev/refreshToken', REFRESH_IDC_URL: 'https://oidc.{{region}}.amazonaws.com/token', BASE_URL: 'https://q.{{region}}.amazonaws.com/generateAssistantResponse', - AMAZON_Q_URL: 'https://codewhisperer.{{region}}.amazonaws.com/SendMessageStreaming', - USAGE_LIMITS_URL: 'https://q.{{region}}.amazonaws.com/getUsageLimits', - DEFAULT_MODEL_NAME: 'claude-opus-4-5', + DEFAULT_MODEL_NAME: 'claude-sonnet-4-5', AXIOS_TIMEOUT: 120000, // 2 minutes timeout for normal requests TOKEN_REFRESH_TIMEOUT: 15000, // 15 seconds timeout for token refresh (shorter to avoid blocking) USER_AGENT: 'KiroIDE', @@ -49,9 +47,7 @@ const FULL_MODEL_MAPPING = { "claude-opus-4-5":"claude-opus-4.5", "claude-opus-4-5-20251101":"claude-opus-4.5", "claude-sonnet-4-5": "CLAUDE_SONNET_4_5_20250929_V1_0", - "claude-sonnet-4-5-20250929": "CLAUDE_SONNET_4_5_20250929_V1_0", - "claude-sonnet-4-20250514": "CLAUDE_SONNET_4_20250514_V1_0", - "claude-3-7-sonnet-20250219": "CLAUDE_3_7_SONNET_20250219_V1_0" + "claude-sonnet-4-5-20250929": "CLAUDE_SONNET_4_5_20250929_V1_0" }; // 只保留 KIRO_MODELS 中存在的模型映射 @@ -362,7 +358,6 @@ export class KiroApiService { // this.refreshUrl = KIRO_CONSTANTS.REFRESH_URL; // this.refreshIDCUrl = KIRO_CONSTANTS.REFRESH_IDC_URL; // this.baseUrl = KIRO_CONSTANTS.BASE_URL; - // this.amazonQUrl = KIRO_CONSTANTS.AMAZON_Q_URL; // Add kiro-oauth-creds-base64 and kiro-oauth-creds-file to config if (config.KIRO_OAUTH_CREDS_BASE64) { @@ -536,16 +531,21 @@ async loadCredentials() { this.expiresAt = this.expiresAt || mergedCredentials.expiresAt; this.profileArn = this.profileArn || mergedCredentials.profileArn; this.region = this.region || mergedCredentials.region; + this.idcRegion = this.idcRegion || mergedCredentials.idcRegion; if (!this.region) { console.warn('[Kiro Auth] Region not found in credentials. Using default region us-east-1 for URLs.'); this.region = 'us-east-1'; } + // idcRegion 用于 REFRESH_IDC_URL,如果未设置则使用 region + if (!this.idcRegion) { + this.idcRegion = this.region; + } + this.refreshUrl = (this.config.KIRO_REFRESH_URL || KIRO_CONSTANTS.REFRESH_URL).replace("{{region}}", this.region); - this.refreshIDCUrl = (this.config.KIRO_REFRESH_IDC_URL || KIRO_CONSTANTS.REFRESH_IDC_URL).replace("{{region}}", this.region); + this.refreshIDCUrl = (this.config.KIRO_REFRESH_IDC_URL || KIRO_CONSTANTS.REFRESH_IDC_URL).replace("{{region}}", this.idcRegion); this.baseUrl = (this.config.KIRO_BASE_URL || KIRO_CONSTANTS.BASE_URL).replace("{{region}}", this.region); - this.amazonQUrl = (KIRO_CONSTANTS.AMAZON_Q_URL).replace("{{region}}", this.region); } catch (error) { console.warn(`[Kiro Auth] Error during credential loading: ${error.message}`); } @@ -2724,7 +2724,8 @@ async saveCredentialsToFile(filePath, newData) { const resourceType = 'AGENTIC_REQUEST'; // 构建请求 URL - const usageLimitsUrl = KIRO_CONSTANTS.USAGE_LIMITS_URL.replace('{{region}}', this.region); + let usageLimitsUrl = this.baseUrl; + usageLimitsUrl = usageLimitsUrl.replace('generateAssistantResponse', 'getUsageLimits'); const params = new URLSearchParams({ isEmailRequired: 'true', origin: KIRO_CONSTANTS.ORIGIN_AI_EDITOR, diff --git a/static/app/i18n.js b/static/app/i18n.js index 7bfc1ae..47e9c77 100644 --- a/static/app/i18n.js +++ b/static/app/i18n.js @@ -143,7 +143,7 @@ const translations = { 'oauth.kiro.batchImportInstructions': '请输入 refreshToken,每行一个。系统将自动刷新并生成凭据文件。', 'oauth.kiro.awsImport': '导入 AWS 账号', 'oauth.kiro.awsImportDesc': '从 AWS SSO cache 目录导入凭据文件,适用于 AWS Builder ID 模式。', - 'oauth.kiro.awsImportInstructions': '请上传 AWS SSO cache 目录中的 JSON 文件,需包含 clientId、clientSecret、accessToken、refreshToken 四个字段。', + 'oauth.kiro.awsImportInstructions': '请上传 AWS SSO cache 目录中的 JSON 文件,需包含 clientId、clientSecret、accessToken、refreshToken 四个字段。如果是AWS企业用户,需增加 idcRegion 字段。', 'oauth.kiro.awsModeFile': '文件上传', 'oauth.kiro.awsModeJson': 'JSON 粘贴', 'oauth.kiro.awsUploadFiles': '上传凭据文件', @@ -856,7 +856,7 @@ const translations = { 'oauth.kiro.batchImportInstructions': 'Enter refreshTokens, one per line. The system will automatically refresh and generate credential files.', 'oauth.kiro.awsImport': 'Import AWS Account', 'oauth.kiro.awsImportDesc': 'Import credential files from AWS SSO cache directory. For AWS Builder ID mode.', - 'oauth.kiro.awsImportInstructions': 'Upload JSON files from AWS SSO cache directory. Must contain clientId, clientSecret, accessToken, and refreshToken.', + 'oauth.kiro.awsImportInstructions': 'Upload JSON files from AWS SSO cache directory. Must contain clientId, clientSecret, accessToken, and refreshToken. For AWS enterprise users, add the idcRegion field.', 'oauth.kiro.awsModeFile': 'File Upload', 'oauth.kiro.awsModeJson': 'Paste JSON', 'oauth.kiro.awsUploadFiles': 'Upload Credential Files', diff --git a/static/app/provider-manager.js b/static/app/provider-manager.js index 98641c1..f3bec46 100644 --- a/static/app/provider-manager.js +++ b/static/app/provider-manager.js @@ -1723,7 +1723,12 @@ function showAuthModal(authUrl, authInfo) {
${t('oauth.modal.provider')} ${authInfo.provider}
-${t('oauth.kiro.builderIDStartURLHint') || '如果您使用 AWS IAM Identity Center,请输入您的 Start URL'}