fix: improve iCloud polling and add-phone handoff
This commit is contained in:
@@ -18,6 +18,8 @@
|
||||
},
|
||||
isStep6RecoverableResult,
|
||||
isStep6SuccessResult,
|
||||
getTabId,
|
||||
phoneVerificationHelpers = null,
|
||||
refreshOAuthUrlBeforeStep6,
|
||||
reuseOrCreateTab,
|
||||
sendToContentScriptResilient,
|
||||
@@ -74,6 +76,49 @@
|
||||
return normalizeStep7IdentifierType(fallbackType) || 'email';
|
||||
}
|
||||
|
||||
function extractAddPhoneUrl(error) {
|
||||
const message = String(typeof error === 'string' ? error : error?.message || '');
|
||||
const match = message.match(/https:\/\/auth\.openai\.com\/add-phone(?:[^\s]*)?/i);
|
||||
return match ? match[0] : 'https://auth.openai.com/add-phone';
|
||||
}
|
||||
|
||||
async function completeStep7AddPhoneHandoff(state = {}, err, completionStep) {
|
||||
if (!state?.phoneVerificationEnabled) {
|
||||
throw new Error(
|
||||
`步骤 ${completionStep}:登录提交后页面进入手机号页面,必须先启用接码/phone verification 后才能继续。URL: ${extractAddPhoneUrl(err)}`
|
||||
);
|
||||
}
|
||||
if (typeof phoneVerificationHelpers?.completePhoneVerificationFlow !== 'function') {
|
||||
throw new Error(`步骤 ${completionStep}:手机号验证流程不可用,接码模块尚未初始化。`);
|
||||
}
|
||||
if (typeof getTabId !== 'function') {
|
||||
throw new Error(`步骤 ${completionStep}:无法定位认证页面标签页,不能继续手机号验证。`);
|
||||
}
|
||||
|
||||
const signupTabId = await getTabId('signup-page');
|
||||
if (!Number.isInteger(signupTabId)) {
|
||||
throw new Error(`步骤 ${completionStep}:认证页面标签页已关闭,无法继续手机号验证。`);
|
||||
}
|
||||
|
||||
const pageState = {
|
||||
addPhonePage: true,
|
||||
phoneVerificationPage: false,
|
||||
state: 'add_phone_page',
|
||||
url: extractAddPhoneUrl(err),
|
||||
};
|
||||
await phoneVerificationHelpers.completePhoneVerificationFlow(signupTabId, pageState, {
|
||||
step: completionStep,
|
||||
visibleStep: completionStep,
|
||||
});
|
||||
await completeStepFromBackground(completionStep, {
|
||||
loginVerificationRequestedAt: null,
|
||||
skipLoginVerificationStep: true,
|
||||
directOAuthConsentPage: true,
|
||||
phoneVerification: true,
|
||||
loginPhoneVerification: true,
|
||||
});
|
||||
}
|
||||
|
||||
async function executeStep7(state) {
|
||||
const visibleStep = Math.floor(Number(state?.visibleStep) || 0);
|
||||
const completionStep = visibleStep > 0 ? visibleStep : 7;
|
||||
@@ -218,7 +263,15 @@
|
||||
} catch (err) {
|
||||
throwIfStopped(err);
|
||||
if (isAddPhoneAuthFailure(err)) {
|
||||
throw err;
|
||||
const latestAddPhoneState = typeof getState === 'function'
|
||||
? await getState().catch(() => state)
|
||||
: state;
|
||||
await completeStep7AddPhoneHandoff(
|
||||
{ ...(state || {}), ...(latestAddPhoneState || {}) },
|
||||
err,
|
||||
completionStep
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (isManagementSecretConfigError(err)) {
|
||||
await addLog(
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
(function attachBackgroundVerificationFlow(root, factory) {
|
||||
root.MultiPageBackgroundVerificationFlow = factory();
|
||||
})(typeof self !== 'undefined' ? self : globalThis, function createBackgroundVerificationFlowModule() {
|
||||
const ICLOUD_MAIL_POLL_RESPONSE_TIMEOUT_CAP_MS = 18000;
|
||||
const ICLOUD_MAIL_POLL_TOTAL_TIMEOUT_CAP_MS = 22000;
|
||||
const ICLOUD_MAIL_POLL_MIN_ATTEMPTS = 5;
|
||||
const ICLOUD_MAIL_POLL_TIMEOUT_MARGIN_MS = 25000;
|
||||
|
||||
function createVerificationFlowHelpers(deps = {}) {
|
||||
const {
|
||||
@@ -78,30 +78,54 @@
|
||||
return step === 4 ? '注册' : '登录';
|
||||
}
|
||||
|
||||
function capIcloudMailPollingTimeouts(mail, timedPoll) {
|
||||
function isIcloudMail(mail) {
|
||||
return mail?.source === 'icloud-mail' || mail?.provider === 'icloud';
|
||||
}
|
||||
|
||||
function normalizeIcloudMailPollPayload(mail, payload = {}) {
|
||||
if (!isIcloudMail(mail)) {
|
||||
return payload;
|
||||
}
|
||||
|
||||
const currentAttempts = Math.max(1, Math.floor(Number(payload?.maxAttempts) || 1));
|
||||
if (currentAttempts >= ICLOUD_MAIL_POLL_MIN_ATTEMPTS) {
|
||||
return payload;
|
||||
}
|
||||
|
||||
return {
|
||||
...payload,
|
||||
maxAttempts: ICLOUD_MAIL_POLL_MIN_ATTEMPTS,
|
||||
};
|
||||
}
|
||||
|
||||
function getMailPollingResponseTimeoutMs(payload = {}) {
|
||||
const maxAttempts = Math.max(1, Math.floor(Number(payload?.maxAttempts) || 1));
|
||||
const intervalMs = Math.max(1, Number(payload?.intervalMs) || 3000);
|
||||
return Math.max(45000, maxAttempts * intervalMs + ICLOUD_MAIL_POLL_TIMEOUT_MARGIN_MS);
|
||||
}
|
||||
|
||||
function resolveMailPollingTimeouts(mail, timedPoll) {
|
||||
const payload = normalizeIcloudMailPollPayload(mail, timedPoll?.payload || {});
|
||||
const defaultResponseTimeoutMs = Math.max(1000, Number(timedPoll?.responseTimeoutMs) || 30000);
|
||||
const defaultTimeoutMs = Math.max(defaultResponseTimeoutMs, Number(timedPoll?.timeoutMs) || defaultResponseTimeoutMs);
|
||||
if (mail?.source !== 'icloud-mail') {
|
||||
if (!isIcloudMail(mail)) {
|
||||
return {
|
||||
payload,
|
||||
responseTimeoutMs: defaultResponseTimeoutMs,
|
||||
timeoutMs: defaultTimeoutMs,
|
||||
capped: false,
|
||||
};
|
||||
}
|
||||
|
||||
const cappedResponseTimeoutMs = Math.max(
|
||||
5000,
|
||||
Math.min(defaultResponseTimeoutMs, ICLOUD_MAIL_POLL_RESPONSE_TIMEOUT_CAP_MS)
|
||||
);
|
||||
const cappedTimeoutMs = Math.max(
|
||||
cappedResponseTimeoutMs,
|
||||
Math.min(defaultTimeoutMs, ICLOUD_MAIL_POLL_TOTAL_TIMEOUT_CAP_MS)
|
||||
const derivedResponseTimeoutMs = Math.max(
|
||||
defaultResponseTimeoutMs,
|
||||
getMailPollingResponseTimeoutMs(payload)
|
||||
);
|
||||
const derivedTimeoutMs = Math.max(defaultTimeoutMs, derivedResponseTimeoutMs);
|
||||
|
||||
return {
|
||||
responseTimeoutMs: cappedResponseTimeoutMs,
|
||||
timeoutMs: cappedTimeoutMs,
|
||||
capped: cappedResponseTimeoutMs < defaultResponseTimeoutMs || cappedTimeoutMs < defaultTimeoutMs,
|
||||
payload,
|
||||
responseTimeoutMs: derivedResponseTimeoutMs,
|
||||
timeoutMs: derivedTimeoutMs,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -707,20 +731,14 @@
|
||||
pollOverrides,
|
||||
`轮询${getVerificationCodeLabel(step)}验证码邮箱`
|
||||
);
|
||||
const timeoutWindow = capIcloudMailPollingTimeouts(mail, timedPoll);
|
||||
if (timeoutWindow.capped) {
|
||||
await addLog(
|
||||
`步骤 ${step}:iCloud 邮箱轮询已启用快速超时保护(${Math.ceil(timeoutWindow.timeoutMs / 1000)} 秒),避免页面无响应导致长时间卡住。`,
|
||||
'info'
|
||||
);
|
||||
}
|
||||
const timeoutWindow = resolveMailPollingTimeouts(mail, timedPoll);
|
||||
const result = await sendToMailContentScriptResilient(
|
||||
mail,
|
||||
{
|
||||
type: 'POLL_EMAIL',
|
||||
step,
|
||||
source: 'background',
|
||||
payload: timedPoll.payload,
|
||||
payload: timeoutWindow.payload,
|
||||
},
|
||||
{
|
||||
timeoutMs: timeoutWindow.timeoutMs,
|
||||
@@ -982,20 +1000,14 @@
|
||||
pollOverrides,
|
||||
`轮询${getVerificationCodeLabel(step)}验证码邮箱`
|
||||
);
|
||||
const timeoutWindow = capIcloudMailPollingTimeouts(mail, timedPoll);
|
||||
if (timeoutWindow.capped) {
|
||||
await addLog(
|
||||
`步骤 ${step}:iCloud 邮箱轮询已启用快速超时保护(${Math.ceil(timeoutWindow.timeoutMs / 1000)} 秒),避免页面无响应导致长时间卡住。`,
|
||||
'info'
|
||||
);
|
||||
}
|
||||
const timeoutWindow = resolveMailPollingTimeouts(mail, timedPoll);
|
||||
const result = await sendToMailContentScriptResilient(
|
||||
mail,
|
||||
{
|
||||
type: 'POLL_EMAIL',
|
||||
step,
|
||||
source: 'background',
|
||||
payload: timedPoll.payload,
|
||||
payload: timeoutWindow.payload,
|
||||
},
|
||||
{
|
||||
timeoutMs: timeoutWindow.timeoutMs,
|
||||
|
||||
Reference in New Issue
Block a user