mirror of
https://github.com/router-for-me/CLIProxyAPIPlus.git
synced 2026-03-21 16:40:22 +00:00
refactor(copilot): improve code quality in authentication module
- Add Unwrap() to AuthenticationError for proper error chain handling with errors.Is/As - Extract hardcoded header values to constants for maintainability - Replace verbose status code checks with isHTTPSuccess() helper - Remove unused ExtractBearerToken() and BuildModelsURL() functions - Make buildChatCompletionURL() private (only used internally) - Remove unused 'strings' import
This commit is contained in:
@@ -8,7 +8,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/router-for-me/CLIProxyAPI/v6/internal/config"
|
"github.com/router-for-me/CLIProxyAPI/v6/internal/config"
|
||||||
@@ -21,6 +20,13 @@ const (
|
|||||||
copilotAPITokenURL = "https://api.github.com/copilot_internal/v2/token"
|
copilotAPITokenURL = "https://api.github.com/copilot_internal/v2/token"
|
||||||
// copilotAPIEndpoint is the base URL for making API requests.
|
// copilotAPIEndpoint is the base URL for making API requests.
|
||||||
copilotAPIEndpoint = "https://api.githubcopilot.com"
|
copilotAPIEndpoint = "https://api.githubcopilot.com"
|
||||||
|
|
||||||
|
// Common HTTP header values for Copilot API requests.
|
||||||
|
copilotUserAgent = "GithubCopilot/1.0"
|
||||||
|
copilotEditorVersion = "vscode/1.100.0"
|
||||||
|
copilotPluginVersion = "copilot/1.300.0"
|
||||||
|
copilotIntegrationID = "vscode-chat"
|
||||||
|
copilotOpenAIIntent = "conversation-panel"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CopilotAPIToken represents the Copilot API token response.
|
// CopilotAPIToken represents the Copilot API token response.
|
||||||
@@ -102,9 +108,9 @@ func (c *CopilotAuth) GetCopilotAPIToken(ctx context.Context, githubAccessToken
|
|||||||
|
|
||||||
req.Header.Set("Authorization", "token "+githubAccessToken)
|
req.Header.Set("Authorization", "token "+githubAccessToken)
|
||||||
req.Header.Set("Accept", "application/json")
|
req.Header.Set("Accept", "application/json")
|
||||||
req.Header.Set("User-Agent", "GithubCopilot/1.0")
|
req.Header.Set("User-Agent", copilotUserAgent)
|
||||||
req.Header.Set("Editor-Version", "vscode/1.100.0")
|
req.Header.Set("Editor-Version", copilotEditorVersion)
|
||||||
req.Header.Set("Editor-Plugin-Version", "copilot/1.300.0")
|
req.Header.Set("Editor-Plugin-Version", copilotPluginVersion)
|
||||||
|
|
||||||
resp, err := c.httpClient.Do(req)
|
resp, err := c.httpClient.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -121,7 +127,7 @@ func (c *CopilotAuth) GetCopilotAPIToken(ctx context.Context, githubAccessToken
|
|||||||
return nil, NewAuthenticationError(ErrTokenExchangeFailed, err)
|
return nil, NewAuthenticationError(ErrTokenExchangeFailed, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices {
|
if !isHTTPSuccess(resp.StatusCode) {
|
||||||
return nil, NewAuthenticationError(ErrTokenExchangeFailed,
|
return nil, NewAuthenticationError(ErrTokenExchangeFailed,
|
||||||
fmt.Errorf("status %d: %s", resp.StatusCode, string(bodyBytes)))
|
fmt.Errorf("status %d: %s", resp.StatusCode, string(bodyBytes)))
|
||||||
}
|
}
|
||||||
@@ -199,32 +205,21 @@ func (c *CopilotAuth) MakeAuthenticatedRequest(ctx context.Context, method, url
|
|||||||
req.Header.Set("Authorization", "Bearer "+apiToken.Token)
|
req.Header.Set("Authorization", "Bearer "+apiToken.Token)
|
||||||
req.Header.Set("Content-Type", "application/json")
|
req.Header.Set("Content-Type", "application/json")
|
||||||
req.Header.Set("Accept", "application/json")
|
req.Header.Set("Accept", "application/json")
|
||||||
req.Header.Set("User-Agent", "GithubCopilot/1.0")
|
req.Header.Set("User-Agent", copilotUserAgent)
|
||||||
req.Header.Set("Editor-Version", "vscode/1.100.0")
|
req.Header.Set("Editor-Version", copilotEditorVersion)
|
||||||
req.Header.Set("Editor-Plugin-Version", "copilot/1.300.0")
|
req.Header.Set("Editor-Plugin-Version", copilotPluginVersion)
|
||||||
req.Header.Set("Openai-Intent", "conversation-panel")
|
req.Header.Set("Openai-Intent", copilotOpenAIIntent)
|
||||||
req.Header.Set("Copilot-Integration-Id", "vscode-chat")
|
req.Header.Set("Copilot-Integration-Id", copilotIntegrationID)
|
||||||
|
|
||||||
return req, nil
|
return req, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// BuildChatCompletionURL builds the URL for chat completions API.
|
// buildChatCompletionURL builds the URL for chat completions API.
|
||||||
func BuildChatCompletionURL() string {
|
func buildChatCompletionURL() string {
|
||||||
return copilotAPIEndpoint + "/chat/completions"
|
return copilotAPIEndpoint + "/chat/completions"
|
||||||
}
|
}
|
||||||
|
|
||||||
// BuildModelsURL builds the URL for listing available models.
|
// isHTTPSuccess checks if the status code indicates success (2xx).
|
||||||
func BuildModelsURL() string {
|
func isHTTPSuccess(statusCode int) bool {
|
||||||
return copilotAPIEndpoint + "/models"
|
return statusCode >= 200 && statusCode < 300
|
||||||
}
|
|
||||||
|
|
||||||
// ExtractBearerToken extracts the bearer token from an Authorization header.
|
|
||||||
func ExtractBearerToken(authHeader string) string {
|
|
||||||
if strings.HasPrefix(authHeader, "Bearer ") {
|
|
||||||
return strings.TrimPrefix(authHeader, "Bearer ")
|
|
||||||
}
|
|
||||||
if strings.HasPrefix(authHeader, "token ") {
|
|
||||||
return strings.TrimPrefix(authHeader, "token ")
|
|
||||||
}
|
|
||||||
return authHeader
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,6 +55,11 @@ func (e *AuthenticationError) Error() string {
|
|||||||
return fmt.Sprintf("%s: %s", e.Type, e.Message)
|
return fmt.Sprintf("%s: %s", e.Type, e.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unwrap returns the underlying cause of the error.
|
||||||
|
func (e *AuthenticationError) Unwrap() error {
|
||||||
|
return e.Cause
|
||||||
|
}
|
||||||
|
|
||||||
// Common authentication error types for GitHub Copilot device flow.
|
// Common authentication error types for GitHub Copilot device flow.
|
||||||
var (
|
var (
|
||||||
// ErrDeviceCodeFailed represents an error when requesting the device code fails.
|
// ErrDeviceCodeFailed represents an error when requesting the device code fails.
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ func (c *DeviceFlowClient) RequestDeviceCode(ctx context.Context) (*DeviceCodeRe
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices {
|
if !isHTTPSuccess(resp.StatusCode) {
|
||||||
bodyBytes, _ := io.ReadAll(resp.Body)
|
bodyBytes, _ := io.ReadAll(resp.Body)
|
||||||
return nil, NewAuthenticationError(ErrDeviceCodeFailed, fmt.Errorf("status %d: %s", resp.StatusCode, string(bodyBytes)))
|
return nil, NewAuthenticationError(ErrDeviceCodeFailed, fmt.Errorf("status %d: %s", resp.StatusCode, string(bodyBytes)))
|
||||||
}
|
}
|
||||||
@@ -235,7 +235,7 @@ func (c *DeviceFlowClient) FetchUserInfo(ctx context.Context, accessToken string
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices {
|
if !isHTTPSuccess(resp.StatusCode) {
|
||||||
bodyBytes, _ := io.ReadAll(resp.Body)
|
bodyBytes, _ := io.ReadAll(resp.Body)
|
||||||
return "", NewAuthenticationError(ErrUserInfoFailed, fmt.Errorf("status %d: %s", resp.StatusCode, string(bodyBytes)))
|
return "", NewAuthenticationError(ErrUserInfoFailed, fmt.Errorf("status %d: %s", resp.StatusCode, string(bodyBytes)))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user