fix: skip login refresh for token-only alist storage

401 responses surface the auth error instead of sending a
credential-less login; the refresh window never exceeds TokenExp.
This commit is contained in:
krau
2026-08-16 21:35:21 +08:00
parent 4c8f35ae80
commit 0d42c9f23d
2 changed files with 20 additions and 3 deletions

View File

@@ -125,6 +125,11 @@ func (a *Alist) Save(ctx context.Context, reader io.Reader, storagePath string)
if resp.StatusCode == http.StatusUnauthorized || resp.StatusCode == http.StatusForbidden {
status := resp.Status
resp.Body.Close()
// Token-only configurations cannot refresh credentials: surface the
// auth error instead of sending a login request with no credentials.
if a.loginInfo == nil {
return fmt.Errorf("failed to save file to Alist: %s", status)
}
if err := a.getToken(ctx); err != nil {
return fmt.Errorf("failed to refresh alist token: %w", err)
}

View File

@@ -13,14 +13,23 @@ import (
)
// minTokenRefreshInterval deduplicates login storms: a successful refresh is
// reused for this window instead of hitting the login endpoint again.
// reused for this window instead of hitting the login endpoint again. It is
// capped by the configured token expiry so refreshes never go stale.
const minTokenRefreshInterval = 30 * time.Second
func (a *Alist) tokenRefreshWindow() time.Duration {
window := minTokenRefreshInterval
if exp := time.Duration(a.config.TokenExp) * time.Second; exp > 0 && exp < window {
window = exp
}
return window
}
// getToken refreshes the JWT, deduplicating concurrent calls so parallel
// uploads and the background refresher share one login request.
func (a *Alist) getToken(ctx context.Context) error {
a.tokenMu.RLock()
fresh := !a.lastLoginAt.IsZero() && time.Since(a.lastLoginAt) < minTokenRefreshInterval
fresh := !a.lastLoginAt.IsZero() && time.Since(a.lastLoginAt) < a.tokenRefreshWindow()
a.tokenMu.RUnlock()
if fresh {
return nil
@@ -28,7 +37,7 @@ func (a *Alist) getToken(ctx context.Context) error {
_, err, _ := a.tokenFlight.Do("token", func() (any, error) {
// Another waiter may have refreshed while this call was queued.
a.tokenMu.RLock()
fresh := !a.lastLoginAt.IsZero() && time.Since(a.lastLoginAt) < minTokenRefreshInterval
fresh := !a.lastLoginAt.IsZero() && time.Since(a.lastLoginAt) < a.tokenRefreshWindow()
a.tokenMu.RUnlock()
if fresh {
return nil, nil
@@ -39,6 +48,9 @@ func (a *Alist) getToken(ctx context.Context) error {
}
func (a *Alist) fetchToken(ctx context.Context) error {
if a.loginInfo == nil {
return fmt.Errorf("token-only alist storage cannot refresh credentials")
}
loginBody, err := json.Marshal(a.loginInfo)
if err != nil {
return fmt.Errorf("failed to marshal login request: %w", err)