feat: add phone verification flow support

This commit is contained in:
sh2001sh
2026-04-20 17:39:01 +08:00
parent d85f7feaef
commit b098726a6f
13 changed files with 2001 additions and 21 deletions
+56 -2
View File
@@ -3,6 +3,7 @@
importScripts(
'managed-alias-utils.js',
'mail2925-utils.js',
'background/phone-verification-flow.js',
'background/account-run-history.js',
'background/contribution-oauth.js',
'background/mail-2925-session.js',
@@ -184,6 +185,11 @@ const DEFAULT_HOTMAIL_LOCAL_BASE_URL = 'http://127.0.0.1:17373';
const DEFAULT_ACCOUNT_RUN_HISTORY_HELPER_BASE_URL = DEFAULT_HOTMAIL_LOCAL_BASE_URL;
const HOTMAIL_LOCAL_HELPER_TIMEOUT_MS = 45000;
const DEFAULT_LUCKMAIL_PROJECT_CODE = 'openai';
const DEFAULT_HERO_SMS_BASE_URL = 'https://hero-sms.com/stubs/handler_api.php';
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 DISPLAY_TIMEZONE = 'Asia/Shanghai';
const MICROSOFT_TOKEN_DNR_RULE_ID = 1001;
const PERSISTENT_ALIAS_STATE_KEYS = ['manualAliasUsage', 'preservedAliases'];
@@ -284,6 +290,9 @@ const PERSISTED_SETTING_DEFAULTS = {
cloudflareTempEmailDomains: [],
hotmailAccounts: [],
mail2925Accounts: [],
heroSmsApiKey: '',
heroSmsCountryId: HERO_SMS_COUNTRY_ID,
heroSmsCountryLabel: HERO_SMS_COUNTRY_LABEL,
};
const PERSISTED_SETTING_KEYS = Object.keys(PERSISTED_SETTING_DEFAULTS);
@@ -341,6 +350,8 @@ const DEFAULT_STATE = {
luckmailPreserveTagName: DEFAULT_LUCKMAIL_PRESERVE_TAG_NAME,
currentLuckmailPurchase: null,
currentLuckmailMailCursor: null,
currentPhoneActivation: null,
reusablePhoneActivation: null,
autoRunning: false, // 当前是否处于自动运行中。
autoRunPhase: 'idle', // 当前自动运行阶段。
autoRunCurrentRun: 0, // 自动运行当前执行到第几轮。
@@ -933,6 +944,12 @@ function normalizePersistentSettingValue(key, value) {
return normalizeHotmailAccounts(value);
case 'mail2925Accounts':
return normalizeMail2925Accounts(value);
case 'heroSmsApiKey':
return String(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;
default:
return value;
}
@@ -6130,7 +6147,7 @@ async function resumeAutoRun() {
// ============================================================
const SIGNUP_ENTRY_URL = 'https://chatgpt.com/';
const SIGNUP_PAGE_INJECT_FILES = ['content/utils.js', 'content/auth-page-recovery.js', 'content/signup-page.js'];
const SIGNUP_PAGE_INJECT_FILES = ['content/utils.js', 'content/auth-page-recovery.js', 'content/phone-auth.js', 'content/signup-page.js'];
const panelBridge = self.MultiPageBackgroundPanelBridge?.createPanelBridge({
chrome,
addLog,
@@ -6199,6 +6216,21 @@ const verificationFlowHelpers = self.MultiPageBackgroundVerificationFlow?.create
throwIfStopped,
VERIFICATION_POLL_MAX_ROUNDS,
});
const phoneVerificationHelpers = self.MultiPageBackgroundPhoneVerification?.createPhoneVerificationHelpers({
addLog,
DEFAULT_HERO_SMS_BASE_URL,
ensureStep8SignupPageReady,
getOAuthFlowStepTimeoutMs,
getState,
HERO_SMS_COUNTRY_ID,
HERO_SMS_COUNTRY_LABEL,
HERO_SMS_SERVICE_CODE,
HERO_SMS_SERVICE_LABEL,
sendToContentScriptResilient,
setState,
sleepWithStop,
throwIfStopped,
});
const step1Executor = self.MultiPageBackgroundStep1?.createStep1Executor({
addLog,
completeStepFromBackground,
@@ -6886,10 +6918,22 @@ function isAddPhoneAuthState(authState = {}) {
async function getPostStep6AutoRestartDecision(step, error) {
const normalizedStep = Number(step);
const errorMessage = getErrorMessage(error);
const shouldForceRestartFromStep7 = /restart step 7 with a new number/i.test(errorMessage);
if (!Number.isFinite(normalizedStep) || normalizedStep < 7 || normalizedStep > LAST_STEP_ID) {
return {
shouldRestart: false,
blockedByAddPhone: false,
forcedByPhoneVerificationTimeout: false,
errorMessage,
authState: null,
};
}
if (shouldForceRestartFromStep7) {
return {
shouldRestart: true,
blockedByAddPhone: false,
forcedByPhoneVerificationTimeout: true,
errorMessage,
authState: null,
};
@@ -6899,6 +6943,7 @@ async function getPostStep6AutoRestartDecision(step, error) {
return {
shouldRestart: false,
blockedByAddPhone: true,
forcedByPhoneVerificationTimeout: false,
errorMessage,
authState: null,
};
@@ -6921,6 +6966,7 @@ async function getPostStep6AutoRestartDecision(step, error) {
return {
shouldRestart: false,
blockedByAddPhone: true,
forcedByPhoneVerificationTimeout: false,
errorMessage,
authState,
};
@@ -6929,6 +6975,7 @@ async function getPostStep6AutoRestartDecision(step, error) {
return {
shouldRestart: true,
blockedByAddPhone: false,
forcedByPhoneVerificationTimeout: false,
errorMessage,
authState,
};
@@ -7050,7 +7097,7 @@ let step8TabUpdatedListener = null;
let step8PendingReject = null;
const STEP8_CLICK_EFFECT_TIMEOUT_MS = 15000;
const STEP8_CLICK_RETRY_DELAY_MS = 500;
const STEP8_READY_WAIT_TIMEOUT_MS = 30000;
const STEP8_READY_WAIT_TIMEOUT_MS = 180000;
const STEP8_MAX_ROUNDS = 5;
const STEP8_STRATEGIES = [
{ mode: 'content', strategy: 'requestSubmit', label: 'form.requestSubmit' },
@@ -7156,6 +7203,13 @@ async function waitForStep8Ready(tabId, timeoutMs = STEP8_READY_WAIT_TIMEOUT_MS)
if (pageState?.maxCheckAttemptsBlocked) {
throw new Error(`${CLOUDFLARE_SECURITY_BLOCK_ERROR_PREFIX}${CLOUDFLARE_SECURITY_BLOCK_USER_MESSAGE}`);
}
if (pageState?.addPhonePage || pageState?.phoneVerificationPage) {
await phoneVerificationHelpers.completePhoneVerificationFlow(tabId, pageState);
recovered = false;
retryRecovered = false;
await sleepWithStop(250);
continue;
}
if (pageState?.addPhonePage) {
throw new Error('步骤 9:认证页进入了手机号页面,当前不是 OAuth 同意页,无法继续自动授权。');
}