From e95be104854b15744d311a29f307dc31a1086b4d Mon Sep 17 00:00:00 2001 From: hkfires <10558748+hkfires@users.noreply.github.com> Date: Sat, 24 Jan 2026 08:33:25 +0800 Subject: [PATCH] fix(auth): validate antigravity token userinfo email --- .../api/handlers/management/auth_files.go | 41 +++++++++++-------- internal/auth/antigravity/auth.go | 27 ++++++++---- sdk/auth/antigravity.go | 21 ++++++---- 3 files changed, 57 insertions(+), 32 deletions(-) diff --git a/internal/api/handlers/management/auth_files.go b/internal/api/handlers/management/auth_files.go index a36dbe20..996ea1a7 100644 --- a/internal/api/handlers/management/auth_files.go +++ b/internal/api/handlers/management/auth_files.go @@ -1148,13 +1148,9 @@ func (h *Handler) RequestGeminiCLIToken(c *gin.Context) { } ifToken["token_uri"] = "https://oauth2.googleapis.com/token" - ifToken["client_id"] = "681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com" - ifToken["client_secret"] = "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" - ifToken["scopes"] = []string{ - "https://www.googleapis.com/auth/cloud-platform", - "https://www.googleapis.com/auth/userinfo.email", - "https://www.googleapis.com/auth/userinfo.profile", - } + ifToken["client_id"] = geminiAuth.ClientID + ifToken["client_secret"] = geminiAuth.ClientSecret + ifToken["scopes"] = geminiAuth.Scopes ifToken["universe_domain"] = "googleapis.com" ts := geminiAuth.GeminiTokenStorage{ @@ -1478,20 +1474,29 @@ func (h *Handler) RequestAntigravityToken(c *gin.Context) { return } - email := "" - if strings.TrimSpace(tokenResp.AccessToken) != "" { - fetchedEmail, errInfo := authSvc.FetchUserInfo(ctx, tokenResp.AccessToken) - if errInfo != nil { - log.Errorf("Failed to fetch user info: %v", errInfo) - SetOAuthSessionError(state, "Failed to fetch user info") - return - } - email = strings.TrimSpace(fetchedEmail) + accessToken := strings.TrimSpace(tokenResp.AccessToken) + if accessToken == "" { + log.Error("antigravity: token exchange returned empty access token") + SetOAuthSessionError(state, "Failed to exchange token") + return + } + + email, errInfo := authSvc.FetchUserInfo(ctx, accessToken) + if errInfo != nil { + log.Errorf("Failed to fetch user info: %v", errInfo) + SetOAuthSessionError(state, "Failed to fetch user info") + return + } + email = strings.TrimSpace(email) + if email == "" { + log.Error("antigravity: user info returned empty email") + SetOAuthSessionError(state, "Failed to fetch user info") + return } projectID := "" - if strings.TrimSpace(tokenResp.AccessToken) != "" { - fetchedProjectID, errProject := authSvc.FetchProjectID(ctx, tokenResp.AccessToken) + if accessToken != "" { + fetchedProjectID, errProject := authSvc.FetchProjectID(ctx, accessToken) if errProject != nil { log.Warnf("antigravity: failed to fetch project ID: %v", errProject) } else { diff --git a/internal/auth/antigravity/auth.go b/internal/auth/antigravity/auth.go index a85aa5e9..409f222a 100644 --- a/internal/auth/antigravity/auth.go +++ b/internal/auth/antigravity/auth.go @@ -100,18 +100,19 @@ func (o *AntigravityAuth) ExchangeCodeForTokens(ctx context.Context, code, redir // FetchUserInfo retrieves user email from Google func (o *AntigravityAuth) FetchUserInfo(ctx context.Context, accessToken string) (string, error) { - if strings.TrimSpace(accessToken) == "" { - return "", nil + accessToken = strings.TrimSpace(accessToken) + if accessToken == "" { + return "", fmt.Errorf("antigravity userinfo: missing access token") } req, err := http.NewRequestWithContext(ctx, http.MethodGet, UserInfoEndpoint, nil) if err != nil { - return "", err + return "", fmt.Errorf("antigravity userinfo: create request: %w", err) } req.Header.Set("Authorization", "Bearer "+accessToken) resp, errDo := o.httpClient.Do(req) if errDo != nil { - return "", errDo + return "", fmt.Errorf("antigravity userinfo: execute request: %w", errDo) } defer func() { if errClose := resp.Body.Close(); errClose != nil { @@ -120,13 +121,25 @@ func (o *AntigravityAuth) FetchUserInfo(ctx context.Context, accessToken string) }() if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices { - return "", nil + bodyBytes, errRead := io.ReadAll(io.LimitReader(resp.Body, 8<<10)) + if errRead != nil { + return "", fmt.Errorf("antigravity userinfo: read response: %w", errRead) + } + body := strings.TrimSpace(string(bodyBytes)) + if body == "" { + return "", fmt.Errorf("antigravity userinfo: request failed: status %d", resp.StatusCode) + } + return "", fmt.Errorf("antigravity userinfo: request failed: status %d: %s", resp.StatusCode, body) } var info userInfo if errDecode := json.NewDecoder(resp.Body).Decode(&info); errDecode != nil { - return "", errDecode + return "", fmt.Errorf("antigravity userinfo: decode response: %w", errDecode) } - return info.Email, nil + email := strings.TrimSpace(info.Email) + if email == "" { + return "", fmt.Errorf("antigravity userinfo: response missing email") + } + return email, nil } // FetchProjectID retrieves the project ID for the authenticated user via loadCodeAssist diff --git a/sdk/auth/antigravity.go b/sdk/auth/antigravity.go index 7281fdb8..ecca0a00 100644 --- a/sdk/auth/antigravity.go +++ b/sdk/auth/antigravity.go @@ -153,17 +153,24 @@ waitForCallback: return nil, fmt.Errorf("antigravity: token exchange failed: %w", errToken) } - email := "" - if tokenResp.AccessToken != "" { - if fetchedEmail, errInfo := authSvc.FetchUserInfo(ctx, tokenResp.AccessToken); errInfo == nil && strings.TrimSpace(fetchedEmail) != "" { - email = strings.TrimSpace(fetchedEmail) - } + accessToken := strings.TrimSpace(tokenResp.AccessToken) + if accessToken == "" { + return nil, fmt.Errorf("antigravity: token exchange returned empty access token") + } + + email, errInfo := authSvc.FetchUserInfo(ctx, accessToken) + if errInfo != nil { + return nil, fmt.Errorf("antigravity: fetch user info failed: %w", errInfo) + } + email = strings.TrimSpace(email) + if email == "" { + return nil, fmt.Errorf("antigravity: empty email returned from user info") } // Fetch project ID via loadCodeAssist (same approach as Gemini CLI) projectID := "" - if tokenResp.AccessToken != "" { - fetchedProjectID, errProject := authSvc.FetchProjectID(ctx, tokenResp.AccessToken) + if accessToken != "" { + fetchedProjectID, errProject := authSvc.FetchProjectID(ctx, accessToken) if errProject != nil { log.Warnf("antigravity: failed to fetch project ID: %v", errProject) } else {