From 15602b8033d7f3dcca6c317fbd503b7281b98298 Mon Sep 17 00:00:00 2001 From: chiyi Date: Mon, 10 Aug 2026 19:38:58 +0800 Subject: [PATCH] =?UTF-8?q?leonardo:=20=E6=8A=8A=20cross-origin-cookie=204?= =?UTF-8?q?01=20=E5=88=A4=E4=B8=BA=E4=BC=9A=E8=AF=9D=E8=A2=AB=E5=90=8A?= =?UTF-8?q?=E9=94=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/internal/provider/leonardo/client.go | 21 ++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/backend/internal/provider/leonardo/client.go b/backend/internal/provider/leonardo/client.go index ef41bfe..8c9365c 100644 --- a/backend/internal/provider/leonardo/client.go +++ b/backend/internal/provider/leonardo/client.go @@ -207,6 +207,9 @@ func (c *Client) GetSession(ctx context.Context, cookie string) (*Session, error var setCookies []string var err error var warmed bool + // 401 from cross-origin-cookie means Leonardo已经作废了这个 session(不是人机校验), + // 记下来好把日志写成"会话被吊销"而不是含糊的 get-session null。 + warmStatus := 0 for attempt := 0; attempt < getSessionAttempts; attempt++ { if attempt > 0 { select { @@ -227,7 +230,9 @@ func (c *Client) GetSession(ctx context.Context, cookie string) (*Session, error // better-auth cookie cache (and CF_Access_Token). Without it get-session // answers 200 null even for a perfectly healthy cookie. warmed = false - if warmCookies, werr := c.warmSession(ctx, client, send); werr == nil { + warmCookies, wstatus, werr := c.warmSession(ctx, client, send) + warmStatus = wstatus + if werr == nil { warmed = true if merged := mergeCookies(send, warmCookies); merged != send && keepsSession(merged) { send = merged @@ -284,6 +289,10 @@ func (c *Client) GetSession(ctx context.Context, cookie string) (*Session, error return nil, fmt.Errorf("%w: get-session non-json", ErrTemporaryUpstream) } if strings.TrimSpace(raw.Session.AccessToken) == "" { + if warmStatus == 401 { + // Leonardo 明确拒了这份 session_token:服务端已把会话吊销,重新导入 cookie 才能恢复。 + return nil, fmt.Errorf("%w: session revoked (cross-origin-cookie 401)", ErrAuth) + } if !warmed { // A cold get-session (the cookie cache was never refreshed) answers null // for healthy accounts too — temporary, never a reason to kill the account. @@ -321,23 +330,23 @@ func (c *Client) GetSession(ctx context.Context, cookie string) (*Session, error // warmSession calls cross-origin-cookie, whose response refreshes better-auth's // cookie cache and CF_Access_Token. It returns the Set-Cookie headers; a // checkpoint answer (403/429) is an error, since get-session would then be cold. -func (c *Client) warmSession(ctx context.Context, client tlsclient.HttpClient, cookie string) ([]string, error) { +func (c *Client) warmSession(ctx context.Context, client tlsclient.HttpClient, cookie string) ([]string, int, error) { req, err := http.NewRequest(http.MethodGet, appBase+"/api/auth/cross-origin-cookie", nil) if err != nil { - return nil, err + return nil, 0, err } req = req.WithContext(ctx) req.Header = sessionHeader(cookie) resp, err := client.Do(req) if err != nil { - return nil, err + return nil, 0, err } defer resp.Body.Close() _, _ = io.Copy(io.Discard, resp.Body) if resp.StatusCode == 403 || resp.StatusCode == 429 { - return nil, fmt.Errorf("cross-origin-cookie http %d", resp.StatusCode) + return nil, resp.StatusCode, fmt.Errorf("cross-origin-cookie http %d", resp.StatusCode) } - return resp.Header["Set-Cookie"], nil + return resp.Header["Set-Cookie"], resp.StatusCode, nil } // fetchSession performs one get-session call and returns its status, body and