feat(flow): stabilize step7-9, expand HeroSMS, and update usage tutorial
This commit is contained in:
+346
-1
@@ -265,6 +265,21 @@ const AUTO_STEP_DELAY_MAX_ALLOWED_SECONDS = 600;
|
||||
const VERIFICATION_RESEND_COUNT_MIN = 0;
|
||||
const VERIFICATION_RESEND_COUNT_MAX = 20;
|
||||
const DEFAULT_VERIFICATION_RESEND_COUNT = 4;
|
||||
const PHONE_REPLACEMENT_LIMIT_MIN = 1;
|
||||
const PHONE_REPLACEMENT_LIMIT_MAX = 20;
|
||||
const DEFAULT_PHONE_VERIFICATION_REPLACEMENT_LIMIT = 3;
|
||||
const PHONE_CODE_WAIT_SECONDS_MIN = 15;
|
||||
const PHONE_CODE_WAIT_SECONDS_MAX = 300;
|
||||
const DEFAULT_PHONE_CODE_WAIT_SECONDS = 60;
|
||||
const PHONE_CODE_TIMEOUT_WINDOWS_MIN = 1;
|
||||
const PHONE_CODE_TIMEOUT_WINDOWS_MAX = 10;
|
||||
const DEFAULT_PHONE_CODE_TIMEOUT_WINDOWS = 2;
|
||||
const PHONE_CODE_POLL_INTERVAL_SECONDS_MIN = 1;
|
||||
const PHONE_CODE_POLL_INTERVAL_SECONDS_MAX = 30;
|
||||
const DEFAULT_PHONE_CODE_POLL_INTERVAL_SECONDS = 5;
|
||||
const PHONE_CODE_POLL_ROUNDS_MIN = 1;
|
||||
const PHONE_CODE_POLL_ROUNDS_MAX = 120;
|
||||
const DEFAULT_PHONE_CODE_POLL_ROUNDS = 4;
|
||||
const LEGACY_AUTO_STEP_DELAY_KEYS = ['autoStepRandomDelayMinSeconds', 'autoStepRandomDelayMaxSeconds'];
|
||||
const LEGACY_VERIFICATION_RESEND_COUNT_KEYS = ['signupVerificationResendCount', 'loginVerificationResendCount'];
|
||||
const DEFAULT_LOCAL_CPA_STEP9_MODE = 'submit';
|
||||
@@ -283,6 +298,10 @@ const HERO_SMS_SERVICE_CODE = 'dr';
|
||||
const HERO_SMS_SERVICE_LABEL = 'OpenAI';
|
||||
const HERO_SMS_COUNTRY_ID = 52;
|
||||
const HERO_SMS_COUNTRY_LABEL = 'Thailand';
|
||||
const DEFAULT_HERO_SMS_REUSE_ENABLED = true;
|
||||
const HERO_SMS_ACQUIRE_PRIORITY_COUNTRY = 'country';
|
||||
const HERO_SMS_ACQUIRE_PRIORITY_PRICE = 'price';
|
||||
const DEFAULT_HERO_SMS_ACQUIRE_PRIORITY = HERO_SMS_ACQUIRE_PRIORITY_COUNTRY;
|
||||
const DISPLAY_TIMEZONE = 'Asia/Shanghai';
|
||||
const MICROSOFT_TOKEN_DNR_RULE_ID = 1001;
|
||||
const PERSISTENT_ALIAS_STATE_KEYS = [
|
||||
@@ -446,6 +465,11 @@ const PERSISTED_SETTING_DEFAULTS = {
|
||||
autoStepDelaySeconds: null,
|
||||
phoneVerificationEnabled: false,
|
||||
verificationResendCount: DEFAULT_VERIFICATION_RESEND_COUNT,
|
||||
phoneVerificationReplacementLimit: DEFAULT_PHONE_VERIFICATION_REPLACEMENT_LIMIT,
|
||||
phoneCodeWaitSeconds: DEFAULT_PHONE_CODE_WAIT_SECONDS,
|
||||
phoneCodeTimeoutWindows: DEFAULT_PHONE_CODE_TIMEOUT_WINDOWS,
|
||||
phoneCodePollIntervalSeconds: DEFAULT_PHONE_CODE_POLL_INTERVAL_SECONDS,
|
||||
phoneCodePollMaxRounds: DEFAULT_PHONE_CODE_POLL_ROUNDS,
|
||||
mailProvider: '163',
|
||||
mail2925Mode: DEFAULT_MAIL_2925_MODE,
|
||||
mail2925UseAccountPool: false,
|
||||
@@ -481,9 +505,12 @@ const PERSISTED_SETTING_DEFAULTS = {
|
||||
mail2925Accounts: [],
|
||||
paypalAccounts: [],
|
||||
heroSmsApiKey: '',
|
||||
heroSmsReuseEnabled: DEFAULT_HERO_SMS_REUSE_ENABLED,
|
||||
heroSmsAcquirePriority: DEFAULT_HERO_SMS_ACQUIRE_PRIORITY,
|
||||
heroSmsMaxPrice: '',
|
||||
heroSmsCountryId: HERO_SMS_COUNTRY_ID,
|
||||
heroSmsCountryLabel: HERO_SMS_COUNTRY_LABEL,
|
||||
heroSmsCountryFallback: [],
|
||||
};
|
||||
|
||||
const PERSISTED_SETTING_KEYS = Object.keys(PERSISTED_SETTING_DEFAULTS);
|
||||
@@ -563,7 +590,13 @@ const DEFAULT_STATE = {
|
||||
currentLuckmailPurchase: null,
|
||||
currentLuckmailMailCursor: null,
|
||||
currentPhoneActivation: null,
|
||||
currentPhoneVerificationCode: '',
|
||||
reusablePhoneActivation: null,
|
||||
heroSmsLastPriceTiers: [],
|
||||
heroSmsLastPriceCountryId: 0,
|
||||
heroSmsLastPriceCountryLabel: '',
|
||||
heroSmsLastPriceUserLimit: '',
|
||||
heroSmsLastPriceAt: 0,
|
||||
pendingPhoneActivationConfirmation: null,
|
||||
autoRunning: false, // 当前是否处于自动运行中。
|
||||
autoRunPhase: 'idle', // 当前自动运行阶段。
|
||||
@@ -664,6 +697,143 @@ function normalizeVerificationResendCount(value, fallback) {
|
||||
);
|
||||
}
|
||||
|
||||
function normalizePhoneVerificationReplacementLimit(value, fallback = DEFAULT_PHONE_VERIFICATION_REPLACEMENT_LIMIT) {
|
||||
const rawValue = String(value ?? '').trim();
|
||||
const numeric = Number(rawValue);
|
||||
if (!rawValue || !Number.isFinite(numeric)) {
|
||||
return Math.min(
|
||||
PHONE_REPLACEMENT_LIMIT_MAX,
|
||||
Math.max(PHONE_REPLACEMENT_LIMIT_MIN, Math.floor(Number(fallback) || DEFAULT_PHONE_VERIFICATION_REPLACEMENT_LIMIT))
|
||||
);
|
||||
}
|
||||
return Math.min(
|
||||
PHONE_REPLACEMENT_LIMIT_MAX,
|
||||
Math.max(PHONE_REPLACEMENT_LIMIT_MIN, Math.floor(numeric))
|
||||
);
|
||||
}
|
||||
|
||||
function normalizePhoneCodeWaitSeconds(value, fallback = DEFAULT_PHONE_CODE_WAIT_SECONDS) {
|
||||
const rawValue = String(value ?? '').trim();
|
||||
const numeric = Number(rawValue);
|
||||
if (!rawValue || !Number.isFinite(numeric)) {
|
||||
return Math.min(
|
||||
PHONE_CODE_WAIT_SECONDS_MAX,
|
||||
Math.max(PHONE_CODE_WAIT_SECONDS_MIN, Math.floor(Number(fallback) || DEFAULT_PHONE_CODE_WAIT_SECONDS))
|
||||
);
|
||||
}
|
||||
return Math.min(
|
||||
PHONE_CODE_WAIT_SECONDS_MAX,
|
||||
Math.max(PHONE_CODE_WAIT_SECONDS_MIN, Math.floor(numeric))
|
||||
);
|
||||
}
|
||||
|
||||
function normalizePhoneCodeTimeoutWindows(value, fallback = DEFAULT_PHONE_CODE_TIMEOUT_WINDOWS) {
|
||||
const rawValue = String(value ?? '').trim();
|
||||
const numeric = Number(rawValue);
|
||||
if (!rawValue || !Number.isFinite(numeric)) {
|
||||
return Math.min(
|
||||
PHONE_CODE_TIMEOUT_WINDOWS_MAX,
|
||||
Math.max(PHONE_CODE_TIMEOUT_WINDOWS_MIN, Math.floor(Number(fallback) || DEFAULT_PHONE_CODE_TIMEOUT_WINDOWS))
|
||||
);
|
||||
}
|
||||
return Math.min(
|
||||
PHONE_CODE_TIMEOUT_WINDOWS_MAX,
|
||||
Math.max(PHONE_CODE_TIMEOUT_WINDOWS_MIN, Math.floor(numeric))
|
||||
);
|
||||
}
|
||||
|
||||
function normalizePhoneCodePollIntervalSeconds(value, fallback = DEFAULT_PHONE_CODE_POLL_INTERVAL_SECONDS) {
|
||||
const rawValue = String(value ?? '').trim();
|
||||
const numeric = Number(rawValue);
|
||||
if (!rawValue || !Number.isFinite(numeric)) {
|
||||
return Math.min(
|
||||
PHONE_CODE_POLL_INTERVAL_SECONDS_MAX,
|
||||
Math.max(PHONE_CODE_POLL_INTERVAL_SECONDS_MIN, Math.floor(Number(fallback) || DEFAULT_PHONE_CODE_POLL_INTERVAL_SECONDS))
|
||||
);
|
||||
}
|
||||
return Math.min(
|
||||
PHONE_CODE_POLL_INTERVAL_SECONDS_MAX,
|
||||
Math.max(PHONE_CODE_POLL_INTERVAL_SECONDS_MIN, Math.floor(numeric))
|
||||
);
|
||||
}
|
||||
|
||||
function normalizePhoneCodePollMaxRounds(value, fallback = DEFAULT_PHONE_CODE_POLL_ROUNDS) {
|
||||
const rawValue = String(value ?? '').trim();
|
||||
const numeric = Number(rawValue);
|
||||
if (!rawValue || !Number.isFinite(numeric)) {
|
||||
return Math.min(
|
||||
PHONE_CODE_POLL_ROUNDS_MAX,
|
||||
Math.max(PHONE_CODE_POLL_ROUNDS_MIN, Math.floor(Number(fallback) || DEFAULT_PHONE_CODE_POLL_ROUNDS))
|
||||
);
|
||||
}
|
||||
return Math.min(
|
||||
PHONE_CODE_POLL_ROUNDS_MAX,
|
||||
Math.max(PHONE_CODE_POLL_ROUNDS_MIN, Math.floor(numeric))
|
||||
);
|
||||
}
|
||||
|
||||
function normalizeHeroSmsMaxPrice(value = '') {
|
||||
const rawValue = String(value ?? '').trim();
|
||||
if (!rawValue) {
|
||||
return '';
|
||||
}
|
||||
const numeric = Number(rawValue);
|
||||
if (!Number.isFinite(numeric) || numeric <= 0) {
|
||||
return '';
|
||||
}
|
||||
return String(Math.round(numeric * 10000) / 10000);
|
||||
}
|
||||
|
||||
function normalizeHeroSmsAcquirePriority(value = '') {
|
||||
return String(value || '').trim().toLowerCase() === HERO_SMS_ACQUIRE_PRIORITY_PRICE
|
||||
? HERO_SMS_ACQUIRE_PRIORITY_PRICE
|
||||
: HERO_SMS_ACQUIRE_PRIORITY_COUNTRY;
|
||||
}
|
||||
|
||||
function normalizeHeroSmsCountryFallback(value = []) {
|
||||
const source = Array.isArray(value)
|
||||
? value
|
||||
: String(value || '')
|
||||
.split(/[\r\n,,;;]+/)
|
||||
.map((entry) => String(entry || '').trim())
|
||||
.filter(Boolean);
|
||||
const seenIds = new Set();
|
||||
const normalized = [];
|
||||
|
||||
for (const entry of source) {
|
||||
let countryId = 0;
|
||||
let countryLabel = '';
|
||||
|
||||
if (entry && typeof entry === 'object' && !Array.isArray(entry)) {
|
||||
countryId = Math.floor(Number(entry.countryId ?? entry.id) || 0);
|
||||
countryLabel = String((entry.countryLabel ?? entry.label) || '').trim();
|
||||
} else {
|
||||
const text = String(entry || '').trim();
|
||||
const structuredMatch = text.match(/^(\d+)\s*(?:[:|/-]\s*(.+))?$/);
|
||||
if (structuredMatch) {
|
||||
countryId = Math.floor(Number(structuredMatch[1]) || 0);
|
||||
countryLabel = String(structuredMatch[2] || '').trim();
|
||||
} else {
|
||||
countryId = Math.floor(Number(text) || 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (!Number.isFinite(countryId) || countryId <= 0 || seenIds.has(countryId)) {
|
||||
continue;
|
||||
}
|
||||
seenIds.add(countryId);
|
||||
normalized.push({
|
||||
id: countryId,
|
||||
label: countryLabel || `Country #${countryId}`,
|
||||
});
|
||||
if (normalized.length >= 20) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return normalized;
|
||||
}
|
||||
|
||||
function resolveLegacyAutoStepDelaySeconds(input = {}) {
|
||||
const hasLegacyMin = input.autoStepRandomDelayMinSeconds !== undefined;
|
||||
const hasLegacyMax = input.autoStepRandomDelayMaxSeconds !== undefined;
|
||||
@@ -1264,6 +1434,16 @@ function normalizePersistentSettingValue(key, value) {
|
||||
return normalizeAutoStepDelaySeconds(value, PERSISTED_SETTING_DEFAULTS.autoStepDelaySeconds);
|
||||
case 'verificationResendCount':
|
||||
return normalizeVerificationResendCount(value, DEFAULT_VERIFICATION_RESEND_COUNT);
|
||||
case 'phoneVerificationReplacementLimit':
|
||||
return normalizePhoneVerificationReplacementLimit(value, DEFAULT_PHONE_VERIFICATION_REPLACEMENT_LIMIT);
|
||||
case 'phoneCodeWaitSeconds':
|
||||
return normalizePhoneCodeWaitSeconds(value, DEFAULT_PHONE_CODE_WAIT_SECONDS);
|
||||
case 'phoneCodeTimeoutWindows':
|
||||
return normalizePhoneCodeTimeoutWindows(value, DEFAULT_PHONE_CODE_TIMEOUT_WINDOWS);
|
||||
case 'phoneCodePollIntervalSeconds':
|
||||
return normalizePhoneCodePollIntervalSeconds(value, DEFAULT_PHONE_CODE_POLL_INTERVAL_SECONDS);
|
||||
case 'phoneCodePollMaxRounds':
|
||||
return normalizePhoneCodePollMaxRounds(value, DEFAULT_PHONE_CODE_POLL_ROUNDS);
|
||||
case 'mailProvider':
|
||||
return normalizeMailProvider(value);
|
||||
case 'mail2925Mode':
|
||||
@@ -1327,12 +1507,18 @@ function normalizePersistentSettingValue(key, value) {
|
||||
return normalizePayPalAccounts(value);
|
||||
case 'heroSmsApiKey':
|
||||
return String(value || '');
|
||||
case 'heroSmsReuseEnabled':
|
||||
return Boolean(value);
|
||||
case 'heroSmsAcquirePriority':
|
||||
return normalizeHeroSmsAcquirePriority(value);
|
||||
case 'heroSmsMaxPrice':
|
||||
return String(value || '').trim();
|
||||
return normalizeHeroSmsMaxPrice(value);
|
||||
case 'heroSmsCountryId':
|
||||
return Math.max(1, Math.floor(Number(value) || HERO_SMS_COUNTRY_ID));
|
||||
case 'heroSmsCountryLabel':
|
||||
return String(value || HERO_SMS_COUNTRY_LABEL).trim() || HERO_SMS_COUNTRY_LABEL;
|
||||
case 'heroSmsCountryFallback':
|
||||
return normalizeHeroSmsCountryFallback(value);
|
||||
default:
|
||||
return value;
|
||||
}
|
||||
@@ -1878,6 +2064,7 @@ async function resetState() {
|
||||
'accounts',
|
||||
'tabRegistry',
|
||||
'sourceLastUrls',
|
||||
'reusablePhoneActivation',
|
||||
'luckmailApiKey',
|
||||
'luckmailBaseUrl',
|
||||
'luckmailEmailType',
|
||||
@@ -1892,6 +2079,25 @@ async function resetState() {
|
||||
getPersistedAliasState(),
|
||||
]);
|
||||
const contributionModeState = buildContributionModeState(Boolean(prev.contributionMode), persistedSettings, prev);
|
||||
const reusablePhoneActivation = (
|
||||
prev.reusablePhoneActivation
|
||||
&& typeof prev.reusablePhoneActivation === 'object'
|
||||
&& !Array.isArray(prev.reusablePhoneActivation)
|
||||
&& String(
|
||||
prev.reusablePhoneActivation.activationId
|
||||
?? prev.reusablePhoneActivation.id
|
||||
?? prev.reusablePhoneActivation.activation
|
||||
?? ''
|
||||
).trim()
|
||||
&& String(
|
||||
prev.reusablePhoneActivation.phoneNumber
|
||||
?? prev.reusablePhoneActivation.number
|
||||
?? prev.reusablePhoneActivation.phone
|
||||
?? ''
|
||||
).trim()
|
||||
)
|
||||
? prev.reusablePhoneActivation
|
||||
: null;
|
||||
await chrome.storage.session.clear();
|
||||
await chrome.storage.session.set({
|
||||
...DEFAULT_STATE,
|
||||
@@ -1912,6 +2118,8 @@ async function resetState() {
|
||||
luckmailPreserveTagName: String(prev.luckmailPreserveTagName || '').trim() || DEFAULT_LUCKMAIL_PRESERVE_TAG_NAME,
|
||||
currentLuckmailPurchase: null,
|
||||
currentLuckmailMailCursor: null,
|
||||
// Keep reusable phone activation across round resets so the same number can be reactivated up to maxUses.
|
||||
reusablePhoneActivation,
|
||||
preferredIcloudHost: prev.preferredIcloudHost || '',
|
||||
});
|
||||
}
|
||||
@@ -6042,6 +6250,7 @@ function getDownstreamStateResets(step, state = {}) {
|
||||
lastSignupCode: null,
|
||||
lastLoginCode: null,
|
||||
localhostUrl: null,
|
||||
currentPhoneVerificationCode: '',
|
||||
};
|
||||
}
|
||||
if (step === 2) {
|
||||
@@ -6057,6 +6266,7 @@ function getDownstreamStateResets(step, state = {}) {
|
||||
lastSignupCode: null,
|
||||
lastLoginCode: null,
|
||||
localhostUrl: null,
|
||||
currentPhoneVerificationCode: '',
|
||||
};
|
||||
}
|
||||
if (step === 3 || step === 4) {
|
||||
@@ -6071,6 +6281,7 @@ function getDownstreamStateResets(step, state = {}) {
|
||||
lastSignupCode: null,
|
||||
lastLoginCode: null,
|
||||
localhostUrl: null,
|
||||
currentPhoneVerificationCode: '',
|
||||
};
|
||||
}
|
||||
if (step === 5 || step === 6 || step === 7 || step === 8) {
|
||||
@@ -6092,6 +6303,7 @@ function getDownstreamStateResets(step, state = {}) {
|
||||
oauthFlowDeadlineSourceUrl: null,
|
||||
pendingPhoneActivationConfirmation: null,
|
||||
localhostUrl: null,
|
||||
currentPhoneVerificationCode: '',
|
||||
};
|
||||
}
|
||||
if (step === 9) {
|
||||
@@ -6099,6 +6311,7 @@ function getDownstreamStateResets(step, state = {}) {
|
||||
pendingPhoneActivationConfirmation: null,
|
||||
plusReturnUrl: '',
|
||||
localhostUrl: null,
|
||||
currentPhoneVerificationCode: '',
|
||||
};
|
||||
}
|
||||
if (stepKey === 'oauth-login' || stepKey === 'fetch-login-code') {
|
||||
@@ -6109,6 +6322,7 @@ function getDownstreamStateResets(step, state = {}) {
|
||||
oauthFlowDeadlineSourceUrl: null,
|
||||
pendingPhoneActivationConfirmation: null,
|
||||
localhostUrl: null,
|
||||
currentPhoneVerificationCode: '',
|
||||
};
|
||||
}
|
||||
if (stepKey === 'confirm-oauth') {
|
||||
@@ -8598,6 +8812,11 @@ const verificationFlowHelpers = self.MultiPageBackgroundVerificationFlow?.create
|
||||
const phoneVerificationHelpers = self.MultiPageBackgroundPhoneVerification?.createPhoneVerificationHelpers({
|
||||
addLog,
|
||||
DEFAULT_HERO_SMS_BASE_URL,
|
||||
DEFAULT_HERO_SMS_REUSE_ENABLED,
|
||||
DEFAULT_PHONE_CODE_WAIT_SECONDS,
|
||||
DEFAULT_PHONE_CODE_TIMEOUT_WINDOWS,
|
||||
DEFAULT_PHONE_CODE_POLL_INTERVAL_SECONDS,
|
||||
DEFAULT_PHONE_CODE_POLL_ROUNDS,
|
||||
ensureStep8SignupPageReady,
|
||||
getOAuthFlowStepTimeoutMs,
|
||||
getState,
|
||||
@@ -9448,6 +9667,10 @@ async function getPostStep6AutoRestartDecision(step, error) {
|
||||
const hasTransientNetworkSignal = /connect:\s*connection refused|failed to fetch|i\/o timeout|context deadline exceeded|eof|connection reset by peer/i.test(normalizedMessage);
|
||||
return mentionsTokenExchange && hasTransientNetworkSignal;
|
||||
};
|
||||
const isPhoneVerificationLocalFailure = (errorMessage = '') => {
|
||||
const normalizedMessage = String(errorMessage || '');
|
||||
return /HeroSMS|phone verification did not succeed|number replacements|sms_timeout_after_resend|phone number is already linked|add-phone keeps rejecting current number|接码|手机号|手机验证码|步骤\s*9.*(?:手机号|验证码)|Step\s*9.*phone verification/i.test(normalizedMessage);
|
||||
};
|
||||
|
||||
const normalizedStep = Number(step);
|
||||
const errorMessage = getErrorMessage(error);
|
||||
@@ -9478,6 +9701,17 @@ async function getPostStep6AutoRestartDecision(step, error) {
|
||||
};
|
||||
}
|
||||
|
||||
if (isPhoneVerificationLocalFailure(errorMessage)) {
|
||||
return {
|
||||
shouldRestart: false,
|
||||
blockedByAddPhone: true,
|
||||
forcedByPhoneVerificationTimeout: false,
|
||||
restartStep: authChainStartStep,
|
||||
errorMessage,
|
||||
authState: null,
|
||||
};
|
||||
}
|
||||
|
||||
if (shouldForceRestartFromStep7) {
|
||||
return {
|
||||
shouldRestart: true,
|
||||
@@ -10080,6 +10314,116 @@ function getStep8EffectLabel(effect) {
|
||||
}
|
||||
}
|
||||
|
||||
function isStep9OAuthLocalhostTimeoutError(error, visibleStep = 9) {
|
||||
const message = getErrorMessage(error);
|
||||
if (!message) {
|
||||
return false;
|
||||
}
|
||||
if (!/从拿到 OAuth 登录地址开始/.test(message)) {
|
||||
return false;
|
||||
}
|
||||
if (!/localhost 回调|OAuth localhost 回调/i.test(message)) {
|
||||
return false;
|
||||
}
|
||||
const normalizedStep = Number(visibleStep);
|
||||
if (Number.isFinite(normalizedStep) && normalizedStep > 0) {
|
||||
const stepPrefix = new RegExp(`步骤\\s*${normalizedStep}\\s*:`);
|
||||
if (!stepPrefix.test(message)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
async function recoverOAuthLocalhostTimeout(details = {}) {
|
||||
const {
|
||||
error,
|
||||
state,
|
||||
visibleStep = 9,
|
||||
} = details;
|
||||
|
||||
if (!isStep9OAuthLocalhostTimeoutError(error, visibleStep)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const authLoginStep = typeof getAuthChainStartStepId === 'function'
|
||||
? getAuthChainStartStepId(state || {})
|
||||
: FINAL_OAUTH_CHAIN_START_STEP;
|
||||
const loginCodeStep = Number(visibleStep) >= 12 ? 11 : 8;
|
||||
|
||||
await addLog(
|
||||
`步骤 ${visibleStep}:检测到 OAuth localhost 回调等待窗口已过期,正在复核认证页并回到步骤 ${authLoginStep} 重拉授权链路。`,
|
||||
'warn'
|
||||
);
|
||||
|
||||
let authState = null;
|
||||
try {
|
||||
authState = await getLoginAuthStateFromContent({
|
||||
timeoutMs: 10000,
|
||||
responseTimeoutMs: 10000,
|
||||
logMessage: `步骤 ${visibleStep}:正在复核认证页状态,确认是否可自动恢复 localhost 回调链路...`,
|
||||
});
|
||||
} catch (inspectError) {
|
||||
await addLog(
|
||||
`步骤 ${visibleStep}:复核认证页状态失败(${getErrorMessage(inspectError)}),将先尝试按步骤 ${loginCodeStep} 收尾恢复。`,
|
||||
'warn'
|
||||
);
|
||||
}
|
||||
|
||||
if (isAddPhoneAuthState(authState)) {
|
||||
const stateLabel = getLoginAuthStateLabel(authState.state);
|
||||
await addLog(
|
||||
`步骤 ${visibleStep}:当前认证页为 ${stateLabel},将直接回到步骤 ${authLoginStep} 重新拉起授权链路,避免步骤 8/9 恢复冲突。`,
|
||||
'warn'
|
||||
);
|
||||
} else if (authState && authState.state && !['verification_page', 'oauth_consent_page'].includes(authState.state)) {
|
||||
const stateLabel = getLoginAuthStateLabel(authState.state);
|
||||
await addLog(
|
||||
`步骤 ${visibleStep}:当前认证页为 ${stateLabel},不满足快速恢复条件,将回到步骤 ${authLoginStep} 重开授权链路。`,
|
||||
'warn'
|
||||
);
|
||||
}
|
||||
|
||||
const latestState = await getState();
|
||||
if (!step7Executor?.executeStep7 || !step8Executor?.executeStep8) {
|
||||
return null;
|
||||
}
|
||||
|
||||
await addLog(
|
||||
`步骤 ${visibleStep}:正在自动重开步骤 ${authLoginStep} -> ${loginCodeStep},恢复到可继续捕获 localhost 回调的状态。`,
|
||||
'warn'
|
||||
);
|
||||
await step7Executor.executeStep7({
|
||||
...latestState,
|
||||
visibleStep: authLoginStep,
|
||||
});
|
||||
|
||||
const stateAfterStep7 = await getState();
|
||||
await step8Executor.executeStep8({
|
||||
...stateAfterStep7,
|
||||
visibleStep: loginCodeStep,
|
||||
});
|
||||
|
||||
const recoveredState = await getState();
|
||||
const oauthUrl = String(recoveredState?.oauthUrl || state?.oauthUrl || '').trim();
|
||||
if (oauthUrl && typeof startOAuthFlowTimeoutWindow === 'function') {
|
||||
await startOAuthFlowTimeoutWindow({
|
||||
step: Number(visibleStep) || 9,
|
||||
oauthUrl,
|
||||
});
|
||||
}
|
||||
|
||||
await setState({
|
||||
localhostUrl: null,
|
||||
});
|
||||
|
||||
await addLog(
|
||||
`步骤 ${visibleStep}:已恢复到步骤 ${authLoginStep} -> ${loginCodeStep} 收尾状态,并刷新 OAuth localhost 回调等待窗口,准备重试当前步骤。`,
|
||||
'warn'
|
||||
);
|
||||
return await getState();
|
||||
}
|
||||
|
||||
const step9Executor = self.MultiPageBackgroundStep9?.createStep9Executor({
|
||||
addLog,
|
||||
chrome,
|
||||
@@ -10097,6 +10441,7 @@ const step9Executor = self.MultiPageBackgroundStep9?.createStep9Executor({
|
||||
getStep8TabUpdatedListener,
|
||||
isTabAlive,
|
||||
prepareStep8DebuggerClick,
|
||||
recoverOAuthLocalhostTimeout,
|
||||
reloadStep8ConsentPage,
|
||||
reuseOrCreateTab,
|
||||
setStep8PendingReject,
|
||||
|
||||
Reference in New Issue
Block a user