Unified · Split
| @@ -1148,13 +1148,9 @@ func (h *Handler) RequestGeminiCLIToken(c *gin.Context) { · 1147 unmodified lines | |||
| 1148 | } | 1148 | } |
| 1149 | 1149 | ||
| 1150 | ifToken["token_uri"] = "https://oauth2.googleapis.com/token" | 1150 | ifToken["token_uri"] = "https://oauth2.googleapis.com/token" |
| 1151 | ifToken["client_id"] = "681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com" | 1151 | ifToken["client_id"] = geminiAuth.ClientID |
| 1152 | ifToken["client_secret"] = "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" | 1152 | ifToken["client_secret"] = geminiAuth.ClientSecret |
| 1153 | ifToken["scopes"] = []string{ | 1153 | ifToken["scopes"] = geminiAuth.Scopes |
| 1154 | "https://www.googleapis.com/auth/cloud-platform", | ||
| 1155 | "https://www.googleapis.com/auth/userinfo.email", | ||
| 1156 | "https://www.googleapis.com/auth/userinfo.profile", | ||
| 1157 | } | ||
| 1158 | ifToken["universe_domain"] = "googleapis.com" | 1154 | ifToken["universe_domain"] = "googleapis.com" |
| 1159 | 1155 | ||
| 1160 | ts := geminiAuth.GeminiTokenStorage{ | 1156 | ts := geminiAuth.GeminiTokenStorage{ |
| @@ -1478,20 +1474,29 @@ func (h *Handler) RequestAntigravityToken(c *gin.Context) { · 317 unmodified lines | |||
| 1478 | return | 1474 | return |
| 1479 | } | 1475 | } |
| 1480 | 1476 | ||
| 1481 | email := "" | 1477 | accessToken := strings.TrimSpace(tokenResp.AccessToken) |
| 1482 | if strings.TrimSpace(tokenResp.AccessToken) != "" { | 1478 | if accessToken == "" { |
| 1483 | fetchedEmail, errInfo := authSvc.FetchUserInfo(ctx, tokenResp.AccessToken) | 1479 | log.Error("antigravity: token exchange returned empty access token") |
| 1484 | if errInfo != nil { | 1480 | SetOAuthSessionError(state, "Failed to exchange token") |
| 1485 | log.Errorf("Failed to fetch user info: %v", errInfo) | 1481 | return |
| 1486 | SetOAuthSessionError(state, "Failed to fetch user info") | 1482 | } |
| 1487 | return | 1483 | |
| 1488 | } | 1484 | email, errInfo := authSvc.FetchUserInfo(ctx, accessToken) |
| 1489 | email = strings.TrimSpace(fetchedEmail) | 1485 | if errInfo != nil { |
| 1486 | log.Errorf("Failed to fetch user info: %v", errInfo) | ||
| 1487 | SetOAuthSessionError(state, "Failed to fetch user info") | ||
| 1488 | return | ||
| 1489 | } | ||
| 1490 | email = strings.TrimSpace(email) | ||
| 1491 | if email == "" { | ||
| 1492 | log.Error("antigravity: user info returned empty email") | ||
| 1493 | SetOAuthSessionError(state, "Failed to fetch user info") | ||
| 1494 | return | ||
| 1490 | } | 1495 | } |
| 1491 | 1496 | ||
| 1492 | projectID := "" | 1497 | projectID := "" |
| 1493 | if strings.TrimSpace(tokenResp.AccessToken) != "" { | 1498 | if accessToken != "" { |
| 1494 | fetchedProjectID, errProject := authSvc.FetchProjectID(ctx, tokenResp.AccessToken) | 1499 | fetchedProjectID, errProject := authSvc.FetchProjectID(ctx, accessToken) |
| 1495 | if errProject != nil { | 1500 | if errProject != nil { |
| 1496 | log.Warnf("antigravity: failed to fetch project ID: %v", errProject) | 1501 | log.Warnf("antigravity: failed to fetch project ID: %v", errProject) |
| 1497 | } else { | 1502 | } else { |
| @@ -100,18 +100,19 @@ func (o *AntigravityAuth) ExchangeCodeForTokens(ctx context.Context, code, redir · 99 unmodified lines | |||
| 100 | 100 | ||
| 101 | // FetchUserInfo retrieves user email from Google | 101 | // FetchUserInfo retrieves user email from Google |
| 102 | func (o *AntigravityAuth) FetchUserInfo(ctx context.Context, accessToken string) (string, error) { | 102 | func (o *AntigravityAuth) FetchUserInfo(ctx context.Context, accessToken string) (string, error) { |
| 103 | if strings.TrimSpace(accessToken) == "" { | 103 | accessToken = strings.TrimSpace(accessToken) |
| 104 | return "", nil | 104 | if accessToken == "" { |
| 105 | return "", fmt.Errorf("antigravity userinfo: missing access token") | ||
| 105 | } | 106 | } |
| 106 | req, err := http.NewRequestWithContext(ctx, http.MethodGet, UserInfoEndpoint, nil) | 107 | req, err := http.NewRequestWithContext(ctx, http.MethodGet, UserInfoEndpoint, nil) |
| 107 | if err != nil { | 108 | if err != nil { |
| 108 | return "", err | 109 | return "", fmt.Errorf("antigravity userinfo: create request: %w", err) |
| 109 | } | 110 | } |
| 110 | req.Header.Set("Authorization", "Bearer "+accessToken) | 111 | req.Header.Set("Authorization", "Bearer "+accessToken) |
| 111 | 112 | ||
| 112 | resp, errDo := o.httpClient.Do(req) | 113 | resp, errDo := o.httpClient.Do(req) |
| 113 | if errDo != nil { | 114 | if errDo != nil { |
| 114 | return "", errDo | 115 | return "", fmt.Errorf("antigravity userinfo: execute request: %w", errDo) |
| 115 | } | 116 | } |
| 116 | defer func() { | 117 | defer func() { |
| 117 | if errClose := resp.Body.Close(); errClose != nil { | 118 | if errClose := resp.Body.Close(); errClose != nil { |
| @@ -120,13 +121,25 @@ func (o *AntigravityAuth) FetchUserInfo(ctx context.Context, accessToken string) · 2 unmodified lines | |||
| 120 | }() | 121 | }() |
| 121 | 122 | ||
| 122 | if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices { | 123 | if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices { |
| 123 | return "", nil | 124 | bodyBytes, errRead := io.ReadAll(io.LimitReader(resp.Body, 8<<10)) |
| 125 | if errRead != nil { | ||
| 126 | return "", fmt.Errorf("antigravity userinfo: read response: %w", errRead) | ||
| 127 | } | ||
| 128 | body := strings.TrimSpace(string(bodyBytes)) | ||
| 129 | if body == "" { | ||
| 130 | return "", fmt.Errorf("antigravity userinfo: request failed: status %d", resp.StatusCode) | ||
| 131 | } | ||
| 132 | return "", fmt.Errorf("antigravity userinfo: request failed: status %d: %s", resp.StatusCode, body) | ||
| 124 | } | 133 | } |
| 125 | var info userInfo | 134 | var info userInfo |
| 126 | if errDecode := json.NewDecoder(resp.Body).Decode(&info); errDecode != nil { | 135 | if errDecode := json.NewDecoder(resp.Body).Decode(&info); errDecode != nil { |
| 127 | return "", errDecode | 136 | return "", fmt.Errorf("antigravity userinfo: decode response: %w", errDecode) |
| 137 | } | ||
| 138 | email := strings.TrimSpace(info.Email) | ||
| 139 | if email == "" { | ||
| 140 | return "", fmt.Errorf("antigravity userinfo: response missing email") | ||
| 128 | } | 141 | } |
| 129 | return info.Email, nil | 142 | return email, nil |
| 130 | } | 143 | } |
| 131 | 144 | ||
| 132 | // FetchProjectID retrieves the project ID for the authenticated user via loadCodeAssist | 145 | // FetchProjectID retrieves the project ID for the authenticated user via loadCodeAssist |
| @@ -153,17 +153,24 @@ waitForCallback: · 152 unmodified lines | |||
| 153 | return nil, fmt.Errorf("antigravity: token exchange failed: %w", errToken) | 153 | return nil, fmt.Errorf("antigravity: token exchange failed: %w", errToken) |
| 154 | } | 154 | } |
| 155 | 155 | ||
| 156 | email := "" | 156 | accessToken := strings.TrimSpace(tokenResp.AccessToken) |
| 157 | if tokenResp.AccessToken != "" { | 157 | if accessToken == "" { |
| 158 | if fetchedEmail, errInfo := authSvc.FetchUserInfo(ctx, tokenResp.AccessToken); errInfo == nil && strings.TrimSpace(fetchedEmail) != "" { | 158 | return nil, fmt.Errorf("antigravity: token exchange returned empty access token") |
| 159 | email = strings.TrimSpace(fetchedEmail) | 159 | } |
| 160 | } | 160 | |
| 161 | email, errInfo := authSvc.FetchUserInfo(ctx, accessToken) | ||
| 162 | if errInfo != nil { | ||
| 163 | return nil, fmt.Errorf("antigravity: fetch user info failed: %w", errInfo) | ||
| 164 | } | ||
| 165 | email = strings.TrimSpace(email) | ||
| 166 | if email == "" { | ||
| 167 | return nil, fmt.Errorf("antigravity: empty email returned from user info") | ||
| 161 | } | 168 | } |
| 162 | 169 | ||
| 163 | // Fetch project ID via loadCodeAssist (same approach as Gemini CLI) | 170 | // Fetch project ID via loadCodeAssist (same approach as Gemini CLI) |
| 164 | projectID := "" | 171 | projectID := "" |
| 165 | if tokenResp.AccessToken != "" { | 172 | if accessToken != "" { |
| 166 | fetchedProjectID, errProject := authSvc.FetchProjectID(ctx, tokenResp.AccessToken) | 173 | fetchedProjectID, errProject := authSvc.FetchProjectID(ctx, accessToken) |
| 167 | if errProject != nil { | 174 | if errProject != nil { |
| 168 | log.Warnf("antigravity: failed to fetch project ID: %v", errProject) | 175 | log.Warnf("antigravity: failed to fetch project ID: %v", errProject) |
| 169 | } else { | 176 | } else { |