mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-02-03 13:00:52 +08:00
111 lines
2.9 KiB
Go
111 lines
2.9 KiB
Go
package cmd
|
|
|
|
import (
|
|
"bufio"
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/router-for-me/CLIProxyAPI/v6/internal/auth/iflow"
|
|
"github.com/router-for-me/CLIProxyAPI/v6/internal/config"
|
|
)
|
|
|
|
// DoIFlowCookieAuth performs the iFlow cookie-based authentication.
|
|
func DoIFlowCookieAuth(cfg *config.Config, options *LoginOptions) {
|
|
if options == nil {
|
|
options = &LoginOptions{}
|
|
}
|
|
|
|
promptFn := options.Prompt
|
|
if promptFn == nil {
|
|
reader := bufio.NewReader(os.Stdin)
|
|
promptFn = func(prompt string) (string, error) {
|
|
fmt.Print(prompt)
|
|
value, err := reader.ReadString('\n')
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return strings.TrimSpace(value), nil
|
|
}
|
|
}
|
|
|
|
// Prompt user for cookie
|
|
cookie, err := promptForCookie(promptFn)
|
|
if err != nil {
|
|
fmt.Printf("Failed to get cookie: %v\n", err)
|
|
return
|
|
}
|
|
|
|
// Authenticate with cookie
|
|
auth := iflow.NewIFlowAuth(cfg)
|
|
ctx := context.Background()
|
|
|
|
tokenData, err := auth.AuthenticateWithCookie(ctx, cookie)
|
|
if err != nil {
|
|
fmt.Printf("iFlow cookie authentication failed: %v\n", err)
|
|
return
|
|
}
|
|
|
|
// Create token storage
|
|
tokenStorage := auth.CreateCookieTokenStorage(tokenData)
|
|
|
|
// Get auth file path using email in filename
|
|
authFilePath := getAuthFilePath(cfg, "iflow", tokenData.Email)
|
|
|
|
// Save token to file
|
|
if err := tokenStorage.SaveTokenToFile(authFilePath); err != nil {
|
|
fmt.Printf("Failed to save authentication: %v\n", err)
|
|
return
|
|
}
|
|
|
|
fmt.Printf("Authentication successful! API key: %s\n", tokenData.APIKey)
|
|
fmt.Printf("Expires at: %s\n", tokenData.Expire)
|
|
fmt.Printf("Authentication saved to: %s\n", authFilePath)
|
|
}
|
|
|
|
// promptForCookie prompts the user to enter their iFlow cookie
|
|
func promptForCookie(promptFn func(string) (string, error)) (string, error) {
|
|
line, err := promptFn("Enter iFlow Cookie (from browser cookies): ")
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to read cookie: %w", err)
|
|
}
|
|
|
|
line = strings.TrimSpace(line)
|
|
if line == "" {
|
|
return "", fmt.Errorf("cookie cannot be empty")
|
|
}
|
|
|
|
// Clean up any extra whitespace and join multiple spaces
|
|
cookie := strings.Join(strings.Fields(line), " ")
|
|
|
|
// Ensure it ends properly
|
|
if !strings.HasSuffix(cookie, ";") {
|
|
cookie = cookie + ";"
|
|
}
|
|
|
|
// Ensure BXAuth is present in the cookie
|
|
if !strings.Contains(cookie, "BXAuth=") {
|
|
return "", fmt.Errorf("BXAuth field not found in cookie")
|
|
}
|
|
|
|
return cookie, nil
|
|
}
|
|
|
|
// getAuthFilePath returns the auth file path for the given provider and email
|
|
func getAuthFilePath(cfg *config.Config, provider, email string) string {
|
|
// Clean email to make it filename-safe
|
|
cleanEmail := strings.ReplaceAll(email, "*", "x")
|
|
|
|
// Remove any unsafe characters, but allow standard email chars (@, ., -)
|
|
var result strings.Builder
|
|
for _, r := range cleanEmail {
|
|
if (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') || (r >= '0' && r <= '9') ||
|
|
r == '_' || r == '@' || r == '.' || r == '-' {
|
|
result.WriteRune(r)
|
|
}
|
|
}
|
|
|
|
return fmt.Sprintf("%s/%s-%s.json", cfg.AuthDir, provider, result.String())
|
|
}
|