Skip to content

Clear signup phone identity before starting the next auto-run round#286

Open
gstranded wants to merge 1 commit into
QLHazyCoder:masterfrom
gstranded:fix/clear-signup-phone-after-success
Open

Clear signup phone identity before starting the next auto-run round#286
gstranded wants to merge 1 commit into
QLHazyCoder:masterfrom
gstranded:fix/clear-signup-phone-after-success

Conversation

@gstranded
Copy link
Copy Markdown

@gstranded gstranded commented May 26, 2026

问题背景

手机号注册链路在第 12 步 platform-verify 成功后,会马上把最终节点标记为完成并释放自动运行的完成信号。此时后续成功收尾逻辑仍然可能在后台异步执行,例如:

  • 标记 / 删除 iCloud Hide My Email 别名
  • 标记当前邮箱或邮箱池账号为已用
  • 关闭 localhost callback 残留标签页
  • 写入账号运行记录

实际运行日志中可以看到上一轮成功收尾和下一轮启动交错发生:第 12 步成功后,下一轮已经开始执行第 1 步,而上一轮的 iCloud 自动删除仍在几秒后继续输出日志。

在这种时间窗口里,手机号注册运行态可能还保留在 chrome.storage.session 中,包括:

  • signupPhoneNumber
  • signupPhoneActivation
  • signupPhoneCompletedActivation
  • signupPhoneVerificationRequestedAt
  • signupPhoneVerificationPurpose
  • accountIdentifierType: "phone"
  • accountIdentifier

如果下一轮启动得很快,或者用户在成功后停止流程并手动从第 7 步继续,这些旧手机号状态就可能被后续 OAuth 手机号登录路径继续读取,导致下一轮复用上一轮已经完成注册的手机号。

根因分析

completeNodeFromBackground() 对最终节点采用的是“先释放完成信号,再异步执行收尾副作用”的设计:

  1. 最终节点被标记为 completed
  2. 立即调用 notifyNodeComplete(...)
  3. 自动运行控制器收到完成信号后可以进入下一轮
  4. runCompletedNodeSideEffects(...) 在后台继续处理成功后的收尾逻辑

这个设计可以避免最终节点被慢收尾阻塞,但也意味着“必须在下一轮可见之前清掉的运行态”不能放在异步收尾里处理。

手机号注册身份正好属于这种运行态:它只应该在同一轮内用于注册后 OAuth 登录和绑定邮箱,不应该跨成功轮次保留给下一轮使用。

解决方案

新增最终节点释放前的同步清理逻辑:clearSignupPhoneIdentityAfterSuccessfulFlow()

completeNodeFromBackground() 判断当前节点是流程最后一个节点时,会在 notifyNodeComplete(...) 之前先清空本轮手机号注册身份:

  • phoneNumber
  • signupPhoneNumber
  • signupPhoneActivation
  • signupPhoneCompletedActivation
  • signupPhoneVerificationRequestedAt
  • signupPhoneVerificationPurpose

如果当前账号身份仍然是手机号身份,还会同步清空:

  • accountIdentifierType
  • accountIdentifier

清理完成后才释放最终节点完成信号,因此下一轮自动运行不会再读到上一轮手机号注册身份。

安全性细节

这个清理逻辑有几个保护点:

  1. 保留成功记录所需的手机号快照

    completionState 仍然是在清理前读取的快照,后续 appendAndBroadcastAccountRunRecord('success', completionState) 仍然可以记录本轮成功账号的手机号身份。也就是说,运行态被清掉,但账号历史不会丢失本轮手机号信息。

  2. 避免误清新手机号

    如果完成时快照里的手机号和当前 state 里的手机号都存在,但二者不一致,清理函数会跳过,避免在极端并发情况下清掉已经被其它流程写入的新手机号身份。

  3. 支持格式差异匹配

    手机号匹配同时支持原始字符串匹配和仅数字匹配,避免 +56...、空格、括号等格式差异导致同一个手机号被误判为不同。

  4. 不等待慢收尾

    iCloud 删除等慢操作仍然保留在异步收尾里,不会重新阻塞最终节点;本 PR 只把“必须在下一轮开始前完成”的手机号运行态清理前移。

  5. 不修改发布版本号

    本 PR 只修改运行态清理和测试,不调整 manifest.json 版本,避免把发布版本管理混入 bugfix。

用户可见变化

手机号注册流程成功后,日志会出现:

手机号注册:流程成功后已清空本轮注册手机号,避免下一轮复用。

这表示当前轮手机号身份已经在下一轮开始前被清空。

测试

新增测试覆盖最终节点完成路径,验证:

  • 最终节点在释放 notifyNodeComplete 前先清空手机号注册身份
  • 清理会广播状态更新
  • signupPhoneNumbersignupPhoneActivationsignupPhoneCompletedActivation 被清空
  • 手机号类型的 accountIdentifierType / accountIdentifier 被清空
  • 原有“最终节点慢收尾不阻塞完成信号”的行为仍然保留

已运行:

node --test tests\background-step-completion.test.js
node --test tests\auto-run-fresh-attempt-reset.test.js
npm.cmd test

全量测试结果:

1271 pass

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