Repository navigation
fix(139): keep valid tokens when refresh metadata is absent - #164
Conversation
Issue #122 reports that existing 139 authorizations became unusable as soon as they entered the 15-day refresh window, even when they were still accepted by the service. The PC refreshToken endpoint requires user_domain_id, but legacy storage configurations may not contain it. Skip only the automatic refresh when user_domain_id is absent; retain the current authorization and allow the normal API request to determine whether the token is still valid. When user_domain_id is present, preserve the existing near-expiry refresh flow and persistence callback. Expose the optional field in the 139 storage form with a description. Validation: 139 driver tests 13/13 passed; mutation check restoring the previous throw makes the new regression test fail; git diff --check passed.
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
openlist-work | 9bfd4fe | Nov 09 2026, 10:14 AM |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| 🔵 In progress View logs |
openlist-tsworkers | 9bfd4fe | Nov 09 2026, 10:13 AM |
There was a problem hiding this comment.
🙏 感谢贡献 PR #164!感谢 @PIKACHUIM 提交~
🤖 AI 自动审核声明:本评审报告由 AI 自动生成,当前使用 DeepSeek-V4.1-Flash 模型进行分析。
🎯 结论
✅ Approve — 把「可选刷新失败」降级为「跳过 + 告警」是对的取舍,可以合并
📖 概要
fix(139): keep valid tokens when refresh metadata is absent · Fixes #122 · 修复 139 云盘在 token 进入 15 天刷新窗口但未配置 user_domain_id 时直接抛错
核心改动:缺 user_domain_id 时跳过 PC refreshToken、保留当前 token 继续使用;表单新增可选字段
🧭 整体方案
把「自动续期」从「硬前置条件」改回「可选增强」——不能因为拿不到续期参数就否掉一个仍然可用的授权。语义收窄、改动集中在一个提前返回上,符合最小改动原则。
📊 变更统计
3 个文件(+65 / -3) | 功能 ⭐⭐⭐⭐⭐ | 最小改动 ⭐⭐⭐⭐⭐ | 前向兼容 ⭐⭐⭐⭐⭐ | 方案设计 ⭐⭐⭐⭐⭐
🚨 关键问题
无重大问题。
P2(可选):
- 💡
drivers/139/util.ts的warnedMissingUserDomainId是实例级去重,而注释里写明refreshAuthorizationIfNeeded()可能在「每次 API 请求前」被调用。如果某些路径上的驱动实例不进缓存(例如deferTokenPersistence的临时实例、或storage/update时新建的实例),过期临近期间仍可能每个请求打一条 warn。建议把告警降为「首次 + N 次心跳」或直接写进storage.status。 - 💡 语义变化值得在描述里点明:跳过刷新后,token 真正过期时上游会返回鉴权错误,用户看到的是「驱动报上游 401」而不是「请配置 user_domain_id」。建议在错误信息里做一次归因提示(例如捕获 401 时附带「可能因未配置
user_domain_id导致无法自动续期」),否则排查成本会从「配置错误」转移到「驱动异常」。
📂 逐文件分析
src/backend/drivers/139/util.ts
改动意图:缺 user_domain_id 时不再抛错。
代码逻辑:if (!userDomainId) → 打一次 warn + return,保留 this.authorization 不变;后续正常请求流程继续。
评价:提前返回点在「构造 PC refresh 请求」之前,没有留下半初始化的状态;pieces.length < 3 / 时间戳解析失败的既有早退分支也未受影响。
src/backend/drivers/139/driver.test.ts
评价:用 calls 数组断言「只发生了 routePolicy 请求、没有打 refreshToken 端点」,再断言 getAuthString() 与原 token 完全一致——比只断言「没抛错」更能防回归。
src/backend/server/admin.ts
评价:user_domain_id 标为 required: false 且 help 说明了用途,与描述里的「可选」一致,没有破坏已有表单。
✅ 待处理清单
- [P2] 告警去重从实例级改为「一次性/状态位」,避免高频路径刷日志
- [P2] token 真正过期时补一条归因提示(指向
user_domain_id)
🎯 结论:✅ Approve — 取舍合理、测试有效、向后兼容。
The PC refreshToken API requires user_domain_id, so configs that only contain Authorization were left with no automatic refresh and emitted a near-expiry warning on every storage init. Fall back to the legacy authTokenRefresh.do endpoint already used by the Go backend when user_domain_id is empty. It only needs the current token and account, accepts both <token> and <accessToken> candidates, and only writes back a token with a later expiry. Refresh failures are silent and keep the current authorization usable until the service rejects it. user_domain_id stays optional and the PC path is unchanged when set. Tests: 139 driver 14/14, drivers 199/199, server 206/206, tsc clean.
Align the Worker driver with the Go backend's credential flow: - Port step1 mail password login, step2 artifact exchange and step3 encrypted third-party login (AES-CBC/ECB, RSA PKCS1 v1.5). - Support fast login with existing mail_cookies and SMS risk control (sms_code), including cookie persistence between attempts. - Persist authorization, user_domain_id, mail_cookies and sms_code after a successful login, matching Go's MustSaveDriverStorage behavior. - Keep manual Authorization + user_domain_id authoritative: when Authorization is present no login runs; a login only overwrites the manual value when it is actually triggered. - Re-login after a refresh failure when credentials are available, matching Go's loginAfterAuthorizationFailure. - Expose authorization (now optional), username, password, sms_code and mail_cookies in the 139 storage form. Tests: driver 25/25, all drivers 210/210, server 206/206, tsc clean.
Go's loginAfterAuthorizationFailure never retries cookie fast login after a refresh failure; mail_cookies are only reused as device context for the password login request. Restrict the refresh-failure re-login to username + password and add a skipFastLogin option so the fallback performs step1 -> step2 -> step3 instead of step2 -> step3. Tests: 139 driver 25/25, tsc clean.
PR #164 正文(更新版)
fix(139): align token refresh and user_domain_id with GoSummary / 摘要
本 PR 让 Worker 的 139 驱动在凭证、刷新与
user_domain_id上对齐 Go 主项目:user_domain_id不再导致存储初始化失败。user_domain_id时使用主项目同款旧版刷新接口。user_domain_id。loginAfterAuthorizationFailure用用户名密码重新登录。Authorization+ 手动user_domain_id仍然优先,不会被无端覆盖。username、password、sms_code、mail_cookies字段,authorization改为可选。Motivation / 背景
Issue #122:现有 139 授权进入 15 天续期窗口后,如果配置里没有
user_domain_id,PCrefreshToken接口不可用,原实现直接抛错,导致仍有效的授权无法使用。同时,Worker 缺少主项目的邮箱登录链路,无法像 Go 一样从登录结果自动获得并保存
userDomainId。Changes / 改动内容
1. 凭证初始化
src/backend/drivers/139/util.ts新增ensureAuthorization():Authorization非空:直接使用,跳过登录。Authorization为空且mail_cookies含Os_SSo_Sid/RMKEY:Step2 → Step3 快速登录。Authorization为空且username+password:Step1 → Step2 → Step3 完整登录。sms_code后继续。authorization、user_domain_id、mail_cookies、sms_code。2. Go 登录链路移植
新增
src/backend/drivers/139/login.ts:mail.10086.cn密码登录,处理 302、Set-Cookie、风险码ec。RMKEY换 artifact。yun.139.com/user/thirdlogin加密登录,提取authToken、account、userDomainId。Headers.getAll("Set-Cookie")与标准getSetCookie()。3. 刷新与回退
user_domain_id:PCrefreshToken。user_domain_id:旧版authTokenRefresh.do。loginAfterAuthorizationFailure重新密码登录;不接受 Cookie 快速登录作为回退。4. 持久化
src/backend/internal/op/storage.ts新增登录状态回调,写入:authorizationuser_domain_idmail_cookiessms_code5. 管理端字段
src/backend/server/admin.ts为139Yun增加:authorization(改为可选)usernamepasswordsms_codemail_cookiesuser_domain_id(可选,登录后自动填充)行为矩阵
Authorizationuser_domain_id直接生效Authorization+mail_cookiesuser_domain_idAuthorization+username/passworduser_domain_idTesting / 验证
覆盖场景:
user_domain_id保留。Compatibility / 兼容性
Authorization的配置继续可用。user_domain_id的后备路径。authorization从必填改为可选,旧前端如仍标记必填,以服务端/驱动校验为准。Known boundaries / 已知边界
OpenList-Frontend的139Yun字段提示仍是旧内容。OpenList-Document/pages/guide/drivers/139.md的“用户域 ID”章节仍主要描述容量用途。ff8c863)。Checklist
tsc --noEmit通过build:edge通过user_domain_id与自动获取逻辑均已覆盖