feat: 添加手机号页面错误处理逻辑,更新步骤7重试机制及文档说明
This commit is contained in:
@@ -19,6 +19,11 @@
|
||||
throwIfStopped,
|
||||
} = deps;
|
||||
|
||||
function isAddPhoneAuthFailure(error) {
|
||||
const message = String(typeof error === 'string' ? error : error?.message || '');
|
||||
return /https:\/\/auth\.openai\.com\/add-phone(?:[/?#]|$)|add-phone|手机号页面|手机号码|手机号|phone\s+number|telephone/i.test(message);
|
||||
}
|
||||
|
||||
async function executeStep7(state) {
|
||||
if (!state.email) {
|
||||
throw new Error('缺少邮箱地址,请先完成步骤 3。');
|
||||
@@ -91,6 +96,9 @@
|
||||
throw new Error('步骤 7:认证页未返回可识别的登录结果。');
|
||||
} catch (err) {
|
||||
throwIfStopped(err);
|
||||
if (isAddPhoneAuthFailure(err)) {
|
||||
throw err;
|
||||
}
|
||||
lastError = err;
|
||||
if (attempt >= STEP6_MAX_ATTEMPTS) {
|
||||
break;
|
||||
|
||||
@@ -75,6 +75,57 @@ test('step 7 retries up to configured limit and then fails', async () => {
|
||||
assert.equal(events.completed, 0);
|
||||
});
|
||||
|
||||
test('step 7 exits internal retry loop immediately when add-phone is detected', async () => {
|
||||
const source = fs.readFileSync('background/steps/oauth-login.js', 'utf8');
|
||||
const globalScope = {};
|
||||
const api = new Function('self', `${source}; return self.MultiPageBackgroundStep7;`)(globalScope);
|
||||
|
||||
const events = {
|
||||
refreshCalls: 0,
|
||||
sendCalls: 0,
|
||||
completed: 0,
|
||||
logs: [],
|
||||
};
|
||||
|
||||
const executor = api.createStep7Executor({
|
||||
addLog: async (message, level = 'info') => {
|
||||
events.logs.push({ message, level });
|
||||
},
|
||||
completeStepFromBackground: async () => {
|
||||
events.completed += 1;
|
||||
},
|
||||
getErrorMessage: (error) => error?.message || String(error || ''),
|
||||
getLoginAuthStateLabel: (state) => state || 'unknown',
|
||||
getState: async () => ({ email: 'user@example.com', password: 'secret' }),
|
||||
isStep6RecoverableResult: (result) => result?.step6Outcome === 'recoverable',
|
||||
isStep6SuccessResult: (result) => result?.step6Outcome === 'success',
|
||||
refreshOAuthUrlBeforeStep6: async () => {
|
||||
events.refreshCalls += 1;
|
||||
return `https://oauth.example/${events.refreshCalls}`;
|
||||
},
|
||||
reuseOrCreateTab: async () => {},
|
||||
sendToContentScriptResilient: async () => {
|
||||
events.sendCalls += 1;
|
||||
throw new Error('提交密码后页面直接进入手机号页面,未经过登录验证码页。URL: https://auth.openai.com/add-phone');
|
||||
},
|
||||
STEP6_MAX_ATTEMPTS: 3,
|
||||
throwIfStopped: () => {},
|
||||
});
|
||||
|
||||
await assert.rejects(
|
||||
() => executor.executeStep7({ email: 'user@example.com', password: 'secret' }),
|
||||
/add-phone/
|
||||
);
|
||||
|
||||
assert.equal(events.refreshCalls, 1, 'add-phone should stop further OAuth refresh attempts');
|
||||
assert.equal(events.sendCalls, 1, 'add-phone should stop after the first failed login attempt');
|
||||
assert.equal(events.completed, 0);
|
||||
assert.ok(
|
||||
!events.logs.some(({ message }) => /准备重试/.test(message)),
|
||||
'add-phone failure should not be logged as an internal retryable attempt'
|
||||
);
|
||||
});
|
||||
|
||||
test('step 7 starts a new oauth timeout window for each refreshed oauth url', async () => {
|
||||
const source = fs.readFileSync('background/steps/oauth-login.js', 'utf8');
|
||||
const globalScope = {};
|
||||
|
||||
+2
-2
@@ -298,7 +298,7 @@
|
||||
2. 打开最新 OAuth 链接
|
||||
3. 登录
|
||||
4. 确保真正进入验证码页
|
||||
5. 如果未进入验证码页,则按可恢复逻辑最多重试 3 次
|
||||
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
|
||||
|
||||
@@ -448,7 +448,7 @@
|
||||
3. 计算是否从中断点继续
|
||||
4. 每轮执行前重置必要运行态
|
||||
5. 执行 `runAutoSequenceFromStep`
|
||||
- 步骤 7 内部仍保留登录态恢复的有限重试
|
||||
- 步骤 7 内部仍保留登录态恢复的有限重试,但 `add-phone / 手机号页` 属于立即跳出的不可重试错误
|
||||
- 一旦进入步骤 7~10,遇到普通报错且认证流程未进入 `add-phone`,则自动回到步骤 7 无限重开
|
||||
- 如果是手动停止,则立即退出自动流程,不会再触发“回到步骤 7 重开”
|
||||
6. 如果失败,根据设置决定:
|
||||
|
||||
+2
-2
@@ -59,7 +59,7 @@
|
||||
- `background/steps/fetch-signup-code.js`:步骤 4 实现,负责注册验证码阶段的页面准备与验证码流程入口。
|
||||
- `background/steps/fill-password.js`:步骤 3 实现,负责密码生成、保存、回填与提交。
|
||||
- `background/steps/fill-profile.js`:步骤 5 实现,负责姓名、生日填写并把资料提交给注册页内容脚本。
|
||||
- `background/steps/oauth-login.js`:步骤 7 实现,负责刷新 OAuth 链接、登录和确保进入验证码页。
|
||||
- `background/steps/oauth-login.js`:步骤 7 实现,负责刷新 OAuth 链接、登录和确保进入验证码页;普通可恢复登录态失败会按上限重试,但一旦识别到认证流程进入 `add-phone / 手机号页`,会立即退出步骤 7 内部重试。
|
||||
- `background/steps/open-chatgpt.js`:步骤 1 实现,负责打开 ChatGPT 官网并确认入口就绪。
|
||||
- `background/steps/platform-verify.js`:步骤 10 实现,负责 CPA / SUB2API 回调验证。
|
||||
- `background/steps/registry.js`:步骤注册表工厂,负责用稳定的步骤元数据映射到执行器。
|
||||
@@ -143,7 +143,7 @@
|
||||
- `tests/background-signup-step2-branching.test.js`:测试在 Gmail / 2925 模式下,已有兼容别名邮箱时应直接复用,不应再次重生成。
|
||||
- `tests/background-step-modules.test.js`:测试步骤模块文件都已由后台入口加载。
|
||||
- `tests/background-step5-submit-short-circuit.test.js`:测试步骤 5 会把生成好的资料直接转发给内容脚本,并依赖完成信号收尾。
|
||||
- `tests/background-step6-retry-limit.test.js`:测试步骤 6 的 Cookie 清理,以及步骤 7 的有限重试上限。
|
||||
- `tests/background-step6-retry-limit.test.js`:测试步骤 6 的 Cookie 清理,以及步骤 7 的有限重试上限与 `add-phone` 命中后的立即跳出行为。
|
||||
- `tests/background-step7-recovery.test.js`:测试步骤 8 获取登录验证码后直接提交(不再回放步骤 7),并为 2925 关闭重发间隔。
|
||||
- `tests/background-step-registry.test.js`:测试后台步骤注册表和共享步骤定义已接入。
|
||||
- `tests/background-tab-runtime-module.test.js`:测试标签运行时模块已接入且导出工厂,并覆盖等待标签完成时的 Stop 中断行为。
|
||||
|
||||
Reference in New Issue
Block a user