fix: route SMS send rejection through phone restart helper
- Merge latest dev into the PR branch before applying the maintainer fix - Expose the phone resend banned classifier from phone verification helpers - Use the helper from auto-run step 4 and keep restart logs reason-specific
This commit is contained in:
+211
-8
@@ -48,6 +48,8 @@ importScripts(
|
||||
'microsoft-email.js',
|
||||
'luckmail-utils.js',
|
||||
'cloudflare-temp-email-utils.js',
|
||||
'cloudmail-utils.js',
|
||||
'background/cloudmail-provider.js',
|
||||
'icloud-utils.js',
|
||||
'mail-provider-utils.js',
|
||||
'content/activation-utils.js'
|
||||
@@ -168,6 +170,17 @@ const {
|
||||
normalizeCloudflareTempEmailDomains,
|
||||
normalizeCloudflareTempEmailMailApiMessages,
|
||||
} = self.CloudflareTempEmailUtils;
|
||||
const {
|
||||
DEFAULT_MAIL_PAGE_SIZE: CLOUD_MAIL_DEFAULT_PAGE_SIZE,
|
||||
buildCloudMailHeaders,
|
||||
getCloudMailTokenFromResponse,
|
||||
joinCloudMailUrl,
|
||||
normalizeCloudMailAddress,
|
||||
normalizeCloudMailBaseUrl,
|
||||
normalizeCloudMailDomain,
|
||||
normalizeCloudMailDomains,
|
||||
normalizeCloudMailMailApiMessages,
|
||||
} = self.CloudMailUtils;
|
||||
const {
|
||||
findIcloudAliasByEmail,
|
||||
getConfiguredIcloudHostPreference,
|
||||
@@ -224,6 +237,8 @@ const HOTMAIL_PROVIDER = 'hotmail-api';
|
||||
const LUCKMAIL_PROVIDER = 'luckmail-api';
|
||||
const CLOUDFLARE_TEMP_EMAIL_PROVIDER = 'cloudflare-temp-email';
|
||||
const CLOUDFLARE_TEMP_EMAIL_GENERATOR = 'cloudflare-temp-email';
|
||||
const CLOUD_MAIL_PROVIDER = 'cloudmail';
|
||||
const CLOUD_MAIL_GENERATOR = 'cloudmail';
|
||||
const CUSTOM_EMAIL_POOL_GENERATOR = 'custom-pool';
|
||||
const HOTMAIL_MAILBOXES = ['INBOX', 'Junk'];
|
||||
const STOP_ERROR_MESSAGE = '流程已被用户停止。';
|
||||
@@ -378,8 +393,18 @@ const FIVE_SIM_COUNTRY_ID = 'vietnam';
|
||||
const FIVE_SIM_COUNTRY_LABEL = '越南 (Vietnam)';
|
||||
const FIVE_SIM_SUPPORTED_COUNTRY_IDS = ['indonesia', 'thailand', 'vietnam'];
|
||||
const FIVE_SIM_SUPPORTED_COUNTRY_ID_SET = new Set(FIVE_SIM_SUPPORTED_COUNTRY_IDS);
|
||||
const HERO_SMS_SUPPORTED_COUNTRY_IDS = [6, 52, 10];
|
||||
const HERO_SMS_SUPPORTED_COUNTRY_IDS = [6, 52, 187, 16, 151, 43, 73, 10];
|
||||
const HERO_SMS_SUPPORTED_COUNTRY_ID_SET = new Set(HERO_SMS_SUPPORTED_COUNTRY_IDS.map(String));
|
||||
const HERO_SMS_COUNTRY_BY_PHONE_PREFIX = Object.freeze([
|
||||
{ prefix: '84', id: 10, label: 'Vietnam' },
|
||||
{ prefix: '66', id: 52, label: 'Thailand' },
|
||||
{ prefix: '62', id: 6, label: 'Indonesia' },
|
||||
{ prefix: '44', id: 16, label: 'United Kingdom' },
|
||||
{ prefix: '81', id: 151, label: 'Japan' },
|
||||
{ prefix: '49', id: 43, label: 'Germany' },
|
||||
{ prefix: '33', id: 73, label: 'France' },
|
||||
{ prefix: '1', id: 187, label: 'USA' },
|
||||
]);
|
||||
const FIVE_SIM_OPERATOR = DEFAULT_FIVE_SIM_OPERATOR;
|
||||
const PLUS_PAYMENT_METHOD_PAYPAL = 'paypal';
|
||||
const PLUS_PAYMENT_METHOD_GOPAY = 'gopay';
|
||||
@@ -698,6 +723,13 @@ const PERSISTED_SETTING_DEFAULTS = {
|
||||
cloudflareTempEmailUseRandomSubdomain: false,
|
||||
cloudflareTempEmailDomain: '',
|
||||
cloudflareTempEmailDomains: [],
|
||||
cloudMailBaseUrl: '',
|
||||
cloudMailAdminEmail: '',
|
||||
cloudMailAdminPassword: '',
|
||||
cloudMailToken: '',
|
||||
cloudMailReceiveMailbox: '',
|
||||
cloudMailDomain: '',
|
||||
cloudMailDomains: [],
|
||||
hotmailAccounts: [],
|
||||
mail2925Accounts: [],
|
||||
paypalAccounts: [],
|
||||
@@ -1690,6 +1722,7 @@ function normalizeEmailGenerator(value = '') {
|
||||
}
|
||||
if (normalized === 'cloudflare') return 'cloudflare';
|
||||
if (normalized === CLOUDFLARE_TEMP_EMAIL_GENERATOR) return CLOUDFLARE_TEMP_EMAIL_GENERATOR;
|
||||
if (normalized === 'cloudmail') return 'cloudmail';
|
||||
return 'duck';
|
||||
}
|
||||
|
||||
@@ -1923,6 +1956,7 @@ function normalizeMailProvider(value = '') {
|
||||
case HOTMAIL_PROVIDER:
|
||||
case LUCKMAIL_PROVIDER:
|
||||
case CLOUDFLARE_TEMP_EMAIL_PROVIDER:
|
||||
case CLOUD_MAIL_PROVIDER:
|
||||
case '163':
|
||||
case '163-vip':
|
||||
case '126':
|
||||
@@ -2118,6 +2152,34 @@ function resolveCloudflareTempEmailPollTargetEmail(state = {}, pollPayload = {},
|
||||
return normalizeCloudflareTempEmailReceiveMailbox(state.email);
|
||||
}
|
||||
|
||||
const cloudMailProvider = self.MultiPageBackgroundCloudMailProvider.createCloudMailProvider({
|
||||
addLog,
|
||||
buildCloudMailHeaders,
|
||||
CLOUD_MAIL_DEFAULT_PAGE_SIZE,
|
||||
CLOUD_MAIL_GENERATOR,
|
||||
CLOUD_MAIL_PROVIDER,
|
||||
getCloudMailTokenFromResponse,
|
||||
getState,
|
||||
joinCloudMailUrl,
|
||||
normalizeCloudMailAddress,
|
||||
normalizeCloudMailBaseUrl,
|
||||
normalizeCloudMailDomain,
|
||||
normalizeCloudMailDomains,
|
||||
normalizeCloudMailMailApiMessages,
|
||||
pickVerificationMessageWithTimeFallback,
|
||||
setEmailState,
|
||||
setPersistentSettings,
|
||||
sleepWithStop,
|
||||
throwIfStopped,
|
||||
});
|
||||
const {
|
||||
getCloudMailConfig,
|
||||
normalizeCloudMailReceiveMailbox,
|
||||
fetchCloudMailAddress,
|
||||
pollCloudMailVerificationCode,
|
||||
resolveCloudMailPollTargetEmail,
|
||||
} = cloudMailProvider;
|
||||
|
||||
function normalizeSub2ApiGroupNames(value = '') {
|
||||
const source = Array.isArray(value)
|
||||
? value
|
||||
@@ -2454,6 +2516,19 @@ function normalizePersistentSettingValue(key, value) {
|
||||
return normalizeCloudflareTempEmailDomain(value);
|
||||
case 'cloudflareTempEmailDomains':
|
||||
return normalizeCloudflareTempEmailDomains(value);
|
||||
case 'cloudMailBaseUrl':
|
||||
return normalizeCloudMailBaseUrl(value);
|
||||
case 'cloudMailAdminEmail':
|
||||
return String(value || '').trim();
|
||||
case 'cloudMailAdminPassword':
|
||||
case 'cloudMailToken':
|
||||
return String(value || '');
|
||||
case 'cloudMailReceiveMailbox':
|
||||
return normalizeCloudMailReceiveMailbox(value);
|
||||
case 'cloudMailDomain':
|
||||
return normalizeCloudMailDomain(value);
|
||||
case 'cloudMailDomains':
|
||||
return normalizeCloudMailDomains(value);
|
||||
case 'hotmailAccounts':
|
||||
return normalizeHotmailAccounts(value);
|
||||
case 'mail2925Accounts':
|
||||
@@ -2563,6 +2638,13 @@ function buildPersistentSettingsPayload(input = {}, options = {}) {
|
||||
}
|
||||
payload.cloudflareTempEmailDomains = domains;
|
||||
}
|
||||
if (payload.cloudMailDomains) {
|
||||
const domains = normalizeCloudMailDomains(payload.cloudMailDomains);
|
||||
if (payload.cloudMailDomain && !domains.includes(payload.cloudMailDomain)) {
|
||||
domains.unshift(payload.cloudMailDomain);
|
||||
}
|
||||
payload.cloudMailDomains = domains;
|
||||
}
|
||||
if (
|
||||
Object.prototype.hasOwnProperty.call(payload, 'sub2apiGroupName')
|
||||
|| Object.prototype.hasOwnProperty.call(payload, 'sub2apiGroupNames')
|
||||
@@ -6708,19 +6790,117 @@ async function clearFreeReusablePhoneActivation() {
|
||||
return { ok: true, freeReusablePhoneActivation: null };
|
||||
}
|
||||
|
||||
function inferHeroSmsCountryFromPhoneNumber(phoneNumber = '') {
|
||||
const digits = String(phoneNumber || '').replace(/\D+/g, '');
|
||||
if (!digits) {
|
||||
return null;
|
||||
}
|
||||
const match = HERO_SMS_COUNTRY_BY_PHONE_PREFIX.find((entry) => digits.startsWith(entry.prefix));
|
||||
if (!match) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
id: Math.max(1, Math.floor(Number(match.id) || 0)),
|
||||
label: String(match.label || '').trim() || `Country #${match.id}`,
|
||||
};
|
||||
}
|
||||
|
||||
function normalizePhoneDigits(value = '') {
|
||||
return String(value || '').replace(/\D+/g, '');
|
||||
}
|
||||
|
||||
function phoneNumbersMatch(left = '', right = '') {
|
||||
const leftDigits = normalizePhoneDigits(left);
|
||||
const rightDigits = normalizePhoneDigits(right);
|
||||
return Boolean(leftDigits && rightDigits && leftDigits === rightDigits);
|
||||
}
|
||||
|
||||
function normalizeLocalHeroSmsActivation(record) {
|
||||
if (!record || typeof record !== 'object' || Array.isArray(record)) {
|
||||
return null;
|
||||
}
|
||||
const activationId = String(record.activationId ?? record.id ?? record.activation ?? '').trim();
|
||||
const phoneNumber = String(record.phoneNumber ?? record.number ?? record.phone ?? '').trim();
|
||||
if (!activationId || !phoneNumber) {
|
||||
return null;
|
||||
}
|
||||
const rawProvider = String(record.provider ?? record.smsProvider ?? '').trim();
|
||||
const provider = rawProvider ? normalizePhoneSmsProvider(rawProvider) : PHONE_SMS_PROVIDER_HERO;
|
||||
if (provider !== PHONE_SMS_PROVIDER_HERO) {
|
||||
return null;
|
||||
}
|
||||
const countryId = Math.max(
|
||||
0,
|
||||
Math.floor(Number(record.countryId ?? record.country ?? record.countryCode) || 0)
|
||||
);
|
||||
const countryLabel = String(record.countryLabel || record.label || '').trim();
|
||||
const serviceCode = String(record.serviceCode || record.service || HERO_SMS_SERVICE_CODE).trim() || HERO_SMS_SERVICE_CODE;
|
||||
return {
|
||||
...record,
|
||||
provider: PHONE_SMS_PROVIDER_HERO,
|
||||
activationId,
|
||||
phoneNumber,
|
||||
serviceCode,
|
||||
...(countryId > 0 ? { countryId } : {}),
|
||||
...(countryLabel ? { countryLabel } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
function findLocalHeroSmsActivationForPhone(state = {}, phoneNumber = '') {
|
||||
const candidates = [
|
||||
state.currentPhoneActivation,
|
||||
state.reusablePhoneActivation,
|
||||
state.pendingPhoneActivationConfirmation,
|
||||
state.signupPhoneActivation,
|
||||
state.signupPhoneCompletedActivation,
|
||||
state.phonePreferredActivation,
|
||||
state.freeReusablePhoneActivation,
|
||||
];
|
||||
if (Array.isArray(state.phoneReusableActivationPool)) {
|
||||
candidates.push(...state.phoneReusableActivationPool);
|
||||
}
|
||||
for (const candidate of candidates) {
|
||||
const normalized = normalizeLocalHeroSmsActivation(candidate);
|
||||
if (normalized && phoneNumbersMatch(normalized.phoneNumber, phoneNumber)) {
|
||||
return normalized;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
async function setFreeReusablePhoneActivation(record = {}) {
|
||||
const phoneNumber = String(record.phoneNumber || record.number || record.phone || '').trim();
|
||||
if (!phoneNumber) {
|
||||
throw new Error('请先填写白嫖复用手机号。');
|
||||
}
|
||||
const state = await getState();
|
||||
const activationId = String(record.activationId || record.id || record.activation || '').trim();
|
||||
const countryId = Math.max(1, Math.floor(Number(record.countryId) || Number(state.heroSmsCountryId) || HERO_SMS_COUNTRY_ID));
|
||||
const localActivation = findLocalHeroSmsActivationForPhone(state, phoneNumber);
|
||||
const activationId = String(
|
||||
record.activationId
|
||||
|| record.id
|
||||
|| record.activation
|
||||
|| localActivation?.activationId
|
||||
|| ''
|
||||
).trim();
|
||||
const inferredCountry = inferHeroSmsCountryFromPhoneNumber(phoneNumber);
|
||||
const hasExplicitCountry = Number.isFinite(Number(record.countryId)) && Number(record.countryId) > 0;
|
||||
const countryId = Math.max(
|
||||
1,
|
||||
Math.floor(
|
||||
Number(record.countryId)
|
||||
|| Number(localActivation?.countryId)
|
||||
|| Number(inferredCountry?.id)
|
||||
|| Number(state.heroSmsCountryId)
|
||||
|| HERO_SMS_COUNTRY_ID
|
||||
)
|
||||
);
|
||||
const stateCountryLabel = Math.floor(Number(state.heroSmsCountryId) || 0) === countryId
|
||||
? String(state.heroSmsCountryLabel || '').trim()
|
||||
: '';
|
||||
const countryLabel = String(
|
||||
record.countryLabel
|
||||
|| (Number(localActivation?.countryId) === countryId ? localActivation?.countryLabel : '')
|
||||
|| (!hasExplicitCountry && inferredCountry?.id === countryId ? inferredCountry.label : '')
|
||||
|| stateCountryLabel
|
||||
|| (countryId === HERO_SMS_COUNTRY_ID ? HERO_SMS_COUNTRY_LABEL : `Country #${countryId}`)
|
||||
).trim();
|
||||
@@ -6728,7 +6908,7 @@ async function setFreeReusablePhoneActivation(record = {}) {
|
||||
...(activationId ? { activationId } : {}),
|
||||
phoneNumber,
|
||||
provider: PHONE_SMS_PROVIDER_HERO,
|
||||
serviceCode: HERO_SMS_SERVICE_CODE,
|
||||
serviceCode: String(record.serviceCode || localActivation?.serviceCode || HERO_SMS_SERVICE_CODE).trim() || HERO_SMS_SERVICE_CODE,
|
||||
countryId,
|
||||
...(countryLabel ? { countryLabel } : {}),
|
||||
successfulUses: Math.max(0, Math.floor(Number(record.successfulUses) || 0)),
|
||||
@@ -7231,6 +7411,7 @@ function getSourceLabel(source) {
|
||||
'hotmail-api': 'Hotmail(API对接/本地助手)',
|
||||
'luckmail-api': 'LuckMail(API 购邮)',
|
||||
'cloudflare-temp-email': 'Cloudflare Temp Email',
|
||||
'cloudmail': 'Cloud Mail',
|
||||
'plus-checkout': 'Plus Checkout',
|
||||
'paypal-flow': 'PayPal 授权页',
|
||||
};
|
||||
@@ -7495,12 +7676,20 @@ async function restartSignupPhonePasswordMismatchAttemptFromStep(step, restartCo
|
||||
} = getSignupPhonePasswordMismatchRestartPayload(preservedState);
|
||||
const emailSuffix = preservedEmail ? `当前邮箱:${preservedEmail};` : '';
|
||||
const phoneSuffix = activeSignupPhoneNumber ? `当前手机号:${activeSignupPhoneNumber};` : '';
|
||||
const errorMessage = getErrorMessage(error);
|
||||
const reasonLabel = /PHONE_RESEND_BANNED_NUMBER::|无法向此(?:电话|手机)号码发送短信|无法发送短信到此(?:电话|手机)号码|unable\s+to\s+send\s+(?:an?\s+)?(?:sms|text(?:\s+message)?)\s+to\s+(?:this|that)\s+(?:phone\s+)?number/i
|
||||
.test(errorMessage)
|
||||
? '当前注册手机号无法接收短信'
|
||||
: (/与此(?:电话|手机)号码相关联的帐户已存在|account\s+associated\s+with\s+this\s+phone\s+number\s+already\s+exists/i
|
||||
.test(errorMessage)
|
||||
? '注册手机号异常'
|
||||
: '手机号/密码不匹配');
|
||||
await addLog(
|
||||
`步骤 ${step}:检测到手机号/密码不匹配,准备丢弃当前注册手机号并回到步骤 1 重新开始(第 ${restartCount} 次重开)。${phoneSuffix}${emailSuffix}原因:${getErrorMessage(error)}`,
|
||||
`步骤 ${step}:检测到${reasonLabel},准备丢弃当前注册手机号并回到步骤 1 重新开始(第 ${restartCount} 次重开)。${phoneSuffix}${emailSuffix}原因:${errorMessage}`,
|
||||
'warn'
|
||||
);
|
||||
await invalidateDownstreamAfterStepRestart(1, {
|
||||
logLabel: `步骤 ${step} 检测到手机号/密码不匹配后准备回到步骤 1 重新获取手机号重试(第 ${restartCount} 次重开)`,
|
||||
logLabel: `步骤 ${step} 检测到${reasonLabel}后准备回到步骤 1 重新获取手机号重试(第 ${restartCount} 次重开)`,
|
||||
});
|
||||
if (shouldClearSignupPhoneRuntime) {
|
||||
await addLog(`步骤 ${step}:已清空本轮注册手机号与接码订单,下一次重开将重新获取号码。`, 'warn');
|
||||
@@ -9239,6 +9428,7 @@ function getEmailGeneratorLabel(generator) {
|
||||
}
|
||||
if (generator === 'cloudflare') return 'Cloudflare 邮箱';
|
||||
if (generator === CLOUDFLARE_TEMP_EMAIL_GENERATOR) return 'Cloudflare Temp Email';
|
||||
if (generator === CLOUD_MAIL_GENERATOR) return 'Cloud Mail';
|
||||
return 'Duck 邮箱';
|
||||
}
|
||||
const mail2925SessionManager = self.MultiPageBackgroundMail2925Session?.createMail2925SessionManager({
|
||||
@@ -9412,6 +9602,11 @@ async function fetchDuckEmail(options = {}) {
|
||||
}
|
||||
|
||||
async function fetchGeneratedEmail(state, options = {}) {
|
||||
const currentState = state || await getState();
|
||||
const generator = normalizeEmailGenerator(options.generator ?? currentState.emailGenerator);
|
||||
if (generator === CLOUD_MAIL_GENERATOR) {
|
||||
return fetchCloudMailAddress(currentState, options);
|
||||
}
|
||||
return generatedEmailHelpers.fetchGeneratedEmail(state, options);
|
||||
}
|
||||
|
||||
@@ -10317,8 +10512,9 @@ async function runAutoSequenceFromStep(startStep, context = {}) {
|
||||
throw err;
|
||||
}
|
||||
step4RestartCount += 1;
|
||||
const isPhoneResendBanned = typeof isPhoneResendBannedNumberError === 'function'
|
||||
&& isPhoneResendBannedNumberError(err);
|
||||
const isPhoneResendBanned = typeof phoneVerificationHelpers !== 'undefined'
|
||||
&& typeof phoneVerificationHelpers?.isPhoneResendBannedNumberError === 'function'
|
||||
&& phoneVerificationHelpers.isPhoneResendBannedNumberError(err);
|
||||
if (isSignupPhonePasswordMismatchFailure(err) || isPhoneResendBanned) {
|
||||
await restartSignupPhonePasswordMismatchAttemptFromStep(4, step4RestartCount, err);
|
||||
} else {
|
||||
@@ -10554,6 +10750,7 @@ const verificationFlowHelpers = self.MultiPageBackgroundVerificationFlow?.create
|
||||
chrome,
|
||||
closeConflictingTabsForSource,
|
||||
CLOUDFLARE_TEMP_EMAIL_PROVIDER,
|
||||
CLOUD_MAIL_PROVIDER,
|
||||
completeStepFromBackground,
|
||||
confirmCustomVerificationStepBypassRequest: (step) => chrome.runtime.sendMessage({
|
||||
type: 'REQUEST_CUSTOM_VERIFICATION_BYPASS_CONFIRMATION',
|
||||
@@ -10572,6 +10769,7 @@ const verificationFlowHelpers = self.MultiPageBackgroundVerificationFlow?.create
|
||||
MAIL_2925_VERIFICATION_INTERVAL_MS,
|
||||
MAIL_2925_VERIFICATION_MAX_ATTEMPTS,
|
||||
pollCloudflareTempEmailVerificationCode,
|
||||
pollCloudMailVerificationCode,
|
||||
pollHotmailVerificationCode,
|
||||
pollLuckmailVerificationCode,
|
||||
sendToContentScript,
|
||||
@@ -10677,6 +10875,7 @@ const step4Executor = self.MultiPageBackgroundStep4?.createStep4Executor({
|
||||
isTabAlive,
|
||||
LUCKMAIL_PROVIDER,
|
||||
CLOUDFLARE_TEMP_EMAIL_PROVIDER,
|
||||
CLOUD_MAIL_PROVIDER,
|
||||
resolveVerificationStep: verificationFlowHelpers.resolveVerificationStep,
|
||||
reuseOrCreateTab,
|
||||
sendToContentScript,
|
||||
@@ -10724,6 +10923,7 @@ const step8Executor = self.MultiPageBackgroundStep8?.createStep8Executor({
|
||||
addLog,
|
||||
chrome,
|
||||
CLOUDFLARE_TEMP_EMAIL_PROVIDER,
|
||||
CLOUD_MAIL_PROVIDER,
|
||||
completeStepFromBackground,
|
||||
confirmCustomVerificationStepBypass: verificationFlowHelpers.confirmCustomVerificationStepBypass,
|
||||
ensureMail2925MailboxSession,
|
||||
@@ -11141,6 +11341,9 @@ function getMailConfig(state) {
|
||||
if (provider === CLOUDFLARE_TEMP_EMAIL_PROVIDER) {
|
||||
return { provider: CLOUDFLARE_TEMP_EMAIL_PROVIDER, label: 'Cloudflare Temp Email' };
|
||||
}
|
||||
if (provider === 'cloudmail') {
|
||||
return { provider: 'cloudmail', label: 'Cloud Mail' };
|
||||
}
|
||||
if (provider === '163') {
|
||||
return { source: 'mail-163', url: 'https://mail.163.com/js6/main.jsp?df=mail163_letter#module=mbox.ListModule%7C%7B%22fid%22%3A1%2C%22order%22%3A%22date%22%2C%22desc%22%3Atrue%7D', label: '163 邮箱' };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user