Skip to content

fix(drivers/139): improve mail login credential renewal - #3029

Open
UcnacDx2 wants to merge 2 commits into
OpenListTeam:mainfrom
UcnacDx2:fix/139-mail-login-pr
Open

fix(drivers/139): improve mail login credential renewal#3029
UcnacDx2 wants to merge 2 commits into
OpenListTeam:mainfrom
UcnacDx2:fix/139-mail-login-pr

Conversation

@UcnacDx2

@UcnacDx2 UcnacDx2 commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

PR title: fix(139): improve mail login credential renewal

Summary / 摘要

This PR improves the 139Yun mail-login credential renewal flow so that password login no longer depends on a pre-login JSESSIONID, can start without pre-supplied mail cookies, and can refresh reusable mail cookies after password/SMS authentication.

此 PR 改进了 139Yun 邮箱登录凭据续期流程:账号密码登录不再依赖预登录阶段获取 JSESSIONID,首次配置时可不预先提供 MailCookies,并可在密码 / 短信验证后自动刷新可复用的 MailCookies。

  • Username + password can now be used without initial mail_cookies; existing cookie-only and Authorization flows remain supported.

  • Password login sends the current raw mail-cookie context, merges response cookies back into driver storage state, and reuses refreshed cookies on later logins.

  • When supported 139 Mail risk control requires SMS verification, the driver sends one verification request, keeps the temporary cookies needed for the follow-up save, verifies sms_code, then continues the normal token/authentication chain.

  • Login and SMS POST requests explicitly disable Resty retries to avoid duplicate non-idempotent authentication/SMS requests.

  • Password login stops at the first 302 response instead of following the redirect, allowing the driver to extract the returned sid directly.

  • Stale input MailCookies are allowed to fail fast-login when username/password fallback is available; MailCookies refreshed by a successful password login are expected to support subsequent fast login.

  • No public API or storage-format migration is introduced. The configuration schema is unchanged, but mail_cookies is now optional when username and password are provided.

  • 现在仅提供用户名和密码也可初始化登录;原有仅 Cookie 和 Authorization 登录方式仍保留。

  • 密码登录会保留现有原始 MailCookies,上游响应中的新 Cookie 会合并回驱动状态,并在后续登录中复用。

  • 遇到受支持的 139 邮箱短信风控时,会发送一次验证码请求、保留下一次保存所需的临时 Cookie,验证 sms_code 后继续完成 token / Authorization 登录链路。

  • 登录和短信 POST 请求显式禁用 Resty 自动重试,避免非幂等认证请求或短信请求被重复发送。

  • 密码登录不会继续跟随首个 302,而是直接从响应中提取 sid

  • 用户手工提供的旧 MailCookies 失效时允许回退到账号密码登录;密码登录刷新得到的新 MailCookies 应可继续用于 fast login。

  • 未引入公开 API 或存储格式迁移;配置字段结构不变,但在提供用户名和密码时 mail_cookies 不再是必填项。

  • This PR has breaking changes.
    / 此 PR 包含破坏性变更。

  • This PR changes public API, config, storage format, or migration behavior.
    / 此 PR 修改了公开 API、配置、存储格式或迁移行为。

    • Backward-compatible config behavior change only: mail_cookies becomes optional for username/password login; no field or storage-format migration is required.
    • 仅包含向后兼容的配置行为变化:账号密码登录时 mail_cookies 改为可选,不需要字段或存储格式迁移。
  • This PR requires corresponding changes in related repositories.
    / 此 PR 需要关联仓库同步修改。

Related repository PRs / 关联仓库 PR:

  • OpenList-Frontend: N/A
  • OpenList-Docs: N/A

Testing / 测试

  • go test ./...
  • go test ./drivers/139 -count=1
  • Manual test / 手动测试:
    • Ran real-account GitHub Actions regression tests with credentials, MailCookies, and SMS code supplied only through masked repository secrets.
    • Verified password fallback with stale input MailCookies completes Step1 -> Step2 -> Step3 and produces Authorization.
    • Verified password/SMS authentication refreshes MailCookies and that the refreshed MailCookies can complete a subsequent fast-login Step2 -> Step3 chain.
    • Verified an already-stale input MailCookies set may fail fast login while password fallback and the refreshed-cookie fast login still succeed.
    • Verified zero-initial-cookie SMS bootstrap in earlier isolated live tests: risk detection -> SMS verification -> Step2 -> Step3 -> reusable device cookies.
    • No sensitive credentials, SMS codes, cookies, SID, RMKEY, or Authorization values are logged by the test workflows.

Deterministic tests additionally cover:

  • credential-state selection for Authorization, full login with/without initial MailCookies, cookies-only login, partial credentials, invalid cookies, and invalid Basic -prefixed Authorization;
  • Cookie merging and extraction of Os_SSo_Sid / RMKEY;
  • SMS risk-code-to-scene mapping, SMS request construction, picture-challenge rejection, SMS verification, Cookie merge, and sms_code clearing;
  • password login without initial cookies, single POST behavior, stopping at the first redirect, and persistence of returned cookies;
  • reuse of stale/raw device-cookie context and refreshed cookies across successive password logins.

Checklist / 检查清单

  • I have read CONTRIBUTING.
    / 我已阅读 CONTRIBUTING
  • I confirm this contribution follows the repository license, contribution policy, and code of conduct.
    / 我确认此贡献符合仓库许可证、贡献规范和行为准则。
  • I have formatted the changed code with gofmt, go fmt, or prettier where applicable.
    / 我已按适用情况使用 gofmtgo fmtprettier 格式化变更代码。
  • I have requested review from relevant maintainers or code owners where applicable.
    / 我已在适用情况下请求相关维护者或代码所有者审查。

AI Disclosure / AI 使用声明

  • This PR includes AI-assisted content.
    / 此 PR 包含 AI 辅助内容。

Tools used / 使用工具:

  • ChatGPT
  • Codex
  • GitHub Copilot
  • Claude
  • Gemini
  • Other (please specify) / 其他(请注明):

Usage scope / 使用范围:

  • Code generation / 代码生成

  • Refactoring / 重构

  • Documentation / 文档

  • Tests / 测试

  • Translation / 翻译

  • Review assistance / 审查辅助

  • I have reviewed and validated all AI-assisted content included in this PR.
    / 我已审核并验证此 PR 中的所有 AI 辅助内容。

  • I have ensured that all AI-assisted commits include Co-Authored-By attribution.
    / 我已确保所有 AI 辅助提交都包含 Co-Authored-By 归属信息。

  • I can reproduce all AI-assisted content included in this PR without any AI tools.
    / 我可以在没有任何 AI 工具的情况下重现此 PR 中包含的所有 AI 辅助内容。

Copilot AI lite review requested due to automatic review settings September 3, 2026 07:35

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Several new code paths call base.RestyClient.Clone() without guarding against base.RestyClient being nil, which can cause a runtime panic in uninitialized contexts (e.g., some tests/embedded usage).

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR refactors and hardens the 139Yun mail-login renewal flow to support username/password login without requiring pre-supplied mail_cookies, refresh cookies after password/SMS auth, and avoid duplicate non-idempotent requests by disabling Resty retries for the login/SMS POSTs.

Changes:

  • Removes the pre-login JSESSIONID dependency and uses the existing raw cookie context (if any), while persisting cookies returned by password/SMS login back into driver state.
  • Updates credential validation to allow full login with just username + password (cookies optional), and avoids attempting cookie fast-login when mail_cookies is empty.
  • Updates tests and config help text to reflect the new credential-state behavior and cookie refresh semantics.
File summaries
File Description
drivers/139/util.go Removes pre-login cookie sanitization, disables retries for login/SMS POSTs, persists response cookies, and relaxes credential-state requirements.
drivers/139/util_test.go Reworks tests to cover password login without initial cookies, redirect stopping, and cookie persistence/reuse.
drivers/139/meta.go Updates configuration help strings to document mail_cookies as optional for username/password login.
Review details

Suppressed comments (2)

drivers/139/util.go:1303

  • base.RestyClient may be nil before base.InitClient() runs; base.RestyClient.Clone() will panic. Add a nil guard and use base.NewRestyClient() as a fallback.
	res, err := base.RestyClient.Clone().SetRetryCount(0).R().
		SetHeaders(mailXMLHeaders(d.MailCookies)).

drivers/139/util.go:1382

  • base.RestyClient.Clone() will panic if the global client hasn't been initialized (base.InitClient not called yet). Consider guarding nil and falling back to base.NewRestyClient() to keep this login path safe in tests/embedded usage.
	res, err := base.RestyClient.Clone().
		SetRetryCount(0).
		SetRedirectPolicy(resty.RedirectPolicyFunc(func(_ *http.Request, _ []*http.Request) error {
			return http.ErrUseLastResponse
		})).R().
  • Files reviewed: 3/3 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread drivers/139/util.go Outdated
Fall back to base.NewRestyClient() when base.RestyClient has not been initialized, while preserving cloned global-client behavior and the login/SMS retry and redirect policies.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants