| |
| |
| |
| package claude |
|
|
| import ( |
| "errors" |
| "fmt" |
| "net/http" |
| ) |
|
|
| |
| type OAuthError struct { |
| |
| Code string `json:"error"` |
| |
| Description string `json:"error_description,omitempty"` |
| |
| URI string `json:"error_uri,omitempty"` |
| |
| StatusCode int `json:"-"` |
| } |
|
|
| |
| func (e *OAuthError) Error() string { |
| if e.Description != "" { |
| return fmt.Sprintf("OAuth error %s: %s", e.Code, e.Description) |
| } |
| return fmt.Sprintf("OAuth error: %s", e.Code) |
| } |
|
|
| |
| func NewOAuthError(code, description string, statusCode int) *OAuthError { |
| return &OAuthError{ |
| Code: code, |
| Description: description, |
| StatusCode: statusCode, |
| } |
| } |
|
|
| |
| type AuthenticationError struct { |
| |
| Type string `json:"type"` |
| |
| Message string `json:"message"` |
| |
| Code int `json:"code"` |
| |
| Cause error `json:"-"` |
| } |
|
|
| |
| func (e *AuthenticationError) Error() string { |
| if e.Cause != nil { |
| return fmt.Sprintf("%s: %s (caused by: %v)", e.Type, e.Message, e.Cause) |
| } |
| return fmt.Sprintf("%s: %s", e.Type, e.Message) |
| } |
|
|
| |
| var ( |
| |
| |
| |
| |
| |
|
|
| |
| ErrInvalidState = &AuthenticationError{ |
| Type: "invalid_state", |
| Message: "OAuth state parameter is invalid", |
| Code: http.StatusBadRequest, |
| } |
|
|
| |
| ErrCodeExchangeFailed = &AuthenticationError{ |
| Type: "code_exchange_failed", |
| Message: "Failed to exchange authorization code for tokens", |
| Code: http.StatusBadRequest, |
| } |
|
|
| |
| ErrServerStartFailed = &AuthenticationError{ |
| Type: "server_start_failed", |
| Message: "Failed to start OAuth callback server", |
| Code: http.StatusInternalServerError, |
| } |
|
|
| |
| ErrPortInUse = &AuthenticationError{ |
| Type: "port_in_use", |
| Message: "OAuth callback port is already in use", |
| Code: 13, |
| } |
|
|
| |
| ErrCallbackTimeout = &AuthenticationError{ |
| Type: "callback_timeout", |
| Message: "Timeout waiting for OAuth callback", |
| Code: http.StatusRequestTimeout, |
| } |
| ) |
|
|
| |
| func NewAuthenticationError(baseErr *AuthenticationError, cause error) *AuthenticationError { |
| return &AuthenticationError{ |
| Type: baseErr.Type, |
| Message: baseErr.Message, |
| Code: baseErr.Code, |
| Cause: cause, |
| } |
| } |
|
|
| |
| func IsAuthenticationError(err error) bool { |
| var authenticationError *AuthenticationError |
| ok := errors.As(err, &authenticationError) |
| return ok |
| } |
|
|
| |
| func IsOAuthError(err error) bool { |
| var oAuthError *OAuthError |
| ok := errors.As(err, &oAuthError) |
| return ok |
| } |
|
|
| |
| func GetUserFriendlyMessage(err error) string { |
| switch { |
| case IsAuthenticationError(err): |
| var authErr *AuthenticationError |
| errors.As(err, &authErr) |
| switch authErr.Type { |
| case "token_expired": |
| return "Your authentication has expired. Please log in again." |
| case "token_invalid": |
| return "Your authentication is invalid. Please log in again." |
| case "authentication_required": |
| return "Please log in to continue." |
| case "port_in_use": |
| return "The required port is already in use. Please close any applications using port 3000 and try again." |
| case "callback_timeout": |
| return "Authentication timed out. Please try again." |
| case "browser_open_failed": |
| return "Could not open your browser automatically. Please copy and paste the URL manually." |
| default: |
| return "Authentication failed. Please try again." |
| } |
| case IsOAuthError(err): |
| var oauthErr *OAuthError |
| errors.As(err, &oauthErr) |
| switch oauthErr.Code { |
| case "access_denied": |
| return "Authentication was cancelled or denied." |
| case "invalid_request": |
| return "Invalid authentication request. Please try again." |
| case "server_error": |
| return "Authentication server error. Please try again later." |
| default: |
| return fmt.Sprintf("Authentication failed: %s", oauthErr.Description) |
| } |
| default: |
| return "An unexpected error occurred. Please try again." |
| } |
| } |
|
|