From 8af97e970aeac806cf2bd871001385f172d9f819 Mon Sep 17 00:00:00 2001 From: F04C Date: Mon, 26 Jan 2026 10:36:49 +0800 Subject: [PATCH] added error message --- handlers/google_auth.go | 78 +++++++++++++++++++++++++++++++++++------ 1 file changed, 67 insertions(+), 11 deletions(-) diff --git a/handlers/google_auth.go b/handlers/google_auth.go index 09aa4bb..74bf08d 100644 --- a/handlers/google_auth.go +++ b/handlers/google_auth.go @@ -162,7 +162,32 @@ func GoogleCallback(w http.ResponseWriter, r *http.Request) { userInfo, err := FetchGoogleUserInfo(w, r) if err != nil { - helper.RespondWithError(w, http.StatusBadGateway, "Failed to fetch user information from Google") + errMsg := err.Error() + helper.LogError(err, "Failed to fetch Google user info") + + // Provide user-friendly error messages for different scenarios + if strings.Contains(errMsg, "TLS handshake timeout") { + helper.RespondWithError(w, http.StatusGatewayTimeout, "Connection to Google failed due to network issues. Please try again in a moment.") + return + } + if strings.Contains(errMsg, "timeout") { + helper.RespondWithError(w, http.StatusGatewayTimeout, "Request to Google took too long. Please try again.") + return + } + if strings.Contains(errMsg, "connection refused") || strings.Contains(errMsg, "no such host") { + helper.RespondWithError(w, http.StatusServiceUnavailable, "Unable to reach Google authentication servers. Please check your internet connection and try again.") + return + } + if strings.Contains(errMsg, "status 401") { + helper.RespondWithError(w, http.StatusUnauthorized, "Invalid authorization code. Please start the login process again.") + return + } + if strings.Contains(errMsg, "status 403") { + helper.RespondWithError(w, http.StatusForbidden, "Access to Google authentication was denied. Please try again later.") + return + } + + helper.RespondWithError(w, http.StatusBadGateway, "Failed to fetch user information from Google. Please try again.") return } @@ -295,25 +320,48 @@ func FetchGoogleUserInfo(w http.ResponseWriter, r *http.Request) (models.UserGoo log.Print("Authorization code received: ", code) token, err := googleOauthConfig.Exchange(context.Background(), code) if err != nil { - helper.LogError(err, "Error exchanging token") - // http.Redirect(w, r, DashboardBaseURL, http.StatusSeeOther) - return models.UserGoogleInfo{}, err + helper.LogError(err, "Error exchanging authorization code for token") + return models.UserGoogleInfo{}, fmt.Errorf("failed to exchange authorization code: %w", err) } helper.LogInfo(fmt.Sprintf("Access Token: %s", token.AccessToken)) - client := googleOauthConfig.Client(context.Background(), token) + // Create a context with a 30-second timeout for the userinfo request + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + client := googleOauthConfig.Client(ctx, token) req, err := http.NewRequest("GET", "https://www.googleapis.com/oauth2/v1/userinfo?alt=json", nil) if err != nil { - helper.LogError(err, "Error creating request") - return models.UserGoogleInfo{}, err + helper.LogError(err, "Error creating request to fetch user info") + return models.UserGoogleInfo{}, fmt.Errorf("failed to create userinfo request: %w", err) } req.Header.Set("Authorization", bearerPrefix+token.AccessToken) + req = req.WithContext(ctx) resp, err := client.Do(req) if err != nil { - helper.LogError(err, "Error sending request") - return models.UserGoogleInfo{}, err + errMsg := fmt.Sprintf("Failed to fetch user info from Google: %v", err) + helper.LogError(err, errMsg) + + // Provide more specific error messages for common issues + if os.IsTimeout(err) { + return models.UserGoogleInfo{}, fmt.Errorf("request timed out: Google userinfo endpoint took too long to respond (timeout: 30s)") + } + if strings.Contains(err.Error(), "net/http: TLS handshake timeout") { + return models.UserGoogleInfo{}, fmt.Errorf("TLS handshake timeout: Unable to establish secure connection to Google") + } + if strings.Contains(err.Error(), "context deadline exceeded") { + return models.UserGoogleInfo{}, fmt.Errorf("request deadline exceeded: Connection attempt exceeded 30 second timeout") + } + if strings.Contains(err.Error(), "connection refused") { + return models.UserGoogleInfo{}, fmt.Errorf("connection refused: Cannot reach Google servers") + } + if strings.Contains(err.Error(), "no such host") { + return models.UserGoogleInfo{}, fmt.Errorf("DNS resolution failed: Cannot resolve googleapis.com") + } + + return models.UserGoogleInfo{}, fmt.Errorf("network error while fetching user info: %w", err) } defer func(Body io.ReadCloser) { err := Body.Close() @@ -322,10 +370,18 @@ func FetchGoogleUserInfo(w http.ResponseWriter, r *http.Request) (models.UserGoo } }(resp.Body) + // Check HTTP status code + if resp.StatusCode != http.StatusOK { + bodyBytes, _ := io.ReadAll(resp.Body) + errMsg := fmt.Sprintf("Google API returned status %d: %s", resp.StatusCode, string(bodyBytes)) + helper.LogError(nil, errMsg) + return models.UserGoogleInfo{}, fmt.Errorf("google api error (status %d): %s", resp.StatusCode, string(bodyBytes)) + } + var userInfo models.UserGoogleInfo if err := json.NewDecoder(resp.Body).Decode(&userInfo); err != nil { - helper.LogError(err, "Error decoding user info") - return models.UserGoogleInfo{}, err + helper.LogError(err, "Error decoding user info from Google response") + return models.UserGoogleInfo{}, fmt.Errorf("failed to parse user info response: %w", err) } return userInfo, nil }