mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-02-02 20:40:52 +08:00
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.
This commit is contained in:
@@ -659,6 +659,19 @@ These endpoints initiate provider login flows and return a URL to open in a brow
|
|||||||
{ "status": "ok", "url": "https://..." }
|
{ "status": "ok", "url": "https://..." }
|
||||||
```
|
```
|
||||||
|
|
||||||
|
- POST `/gemini-web-token` — Save Gemini Web cookies directly
|
||||||
|
- Request:
|
||||||
|
```bash
|
||||||
|
curl -H 'Authorization: Bearer <MANAGEMENT_KEY>' \
|
||||||
|
-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-<hash>.json" }
|
||||||
|
```
|
||||||
|
|
||||||
- GET `/qwen-auth-url` — Start Qwen login (device flow)
|
- GET `/qwen-auth-url` — Start Qwen login (device flow)
|
||||||
- Request:
|
- Request:
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -659,6 +659,19 @@
|
|||||||
{ "status": "ok", "url": "https://..." }
|
{ "status": "ok", "url": "https://..." }
|
||||||
```
|
```
|
||||||
|
|
||||||
|
- POST `/gemini-web-token` — 直接保存 Gemini Web Cookie
|
||||||
|
- 请求:
|
||||||
|
```bash
|
||||||
|
curl -H 'Authorization: Bearer <MANAGEMENT_KEY>' \
|
||||||
|
-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-<hash>.json" }
|
||||||
|
```
|
||||||
|
|
||||||
- GET `/qwen-auth-url` — 开始 Qwen 登录(设备授权流程)
|
- GET `/qwen-auth-url` — 开始 Qwen 登录(设备授权流程)
|
||||||
- 请求:
|
- 请求:
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package management
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@@ -681,6 +683,55 @@ func (h *Handler) RequestGeminiCLIToken(c *gin.Context) {
|
|||||||
c.JSON(200, gin.H{"status": "ok", "url": authURL, "state": state})
|
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) {
|
func (h *Handler) RequestCodexToken(c *gin.Context) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
|
|||||||
@@ -340,6 +340,7 @@ func (s *Server) setupRoutes() {
|
|||||||
mgmt.GET("/anthropic-auth-url", s.mgmt.RequestAnthropicToken)
|
mgmt.GET("/anthropic-auth-url", s.mgmt.RequestAnthropicToken)
|
||||||
mgmt.GET("/codex-auth-url", s.mgmt.RequestCodexToken)
|
mgmt.GET("/codex-auth-url", s.mgmt.RequestCodexToken)
|
||||||
mgmt.GET("/gemini-cli-auth-url", s.mgmt.RequestGeminiCLIToken)
|
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("/qwen-auth-url", s.mgmt.RequestQwenToken)
|
||||||
mgmt.GET("/get-auth-status", s.mgmt.GetAuthStatus)
|
mgmt.GET("/get-auth-status", s.mgmt.GetAuthStatus)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user