56 KiB
项目完整链路说明
本文档面向 AI 与开发者,目标是让阅读者在最短时间内理解“项目做什么、怎么跑、数据怎么流、功能链路怎么串”,从而在新增功能时不漏逻辑、不误改边界。
使用建议:
- 先阅读 项目文件结构说明.md
- 再阅读本文
- 最后阅读 项目开发规范(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 并展示更新卡片;当前更新服务会区分
Ultra、历史Pro与 legacyv三个版本族,排序时固定以Ultra为最高正式系列,同时会在读取缓存后重新排序,避免历史Pro或v版本误显示为比Ultra更新 - 展示一个单独的“接码”开关;开启后才展示 HeroSMS 的接码国家与 API Key 设置,用于 OAuth 登录链路命中手机号验证页时直接续跑手机验证
- 展示
Plus 模式开关与 PayPal 账号池配置;开启后 PayPal 配置行会切换为“账号下拉框 + 添加按钮”,添加按钮复用公共表单弹窗录入账号和密码;步骤列表切换为 Plus 模式 13 步定义,普通模式的 Cookie 清理步骤不再显示或执行,登录验证码步骤会移动到 Plus 可见第 11 步 - 为 Hotmail / 2925 账号池复用同一套“添加账号 / 取消添加 / 批量导入 / 收起列表”表单交互;共享的显隐控制放在
sidepanel/account-pool-ui.js,各自 manager 只保留 provider 相关字段校验与业务操作
2.2 Background Service Worker
职责:
- 扩展后台入口
- 装配所有模块
- 统一承接 runtime message
- 协调步骤执行
- 管理状态、自动运行、标签页与内容脚本通信
2.3 Content Scripts
职责:
- 在目标网页上执行 DOM 交互
- 读取邮件内容或页面状态
- 将步骤成功/失败状态上报给后台
2.4 Helper / Utils / Provider Logic
分布在根目录和 background/ 下。
职责:
- 抽离第三方邮箱 provider 的纯逻辑
- 抽离邮件匹配与验证码提取
- 抽离共享验证码流程、自动运行流程和运行时基础设施
3. 入口与装配关系
3.1 扩展入口
manifest.json 声明:
background.service_worker = background.jsside_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 会话字段:
contributionSessionIdcontributionAuthUrlcontributionAuthStatecontributionCallbackUrlcontributionStatuscontributionStatusMessagecontributionLastPollAt
- OAuth 链接
- 当前邮箱 / 密码
- 第 8 步固定的验证码页显示邮箱
step8VerificationTargetEmail - 当前手机号验证激活记录
currentPhoneActivation - 可复用的手机号验证激活记录
reusablePhoneActivation - localhost 回调地址
- 自动运行轮次信息
- 当前自动运行 session 标识
autoRunSessionId - IP 代理运行态:
ipProxyApiPool / ipProxyAccountPool / ipProxyCurrent / ipProxyApplied*,用于记录当前代理池、当前代理节点、PAC 接管结果、出口检测结果和诊断信息 - 标签注册表
- 最近打开的来源地址
- LuckMail 当前运行时选择
- 2925 当前选中的账号 ID
currentMail2925AccountId(运行时会同步到持久配置,用于重开浏览器后恢复同一个号池账号)
补充:
content/mail-2925.js会把“当前验证码步骤启动会话”对应的已试验证码写入chrome.storage.session,键为seen2925CodeState;同一个 Step 4 / Step 8 会话里试过的验证码不会再次提交,新会话开始时会重置。
4.2 chrome.storage.local
保存持久配置与账号运行历史:
- CPA / SUB2API 配置
- Codex2API 配置
- IP 代理持久配置:
ipProxyEnabled、服务商、模式、API 地址、服务商配置快照、账号列表、固定 Host / Port / Protocol / Username / Password、地区参数、session 与自动切换阈值 - Plus 模式开关
plusModeEnabled - PayPal 账号池配置
paypalAccounts / currentPayPalAccountId,以及供后台步骤兼容读取的paypalEmail / paypalPassword - 邮箱 provider 配置
- Hotmail 账号池
- 2925 账号池
- 2925 是否启用号池模式
mail2925UseAccountPool - 2925 当前选中的号池账号 ID
currentMail2925AccountId - Cloudflare / Temp Email 设置
- 接码开关,以及 HeroSMS 的 API Key 与默认国家设置
- iCloud 相关偏好
- LuckMail API 配置
- 自动运行默认配置
- OAuth 授权后链总超时开关
oauthFlowTimeoutEnabled:默认开启;关闭后会立即清空已存在的 OAuth 总预算 deadline,仅保留各步骤本地等待超时 - 账号运行历史
accountRunHistory(以邮箱为主键,保存该邮箱最近一次状态:成功/失败/停止) - 账号运行历史本地同步 helper 地址
注意:
contributionMode不属于持久配置,也不参与导入/导出;它只存在于运行态panelMode当前表示cpa | sub2api | codex2api三个来源;贡献模式仍不是新的来源枚举
账号运行历史会默认通过 scripts/hotmail_helper.py 的本地 helper 地址尝试同步写入 data/account-run-history.json 快照文件;如果 helper 没有运行,则静默跳过,不再要求用户先手动打开一个“本地同步”开关。
这条配置链路独立于 mailProvider 和 Hotmail 的接码模式。
4.3 状态广播
后台通过 runtime message 向 sidepanel 广播:
LOG_ENTRYSTEP_STATUS_CHANGEDDATA_UPDATEDAUTO_RUN_STATUSICLOUD_LOGIN_REQUIREDICLOUD_ALIASES_CHANGED
IP 代理模块在同步、切换、Change、出口探测和自动运行成功阈值切换后,会通过 DATA_UPDATED 广播 ipProxyApplied* 与当前代理池字段,sidepanel 只根据广播更新状态卡,不在 UI 层重新推断后台代理结果。
4.4 贡献模式链路
贡献模式的目标不是新增一个 provider,而是在 sidepanel 内开启一套“贡献账号”专用 UI,并把公开贡献服务并进原有 10 步主链:
- 用户点击顶部
贡献 - sidepanel 直接通过
SET_CONTRIBUTION_MODE切换运行态,不再弹确认窗口 - 进入贡献模式后会强制
panelMode = cpa,并临时清空运行态customPassword、禁用运行态账号记录快照同步 - sidepanel 隐藏 CPA 管理地址、管理密钥、SUB2API 配置、Codex2API 配置、自定义密码等普通模式配置,并禁用来源选择、配置菜单和记录入口
- 用户点击
开始贡献后,不再单独走一条旁路 OAuth 流程,而是直接复用顶部自动的同一套主自动流 - 步骤 1~6 仍按原来的注册自动化执行
- 当主流程进入步骤 7 时,后台改为调用公开接口
POST https://apikey.qzz.io/oauth/api/start申请贡献登录地址,而不是去 CPA / SUB2API / Codex2API 来源刷新 OAuth - 步骤 7 拿到
session_id / auth_url / state后,继续沿用原有登录链路进入授权页 - 步骤 9 仍负责捕获 localhost callback;贡献模式下后台也会持续监听导航变化,必要时提前兼容处理 callback
- 步骤 10 在贡献模式下不再打开 CPA 管理页,而是围绕公开贡献会话做 callback 提交兼容和最终状态确认;当状态进入
auto_approved / auto_rejected / manual_review_required / expired / error时结束 - 当前服务端如果返回“无需手动提交 callback”,扩展会把它视为兼容成功态,而不是报错
已有认证文件?前往上传继续打开https://apikey.qzz.io/退出贡献模式会清理贡献会话相关运行态,重置只重置主流程状态,不会自动退出贡献模式
这条链路的关键边界是:
- 扩展会调用公开贡献 API,但这条调用被折叠进主 10 步自动链,而不是额外分出一条独立“贡献 OAuth 小流程”
- 扩展不会保存 token
- 扩展不会持有任何管理密钥
- 扩展代码中不能直接调用
/v0/management/* - 扩展不会直接访问生产管理面或生产 auth-dir
- 安全边界仍然在服务端;扩展只负责公开 OAuth 贡献前端流程
- 退出贡献模式后,要恢复普通模式 UI,并恢复持久配置中的自定义密码等普通模式偏好
4.5 贡献内容更新提示链路
这条链路用于把 apikey.qzz.io 上的公开公告 / 使用教程更新,映射成 sidepanel 顶部“贡献/使用”按钮下方的轻提示。
- 贡献站公开暴露
GET https://apikey.qzz.io/api/content-summary - 接口返回
announcement / tutorial两类内容的可见状态、更新时间,以及聚合后的promptVersion sidepanel/contribution-content-update-service.js负责拉取这个摘要,并在本地缓存最近一次可用结果sidepanel.js在 sidepanel 初始化时会先拉一次摘要;如果当前promptVersion没被本地关闭过,就显示提示- 用户点击提示右侧
X后,只会把当前promptVersion记入localStorage,不会永久关闭整个能力 - 当公告或教程再次更新,服务端返回新的
promptVersion,提示会重新出现 - 用户点击“自动”按钮时,sidepanel 会在真正启动自动流程前再刷新一次摘要,尽量让提示状态更及时
- 如果这次刷新失败,sidepanel 只记录警告并继续自动流程,不会因为提示链路故障阻塞主功能
这条链路的关键边界是:
- 它只消费公开摘要接口,不接触任何管理接口
- 它只影响顶部轻提示,不改变贡献模式主状态机
- 它使用
localStorage做缓存和关闭版本记录,而不是写入chrome.storage.session/local - 它是辅助提示链路,不允许反向阻塞自动运行
5. 内容脚本通信链路
5.1 READY 机制
content/utils.js 在脚本加载后会发送 CONTENT_SCRIPT_READY。
后台收到后会:
- 注册当前来源对应的 tab
- 标记 ready
- 冲刷排队命令
5.2 队列与重试
queueCommandflushCommandsendTabMessageWithTimeoutsendToContentScriptResilientsendToMailContentScriptResilient
这保证了:
- 页面切换导致脚本暂时失联时,后台不会立刻误判彻底失败
- 邮箱页或注册页能在注入恢复后继续执行
- 用户点击 Stop 后,标签完成等待、注入后的短暂延迟和内容脚本重试等待会尽快中断,不会因为底层轮询还在 sleep 而继续往下恢复
6. 手动步骤完整链路
Step 1
文件:
流程:
- 后台打开 ChatGPT 官网并复用/创建注册页标签
- 等待注册页内容脚本就绪(仅做连接与注入确认)
- 不在 Step 1 检测或点击注册入口
- 标记 Step 1 完成
补充:
- 手动点击“跳过步骤 1”时,会级联将步骤 2~5 标记为跳过;其中已完成或正在运行的步骤不会被改写。
Step 2
文件:
流程:
- 解析本轮应使用的邮箱
- 打开或复用注册页
- 如果注册弹窗默认停留在手机号输入模式,会先尝试点击
继续使用电子邮件地址登录 / Continue using email address一类按钮切回邮箱输入模式 - 在邮箱输入模式下提交邮箱;邮箱输入框识别同时兼容本地化占位与
aria-label - 以当前邮箱先写入一条“停止(流程尚未完成)”的记录占位
- 等待邮箱提交后的真实落地页
- 如果进入密码页,则继续执行 Step 3
- 如果直接进入邮箱验证码页,则自动跳过 Step 3 并进入 Step 4
Step 3
文件:
流程:
- 生成或读取密码
- 更新运行态密码
- 记录账号快照
- 让内容脚本填写密码
- 内容脚本先上报 Step 3 完成信号
- 上报完成后再异步点击提交,避免页面跳转打断响应通道
- 延迟提交真正触发前会再次检查 Stop 状态,避免用户已停止时页面仍继续自动提交
- 后台在真正确认 Step 3 完成前,会额外检查提交后是否切换页面;如果出现认证页
Try again / 重试页面,或/email-verification上的405 / Route Error重试页,会先通过共享恢复逻辑最多自动点击 5 次重试尝试恢复,再继续后续链路 - Step 3 收尾阶段如果页面切换导致旧内容脚本失联,后台会把单次消息等待收口到当前收尾预算内,优先尽快重试重连;若最终仍未恢复,则输出中文的步骤级错误,而不是直接暴露底层英文通信超时
Step 4 / Step 8
文件:
- background/steps/fetch-signup-code.js
- background/steps/fetch-login-code.js
- background/verification-flow.js
这两步共享验证码主流程:
- 确定 provider
- 必要时重发验证码
- 轮询邮箱或 API
- 提取验证码
- 回填页面
- 若页面拒绝,则重试或回退
补充行为:
-
2925provider 会关闭 Step 4 / 8 的自动重发间隔 25 秒节流;每次“重新发送验证码”之间,会在邮箱页内部执行一轮固定 15 次的刷新轮询,不再因 OAuth 剩余时间预算而缩短。 -
当 provider 为
2925时,Step 4 会优先直接打开当前 2925 邮箱页,并先比对页面顶部显示的邮箱地址是否与当前目标邮箱一致:如果一致,就直接复用当前已登录页面;如果不一致且启用了 2925 账号池,则会先清理 cookie 再登录当前选中的账号;如果不一致且未启用账号池,则直接复用现有停止逻辑结束流程。Step 8 不再额外承接这套登录态处理。 -
2925在执行自动登录后,如果登录页因为跳转或重载导致原内容脚本通信中断,后台不会立刻判失败;而是会等待当前标签页重新加载完成、重新确认内容脚本就绪后,再继续确认是否已经进入收件箱。这段登录恢复窗口当前按 2 分钟控制。 -
普通邮箱仍会携带
filterAfterTimestamp做时间窗筛选;2925在 Step 4 / Step 8 会固定使用“步骤开始时间向前回看 10 分钟”的时间窗,不再做“新旧邮件快照差集”比较,而是每次刷新后直接遍历当前列表中落在该固定时间窗内的匹配邮件。 -
自动重新发送验证码次数现在使用 sidepanel 里的单一“验证码重发”配置;普通邮箱仍按 25 秒间隔节流,Hotmail / 2925 不走这个 25 秒间隔。Step 4 若启用先请求新验证码,会先消耗一次当前步骤的自动重发次数。
-
LuckMail在/code接口暂未拿到新验证码时,会先点击一次认证页“重新发送验证码”,再等待 15 秒后继续轮询/code,避免只空等不触发新邮件。 -
验证码提交重试上限当前为 15 次;页面明确拒绝验证码时,会在上限内继续拉取新验证码并重提。
-
2925内容脚本会把每一封实际打开检测的邮件立即删除;同一验证码步骤启动后,试过的验证码会按“步骤 ID + 启动时间”隔离缓存,不会在本次步骤里重复提交;如果再次遇到相同验证码,对应邮件也会在读取后立即删除,避免后续反复打开。 -
2925在 provide 模式下仍保持宽松匹配:只要邮件内容命中 ChatGPT / OpenAI 验证码过滤条件,就会尝试该邮件。 -
2925在 receive 模式下会恢复“弱目标邮箱匹配”:只有当邮件里显式出现了其他收件邮箱时才会跳过;如果邮件里没有明确写出邮箱,仍允许继续尝试该验证码。 -
手动点击 Step 4 重新执行时,后台会先检查
signup-page认证页标签是否仍然存在;如果步骤 1 / 2 打开的认证页已经关闭,就会直接提示“请先执行步骤 1 或步骤 2,确保认证页仍然打开并停留在验证码页”,不会先重置后续步骤再报技术错误。 -
当验证码最终提交成功后,后台会异步向 2925 邮箱页发送
DELETE_ALL_EMAILS,执行“全选 + 删除”清理剩余邮件,不阻塞主流程。 -
如果
2925邮箱页在轮询期间出现“子邮箱已达上限邮箱”,后台会记录当前时间,把当前 2925 账号禁用 24 小时,自动切到下一个可用账号并完成登录,然后直接报错结束当前尝试;如果 Auto 开启了自动重试,现有控制器会按原逻辑进入下一次尝试。 -
Auto 模式下,普通 Step 4 失败仍会沿用当前邮箱回到 Step 1 重新开始当前轮;但若失败原因是 2925 主动要求“结束当前尝试”,则不会再回到 Step 1 重开,而是直接把错误抛给自动重试控制器。
Step 5
文件:
流程:
- 生成随机姓名和生日
- 内容脚本填写资料;如果资料页出现顶部“我同意以下所有各项”总勾选框,会先自动勾选后再提交
- 内容脚本点击“完成帐户创建”
- 点击后立即上报 Step 5 完成,不再等待页面结果
- 自动运行在进入 Step 6 前会等待当前页面完成加载并短暂稳定,避免 Step 5 刚点击提交、后续跳转尚未真正开始时就执行下一步;但仍不在 Step 5 阶段接管 ChatGPT 跳转或 onboarding 跳过
Step 6
文件:
流程:
- 等待登录前清理延迟
- 直接删除 ChatGPT / OpenAI cookies
- 必要时用
browsingData补扫 cookies - 完成后进入后续登录链路
Step 7
文件:
流程:
- 按当前来源刷新 OAuth 地址:
- CPA:打开管理页并读取 OAuth 地址
- SUB2API:打开后台并生成 OAuth 地址
- Codex2API:直接调用后台协议
/api/admin/oauth/generate-auth-url
- 打开最新 OAuth 链接
- 登录;如果进入密码页且当前有密码,则填写并提交密码;如果当前没有密码但检测到一次性验证码入口,则直接切换到一次性验证码登录
- 确保真正进入验证码页
- 如果未进入验证码页,则按可恢复逻辑最多重试 3 次;但一旦当前失败已经明确进入
https://auth.openai.com/add-phone,则立即退出步骤 7 内部重试,不再继续第 2 / 3 次尝试 - 自动运行一旦进入步骤 7 之后的链路,若后续步骤报错且认证页未进入
https://auth.openai.com/add-phone,则统一回到步骤 7 重新开始授权流程 - CPA 回调阶段固定为步骤 9,不再支持“第七步回调”跳过步骤 7/8
贡献模式补充:
- 贡献模式下,步骤 7 不再从 CPA / SUB2API / Codex2API 来源刷新 OAuth,而是直接调用公开贡献接口
/oauth/api/start - 贡献接口返回的
auth_url会写回运行态oauthUrl,后续步骤 7 / 8 / 9 继续复用现有授权链路
Step 8
文件:
流程:
- 确认当前认证页已经进入登录验证码页
- 对非 2925 provider,固定当前验证码页显示邮箱为本次 Step 8 的目标邮箱
- 打开邮箱页或 API 轮询入口
- 轮询登录验证码
- 回填登录验证码
- 如果登录验证码提交后页面进入
add-phone / 手机号页,则步骤 8 会保留“登录验证码已提交成功”的结果,并把后续手机号验证需求继续交给步骤 9 处理 - 如遇邮箱轮询类失败或显式的
STEP8_RESTART_STEP7恢复错误,则按有限次数回到 Step 7 重试 - 获取到登录验证码后不再触发“刷新 OAuth 并重走 Step 7”的前置回放,直接在当前验证码页提交并继续进入 Step 9
补充:
- 对
2925 provide而言,Step 8 仍不依赖验证码页显示邮箱做收件匹配,而是直接测试所有命中 ChatGPT / OpenAI 过滤条件的邮件。 - 对
2925 receive而言,Step 8 会把当前目标注册邮箱一并传给 2925 内容脚本;只有当邮件里显式写出了其他邮箱时才会跳过,从而在不破坏历史兼容性的前提下,尽量降低误收验证码的概率。 - 对
customprovider 而言,Step 8 仍使用手动验证码确认弹窗;弹窗当前额外提供“出现手机号验证”按钮,点击后会直接抛出与真实add-phone页面一致的 fatal 错误,供 Auto 按既有 add-phone 分支继续下一邮箱。 - 当登录验证码提交后进入
phone-verification页时,内容脚本会显式把该页面识别为“手机验证码页”,避免与邮箱验证码页混淆。
Step 9
文件:
流程:
- 监听 localhost callback
- 准备 OAuth 同意页;如果页面已进入
add-phone / phone-verification,先切入手机号验证共享流程 - 手机号验证共享流程会按当前 sidepanel 中保存的 HeroSMS 国家与 API Key 申请或复用号码、提交号码、轮询短信验证码,并在验证码被拒绝或长时间收不到短信时决定重发、换号或把自动流拉回 Step 7
- 手机号验证完成后,继续等待 OAuth 同意页出现
- 尝试多轮点击“继续”
- 一旦捕获 localhost callback,写入状态并完成步骤
补充:
- HeroSMS 号码当前最多复用 3 次成功注册;超过上限后会清空可复用激活记录,下次重新申请新号码。
- 如果同一个号码在重发短信后 60 秒仍收不到验证码,后台会抛出“回到步骤 7 重新拿新号码”的恢复错误,而不是把当前号码无限重试下去。
- Step 9 在等待 localhost callback 时会动态读取
oauthFlowTimeoutEnabled:开启时继续受 Step 7 后链总预算约束;关闭时仅保留本地 240 秒回调等待上限,不再因 5 分钟总预算触发回跳 Step 7。
Step 10
文件:
流程:
- 校验 localhost callback 是否有效
- 判断当前来源是 CPA、SUB2API 还是 Codex2API
- CPA / SUB2API 打开相应后台;Codex2API 直接走协议分支,不打开后台页面
- 提交回调地址或等价的授权码交换请求
- 仅当出现精确成功徽标,且该徽标不是红色/错误态、页面上也没有同时可见的失败提示时,才判定成功
- 识别
认证失败:*、认证失败: timeout of 30000ms exceeded、回调 URL 提交失败: oauth flow is not pending等失败提示并立即报错 - 完成平台侧验证
- 追加账号运行历史成功记录
- 做成功后的清理与标记
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_approved与manual_review_required视为主流程完成;auto_rejected / expired / error视为当前轮失败
6.1 Plus 模式链路
Plus 模式通过 plusModeEnabled 开启,目标是在普通注册资料完成后,不执行原 Step 6 Cookie 清理,也不执行原 Step 8 登录验证码步骤,而是先完成 Plus Checkout 与 PayPal 授权,再复用现有 OAuth 后半段。
Plus 模式可见步骤:
- 第 1~5 步:沿用普通注册入口、邮箱、密码、注册验证码、资料填写链路。
- 第 6 步
创建 Plus Checkout:打开已登录 ChatGPT 页面,通过/api/auth/session读取 accessToken,再请求https://chatgpt.com/backend-api/payments/checkout创建chatgptplusplan的 checkout session,并打开https://chatgpt.com/checkout/openai_ie/{checkout_session_id}。 - 第 7 步
填写账单并提交订阅:选择 PayPal,生成账单全名,从data/address-sources.js读取同国家 seed query,触发 checkout 内置 Google 地址推荐,选择推荐项并校验地址第 1 行、城市、州/省、邮编等结构化字段,再点击“订阅”。运行时会按 Stripe iframe 拆分执行:付款方式在elements-inner-paymentframe,账单地址在elements-inner-addressframe,Google 推荐在elements-inner-autocomplframe 时单独点击推荐项。 - 第 8 步
PayPal 登录与授权:后台优先读取侧边栏当前选中的 PayPal 账号;为兼容旧链路,也会把该账号同步回paypalEmail / paypalPassword。当页面处于账号输入阶段时,内容脚本会固定对邮箱输入框执行focus -> clear -> fill -> blur -> click next,即使文本框里已经预填了同一个账号,也会重新触发输入事件,避免 PayPal 因跳过重填而停在邮箱页;登录前固定等待 1 秒,关闭可见通行密钥提示,点击“同意并继续”。 - 第 9 步
订阅回跳确认:等待 PayPal 授权后回跳到 ChatGPT / OpenAI 页面,页面加载完成后固定等待 1 秒。 - 第 10 步:复用原 Step 7 OAuth 登录执行器,但状态和日志按 Plus 可见第 10 步记录。
- 第 11 步:复用原 Step 8 登录验证码执行器,但状态和日志按 Plus 可见第 11 步记录。
- 第 12 步:复用原 Step 9 OAuth 同意页点击和 localhost callback 捕获执行器,但状态和日志按 Plus 可见第 12 步记录。
- 第 13 步:复用原 Step 10 CPA / SUB2API / Codex2API 平台回调验证执行器,但状态和日志按 Plus 可见第 13 步记录。
隐藏与跳过规则:
- 原 Step 6
清理登录 Cookies:Plus 模式下隐藏且不执行,因为 Plus Checkout 创建依赖当前 ChatGPT 登录态。 - 原 Step 8
获取登录验证码:Plus 模式下移动到可见第 11 步,继续负责登录验证码页的收码与提交。 - 原 Step 9 不能跳过;它负责点击 OAuth 同意页并捕获
localhostUrl。 - 原 Step 10 不能跳过;它依赖
localhostUrl完成平台侧账号创建或回调验证。
等待模型:
- Plus Checkout 和 PayPal 专用步骤使用“无限等待但可停止”的后台等待 helper。
- 每次页面加载完成后固定等待 1 秒,再继续下一次输入、点击或状态判断。
- 第一版不实时抓取外部地址网站;地址自动化只依赖本地 seed query 和 checkout 页面内置 Google 地址推荐。
7. 邮箱与 provider 链路
7.1 2026-04-17 补充:Gmail / 2925 统一别名邮箱链路
本轮将 Gmail 与 2925 + provide 的注册邮箱逻辑统一收敛为“共享别名邮箱链路”:
- 两者都先填写“基邮箱”
- Gmail:
name@gmail.com - 2925(仅 provide 模式):
name@2925.com
- Gmail:
- 两者都允许两种入口:
- 点击侧边栏按钮自动生成完整注册邮箱
- 直接在“注册邮箱”输入框中手动填写完整邮箱
- 当
mailProvider = 2925且mail2925Mode = receive时,不再走别名基邮箱链路,而是回退到普通“邮箱生成 / 手动填写注册邮箱”路线;2925 仅负责后续收信与登录态管理
当前行为约定:
- sidepanel 会根据当前 provider 与
mail2925Mode决定是否展示“别名基邮箱”输入框 - 点击
获取 / 生成时:- Gmail 生成
name+tag@gmail.com - 2925 仅在 provide 模式下生成
name123456@2925.com
- Gmail 生成
- Step 2 / Step 3 进入注册流程前,会先判断当前
state.email- 如果已经是与当前基邮箱兼容的完整邮箱,则直接复用
- 如果为空或不兼容,则按当前 provider / mode 重新生成
- 保存或执行 Step 3 时,如果手动填写的完整邮箱与当前 Gmail / 2925 provide 基邮箱不兼容,sidepanel 会直接拦截;
2925 receive不参与这条兼容性约束 - auto-run fresh attempt reset 时,会保留:
gmailBaseEmailmail2925BaseEmail
7.1.1 2026-04-23 补充:自定义邮箱池链路
本轮新增 custom-pool 生成方式,用于把一批已准备好的邮箱按顺序并入现有自动流,而不是继续为每种邮箱页面单独适配一套“新地址生成器”。
当前行为约定:
- sidepanel 在
邮箱生成中新增自定义邮箱池选项,并显示多行邮箱池输入框 - 输入框中的邮箱会按“每行一个”归一化为数组,写入持久配置
customEmailPool - Auto 启动前会先保存当前配置;如果当前生成方式是
custom-pool,则自动把总轮数锁定为邮箱池长度 - 后台在每个目标轮次开始前,会按
targetRun从邮箱池读取对应邮箱,并写入当前state.email - 同一目标轮次里的失败重试会继续复用该轮邮箱,不会提前跳到下一个
- 如果当前目标轮次超出了邮箱池数量,后台会直接报错提示数量不一致
- 自定义邮箱池只负责“本轮注册邮箱分配”,实际收码仍由当前
mailProvider对应的既有链路负责
7.1.2 2026-04-23 补充:自定义邮箱服务号池链路
本轮给 mailProvider = custom 这条链路补上了“号池式注册邮箱分配”,目标是让“手动验证码模式”也能稳定跑多轮不同邮箱,而不是每轮都手动改一次注册邮箱。
当前行为约定:
- sidepanel 在
邮箱服务 = 自定义邮箱时,会额外显示自定义号池文本框 - 文本框中的邮箱会按“每行一个”归一化为数组,写入持久配置
customMailProviderPool - 如果当前
Mail = 自定义邮箱且号池不为空,Auto 启动前会把总轮数锁定为号池长度 - 后台在每个目标轮次开始前,会按
targetRun从customMailProviderPool读取对应邮箱,并写入当前state.email - 只要当前邮箱还没成功认证、也没出现
add-phone / 手机号验证,Auto 就会继续复用该邮箱重试,不会提前切到下一个 - 只有当当前邮箱成功完成整轮,或明确进入
add-phone / 手机号验证fatal 分支时,Auto 才会切到号池中的下一个邮箱 - 如果当前目标轮次超出了号池数量,后台会直接报错提示数量不一致
- 这条链路只影响“注册邮箱分配”;Step 4 / Step 8 仍然走
customprovider 既有的手动验证码确认逻辑
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
组成:
- hotmail-utils.js
- microsoft-email.js
- scripts/hotmail_helper.py
- sidepanel/hotmail-manager.js
- sidepanel/account-pool-ui.js
模式:
- API 对接
- 本地 helper
补充:
- 本地 helper 除了收信与验证码读取,还提供邮箱记录 JSON 快照同步接口。
- 账号运行历史快照会按默认本地 helper 地址自动尝试同步,不再要求用户手动打开独立开关,也不再绑定 Hotmail 的本地助手模式。
- sidepanel 中 Hotmail 账号池的新增表单默认收起,头部通过共享按钮切换“添加账号 / 取消添加”;表单显隐、按钮文案切换、清空与聚焦都复用
sidepanel/account-pool-ui.js,不在 Hotmail manager 内重复实现一套。
7.3 LuckMail
组成:
- luckmail-utils.js
- LuckMail 相关后台领域逻辑仍在 background.js
7.4 163 / 163 VIP / 126 网页邮箱
组成:
行为约定:
163、163 VIP、126都走同一条“网易网页邮箱”验证码链路。- sidepanel 只负责切换 provider 与展示登录入口;后台根据 provider 选择对应网页邮箱首页。
- 内容脚本来源统一归类到
mail-163,这样 Step 4 / Step 8 继续复用同一套验证码读取与邮件清理逻辑。 manifest.json需要同时覆盖:https://mail.163.com/*https://webmail.vip.163.com/*https://mail.126.com/*
7.5 2925 账号池
组成:
- mail2925-utils.js
- background/mail-2925-session.js
- sidepanel/mail-2925-manager.js
- sidepanel/account-pool-ui.js
职责:
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 不再单独维护另一套表单开关状态机。
链路:
- 用户在 sidepanel 的 2925 账号池中保存
email / password - sidepanel 中会单独展示
提供邮箱 / 接收邮箱模式切换,以及独立的2925 号池开关 / 当前账号下拉框;这样即使切到 receive 模式,账号池设置也不会被别名基邮箱行一起隐藏 - 只有当 sidepanel 中的
mail2925UseAccountPool开关开启时,provide 模式下的别名基邮箱才会优先取当前账号池选中的 2925 账号邮箱;关闭时会回退到原来的手填mail2925BaseEmail - 手动点击
登录或自动流程进入 Step 4 前,后台会先打开当前 2925 邮箱页,并读取页面顶部当前邮箱地址:如果仍停留在收件箱且顶部邮箱与目标邮箱一致,则直接复用;如果顶部邮箱不一致且启用了号池模式,则先清理 cookie 后登录当前选中的账号;如果顶部邮箱不一致且未启用号池模式,则直接调用现有停止逻辑结束流程;如果页面跳到登录页,则仍然只有号池模式开启时才自动登录 - 一旦轮询期间出现“子邮箱已达上限邮箱”,后台会先判断是否启用了号池模式:若已启用且还有下一个可用账号,则把当前账号禁用 24 小时并自动切到下一个账号重新登录;若未启用,则直接调用现有停止逻辑结束流程
- 如果登录页已经识别到账号密码输入框,内容脚本会在填完账号密码后额外等待 1 秒再点击登录;若点击登录后 40 秒内仍未进入收件箱,且当前正处于自动运行中,则后台会直接复用现有
requestStop()停止链路,把整个自动流程停成和用户手动点击“停止”一致的状态;这类情况常见于图片验证、行为验证或其他阻断登录的中间页 - 如果没有下一个可用账号,或当前未启用号池模式,则不会继续消耗自动重试次数,而是直接复用现有
requestStop()停止链路,把整个自动流程停成和用户手动点击“停止”一致的状态 - sidepanel 中 2925 账号池的新增表单也走与 Hotmail 相同的共享交互:默认收起,头部按钮切换“添加账号 / 取消添加”,操作行右侧提供“批量导入”,保存成功后自动收起并清空。
- 当 2925 号池模式开启时,当前选中的号池邮箱会同步回写到同一个
mail2925BaseEmail字段;因此用户切换号池账号后,即使再次关闭号池模式,也会直接沿用刚才选中的邮箱作为手动基邮箱,无需重新输入。
7.5.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模式开启弱目标邮箱匹配
- 负责决定是否给 2925 内容脚本下发
content/mail-2925.js- 负责真正执行“弱目标邮箱匹配”
- 当前约定:只有邮件里显式出现了其他邮箱才跳过;若邮件里没有写邮箱,仍允许继续尝试
- 这样做的目的,是在不破坏历史兼容性的前提下,降低 receive 模式误收验证码的概率
-
账号池与登录态层:
background/mail-2925-session.js- 不关心
provide / receive哪个负责生成注册邮箱 - 只关心当前是否允许自动登录、是否需要切号、是否命中上限、是否需要停止自动流程
- 因此后续如果只改别名生成语义,不应把这层重新卷入 provider 判定
- 不关心
后续如果再改 2925,建议最少按下面顺序自检:
managed-alias-utils.js是否仍是provide / receive的唯一共享语义来源sidepanel/sidepanel.js是否只做接线,没有复制业务规则background/generated-email-helpers.js/background/signup-flow-helpers.js是否仍然只做调度,不重复写模式语义background/verification-flow.js与content/mail-2925.js的“弱目标邮箱匹配”是否保持同步项目文件结构说明.md与当前文件是否已同步更新
7.6 iCloud
组成:
配置:
icloudHostPreference只决定 iCloud 登录、别名管理和 iCloud Mail 收件箱 Host。icloudFetchMode决定生成注册邮箱时复用已有 Hide My Email 别名,还是始终创建新别名。icloudTargetMailboxType = icloud-inbox时,Step 4 / Step 8 直接打开 iCloud Mail 收件箱轮询验证码。icloudTargetMailboxType = forward-mailbox时,注册邮箱仍由 iCloud Hide My Email 生成,但 Step 4 / Step 8 改为打开icloudForwardMailProvider指定的转发目标邮箱收码;当前支持qq / 163 / 163-vip / 126 / gmail。
Hide My Email 获取与管理链路:
- 后台优先通过
setup.icloud.com*/setup/ws/1/validate解析premiummailsettings.url,并记录最近可用服务节点。 - 如果后台请求受 401 / 403 / 409 / 421 / 429 / 5xx、CORS、超时或地址空间限制影响,会优先尝试在已打开或自动创建的
www.icloud.com*/mail/页面主上下文中重放请求。 maildomainws请求会补充clientBuildNumber / clientMasteringNumber / clientId / dsid查询参数,写请求使用text/plain;charset=UTF-8,以兼容 iCloud 网页端接口。- 别名列表加载成功后会缓存到
icloudAliasCache;遇到短暂上下文波动时,列表展示会按“最近缓存 -> 历史缓存 -> 本地已用/保留记录”回退。 - 生成新别名后若
reserve返回鉴权或网络异常,会先回查列表确认候选别名是否已经创建;必要时刷新服务节点重试一次,最后才进入可复用别名回退或暂停等待用户处理。 - 自动运行获取 iCloud 别名时,检测到会话或网络上下文异常后会停止重复消耗获取重试次数,转入等待邮箱状态,避免连续请求放大 iCloud 风控或上下文抖动。
维护约定:
- iCloud 转发目标邮箱 provider 的 label、URL、source、inject 配置统一由
mail-provider-utils.js输出。 background.js只根据icloudTargetMailboxType选择 iCloud Mail 收件箱或共享转发邮箱配置,不再在主文件内硬编码各 provider 地址。sidepanel/sidepanel.js只负责展示、保存和回显目标邮箱类型 / 转发邮箱 provider,不重复定义 provider 业务清单。- iCloud 登录态提示必须区分“真实未登录”和“已登录但请求上下文波动”;不能把所有 401 / 403 / 421 都直接提示为未登录。
- iCloud 别名缓存只用于短暂失败回退,不应改变最终的已用 / 保留状态来源;状态仍以
manualAliasUsage、preservedAliases与最新线上列表合并后的结果为准。
7.7 IP Proxy
组成:
- background/ip-proxy-core.js
- background/ip-proxy-provider-711proxy.js
- sidepanel/ip-proxy-panel.js
- sidepanel/ip-proxy-provider-711proxy.js
- docs/ip-proxy-module.md
职责边界:
background/ip-proxy-core.js负责代理条目解析、运行态代理池、PAC 应用与清除、webRequest.onAuthRequired代理鉴权回填、出口探测和失败时的目标站点 fail-close 规则。background/ip-proxy-provider-711proxy.js只承接 711Proxy 的账号串参数规则,负责把region / session / sessTime叠加到最终用户名。background/message-router.js只暴露REFRESH_IP_PROXY_POOL / SWITCH_IP_PROXY / CHANGE_IP_PROXY_EXIT / PROBE_IP_PROXY_EXIT消息,不在路由层复制代理解析逻辑。sidepanel/ip-proxy-panel.js负责 UI 状态渲染、表单快照、按钮动作和 711 参数输入联动;sidepanel/sidepanel.js只保留配置保存、事件绑定和广播接线。
基础链路:
- 用户在 sidepanel 打开
IP代理,选择服务和账号模式。 - 首版只开放
711proxy + account主路径;API 模式和账号列表入口保留但默认禁用。 - 用户填写固定账号的 Host / Port / Protocol / Username / Password,可选填写地区、session 和时长。
- 点击
同步后,sidepanel 发送REFRESH_IP_PROXY_POOL,后台解析当前账号为代理池并调用chrome.proxy.settings.set写入 PAC。 - 如果代理需要账号密码,后台通过
webRequest.onAuthRequired对代理 407 challenge 回填用户名和密码。 - PAC 成功应用后,后台关闭 fail-close 规则;如果配置缺失、应用失败或出口探测失败,则开启只覆盖 OpenAI / ChatGPT 目标域的阻断规则,避免误以为已经走代理。
检测出口会优先用页面上下文探测公网 IP,再用后台请求兜底,并把出口 IP、地区、探测来源和诊断摘要写回运行态。下一条根据当前代理池 index 切换节点;Change在 711 session 场景下强制重绑代理链路,用于刷新出口。- 自动运行成功轮数命中
ipProxyPoolTargetCount时,后台会尝试自动切到下一条代理;只有代理候选数量大于 1 时才执行切换。
维护约定:
- 代理解析、PAC、鉴权和出口检测必须留在后台模块,不应继续堆进
background.js。 - UI 层不能凭输入值直接判断“代理已接管”,只能展示后台返回的
ipProxyApplied*状态。 - 新增代理服务商时,应优先新增 provider 规则模块,并让共享解析/运行态继续走
background/ip-proxy-core.js。 - 修改代理字段、权限或链路时,需要同步更新 docs/ip-proxy-module.md、当前完整链路说明和结构说明。
8. 自动运行完整链路
文件:
流程:
- 读取总轮数与模式
- 为本轮自动流程分配唯一
autoRunSessionId - 计算是否从中断点继续
- 每轮执行前重置必要运行态
- 如果当前
Mail = 自定义邮箱且配置了customMailProviderPool,会先按当前目标轮次把号池中的对应邮箱写回运行态 - 如果当前生成方式是
custom-pool,会先按当前目标轮次把邮箱池中的对应邮箱写回运行态
- 如果当前
- 执行
runAutoSequenceFromStep- 步骤 7 内部仍保留登录态恢复的有限重试,但
add-phone / 手机号页属于立即跳出的不可重试错误 - 步骤 8 若在验证码提交后进入
add-phone / 手机号页,会直接抛出 fatal 错误,不再先标记步骤成功 - 一旦进入步骤 7~10,遇到普通报错且认证流程未进入
add-phone,则自动回到步骤 7 无限重开 - 如果命中
add-phone / 手机号页这类 fatal 错误,则不会再做当前轮的内部重试;当开启自动重试/跳过失败时,会直接结束当前轮并继续下一轮,而不是把整条自动流程暂停 - 如果是手动停止,则立即退出自动流程,不会再触发“回到步骤 7 重开”
- 步骤 7 内部仍保留登录态恢复的有限重试,但
- 如果失败,根据设置决定:
- 立即停止
- 当前轮重试
- 下一轮继续
- 当前轮最终失败时,写入邮箱记录,并在自动重试链路中累计重试次数
- 手动停止与自动停止会写入“停止”状态(若后续同邮箱成功/失败,会被覆盖为最新状态)
- 如果配置了线程间隔,则挂计时计划;计时计划会带上当前
autoRunSessionId - 旧 timer / 旧 alarm / 旧恢复入口只有在 session 仍有效时才允许恢复执行;Stop 会立即使当前 session 失效,防止“停止后旧倒计时又把流程重新拉起”
- 如果启用 IP 代理,后台会在每轮成功后按
ipProxyPoolTargetCount检查是否需要切换出口;候选代理不足时只记录日志并跳过切换 - 所有轮次结束后输出汇总,并清空当前 session 标识
9. 新增功能时最容易漏掉的地方
新增步骤
必须同时检查:
- data/step-definitions.js
- background/steps
- background/steps/registry.js
- 自动运行链路是否需要纳入
- Step 状态传播和侧边栏展示是否需要适配
- 测试是否要补
新增 provider
必须同时检查:
- provider 纯工具
- 后台 provider 调度分支
- 侧边栏配置项
- 动态邮箱生成逻辑
- Step 4 / 7 的验证码流
- 成功收尾逻辑
如果来源本身提供稳定协议接口,还必须额外判断:
- 是否可以不打开来源后台页面,直接把步骤 7 / 10 收敛到协议分支
新增配置项
必须同时检查:
PERSISTED_SETTING_DEFAULTSnormalizePersistentSettingValue- 导入导出逻辑
- sidepanel 表单与状态恢复
- 是否错误挂靠到无关 provider / manager 配置下
- 结构文档 / 开发规范是否需要更新
10. 文档联动规则
修改下列内容时,必须同步更新文档:
- 文件结构变更
更新 项目文件结构说明.md - 运行链路变更
更新 项目完整链路说明.md - 规范、边界、步骤接入方式变更
更新 项目开发规范(AI协作).md
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做收尾清理。