From 27246304300900f4a4178b9d468d787fd233e7c9 Mon Sep 17 00:00:00 2001 From: Luis Pater Date: Thu, 25 Sep 2025 08:06:58 +0800 Subject: [PATCH] feat(auth): add Gemini Web token saving endpoint - Introduced `POST /gemini-web-token` endpoint to save Gemini Web cookies directly. - Added payload validation and hashed-based file naming for persistence. - Updated documentation to reflect the new management API functionality. --- MANAGEMENT_API.md | 13 +++++ MANAGEMENT_API_CN.md | 13 +++++ .../api/handlers/management/auth_files.go | 51 +++++++++++++++++++ internal/api/server.go | 1 + 4 files changed, 78 insertions(+) diff --git a/MANAGEMENT_API.md b/MANAGEMENT_API.md index 7cd5a00a..6421f5f2 100644 --- a/MANAGEMENT_API.md +++ b/MANAGEMENT_API.md @@ -659,6 +659,19 @@ These endpoints initiate provider login flows and return a URL to open in a brow { "status": "ok", "url": "https://..." } ``` +- POST `/gemini-web-token` — Save Gemini Web cookies directly + - Request: + ```bash + curl -H 'Authorization: Bearer ' \ + -H 'Content-Type: application/json' \ + -d '{"secure_1psid": "<__Secure-1PSID>", "secure_1psidts": "<__Secure-1PSIDTS>"}' \ + http://localhost:8317/v0/management/gemini-web-token + ``` + - Response: + ```json + { "status": "ok", "file": "gemini-web-.json" } + ``` + - GET `/qwen-auth-url` — Start Qwen login (device flow) - Request: ```bash diff --git a/MANAGEMENT_API_CN.md b/MANAGEMENT_API_CN.md index 803d9d41..0626e0c8 100644 --- a/MANAGEMENT_API_CN.md +++ b/MANAGEMENT_API_CN.md @@ -659,6 +659,19 @@ { "status": "ok", "url": "https://..." } ``` +- POST `/gemini-web-token` — 直接保存 Gemini Web Cookie + - 请求: + ```bash + curl -H 'Authorization: Bearer ' \ + -H 'Content-Type: application/json' \ + -d '{"secure_1psid": "<__Secure-1PSID>", "secure_1psidts": "<__Secure-1PSIDTS>"}' \ + http://localhost:8317/v0/management/gemini-web-token + ``` + - 响应: + ```json + { "status": "ok", "file": "gemini-web-.json" } + ``` + - GET `/qwen-auth-url` — 开始 Qwen 登录(设备授权流程) - 请求: ```bash diff --git a/internal/api/handlers/management/auth_files.go b/internal/api/handlers/management/auth_files.go index dc6938bb..5d0c750e 100644 --- a/internal/api/handlers/management/auth_files.go +++ b/internal/api/handlers/management/auth_files.go @@ -2,6 +2,8 @@ package management import ( "context" + "crypto/sha256" + "encoding/hex" "encoding/json" "fmt" "io" @@ -681,6 +683,55 @@ func (h *Handler) RequestGeminiCLIToken(c *gin.Context) { c.JSON(200, gin.H{"status": "ok", "url": authURL, "state": state}) } +func (h *Handler) CreateGeminiWebToken(c *gin.Context) { + ctx := c.Request.Context() + + var payload struct { + Secure1PSID string `json:"secure_1psid"` + Secure1PSIDTS string `json:"secure_1psidts"` + } + if err := c.ShouldBindJSON(&payload); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "invalid body"}) + return + } + payload.Secure1PSID = strings.TrimSpace(payload.Secure1PSID) + payload.Secure1PSIDTS = strings.TrimSpace(payload.Secure1PSIDTS) + if payload.Secure1PSID == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "secure_1psid is required"}) + return + } + if payload.Secure1PSIDTS == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "secure_1psidts is required"}) + return + } + + sha := sha256.New() + sha.Write([]byte(payload.Secure1PSID)) + hash := hex.EncodeToString(sha.Sum(nil)) + fileName := fmt.Sprintf("gemini-web-%s.json", hash[:16]) + + tokenStorage := &geminiAuth.GeminiWebTokenStorage{ + Secure1PSID: payload.Secure1PSID, + Secure1PSIDTS: payload.Secure1PSIDTS, + } + + record := &sdkAuth.TokenRecord{ + Provider: "gemini-web", + FileName: fileName, + Storage: tokenStorage, + } + + savedPath, errSave := h.saveTokenRecord(ctx, record) + if errSave != nil { + log.Errorf("Failed to save Gemini Web token: %v", errSave) + c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to save token"}) + return + } + + log.Infof("Successfully saved Gemini Web token to: %s", savedPath) + c.JSON(http.StatusOK, gin.H{"status": "ok", "file": filepath.Base(savedPath)}) +} + func (h *Handler) RequestCodexToken(c *gin.Context) { ctx := context.Background() diff --git a/internal/api/server.go b/internal/api/server.go index f96c8be2..3aab2d17 100644 --- a/internal/api/server.go +++ b/internal/api/server.go @@ -340,6 +340,7 @@ func (s *Server) setupRoutes() { mgmt.GET("/anthropic-auth-url", s.mgmt.RequestAnthropicToken) mgmt.GET("/codex-auth-url", s.mgmt.RequestCodexToken) mgmt.GET("/gemini-cli-auth-url", s.mgmt.RequestGeminiCLIToken) + mgmt.POST("/gemini-web-token", s.mgmt.CreateGeminiWebToken) mgmt.GET("/qwen-auth-url", s.mgmt.RequestQwenToken) mgmt.GET("/get-auth-status", s.mgmt.GetAuthStatus) }