mirror of
https://github.com/router-for-me/CLIProxyAPIPlus.git
synced 2026-03-30 01:06:39 +00:00
238 lines
6.8 KiB
Go
238 lines
6.8 KiB
Go
// 测试脚本 2:模拟 kiro2Api_js 的认证方式
|
||
// 这个脚本完整模拟 kiro-gateway/temp/kiro2Api_js 的认证逻辑
|
||
// 运行方式: go run test_auth_js_style.go
|
||
package main
|
||
|
||
import (
|
||
"bytes"
|
||
"encoding/json"
|
||
"fmt"
|
||
"io"
|
||
"net/http"
|
||
"os"
|
||
"path/filepath"
|
||
"strings"
|
||
"time"
|
||
)
|
||
|
||
// 常量 - 来自 kiro2Api_js/src/kiro/auth.js
|
||
const (
|
||
REFRESH_URL_TEMPLATE = "https://prod.{{region}}.auth.desktop.kiro.dev/refreshToken"
|
||
REFRESH_IDC_URL_TEMPLATE = "https://oidc.{{region}}.amazonaws.com/token"
|
||
AUTH_METHOD_SOCIAL = "social"
|
||
AUTH_METHOD_IDC = "IdC"
|
||
)
|
||
|
||
func main() {
|
||
fmt.Println("=" + strings.Repeat("=", 59))
|
||
fmt.Println(" 测试脚本 2: kiro2Api_js 风格认证")
|
||
fmt.Println("=" + strings.Repeat("=", 59))
|
||
|
||
// Step 1: 加载 token 文件
|
||
fmt.Println("\n[Step 1] 加载 Token 文件")
|
||
fmt.Println("-" + strings.Repeat("-", 59))
|
||
|
||
tokenPaths := []string{
|
||
filepath.Join(os.Getenv("USERPROFILE"), ".aws", "sso", "cache", "kiro-auth-token.json"),
|
||
"E:/ai_project_2api/kiro-gateway/configs/kiro/kiro-auth-token-1768317098.json",
|
||
}
|
||
|
||
var tokenData map[string]interface{}
|
||
var loadedPath string
|
||
|
||
for _, p := range tokenPaths {
|
||
data, err := os.ReadFile(p)
|
||
if err == nil {
|
||
if err := json.Unmarshal(data, &tokenData); err == nil {
|
||
loadedPath = p
|
||
break
|
||
}
|
||
}
|
||
}
|
||
|
||
if tokenData == nil {
|
||
fmt.Println("❌ 无法加载任何 token 文件")
|
||
return
|
||
}
|
||
|
||
fmt.Printf("✅ 加载文件: %s\n", loadedPath)
|
||
|
||
// 提取字段 - 模拟 kiro2Api_js/src/kiro/auth.js initializeAuth
|
||
accessToken, _ := tokenData["accessToken"].(string)
|
||
refreshToken, _ := tokenData["refreshToken"].(string)
|
||
clientId, _ := tokenData["clientId"].(string)
|
||
clientSecret, _ := tokenData["clientSecret"].(string)
|
||
authMethod, _ := tokenData["authMethod"].(string)
|
||
region, _ := tokenData["region"].(string)
|
||
|
||
if region == "" {
|
||
region = "us-east-1"
|
||
fmt.Println("⚠️ Region 未设置,使用默认值 us-east-1")
|
||
}
|
||
|
||
fmt.Printf("\nToken 信息:\n")
|
||
fmt.Printf(" AuthMethod: %s\n", authMethod)
|
||
fmt.Printf(" Region: %s\n", region)
|
||
fmt.Printf(" 有 ClientID: %v\n", clientId != "")
|
||
fmt.Printf(" 有 ClientSecret: %v\n", clientSecret != "")
|
||
|
||
// Step 2: 测试当前 token
|
||
fmt.Println("\n[Step 2] 测试当前 AccessToken")
|
||
fmt.Println("-" + strings.Repeat("-", 59))
|
||
|
||
if testAPI(accessToken, region) {
|
||
fmt.Println("✅ 当前 AccessToken 有效")
|
||
return
|
||
}
|
||
|
||
fmt.Println("⚠️ 当前 AccessToken 无效,开始刷新...")
|
||
|
||
// Step 3: 根据 authMethod 选择刷新方式 - 模拟 doRefreshToken
|
||
fmt.Println("\n[Step 3] 刷新 Token (JS 风格)")
|
||
fmt.Println("-" + strings.Repeat("-", 59))
|
||
|
||
var refreshURL string
|
||
var requestBody map[string]interface{}
|
||
|
||
// 判断认证方式 - 模拟 kiro2Api_js auth.js doRefreshToken
|
||
if authMethod == AUTH_METHOD_SOCIAL {
|
||
// Social 认证
|
||
refreshURL = strings.Replace(REFRESH_URL_TEMPLATE, "{{region}}", region, 1)
|
||
requestBody = map[string]interface{}{
|
||
"refreshToken": refreshToken,
|
||
}
|
||
fmt.Println("使用 Social 认证方式")
|
||
} else {
|
||
// IdC 认证 (默认)
|
||
refreshURL = strings.Replace(REFRESH_IDC_URL_TEMPLATE, "{{region}}", region, 1)
|
||
requestBody = map[string]interface{}{
|
||
"refreshToken": refreshToken,
|
||
"clientId": clientId,
|
||
"clientSecret": clientSecret,
|
||
"grantType": "refresh_token",
|
||
}
|
||
fmt.Println("使用 IdC 认证方式")
|
||
}
|
||
|
||
fmt.Printf("刷新 URL: %s\n", refreshURL)
|
||
fmt.Printf("请求字段: %v\n", getKeys(requestBody))
|
||
|
||
// 发送刷新请求
|
||
body, _ := json.Marshal(requestBody)
|
||
req, _ := http.NewRequest("POST", refreshURL, bytes.NewBuffer(body))
|
||
req.Header.Set("Content-Type", "application/json")
|
||
|
||
client := &http.Client{Timeout: 30 * time.Second}
|
||
resp, err := client.Do(req)
|
||
if err != nil {
|
||
fmt.Printf("❌ 请求失败: %v\n", err)
|
||
return
|
||
}
|
||
defer resp.Body.Close()
|
||
|
||
respBody, _ := io.ReadAll(resp.Body)
|
||
|
||
fmt.Printf("\n响应状态: HTTP %d\n", resp.StatusCode)
|
||
|
||
if resp.StatusCode != 200 {
|
||
fmt.Printf("❌ 刷新失败: %s\n", string(respBody))
|
||
|
||
// 分析错误
|
||
var errResp map[string]interface{}
|
||
if err := json.Unmarshal(respBody, &errResp); err == nil {
|
||
if errType, ok := errResp["error"].(string); ok {
|
||
fmt.Printf("错误类型: %s\n", errType)
|
||
if errType == "invalid_grant" {
|
||
fmt.Println("\n💡 提示: refresh_token 可能已过期,需要重新授权")
|
||
}
|
||
}
|
||
if errDesc, ok := errResp["error_description"].(string); ok {
|
||
fmt.Printf("错误描述: %s\n", errDesc)
|
||
}
|
||
}
|
||
return
|
||
}
|
||
|
||
// 解析响应
|
||
var refreshResp map[string]interface{}
|
||
json.Unmarshal(respBody, &refreshResp)
|
||
|
||
newAccessToken, _ := refreshResp["accessToken"].(string)
|
||
newRefreshToken, _ := refreshResp["refreshToken"].(string)
|
||
expiresIn, _ := refreshResp["expiresIn"].(float64)
|
||
|
||
fmt.Println("✅ Token 刷新成功!")
|
||
fmt.Printf(" 新 AccessToken: %s...\n", truncate(newAccessToken, 50))
|
||
fmt.Printf(" ExpiresIn: %.0f 秒\n", expiresIn)
|
||
if newRefreshToken != "" {
|
||
fmt.Printf(" 新 RefreshToken: %s...\n", truncate(newRefreshToken, 50))
|
||
}
|
||
|
||
// Step 4: 验证新 token
|
||
fmt.Println("\n[Step 4] 验证新 Token")
|
||
fmt.Println("-" + strings.Repeat("-", 59))
|
||
|
||
if testAPI(newAccessToken, region) {
|
||
fmt.Println("✅ 新 Token 验证成功!")
|
||
|
||
// 保存新 token - 模拟 saveCredentialsToFile
|
||
tokenData["accessToken"] = newAccessToken
|
||
if newRefreshToken != "" {
|
||
tokenData["refreshToken"] = newRefreshToken
|
||
}
|
||
tokenData["expiresAt"] = time.Now().Add(time.Duration(expiresIn) * time.Second).Format(time.RFC3339)
|
||
|
||
saveData, _ := json.MarshalIndent(tokenData, "", " ")
|
||
newPath := strings.TrimSuffix(loadedPath, ".json") + "_js_refreshed.json"
|
||
os.WriteFile(newPath, saveData, 0644)
|
||
fmt.Printf("✅ 已保存到: %s\n", newPath)
|
||
} else {
|
||
fmt.Println("❌ 新 Token 验证失败")
|
||
}
|
||
|
||
fmt.Println("\n" + strings.Repeat("=", 60))
|
||
fmt.Println(" 测试完成")
|
||
fmt.Println(strings.Repeat("=", 60))
|
||
}
|
||
|
||
func testAPI(accessToken, region string) bool {
|
||
url := fmt.Sprintf("https://codewhisperer.%s.amazonaws.com", region)
|
||
|
||
payload := map[string]interface{}{
|
||
"origin": "AI_EDITOR",
|
||
"isEmailRequired": true,
|
||
"resourceType": "AGENTIC_REQUEST",
|
||
}
|
||
body, _ := json.Marshal(payload)
|
||
|
||
req, _ := http.NewRequest("POST", url, bytes.NewBuffer(body))
|
||
req.Header.Set("Content-Type", "application/x-amz-json-1.0")
|
||
req.Header.Set("x-amz-target", "AmazonCodeWhispererService.GetUsageLimits")
|
||
req.Header.Set("Authorization", "Bearer "+accessToken)
|
||
req.Header.Set("Accept", "application/json")
|
||
|
||
client := &http.Client{Timeout: 30 * time.Second}
|
||
resp, err := client.Do(req)
|
||
if err != nil {
|
||
return false
|
||
}
|
||
defer resp.Body.Close()
|
||
|
||
return resp.StatusCode == 200
|
||
}
|
||
|
||
func getKeys(m map[string]interface{}) []string {
|
||
keys := make([]string, 0, len(m))
|
||
for k := range m {
|
||
keys = append(keys, k)
|
||
}
|
||
return keys
|
||
}
|
||
|
||
func truncate(s string, n int) string {
|
||
if len(s) <= n {
|
||
return s
|
||
}
|
||
return s[:n]
|
||
}
|