mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-02-03 04:50:52 +08:00
@@ -714,6 +714,8 @@ func (h *Handler) CreateGeminiWebToken(c *gin.Context) {
|
|||||||
Secure1PSID: payload.Secure1PSID,
|
Secure1PSID: payload.Secure1PSID,
|
||||||
Secure1PSIDTS: payload.Secure1PSIDTS,
|
Secure1PSIDTS: payload.Secure1PSIDTS,
|
||||||
}
|
}
|
||||||
|
// Provide a stable label (gemini-web-<hash>) for logging and identification
|
||||||
|
tokenStorage.Label = strings.TrimSuffix(fileName, ".json")
|
||||||
|
|
||||||
record := &sdkAuth.TokenRecord{
|
record := &sdkAuth.TokenRecord{
|
||||||
Provider: "gemini-web",
|
Provider: "gemini-web",
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/router-for-me/CLIProxyAPI/v6/internal/misc"
|
"github.com/router-for-me/CLIProxyAPI/v6/internal/misc"
|
||||||
@@ -20,12 +21,25 @@ type GeminiWebTokenStorage struct {
|
|||||||
Secure1PSIDTS string `json:"secure_1psidts"`
|
Secure1PSIDTS string `json:"secure_1psidts"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
LastRefresh string `json:"last_refresh,omitempty"`
|
LastRefresh string `json:"last_refresh,omitempty"`
|
||||||
|
// Label is a stable account identifier used for logging, e.g. "gemini-web-<hash>".
|
||||||
|
// It is derived from the auth file name when not explicitly set.
|
||||||
|
Label string `json:"label,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveTokenToFile serializes the Gemini Web token storage to a JSON file.
|
// SaveTokenToFile serializes the Gemini Web token storage to a JSON file.
|
||||||
func (ts *GeminiWebTokenStorage) SaveTokenToFile(authFilePath string) error {
|
func (ts *GeminiWebTokenStorage) SaveTokenToFile(authFilePath string) error {
|
||||||
misc.LogSavingCredentials(authFilePath)
|
misc.LogSavingCredentials(authFilePath)
|
||||||
ts.Type = "gemini-web"
|
ts.Type = "gemini-web"
|
||||||
|
// Auto-derive a stable label from the file name if missing.
|
||||||
|
if ts.Label == "" {
|
||||||
|
base := filepath.Base(authFilePath)
|
||||||
|
if strings.HasSuffix(strings.ToLower(base), ".json") {
|
||||||
|
base = strings.TrimSuffix(base, filepath.Ext(base))
|
||||||
|
}
|
||||||
|
if base != "" {
|
||||||
|
ts.Label = base
|
||||||
|
}
|
||||||
|
}
|
||||||
if ts.LastRefresh == "" {
|
if ts.LastRefresh == "" {
|
||||||
ts.LastRefresh = time.Now().Format(time.RFC3339)
|
ts.LastRefresh = time.Now().Format(time.RFC3339)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,10 @@ func DoGeminiWebAuth(cfg *config.Config) {
|
|||||||
hasher.Write([]byte(secure1psid))
|
hasher.Write([]byte(secure1psid))
|
||||||
hash := hex.EncodeToString(hasher.Sum(nil))
|
hash := hex.EncodeToString(hasher.Sum(nil))
|
||||||
fileName := fmt.Sprintf("gemini-web-%s.json", hash[:16])
|
fileName := fmt.Sprintf("gemini-web-%s.json", hash[:16])
|
||||||
|
// Set a stable label for logging, e.g. gemini-web-<hash>
|
||||||
|
if tokenStorage != nil {
|
||||||
|
tokenStorage.Label = strings.TrimSuffix(fileName, ".json")
|
||||||
|
}
|
||||||
record := &sdkAuth.TokenRecord{
|
record := &sdkAuth.TokenRecord{
|
||||||
Provider: "gemini-web",
|
Provider: "gemini-web",
|
||||||
FileName: fileName,
|
FileName: fileName,
|
||||||
|
|||||||
@@ -97,8 +97,12 @@ func getAccessToken(baseCookies map[string]string, proxy string, verbose bool, i
|
|||||||
{
|
{
|
||||||
client := newHTTPClient(httpOptions{ProxyURL: proxy, Insecure: insecure, FollowRedirects: true})
|
client := newHTTPClient(httpOptions{ProxyURL: proxy, Insecure: insecure, FollowRedirects: true})
|
||||||
req, _ := http.NewRequest(http.MethodGet, EndpointGoogle, nil)
|
req, _ := http.NewRequest(http.MethodGet, EndpointGoogle, nil)
|
||||||
resp, _ := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
if resp != nil {
|
if err != nil {
|
||||||
|
if verbose {
|
||||||
|
log.Debugf("priming google cookies failed: %v", err)
|
||||||
|
}
|
||||||
|
} else if resp != nil {
|
||||||
if u, err := url.Parse(EndpointGoogle); err == nil {
|
if u, err := url.Parse(EndpointGoogle); err == nil {
|
||||||
for _, c := range client.Jar.Cookies(u) {
|
for _, c := range client.Jar.Cookies(u) {
|
||||||
extraCookies[c.Name] = c.Value
|
extraCookies[c.Name] = c.Value
|
||||||
@@ -172,18 +176,10 @@ func rotate1PSIDTS(cookies map[string]string, proxy string, insecure bool) (stri
|
|||||||
return "", &AuthError{Msg: "__Secure-1PSID missing"}
|
return "", &AuthError{Msg: "__Secure-1PSID missing"}
|
||||||
}
|
}
|
||||||
|
|
||||||
tr := &http.Transport{}
|
// Reuse shared HTTP client helper for consistency.
|
||||||
if proxy != "" {
|
client := newHTTPClient(httpOptions{ProxyURL: proxy, Insecure: insecure, FollowRedirects: true})
|
||||||
if pu, err := url.Parse(proxy); err == nil {
|
|
||||||
tr.Proxy = http.ProxyURL(pu)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if insecure {
|
|
||||||
tr.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
|
|
||||||
}
|
|
||||||
client := &http.Client{Transport: tr, Timeout: 60 * time.Second}
|
|
||||||
|
|
||||||
req, _ := http.NewRequest(http.MethodPost, EndpointRotateCookies, io.NopCloser(stringsReader("[000,\"-0000000000000000000\"]")))
|
req, _ := http.NewRequest(http.MethodPost, EndpointRotateCookies, strings.NewReader("[000,\"-0000000000000000000\"]"))
|
||||||
applyHeaders(req, HeadersRotateCookies)
|
applyHeaders(req, HeadersRotateCookies)
|
||||||
applyCookies(req, cookies)
|
applyCookies(req, cookies)
|
||||||
|
|
||||||
@@ -207,25 +203,18 @@ func rotate1PSIDTS(cookies map[string]string, proxy string, insecure bool) (stri
|
|||||||
return c.Value, nil
|
return c.Value, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Fallback: check cookie jar in case the Set-Cookie was on a redirect hop
|
||||||
|
if u, err := url.Parse(EndpointRotateCookies); err == nil && client.Jar != nil {
|
||||||
|
for _, c := range client.Jar.Cookies(u) {
|
||||||
|
if c.Name == "__Secure-1PSIDTS" && c.Value != "" {
|
||||||
|
return c.Value, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type constReader struct {
|
// MaskToken28 masks a sensitive token for safe logging. Keep middle partially visible.
|
||||||
s string
|
|
||||||
i int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *constReader) Read(p []byte) (int, error) {
|
|
||||||
if r.i >= len(r.s) {
|
|
||||||
return 0, io.EOF
|
|
||||||
}
|
|
||||||
n := copy(p, r.s[r.i:])
|
|
||||||
r.i += n
|
|
||||||
return n, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func stringsReader(s string) io.Reader { return &constReader{s: s} }
|
|
||||||
|
|
||||||
func MaskToken28(s string) string {
|
func MaskToken28(s string) string {
|
||||||
n := len(s)
|
n := len(s)
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
@@ -431,21 +420,10 @@ func (c *GeminiClient) generateOnce(prompt string, files []string, model Model,
|
|||||||
form.Set("f.req", string(outerJSON))
|
form.Set("f.req", string(outerJSON))
|
||||||
|
|
||||||
req, _ := http.NewRequest(http.MethodPost, EndpointGenerate, strings.NewReader(form.Encode()))
|
req, _ := http.NewRequest(http.MethodPost, EndpointGenerate, strings.NewReader(form.Encode()))
|
||||||
// headers
|
applyHeaders(req, HeadersGemini)
|
||||||
for k, v := range HeadersGemini {
|
applyHeaders(req, model.ModelHeader)
|
||||||
for _, vv := range v {
|
|
||||||
req.Header.Add(k, vv)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for k, v := range model.ModelHeader {
|
|
||||||
for _, vv := range v {
|
|
||||||
req.Header.Add(k, vv)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded;charset=utf-8")
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded;charset=utf-8")
|
||||||
for k, v := range c.Cookies {
|
applyCookies(req, c.Cookies)
|
||||||
req.AddCookie(&http.Cookie{Name: k, Value: v})
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := c.httpClient.Do(req)
|
resp, err := c.httpClient.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package geminiwebapi
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/tls"
|
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
@@ -11,8 +10,6 @@ import (
|
|||||||
"math"
|
"math"
|
||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/cookiejar"
|
|
||||||
"net/url"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
@@ -69,18 +66,9 @@ func (i Image) Save(path string, filename string, cookies map[string]string, ver
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Build client with cookie jar so cookies persist across redirects.
|
// Build client using shared helper to keep proxy/TLS behavior consistent.
|
||||||
tr := &http.Transport{}
|
client := newHTTPClient(httpOptions{ProxyURL: i.Proxy, Insecure: insecure, FollowRedirects: true})
|
||||||
if i.Proxy != "" {
|
client.Timeout = 120 * time.Second
|
||||||
if pu, err := url.Parse(i.Proxy); err == nil {
|
|
||||||
tr.Proxy = http.ProxyURL(pu)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if insecure {
|
|
||||||
tr.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
|
|
||||||
}
|
|
||||||
jar, _ := cookiejar.New(nil)
|
|
||||||
client := &http.Client{Transport: tr, Timeout: 120 * time.Second, Jar: jar}
|
|
||||||
|
|
||||||
// Helper to set raw Cookie header using provided cookies (to mirror Python client behavior).
|
// Helper to set raw Cookie header using provided cookies (to mirror Python client behavior).
|
||||||
buildCookieHeader := func(m map[string]string) string {
|
buildCookieHeader := func(m map[string]string) string {
|
||||||
@@ -352,23 +340,11 @@ func uploadFile(path string, proxy string, insecure bool) (string, error) {
|
|||||||
}
|
}
|
||||||
_ = mw.Close()
|
_ = mw.Close()
|
||||||
|
|
||||||
tr := &http.Transport{}
|
client := newHTTPClient(httpOptions{ProxyURL: proxy, Insecure: insecure, FollowRedirects: true})
|
||||||
if proxy != "" {
|
client.Timeout = 300 * time.Second
|
||||||
if pu, errParse := url.Parse(proxy); errParse == nil {
|
|
||||||
tr.Proxy = http.ProxyURL(pu)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if insecure {
|
|
||||||
tr.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
|
|
||||||
}
|
|
||||||
client := &http.Client{Transport: tr, Timeout: 300 * time.Second}
|
|
||||||
|
|
||||||
req, _ := http.NewRequest(http.MethodPost, EndpointUpload, &buf)
|
req, _ := http.NewRequest(http.MethodPost, EndpointUpload, &buf)
|
||||||
for k, v := range HeadersUpload {
|
applyHeaders(req, HeadersUpload)
|
||||||
for _, vv := range v {
|
|
||||||
req.Header.Add(k, vv)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
req.Header.Set("Content-Type", mw.FormDataContentType())
|
req.Header.Set("Content-Type", mw.FormDataContentType())
|
||||||
req.Header.Set("Accept", "*/*")
|
req.Header.Set("Accept", "*/*")
|
||||||
req.Header.Set("Connection", "keep-alive")
|
req.Header.Set("Connection", "keep-alive")
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import (
|
|||||||
"github.com/router-for-me/CLIProxyAPI/v6/internal/interfaces"
|
"github.com/router-for-me/CLIProxyAPI/v6/internal/interfaces"
|
||||||
"github.com/router-for-me/CLIProxyAPI/v6/internal/translator/translator"
|
"github.com/router-for-me/CLIProxyAPI/v6/internal/translator/translator"
|
||||||
cliproxyexecutor "github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/executor"
|
cliproxyexecutor "github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/executor"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/tidwall/gjson"
|
"github.com/tidwall/gjson"
|
||||||
"github.com/tidwall/sjson"
|
"github.com/tidwall/sjson"
|
||||||
bolt "go.etcd.io/bbolt"
|
bolt "go.etcd.io/bbolt"
|
||||||
@@ -97,12 +98,12 @@ func (s *GeminiWebState) Label() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *GeminiWebState) loadConversationCaches() {
|
func (s *GeminiWebState) loadConversationCaches() {
|
||||||
if path := s.convStorePath(); path != "" {
|
if path := s.convPath(); path != "" {
|
||||||
if store, err := LoadConvStore(path); err == nil {
|
if store, err := LoadConvStore(path); err == nil {
|
||||||
s.convStore = store
|
s.convStore = store
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if path := s.convDataPath(); path != "" {
|
if path := s.convPath(); path != "" {
|
||||||
if items, index, err := LoadConvData(path); err == nil {
|
if items, index, err := LoadConvData(path); err == nil {
|
||||||
s.convData = items
|
s.convData = items
|
||||||
s.convIndex = index
|
s.convIndex = index
|
||||||
@@ -110,20 +111,14 @@ func (s *GeminiWebState) loadConversationCaches() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *GeminiWebState) convStorePath() string {
|
// convPath returns the BoltDB file path used for both account metadata and conversation data.
|
||||||
|
func (s *GeminiWebState) convPath() string {
|
||||||
base := s.storagePath
|
base := s.storagePath
|
||||||
if base == "" {
|
if base == "" {
|
||||||
base = s.accountID + ".json"
|
// Use accountID directly as base name; ConvBoltPath will append .bolt.
|
||||||
|
base = s.accountID
|
||||||
}
|
}
|
||||||
return ConvStorePath(base)
|
return ConvBoltPath(base)
|
||||||
}
|
|
||||||
|
|
||||||
func (s *GeminiWebState) convDataPath() string {
|
|
||||||
base := s.storagePath
|
|
||||||
if base == "" {
|
|
||||||
base = s.accountID + ".json"
|
|
||||||
}
|
|
||||||
return ConvDataPath(base)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *GeminiWebState) GetRequestMutex() *sync.Mutex { return &s.reqMu }
|
func (s *GeminiWebState) GetRequestMutex() *sync.Mutex { return &s.reqMu }
|
||||||
@@ -174,6 +169,8 @@ func (s *GeminiWebState) Refresh(ctx context.Context) error {
|
|||||||
s.client.Cookies["__Secure-1PSIDTS"] = newTS
|
s.client.Cookies["__Secure-1PSIDTS"] = newTS
|
||||||
}
|
}
|
||||||
s.tokenMu.Unlock()
|
s.tokenMu.Unlock()
|
||||||
|
// Detailed debug log: provider and account.
|
||||||
|
log.Debugf("gemini web account %s rotated 1PSIDTS: %s", s.accountID, MaskToken28(newTS))
|
||||||
}
|
}
|
||||||
s.lastRefresh = time.Now()
|
s.lastRefresh = time.Now()
|
||||||
return nil
|
return nil
|
||||||
@@ -405,7 +402,7 @@ func (s *GeminiWebState) persistConversation(modelName string, prep *geminiWebPr
|
|||||||
storeSnapshot[k] = cp
|
storeSnapshot[k] = cp
|
||||||
}
|
}
|
||||||
s.convMu.Unlock()
|
s.convMu.Unlock()
|
||||||
_ = SaveConvStore(s.convStorePath(), storeSnapshot)
|
_ = SaveConvStore(s.convPath(), storeSnapshot)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !s.useReusableContext() {
|
if !s.useReusableContext() {
|
||||||
@@ -433,7 +430,7 @@ func (s *GeminiWebState) persistConversation(modelName string, prep *geminiWebPr
|
|||||||
indexSnapshot[k] = v
|
indexSnapshot[k] = v
|
||||||
}
|
}
|
||||||
s.convMu.Unlock()
|
s.convMu.Unlock()
|
||||||
_ = SaveConvData(s.convDataPath(), dataSnapshot, indexSnapshot)
|
_ = SaveConvData(s.convPath(), dataSnapshot, indexSnapshot)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *GeminiWebState) addAPIResponseData(ctx context.Context, line []byte) {
|
func (s *GeminiWebState) addAPIResponseData(ctx context.Context, line []byte) {
|
||||||
@@ -570,19 +567,9 @@ func HashConversation(clientID, model string, msgs []StoredMessage) string {
|
|||||||
return Sha256Hex(b.String())
|
return Sha256Hex(b.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConvStorePath returns the path for account-level metadata persistence based on token file path.
|
// ConvBoltPath returns the BoltDB file path used for both account metadata and conversation data.
|
||||||
func ConvStorePath(tokenFilePath string) string {
|
// Different logical datasets are kept in separate buckets within this single DB file.
|
||||||
wd, err := os.Getwd()
|
func ConvBoltPath(tokenFilePath string) string {
|
||||||
if err != nil || wd == "" {
|
|
||||||
wd = "."
|
|
||||||
}
|
|
||||||
convDir := filepath.Join(wd, "conv")
|
|
||||||
base := strings.TrimSuffix(filepath.Base(tokenFilePath), filepath.Ext(tokenFilePath))
|
|
||||||
return filepath.Join(convDir, base+".bolt")
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConvDataPath returns the path for full conversation persistence based on token file path.
|
|
||||||
func ConvDataPath(tokenFilePath string) string {
|
|
||||||
wd, err := os.Getwd()
|
wd, err := os.Getwd()
|
||||||
if err != nil || wd == "" {
|
if err != nil || wd == "" {
|
||||||
wd = "."
|
wd = "."
|
||||||
|
|||||||
@@ -286,7 +286,8 @@ func (m *Manager) executeWithProvider(ctx context.Context, provider string, req
|
|||||||
} else if accountType == "oauth" {
|
} else if accountType == "oauth" {
|
||||||
log.Debugf("Use OAuth %s for model %s", accountInfo, req.Model)
|
log.Debugf("Use OAuth %s for model %s", accountInfo, req.Model)
|
||||||
} else if accountType == "cookie" {
|
} else if accountType == "cookie" {
|
||||||
log.Debugf("Use Cookie %s for model %s", util.HideAPIKey(accountInfo), req.Model)
|
// Only Gemini Web uses cookie; print stable account label as-is.
|
||||||
|
log.Debugf("Use Cookie %s for model %s", accountInfo, req.Model)
|
||||||
}
|
}
|
||||||
|
|
||||||
tried[auth.ID] = struct{}{}
|
tried[auth.ID] = struct{}{}
|
||||||
@@ -333,7 +334,7 @@ func (m *Manager) executeCountWithProvider(ctx context.Context, provider string,
|
|||||||
} else if accountType == "oauth" {
|
} else if accountType == "oauth" {
|
||||||
log.Debugf("Use OAuth %s for model %s", accountInfo, req.Model)
|
log.Debugf("Use OAuth %s for model %s", accountInfo, req.Model)
|
||||||
} else if accountType == "cookie" {
|
} else if accountType == "cookie" {
|
||||||
log.Debugf("Use Cookie %s for model %s", util.HideAPIKey(accountInfo), req.Model)
|
log.Debugf("Use Cookie %s for model %s", accountInfo, req.Model)
|
||||||
}
|
}
|
||||||
|
|
||||||
tried[auth.ID] = struct{}{}
|
tried[auth.ID] = struct{}{}
|
||||||
@@ -380,7 +381,7 @@ func (m *Manager) executeStreamWithProvider(ctx context.Context, provider string
|
|||||||
} else if accountType == "oauth" {
|
} else if accountType == "oauth" {
|
||||||
log.Debugf("Use OAuth %s for model %s", accountInfo, req.Model)
|
log.Debugf("Use OAuth %s for model %s", accountInfo, req.Model)
|
||||||
} else if accountType == "cookie" {
|
} else if accountType == "cookie" {
|
||||||
log.Debugf("Use Cookie %s for model %s", util.HideAPIKey(accountInfo), req.Model)
|
log.Debugf("Use Cookie %s for model %s", accountInfo, req.Model)
|
||||||
}
|
}
|
||||||
|
|
||||||
tried[auth.ID] = struct{}{}
|
tried[auth.ID] = struct{}{}
|
||||||
|
|||||||
@@ -129,6 +129,13 @@ func (a *Auth) AccountInfo() (string, string) {
|
|||||||
return "", ""
|
return "", ""
|
||||||
}
|
}
|
||||||
if strings.ToLower(a.Provider) == "gemini-web" {
|
if strings.ToLower(a.Provider) == "gemini-web" {
|
||||||
|
// Prefer explicit label written into auth file (e.g., gemini-web-<hash>)
|
||||||
|
if a.Metadata != nil {
|
||||||
|
if v, ok := a.Metadata["label"].(string); ok && strings.TrimSpace(v) != "" {
|
||||||
|
return "cookie", strings.TrimSpace(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Minimal fallback to cookie value for backward compatibility
|
||||||
if a.Metadata != nil {
|
if a.Metadata != nil {
|
||||||
if v, ok := a.Metadata["secure_1psid"].(string); ok && v != "" {
|
if v, ok := a.Metadata["secure_1psid"].(string); ok && v != "" {
|
||||||
return "cookie", v
|
return "cookie", v
|
||||||
@@ -137,14 +144,6 @@ func (a *Auth) AccountInfo() (string, string) {
|
|||||||
return "cookie", v
|
return "cookie", v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if a.Attributes != nil {
|
|
||||||
if v := a.Attributes["secure_1psid"]; v != "" {
|
|
||||||
return "cookie", v
|
|
||||||
}
|
|
||||||
if v := a.Attributes["api_key"]; v != "" {
|
|
||||||
return "cookie", v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if a.Metadata != nil {
|
if a.Metadata != nil {
|
||||||
if v, ok := a.Metadata["email"].(string); ok {
|
if v, ok := a.Metadata["email"].(string); ok {
|
||||||
|
|||||||
Reference in New Issue
Block a user