| package auth |
|
|
| import ( |
| "context" |
| "fmt" |
| "strings" |
| "time" |
|
|
| "github.com/router-for-me/CLIProxyAPI/v6/internal/auth/qwen" |
| "github.com/router-for-me/CLIProxyAPI/v6/internal/browser" |
| |
| "github.com/router-for-me/CLIProxyAPI/v6/internal/config" |
| coreauth "github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/auth" |
| log "github.com/sirupsen/logrus" |
| ) |
|
|
| |
| type QwenAuthenticator struct{} |
|
|
| |
| func NewQwenAuthenticator() *QwenAuthenticator { |
| return &QwenAuthenticator{} |
| } |
|
|
| func (a *QwenAuthenticator) Provider() string { |
| return "qwen" |
| } |
|
|
| func (a *QwenAuthenticator) RefreshLead() *time.Duration { |
| d := 3 * time.Hour |
| return &d |
| } |
|
|
| func (a *QwenAuthenticator) Login(ctx context.Context, cfg *config.Config, opts *LoginOptions) (*coreauth.Auth, error) { |
| if cfg == nil { |
| return nil, fmt.Errorf("cliproxy auth: configuration is required") |
| } |
| if ctx == nil { |
| ctx = context.Background() |
| } |
| if opts == nil { |
| opts = &LoginOptions{} |
| } |
|
|
| authSvc := qwen.NewQwenAuth(cfg) |
|
|
| deviceFlow, err := authSvc.InitiateDeviceFlow(ctx) |
| if err != nil { |
| return nil, fmt.Errorf("qwen device flow initiation failed: %w", err) |
| } |
|
|
| authURL := deviceFlow.VerificationURIComplete |
|
|
| if !opts.NoBrowser { |
| fmt.Println("Opening browser for Qwen authentication") |
| if !browser.IsAvailable() { |
| log.Warn("No browser available; please open the URL manually") |
| fmt.Printf("Visit the following URL to continue authentication:\n%s\n", authURL) |
| } else if err = browser.OpenURL(authURL); err != nil { |
| log.Warnf("Failed to open browser automatically: %v", err) |
| fmt.Printf("Visit the following URL to continue authentication:\n%s\n", authURL) |
| } |
| } else { |
| fmt.Printf("Visit the following URL to continue authentication:\n%s\n", authURL) |
| } |
|
|
| fmt.Println("Waiting for Qwen authentication...") |
|
|
| tokenData, err := authSvc.PollForToken(deviceFlow.DeviceCode, deviceFlow.CodeVerifier) |
| if err != nil { |
| return nil, fmt.Errorf("qwen authentication failed: %w", err) |
| } |
|
|
| tokenStorage := authSvc.CreateTokenStorage(tokenData) |
|
|
| email := "" |
| if opts.Metadata != nil { |
| email = opts.Metadata["email"] |
| if email == "" { |
| email = opts.Metadata["alias"] |
| } |
| } |
|
|
| if email == "" && opts.Prompt != nil { |
| email, err = opts.Prompt("Please input your email address or alias for Qwen:") |
| if err != nil { |
| return nil, err |
| } |
| } |
|
|
| email = strings.TrimSpace(email) |
| if email == "" { |
| return nil, &EmailRequiredError{Prompt: "Please provide an email address or alias for Qwen."} |
| } |
|
|
| tokenStorage.Email = email |
|
|
| |
|
|
| fileName := fmt.Sprintf("qwen-%s.json", tokenStorage.Email) |
| metadata := map[string]any{ |
| "email": tokenStorage.Email, |
| } |
|
|
| fmt.Println("Qwen authentication successful") |
|
|
| return &coreauth.Auth{ |
| ID: fileName, |
| Provider: a.Provider(), |
| FileName: fileName, |
| Storage: tokenStorage, |
| Metadata: metadata, |
| }, nil |
| } |
|
|