mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-02-03 04:50:52 +08:00
fix(auth): validate antigravity token userinfo email
This commit is contained in:
@@ -1148,13 +1148,9 @@ func (h *Handler) RequestGeminiCLIToken(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ifToken["token_uri"] = "https://oauth2.googleapis.com/token"
|
ifToken["token_uri"] = "https://oauth2.googleapis.com/token"
|
||||||
ifToken["client_id"] = "681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com"
|
ifToken["client_id"] = geminiAuth.ClientID
|
||||||
ifToken["client_secret"] = "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"
|
ifToken["client_secret"] = geminiAuth.ClientSecret
|
||||||
ifToken["scopes"] = []string{
|
ifToken["scopes"] = geminiAuth.Scopes
|
||||||
"https://www.googleapis.com/auth/cloud-platform",
|
|
||||||
"https://www.googleapis.com/auth/userinfo.email",
|
|
||||||
"https://www.googleapis.com/auth/userinfo.profile",
|
|
||||||
}
|
|
||||||
ifToken["universe_domain"] = "googleapis.com"
|
ifToken["universe_domain"] = "googleapis.com"
|
||||||
|
|
||||||
ts := geminiAuth.GeminiTokenStorage{
|
ts := geminiAuth.GeminiTokenStorage{
|
||||||
@@ -1478,20 +1474,29 @@ func (h *Handler) RequestAntigravityToken(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
email := ""
|
accessToken := strings.TrimSpace(tokenResp.AccessToken)
|
||||||
if strings.TrimSpace(tokenResp.AccessToken) != "" {
|
if accessToken == "" {
|
||||||
fetchedEmail, errInfo := authSvc.FetchUserInfo(ctx, tokenResp.AccessToken)
|
log.Error("antigravity: token exchange returned empty access token")
|
||||||
if errInfo != nil {
|
SetOAuthSessionError(state, "Failed to exchange token")
|
||||||
log.Errorf("Failed to fetch user info: %v", errInfo)
|
return
|
||||||
SetOAuthSessionError(state, "Failed to fetch user info")
|
}
|
||||||
return
|
|
||||||
}
|
email, errInfo := authSvc.FetchUserInfo(ctx, accessToken)
|
||||||
email = strings.TrimSpace(fetchedEmail)
|
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 := ""
|
projectID := ""
|
||||||
if strings.TrimSpace(tokenResp.AccessToken) != "" {
|
if accessToken != "" {
|
||||||
fetchedProjectID, errProject := authSvc.FetchProjectID(ctx, tokenResp.AccessToken)
|
fetchedProjectID, errProject := authSvc.FetchProjectID(ctx, accessToken)
|
||||||
if errProject != nil {
|
if errProject != nil {
|
||||||
log.Warnf("antigravity: failed to fetch project ID: %v", errProject)
|
log.Warnf("antigravity: failed to fetch project ID: %v", errProject)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -100,18 +100,19 @@ func (o *AntigravityAuth) ExchangeCodeForTokens(ctx context.Context, code, redir
|
|||||||
|
|
||||||
// FetchUserInfo retrieves user email from Google
|
// FetchUserInfo retrieves user email from Google
|
||||||
func (o *AntigravityAuth) FetchUserInfo(ctx context.Context, accessToken string) (string, error) {
|
func (o *AntigravityAuth) FetchUserInfo(ctx context.Context, accessToken string) (string, error) {
|
||||||
if strings.TrimSpace(accessToken) == "" {
|
accessToken = strings.TrimSpace(accessToken)
|
||||||
return "", nil
|
if accessToken == "" {
|
||||||
|
return "", fmt.Errorf("antigravity userinfo: missing access token")
|
||||||
}
|
}
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, UserInfoEndpoint, nil)
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, UserInfoEndpoint, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", fmt.Errorf("antigravity userinfo: create request: %w", err)
|
||||||
}
|
}
|
||||||
req.Header.Set("Authorization", "Bearer "+accessToken)
|
req.Header.Set("Authorization", "Bearer "+accessToken)
|
||||||
|
|
||||||
resp, errDo := o.httpClient.Do(req)
|
resp, errDo := o.httpClient.Do(req)
|
||||||
if errDo != nil {
|
if errDo != nil {
|
||||||
return "", errDo
|
return "", fmt.Errorf("antigravity userinfo: execute request: %w", errDo)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if errClose := resp.Body.Close(); errClose != nil {
|
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 {
|
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
|
var info userInfo
|
||||||
if errDecode := json.NewDecoder(resp.Body).Decode(&info); errDecode != nil {
|
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
|
// FetchProjectID retrieves the project ID for the authenticated user via loadCodeAssist
|
||||||
|
|||||||
@@ -153,17 +153,24 @@ waitForCallback:
|
|||||||
return nil, fmt.Errorf("antigravity: token exchange failed: %w", errToken)
|
return nil, fmt.Errorf("antigravity: token exchange failed: %w", errToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
email := ""
|
accessToken := strings.TrimSpace(tokenResp.AccessToken)
|
||||||
if tokenResp.AccessToken != "" {
|
if accessToken == "" {
|
||||||
if fetchedEmail, errInfo := authSvc.FetchUserInfo(ctx, tokenResp.AccessToken); errInfo == nil && strings.TrimSpace(fetchedEmail) != "" {
|
return nil, fmt.Errorf("antigravity: token exchange returned empty access token")
|
||||||
email = strings.TrimSpace(fetchedEmail)
|
}
|
||||||
}
|
|
||||||
|
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)
|
// Fetch project ID via loadCodeAssist (same approach as Gemini CLI)
|
||||||
projectID := ""
|
projectID := ""
|
||||||
if tokenResp.AccessToken != "" {
|
if accessToken != "" {
|
||||||
fetchedProjectID, errProject := authSvc.FetchProjectID(ctx, tokenResp.AccessToken)
|
fetchedProjectID, errProject := authSvc.FetchProjectID(ctx, accessToken)
|
||||||
if errProject != nil {
|
if errProject != nil {
|
||||||
log.Warnf("antigravity: failed to fetch project ID: %v", errProject)
|
log.Warnf("antigravity: failed to fetch project ID: %v", errProject)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user