Files
FlowPilot/项目完整链路说明.md
T
Q3CC 1a993e9d6a Merge origin/dev into codex2api source
- resolve the sidepanel contribution-mode test conflict while keeping the new Codex2API assertions\n- update the mail2925 payload test harness for newly added Codex2API and random-subdomain inputs\n- renumber the README quick-start plan headings and strip trailing whitespace from the new tutorial doc
2026-04-22 22:18:09 +08:00

39 KiB
Raw Blame History

项目完整链路说明

本文档面向 AI 与开发者,目标是让阅读者在最短时间内理解“项目做什么、怎么跑、数据怎么流、功能链路怎么串”,从而在新增功能时不漏逻辑、不误改边界。

使用建议:

  1. 先阅读 项目文件结构说明.md
  2. 再阅读本文
  3. 最后阅读 项目开发规范(AI协作).md

1. 项目目标

这是一个 Chrome 扩展,用于自动执行一整套 OpenAI / ChatGPT OAuth 注册与登录流程。

它的核心价值不是“打开一个页面点几个按钮”,而是把下面这些环节串成一条完整可恢复的自动化链路:

  • 生成或选取注册邮箱
  • 打开 ChatGPT / OpenAI 注册入口
  • 提交邮箱和密码
  • 轮询注册验证码
  • 填写姓名和生日
  • 刷新 OAuth 链接并登录
  • 轮询登录验证码
  • 自动确认 OAuth 同意页
  • 把 localhost 回调提交到 CPA、SUB2API 或 Codex2API

2. 核心运行参与者

2.1 Sidepanel

sidepanel/sidepanel.html + sidepanel/sidepanel.js + sidepanel/account-pool-ui.js + sidepanel/update-service.js + sidepanel/contribution-content-update-service.js

职责:

  • 展示配置与步骤状态
  • 接收用户输入
  • 向后台发送命令
  • 接收后台广播并更新 UI
  • 动态渲染步骤列表
  • 管理顶部“贡献”按钮与贡献模式主面板;贡献模式本身是 sidepanel 的运行态 UI 模式,不是新的 panelMode 来源
  • 在贡献模式下复用同一套主自动流程启动,并在面板内展示贡献链路的 OAUTH / 回调 / 总状态 三块实时状态
  • 在顶部“贡献/使用”按钮下方展示一个非强制的内容更新轻提示;提示来源于 apikey.qzz.io 的公开公告 / 教程摘要,用户关闭后仅对当前 promptVersion 静默,下次内容版本变化后会重新出现
  • 在 sidepanel 初始化和点击“自动”按钮前刷新一次贡献站公开内容摘要;如果刷新失败,不阻塞主自动流程
  • 在日志区通过“记录”按钮打开独立的邮箱记录覆盖层,并展示成功/失败/停止/重试统计与分页列表
  • 查询 GitHub Releases 并展示更新卡片;当前更新服务会区分 Pro 与 legacy v 两个版本族,排序时优先保持版本族语义一致,同时会在读取缓存后重新排序,避免旧缓存把 v 版本误显示为比 Pro 更新
  • 为 Hotmail / 2925 账号池复用同一套“添加账号 / 取消添加 / 批量导入 / 收起列表”表单交互;共享的显隐控制放在 sidepanel/account-pool-ui.js,各自 manager 只保留 provider 相关字段校验与业务操作

2.2 Background Service Worker

background.js

职责:

  • 扩展后台入口
  • 装配所有模块
  • 统一承接 runtime message
  • 协调步骤执行
  • 管理状态、自动运行、标签页与内容脚本通信

2.3 Content Scripts

content

职责:

  • 在目标网页上执行 DOM 交互
  • 读取邮件内容或页面状态
  • 将步骤成功/失败状态上报给后台

2.4 Helper / Utils / Provider Logic

分布在根目录和 background/ 下。

职责:

  • 抽离第三方邮箱 provider 的纯逻辑
  • 抽离邮件匹配与验证码提取
  • 抽离共享验证码流程、自动运行流程和运行时基础设施

3. 入口与装配关系

3.1 扩展入口

manifest.json 声明:

  • background.service_worker = background.js
  • side_panel.default_path = sidepanel/sidepanel.html
  • 多组内容脚本自动注入规则

3.2 背景层装配

background.js 通过 importScripts(...) 依次加载:

  • 共享数据与纯工具
  • provider 纯逻辑
  • 后台桥接层
  • 后台共享流程层
  • 后台运行时与消息路由层
  • 步骤执行模块

因此 background.js 现在更像:

  • 常量定义中心
  • 模块依赖装配器
  • 极少量保留函数
  • Chrome 事件挂接入口

3.3 步骤注册

data/step-definitions.js 提供共享步骤元数据。
background/steps/registry.js 负责把“步骤元数据”映射到“步骤执行器”。

这意味着:

  • 步骤顺序靠 order
  • 步骤文件名靠语义
  • 新增步骤时不需要重命名后续文件

4. 状态与存储链路

4.1 chrome.storage.session

保存运行态:

  • 当前步骤状态
  • 当前 sidepanel UI 模式 contributionMode
  • 贡献 OAuth 会话字段:
    • contributionSessionId
    • contributionAuthUrl
    • contributionAuthState
    • contributionCallbackUrl
    • contributionStatus
    • contributionStatusMessage
    • contributionLastPollAt
  • OAuth 链接
  • 当前邮箱 / 密码
  • 第 8 步固定的验证码页显示邮箱 step8VerificationTargetEmail
  • localhost 回调地址
  • 自动运行轮次信息
  • 当前自动运行 session 标识 autoRunSessionId
  • 标签注册表
  • 最近打开的来源地址
  • LuckMail 当前运行时选择
  • 2925 当前选中的账号 ID currentMail2925AccountId(运行时会同步到持久配置,用于重开浏览器后恢复同一个号池账号)

补充:

  • content/mail-2925.js 会把“当前验证码步骤启动会话”对应的已试验证码写入 chrome.storage.session,键为 seen2925CodeState;同一个 Step 4 / Step 8 会话里试过的验证码不会再次提交,新会话开始时会重置。

4.2 chrome.storage.local

保存持久配置与账号运行历史:

  • CPA / SUB2API 配置
  • Codex2API 配置
  • 邮箱 provider 配置
  • Hotmail 账号池
  • 2925 账号池
  • 2925 是否启用号池模式 mail2925UseAccountPool
  • 2925 当前选中的号池账号 ID currentMail2925AccountId
  • Cloudflare / Temp Email 设置
  • iCloud 相关偏好
  • LuckMail API 配置
  • 自动运行默认配置
  • 账号运行历史 accountRunHistory(以邮箱为主键,保存该邮箱最近一次状态:成功/失败/停止)
  • 账号运行历史本地同步开关与 helper 地址

注意:

  • contributionMode 不属于持久配置,也不参与导入/导出;它只存在于运行态
  • panelMode 当前表示 cpa | sub2api | codex2api 三个来源;贡献模式仍不是新的来源枚举

当启用了独立的账号运行历史本地同步配置时,账号运行历史会通过 scripts/hotmail_helper.py 整体同步写入 data/account-run-history.json 快照文件,便于开发者直接查看完整记录。 这条配置链路独立于 mailProvider 和 Hotmail 的接码模式。

4.3 状态广播

后台通过 runtime message 向 sidepanel 广播:

  • LOG_ENTRY
  • STEP_STATUS_CHANGED
  • DATA_UPDATED
  • AUTO_RUN_STATUS
  • ICLOUD_LOGIN_REQUIRED
  • ICLOUD_ALIASES_CHANGED

4.4 贡献模式链路

贡献模式的目标不是新增一个 provider,而是在 sidepanel 内开启一套“贡献账号”专用 UI,并把公开贡献服务并进原有 10 步主链:

  1. 用户点击顶部 贡献
  2. sidepanel 直接通过 SET_CONTRIBUTION_MODE 切换运行态,不再弹确认窗口
  3. 进入贡献模式后会强制 panelMode = cpa,并临时清空运行态 customPassword、禁用运行态账号记录快照同步
  4. sidepanel 隐藏 CPA 管理地址、管理密钥、SUB2API 配置、Codex2API 配置、自定义密码、本地同步等普通模式配置,并禁用来源选择、配置菜单和记录入口
  5. 用户点击 开始贡献 后,不再单独走一条旁路 OAuth 流程,而是直接复用顶部 自动 的同一套主自动流
  6. 步骤 1~6 仍按原来的注册自动化执行
  7. 当主流程进入步骤 7 时,后台改为调用公开接口 POST https://apikey.qzz.io/oauth/api/start 申请贡献登录地址,而不是去 CPA / SUB2API / Codex2API 来源刷新 OAuth
  8. 步骤 7 拿到 session_id / auth_url / state 后,继续沿用原有登录链路进入授权页
  9. 步骤 9 仍负责捕获 localhost callback;贡献模式下后台也会持续监听导航变化,必要时提前兼容处理 callback
  10. 步骤 10 在贡献模式下不再打开 CPA 管理页,而是围绕公开贡献会话做 callback 提交兼容和最终状态确认;当状态进入 auto_approved / auto_rejected / manual_review_required / expired / error 时结束
  11. 当前服务端如果返回“无需手动提交 callback”,扩展会把它视为兼容成功态,而不是报错
  12. 已有认证文件?前往上传 继续打开 https://apikey.qzz.io/
  13. 退出贡献模式 会清理贡献会话相关运行态,重置 只重置主流程状态,不会自动退出贡献模式

这条链路的关键边界是:

  • 扩展会调用公开贡献 API,但这条调用被折叠进主 10 步自动链,而不是额外分出一条独立“贡献 OAuth 小流程”
  • 扩展不会保存 token
  • 扩展不会持有任何管理密钥
  • 扩展代码中不能直接调用 /v0/management/*
  • 扩展不会直接访问生产管理面或生产 auth-dir
  • 安全边界仍然在服务端;扩展只负责公开 OAuth 贡献前端流程
  • 退出贡献模式后,要恢复普通模式 UI,并恢复持久配置中的自定义密码/本地同步偏好

4.5 贡献内容更新提示链路

这条链路用于把 apikey.qzz.io 上的公开公告 / 使用教程更新,映射成 sidepanel 顶部“贡献/使用”按钮下方的轻提示。

  1. 贡献站公开暴露 GET https://apikey.qzz.io/api/content-summary
  2. 接口返回 announcement / tutorial 两类内容的可见状态、更新时间,以及聚合后的 promptVersion
  3. sidepanel/contribution-content-update-service.js 负责拉取这个摘要,并在本地缓存最近一次可用结果
  4. sidepanel.js 在 sidepanel 初始化时会先拉一次摘要;如果当前 promptVersion 没被本地关闭过,就显示提示
  5. 用户点击提示右侧 X 后,只会把当前 promptVersion 记入 localStorage,不会永久关闭整个能力
  6. 当公告或教程再次更新,服务端返回新的 promptVersion,提示会重新出现
  7. 用户点击“自动”按钮时,sidepanel 会在真正启动自动流程前再刷新一次摘要,尽量让提示状态更及时
  8. 如果这次刷新失败,sidepanel 只记录警告并继续自动流程,不会因为提示链路故障阻塞主功能

这条链路的关键边界是:

  • 它只消费公开摘要接口,不接触任何管理接口
  • 它只影响顶部轻提示,不改变贡献模式主状态机
  • 它使用 localStorage 做缓存和关闭版本记录,而不是写入 chrome.storage.session/local
  • 它是辅助提示链路,不允许反向阻塞自动运行

5. 内容脚本通信链路

5.1 READY 机制

content/utils.js 在脚本加载后会发送 CONTENT_SCRIPT_READY

后台收到后会:

  • 注册当前来源对应的 tab
  • 标记 ready
  • 冲刷排队命令

5.2 队列与重试

background/tab-runtime.js 负责:

  • queueCommand
  • flushCommand
  • sendTabMessageWithTimeout
  • sendToContentScriptResilient
  • sendToMailContentScriptResilient

这保证了:

  • 页面切换导致脚本暂时失联时,后台不会立刻误判彻底失败
  • 邮箱页或注册页能在注入恢复后继续执行
  • 用户点击 Stop 后,标签完成等待、注入后的短暂延迟和内容脚本重试等待会尽快中断,不会因为底层轮询还在 sleep 而继续往下恢复

6. 手动步骤完整链路

Step 1

文件:

流程:

  1. 后台打开 ChatGPT 官网并复用/创建注册页标签
  2. 等待注册页内容脚本就绪(仅做连接与注入确认)
  3. 不在 Step 1 检测或点击注册入口
  4. 标记 Step 1 完成

补充:

  • 手动点击“跳过步骤 1”时,会级联将步骤 2~5 标记为跳过;其中已完成或正在运行的步骤不会被改写。

Step 2

文件:

流程:

  1. 解析本轮应使用的邮箱
  2. 打开或复用注册页
  3. 点击注册入口并提交邮箱
  4. 以当前邮箱先写入一条“停止(流程尚未完成)”的记录占位
  5. 等待邮箱提交后的真实落地页
  6. 如果进入密码页,则继续执行 Step 3
  7. 如果直接进入邮箱验证码页,则自动跳过 Step 3 并进入 Step 4

Step 3

文件:

流程:

  1. 生成或读取密码
  2. 更新运行态密码
  3. 记录账号快照
  4. 让内容脚本填写密码
  5. 内容脚本先上报 Step 3 完成信号
  6. 上报完成后再异步点击提交,避免页面跳转打断响应通道
  7. 延迟提交真正触发前会再次检查 Stop 状态,避免用户已停止时页面仍继续自动提交
  8. 后台在真正确认 Step 3 完成前,会额外检查提交后是否切换页面;如果出现认证页 Try again / 重试 页面,或 /email-verification 上的 405 / Route Error 重试页,会先通过共享恢复逻辑最多自动点击 5 次 重试 尝试恢复,再继续后续链路

Step 4 / Step 8

文件:

这两步共享验证码主流程:

  1. 确定 provider
  2. 必要时重发验证码
  3. 轮询邮箱或 API
  4. 提取验证码
  5. 回填页面
  6. 若页面拒绝,则重试或回退

补充行为:

  • 2925 provider 会关闭 Step 4 / 8 的自动重发间隔 25 秒节流;每次“重新发送验证码”之间,会在邮箱页内部执行一轮固定 15 次的刷新轮询,不再因 OAuth 剩余时间预算而缩短。

  • 当 provider 为 2925 时,Step 4 会优先直接打开当前 2925 邮箱页,并先比对页面顶部显示的邮箱地址是否与当前目标邮箱一致:如果一致,就直接复用当前已登录页面;如果不一致且启用了 2925 账号池,则会先清理 cookie 再登录当前选中的账号;如果不一致且未启用账号池,则直接复用现有停止逻辑结束流程。Step 8 不再额外承接这套登录态处理。

  • 普通邮箱仍会携带 filterAfterTimestamp 做时间窗筛选;2925 当前既不依赖时间窗,也不再做“新旧邮件快照差集”比较,而是每次刷新后直接遍历当前列表中的匹配邮件。

  • 自动重新发送验证码次数现在使用 sidepanel 里的单一“验证码重发”配置;普通邮箱仍按 25 秒间隔节流,Hotmail / 2925 不走这个 25 秒间隔。Step 4 若启用先请求新验证码,会先消耗一次当前步骤的自动重发次数。

  • 验证码提交重试上限当前为 15 次;页面明确拒绝验证码时,会在上限内继续拉取新验证码并重提。

  • 2925 内容脚本会把每一封实际打开检测的邮件立即删除;同一验证码步骤启动后,试过的验证码会按“步骤 ID + 启动时间”隔离缓存,不会在本次步骤里重复提交;如果再次遇到相同验证码,对应邮件也会在读取后立即删除,避免后续反复打开。

  • 2925 在 provide 模式下仍保持宽松匹配:只要邮件内容命中 ChatGPT / OpenAI 验证码过滤条件,就会尝试该邮件。

  • 2925 在 receive 模式下会恢复“弱目标邮箱匹配”:只有当邮件里显式出现了其他收件邮箱时才会跳过;如果邮件里没有明确写出邮箱,仍允许继续尝试该验证码。

  • 当验证码最终提交成功后,后台会异步向 2925 邮箱页发送 DELETE_ALL_EMAILS,执行“全选 + 删除”清理剩余邮件,不阻塞主流程。

  • 如果 2925 邮箱页在轮询期间出现“子邮箱已达上限邮箱”,后台会记录当前时间,把当前 2925 账号禁用 24 小时,自动切到下一个可用账号并完成登录,然后直接报错结束当前尝试;如果 Auto 开启了自动重试,现有控制器会按原逻辑进入下一次尝试。

  • Auto 模式下,普通 Step 4 失败仍会沿用当前邮箱回到 Step 1 重新开始当前轮;但若失败原因是 2925 主动要求“结束当前尝试”,则不会再回到 Step 1 重开,而是直接把错误抛给自动重试控制器。

Step 5

文件:

流程:

  1. 生成随机姓名和生日
  2. 内容脚本填写资料;如果资料页出现顶部“我同意以下所有各项”总勾选框,会先自动勾选后再提交
  3. 内容脚本点击“完成帐户创建”
  4. 点击后立即上报 Step 5 完成,不再等待页面结果
  5. 自动运行在进入 Step 6 前仅额外等待当前页面加载完成,不再在 Step 5 阶段接管 ChatGPT 跳转或 onboarding 跳过

Step 6

文件:

流程:

  1. 等待登录前清理延迟
  2. 直接删除 ChatGPT / OpenAI cookies
  3. 必要时用 browsingData 补扫 cookies
  4. 完成后进入后续登录链路

Step 7

文件:

流程:

  1. 按当前来源刷新 OAuth 地址:
    • CPA:打开管理页并读取 OAuth 地址
    • SUB2API:打开后台并生成 OAuth 地址
    • Codex2API:直接调用后台协议 /api/admin/oauth/generate-auth-url
  2. 打开最新 OAuth 链接
  3. 登录;如果进入密码页且当前有密码,则填写并提交密码;如果当前没有密码但检测到一次性验证码入口,则直接切换到一次性验证码登录
  4. 确保真正进入验证码页
  5. 如果未进入验证码页,则按可恢复逻辑最多重试 3 次;但一旦当前失败已经明确进入 https://auth.openai.com/add-phone,则立即退出步骤 7 内部重试,不再继续第 2 / 3 次尝试
  6. 自动运行一旦进入步骤 7 之后的链路,若后续步骤报错且认证页未进入 https://auth.openai.com/add-phone,则统一回到步骤 7 重新开始授权流程
  7. CPA 回调阶段固定为步骤 9,不再支持“第七步回调”跳过步骤 7/8

贡献模式补充:

  • 贡献模式下,步骤 7 不再从 CPA / SUB2API / Codex2API 来源刷新 OAuth,而是直接调用公开贡献接口 /oauth/api/start
  • 贡献接口返回的 auth_url 会写回运行态 oauthUrl,后续步骤 7 / 8 / 9 继续复用现有授权链路

Step 8

文件:

流程:

  1. 确认当前认证页已经进入登录验证码页
  2. 对非 2925 provider,固定当前验证码页显示邮箱为本次 Step 8 的目标邮箱
  3. 打开邮箱页或 API 轮询入口
  4. 轮询登录验证码
  5. 回填登录验证码
  6. 如果登录验证码提交后页面进入 add-phone / 手机号页,则立即判为 fatal 错误,不再把步骤 8 视为成功
  7. 如遇邮箱轮询类失败或显式的 STEP8_RESTART_STEP7 恢复错误,则按有限次数回到 Step 7 重试
  8. 获取到登录验证码后不再触发“刷新 OAuth 并重走 Step 7”的前置回放,直接在当前验证码页提交并继续进入 Step 9

补充:

  • 2925 provide 而言,Step 8 仍不依赖验证码页显示邮箱做收件匹配,而是直接测试所有命中 ChatGPT / OpenAI 过滤条件的邮件。
  • 2925 receive 而言,Step 8 会把当前目标注册邮箱一并传给 2925 内容脚本;只有当邮件里显式写出了其他邮箱时才会跳过,从而在不破坏历史兼容性的前提下,尽量降低误收验证码的概率。

Step 9

文件:

流程:

  1. 监听 localhost callback
  2. 准备 OAuth 同意页
  3. 尝试多轮点击“继续”
  4. 一旦捕获 localhost callback,写入状态并完成步骤

Step 10

文件:

流程:

  1. 校验 localhost callback 是否有效
  2. 判断当前来源是 CPA、SUB2API 还是 Codex2API
  3. CPA / SUB2API 打开相应后台;Codex2API 直接走协议分支,不打开后台页面
  4. 提交回调地址或等价的授权码交换请求
  5. 仅当出现精确成功徽标,且该徽标不是红色/错误态、页面上也没有同时可见的失败提示时,才判定成功
  6. 识别 认证失败:*认证失败: timeout of 30000ms exceeded回调 URL 提交失败: oauth flow is not pending 等失败提示并立即报错
  7. 完成平台侧验证
  8. 追加账号运行历史成功记录
  9. 做成功后的清理与标记

Codex2API 补充:

  • 步骤 7 直接调用 POST /api/admin/oauth/generate-auth-url 获取 auth_url / session_id
  • 授权页仍沿用现有 OpenAI 登录、验证码、OAuth 同意页与 localhost callback 主链
  • 步骤 10 直接调用 POST /api/admin/oauth/exchange-code,用 callback 中的 code / state 完成账号创建
  • Codex2API 这条来源不新增 panel content script,也不依赖“添加账号 -> OAuth 授权 -> 生成授权链接”页面按钮 DOM

贡献模式补充:

  • 贡献模式下,步骤 10 不再打开 CPA 管理页
  • 步骤 10 会先尝试提交已捕获的 callback URL,随后轮询公开贡献状态,直到进入最终态
  • auto_approvedmanual_review_required 视为主流程完成;auto_rejected / expired / error 视为当前轮失败

7. 邮箱与 provider 链路

7.1 2026-04-17 补充:Gmail / 2925 统一别名邮箱链路

本轮将 Gmail 与 2925 + provide 的注册邮箱逻辑统一收敛为“共享别名邮箱链路”:

  • 两者都先填写“基邮箱”
    • Gmailname@gmail.com
    • 2925(仅 provide 模式):name@2925.com
  • 两者都允许两种入口:
    • 点击侧边栏按钮自动生成完整注册邮箱
    • 直接在“注册邮箱”输入框中手动填写完整邮箱
  • mailProvider = 2925mail2925Mode = receive 时,不再走别名基邮箱链路,而是回退到普通“邮箱生成 / 手动填写注册邮箱”路线;2925 仅负责后续收信与登录态管理

当前行为约定:

  1. sidepanel 会根据当前 provider 与 mail2925Mode 决定是否展示“别名基邮箱”输入框
  2. 点击 获取 / 生成 时:
    • Gmail 生成 name+tag@gmail.com
    • 2925 仅在 provide 模式下生成 name123456@2925.com
  3. Step 2 / Step 3 进入注册流程前,会先判断当前 state.email
    • 如果已经是与当前基邮箱兼容的完整邮箱,则直接复用
    • 如果为空或不兼容,则按当前 provider / mode 重新生成
  4. 保存或执行 Step 3 时,如果手动填写的完整邮箱与当前 Gmail / 2925 provide 基邮箱不兼容,sidepanel 会直接拦截;2925 receive 不参与这条兼容性约束
  5. auto-run fresh attempt reset 时,会保留:
    • gmailBaseEmail
    • mail2925BaseEmail

7.2 共享模块分工

  • managed-alias-utils.js 统一承接 Gmail / 2925 的:

    • 基邮箱解析
    • 完整邮箱兼容性判断
    • 别名邮箱生成
    • UI 文案输出
  • background/generated-email-helpers.js 在原有 Duck / Cloudflare / iCloud / Cloudflare Temp Email 生成链路之外,新增 Gmail / 2925 的共享生成接入。

  • background/signup-flow-helpers.js 负责在真正提交注册邮箱前做“复用已有完整邮箱 / 重新生成”的最终决策。

7.1 生成邮箱

文件:

支持:

  • Duck
  • Cloudflare
  • Cloudflare Temp Email
  • iCloud 隐私邮箱

7.2 Hotmail

组成:

模式:

  • API 对接
  • 本地 helper

补充:

  • 本地 helper 除了收信与验证码读取,还提供邮箱记录 JSON 快照同步接口。
  • 账号运行历史本地同步由独立配置控制,不再绑定 Hotmail 的本地助手模式。
  • sidepanel 中 Hotmail 账号池的新增表单默认收起,头部通过共享按钮切换“添加账号 / 取消添加”;表单显隐、按钮文案切换、清空与聚焦都复用 sidepanel/account-pool-ui.js,不在 Hotmail manager 内重复实现一套。

7.3 LuckMail

组成:

7.4 2925 账号池

组成:

职责:

  • mail2925-utils.js 统一承接 2925 账号池的归一化、冷却期判断、可用账号挑选、导入格式解析与列表更新。
  • background/mail-2925-session.js 统一承接 2925 账号池的持久化、当前账号切换、cookie 清理登出、网页登录态确认、自动登录,以及命中“子邮箱已达上限邮箱”后的 24 小时禁用与自动切号。
  • sidepanel/mail-2925-manager.js 负责 2925 账号池的新增、导入、切换、手动登录、禁用、清冷却与删除。
  • sidepanel/account-pool-ui.js 负责 Hotmail / 2925 账号池共用的新增表单显隐、头部按钮文案切换、清空表单与首字段聚焦;2925 manager 不再单独维护另一套表单开关状态机。

链路:

  1. 用户在 sidepanel 的 2925 账号池中保存 email / password
  2. sidepanel 中会单独展示 提供邮箱 / 接收邮箱 模式切换,以及独立的 2925 号池 开关 / 当前账号下拉框;这样即使切到 receive 模式,账号池设置也不会被别名基邮箱行一起隐藏
  3. 只有当 sidepanel 中的 mail2925UseAccountPool 开关开启时,provide 模式下的别名基邮箱才会优先取当前账号池选中的 2925 账号邮箱;关闭时会回退到原来的手填 mail2925BaseEmail
  4. 手动点击 登录 或自动流程进入 Step 4 前,后台会先打开当前 2925 邮箱页,并读取页面顶部当前邮箱地址:如果仍停留在收件箱且顶部邮箱与目标邮箱一致,则直接复用;如果顶部邮箱不一致且启用了号池模式,则先清理 cookie 后登录当前选中的账号;如果顶部邮箱不一致且未启用号池模式,则直接调用现有停止逻辑结束流程;如果页面跳到登录页,则仍然只有号池模式开启时才自动登录
  5. 一旦轮询期间出现“子邮箱已达上限邮箱”,后台会先判断是否启用了号池模式:若已启用且还有下一个可用账号,则把当前账号禁用 24 小时并自动切到下一个账号重新登录;若未启用,则直接调用现有停止逻辑结束流程
  6. 如果登录页已经识别到账号密码输入框,内容脚本会在填完账号密码后额外等待 1 秒再点击登录;若点击登录后 40 秒内仍未进入收件箱,且当前正处于自动运行中,则后台会直接复用现有 requestStop() 停止链路,把整个自动流程停成和用户手动点击“停止”一致的状态;这类情况常见于图片验证、行为验证或其他阻断登录的中间页
  7. 如果没有下一个可用账号,或当前未启用号池模式,则不会继续消耗自动重试次数,而是直接复用现有 requestStop() 停止链路,把整个自动流程停成和用户手动点击“停止”一致的状态
  8. sidepanel 中 2925 账号池的新增表单也走与 Hotmail 相同的共享交互:默认收起,头部按钮切换“添加账号 / 取消添加”,操作行右侧提供“批量导入”,保存成功后自动收起并清空。
  9. 当 2925 号池模式开启时,当前选中的号池邮箱会同步回写到同一个 mail2925BaseEmail 字段;因此用户切换号池账号后,即使再次关闭号池模式,也会直接沿用刚才选中的邮箱作为手动基邮箱,无需重新输入。

7.4.1 2925 双模式维护约定

这是后续维护 2925 时最容易被重新打散的一段链路,建议按下面的职责边界理解:

  • UI 层:

    • sidepanel/sidepanel.html
      • 负责展示 提供邮箱 / 接收邮箱
      • 负责展示独立的 2925 号池 配置行
      • 不负责决定“2925 是否参与别名邮箱生成”
    • sidepanel/sidepanel.js
      • 只负责把当前 mail2925Mode、号池开关、当前账号选择同步到 state / runtime message
      • 只负责用共享规则决定当前文案、显隐和前端校验
      • 不应再次复制一套“provide / receive 对应什么行为”的业务判断
  • 共享规则层:

    • managed-alias-utils.js
      • 负责 mail2925Mode 归一化
      • 负责判断 2925 当前是否属于“别名邮箱 provider”
      • 负责保证 2925 只有在 provide 模式下才进入共享别名邮箱链路
      • 如果未来要新增第三种模式,应该先改这里,再改 sidepanel / background 接线
  • 注册邮箱生成层:

    • background/generated-email-helpers.js
      • 只负责根据当前 provider / mode 选择“共享别名邮箱”还是“普通邮箱生成器”
      • 不负责定义 provide / receive 的语义本身
    • background/signup-flow-helpers.js
      • 只负责真正提交前的“复用已有邮箱 / 重新生成邮箱”
      • 这里看到的 isGeneratedAliasProvider(state) 已经包含 mail2925Mode 语义,不应该再手写 state.mail2925Mode === 'provide'
  • 收信与验证码层:

    • background/verification-flow.js
      • 负责决定是否给 2925 内容脚本下发 mail2925MatchTargetEmail
      • 当前约定:仅 receive 模式开启弱目标邮箱匹配
    • content/mail-2925.js
      • 负责真正执行“弱目标邮箱匹配”
      • 当前约定:只有邮件里显式出现了其他邮箱才跳过;若邮件里没有写邮箱,仍允许继续尝试
      • 这样做的目的,是在不破坏历史兼容性的前提下,降低 receive 模式误收验证码的概率
  • 账号池与登录态层:

    • background/mail-2925-session.js
      • 不关心 provide / receive 哪个负责生成注册邮箱
      • 只关心当前是否允许自动登录、是否需要切号、是否命中上限、是否需要停止自动流程
      • 因此后续如果只改别名生成语义,不应把这层重新卷入 provider 判定

后续如果再改 2925,建议最少按下面顺序自检:

  1. managed-alias-utils.js 是否仍是 provide / receive 的唯一共享语义来源
  2. sidepanel/sidepanel.js 是否只做接线,没有复制业务规则
  3. background/generated-email-helpers.js / background/signup-flow-helpers.js 是否仍然只做调度,不重复写模式语义
  4. background/verification-flow.jscontent/mail-2925.js 的“弱目标邮箱匹配”是否保持同步
  5. 项目文件结构说明.md 与当前文件是否已同步更新

7.5 iCloud

组成:

8. 自动运行完整链路

文件:

流程:

  1. 读取总轮数与模式
  2. 为本轮自动流程分配唯一 autoRunSessionId
  3. 计算是否从中断点继续
  4. 每轮执行前重置必要运行态
  5. 执行 runAutoSequenceFromStep
    • 步骤 7 内部仍保留登录态恢复的有限重试,但 add-phone / 手机号页 属于立即跳出的不可重试错误
    • 步骤 8 若在验证码提交后进入 add-phone / 手机号页,会直接抛出 fatal 错误,不再先标记步骤成功
    • 一旦进入步骤 7~10,遇到普通报错且认证流程未进入 add-phone,则自动回到步骤 7 无限重开
    • 如果命中 add-phone / 手机号页 这类 fatal 错误,则不会再做当前轮的内部重试;当开启自动重试/跳过失败时,会直接结束当前轮并继续下一轮,而不是把整条自动流程暂停
    • 如果是手动停止,则立即退出自动流程,不会再触发“回到步骤 7 重开”
  6. 如果失败,根据设置决定:
    • 立即停止
    • 当前轮重试
    • 下一轮继续
  7. 当前轮最终失败时,写入邮箱记录,并在自动重试链路中累计重试次数
    • 手动停止与自动停止会写入“停止”状态(若后续同邮箱成功/失败,会被覆盖为最新状态)
  8. 如果配置了线程间隔,则挂计时计划;计时计划会带上当前 autoRunSessionId
  9. 旧 timer / 旧 alarm / 旧恢复入口只有在 session 仍有效时才允许恢复执行;Stop 会立即使当前 session 失效,防止“停止后旧倒计时又把流程重新拉起”
  10. 所有轮次结束后输出汇总,并清空当前 session 标识

9. 新增功能时最容易漏掉的地方

新增步骤

必须同时检查:

  1. data/step-definitions.js
  2. background/steps
  3. background/steps/registry.js
  4. 自动运行链路是否需要纳入
  5. Step 状态传播和侧边栏展示是否需要适配
  6. 测试是否要补

新增 provider

必须同时检查:

  1. provider 纯工具
  2. 后台 provider 调度分支
  3. 侧边栏配置项
  4. 动态邮箱生成逻辑
  5. Step 4 / 7 的验证码流
  6. 成功收尾逻辑

如果来源本身提供稳定协议接口,还必须额外判断:

  1. 是否可以不打开来源后台页面,直接把步骤 7 / 10 收敛到协议分支

新增配置项

必须同时检查:

  1. PERSISTED_SETTING_DEFAULTS
  2. normalizePersistentSettingValue
  3. 导入导出逻辑
  4. sidepanel 表单与状态恢复
  5. 是否错误挂靠到无关 provider / manager 配置下
  6. 结构文档 / 开发规范是否需要更新

10. 文档联动规则

修改下列内容时,必须同步更新文档:

2026-04 链路补充:认证页共享恢复

  • 新增共享恢复层:content/auth-page-recovery.js
  • Step 4 在等待注册验证码页时,如果命中认证页 Try again / 重试 页,或 /email-verification 上的 405 / Route Error 重试页,会先通过共享恢复逻辑最多自动点击 5 次 重试 尝试恢复,再继续回到密码页重提和验证码页确认流程。
  • 但如果 Step 4 的认证重试页正文中出现 user_already_exists,则会直接视为“当前用户已存在”:不点击 重试,不再回到步骤 1 重开当前轮,而是立即结束当前轮;开启自动重试时直接进入下一轮。
  • Step 7 在识别到登录超时报错页时,会先通过共享恢复逻辑最多自动点击 5 次 重试 尝试恢复当前页面;若仍未恢复,则按原有可恢复失败逻辑重跑 Step 7。
  • Step 7 在首次识别到登录验证码页后,不会立刻把步骤判定为成功;还会额外做一轮“收尾确认”,确保页面稳定停留在登录验证码页。如果只是短暂进入验证码页、随后又掉进登录重试页,则会先走共享恢复逻辑,再按既有可恢复失败逻辑重跑 Step 7。
  • Step 7 的这轮收尾确认是主要责任边界;Step 8 默认建立在“登录验证码页已经由 Step 7 稳定确认”的前提上,只在后台入口保留防御性回退判断,不替代 Step 7 收尾。
  • Step 8 如果发现认证页已经进入登录超时报错/重试页,会直接报错并回到 Step 7 重新开始,而不是在 Step 8 内部点击 重试
  • Step 8 的登录重试页判定也覆盖 /email-verification 上的 405 / Route Error,避免这类页面被误当成普通未知页。
  • 任意认证页重试页如果正文中出现 max_check_attempts,会被视为 Cloudflare 风控触发:后台立刻完全停止流程,侧边栏会复用现有确认弹窗提示等待 15~30 分钟后再试,避免继续刷新或反复重试加重风控,确认按钮显示为“我知道了”。
  • Step 9 在点击 OAuth 同意页 继续 后,会持续等待页面跳转;若点击后命中认证页重试页,则直接报错,不会在 Step 9 内部点击 重试

2026-04-21 2925 邮件时间窗补充

  • 2925 在 Step 4 / Step 8 现在会携带固定的步骤开始时间窗口,实际筛选下限为“步骤开始时间向前回看 10 分钟”。
  • 为了保留这段固定时间窗内已经到达的验证码邮件,后台不再在轮询开始前预先清空 2925 邮箱。
  • 2925 验证码最终提交成功后,后台仍会异步发送 DELETE_ALL_EMAILS 做收尾清理。